|
Packit |
875988 |
/*
|
|
Packit |
875988 |
This file is part of libmicrohttpd
|
|
Packit |
875988 |
Copyright (C) 2007, 2009, 2010, 2016, 2017 Daniel Pittman and Christian Grothoff
|
|
Packit |
875988 |
|
|
Packit |
875988 |
This library is free software; you can redistribute it and/or
|
|
Packit |
875988 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
875988 |
License as published by the Free Software Foundation; either
|
|
Packit |
875988 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
875988 |
|
|
Packit |
875988 |
This library is distributed in the hope that it will be useful,
|
|
Packit |
875988 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
875988 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
875988 |
Lesser General Public License for more details.
|
|
Packit |
875988 |
|
|
Packit |
875988 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
875988 |
License along with this library; if not, write to the Free Software
|
|
Packit |
875988 |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* @file response.c
|
|
Packit |
875988 |
* @brief Methods for managing response objects
|
|
Packit |
875988 |
* @author Daniel Pittman
|
|
Packit |
875988 |
* @author Christian Grothoff
|
|
Packit |
875988 |
* @author Karlson2k (Evgeny Grin)
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#define MHD_NO_DEPRECATION 1
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#include "mhd_options.h"
|
|
Packit |
875988 |
#ifdef HAVE_SYS_IOCTL_H
|
|
Packit |
875988 |
#include <sys/ioctl.h>
|
|
Packit |
875988 |
#endif /* HAVE_SYS_IOCTL_H */
|
|
Packit |
875988 |
#if defined(_WIN32) && ! defined(__CYGWIN__)
|
|
Packit |
875988 |
#include <windows.h>
|
|
Packit |
875988 |
#endif /* _WIN32 && !__CYGWIN__ */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#include "internal.h"
|
|
Packit |
875988 |
#include "response.h"
|
|
Packit |
875988 |
#include "mhd_limits.h"
|
|
Packit |
875988 |
#include "mhd_sockets.h"
|
|
Packit |
875988 |
#include "mhd_itc.h"
|
|
Packit |
875988 |
#include "mhd_str.h"
|
|
Packit |
875988 |
#include "connection.h"
|
|
Packit |
875988 |
#include "memorypool.h"
|
|
Packit |
875988 |
#include "mhd_compat.h"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#if defined(MHD_W32_MUTEX_)
|
|
Packit |
875988 |
#ifndef WIN32_LEAN_AND_MEAN
|
|
Packit |
875988 |
#define WIN32_LEAN_AND_MEAN 1
|
|
Packit |
875988 |
#endif /* !WIN32_LEAN_AND_MEAN */
|
|
Packit |
875988 |
#include <windows.h>
|
|
Packit |
875988 |
#endif /* MHD_W32_MUTEX_ */
|
|
Packit |
875988 |
#if defined(_WIN32)
|
|
Packit |
875988 |
#include <io.h> /* for lseek(), read() */
|
|
Packit |
875988 |
#endif /* _WIN32 */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Add a header or footer line to the response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response response to add a header to
|
|
Packit |
875988 |
* @param kind header or footer
|
|
Packit |
875988 |
* @param header the header to add
|
|
Packit |
875988 |
* @param content value to add
|
|
Packit |
875988 |
* @return #MHD_NO on error (i.e. invalid header or content format).
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static int
|
|
Packit |
875988 |
add_response_entry (struct MHD_Response *response,
|
|
Packit |
875988 |
enum MHD_ValueKind kind,
|
|
Packit |
875988 |
const char *header,
|
|
Packit |
875988 |
const char *content)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_HTTP_Header *hdr;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ( (NULL == response) ||
|
|
Packit |
875988 |
(NULL == header) ||
|
|
Packit |
875988 |
(NULL == content) ||
|
|
Packit |
875988 |
(0 == header[0]) ||
|
|
Packit |
875988 |
(0 == content[0]) ||
|
|
Packit |
875988 |
(NULL != strchr (header, '\t')) ||
|
|
Packit |
875988 |
(NULL != strchr (header, '\r')) ||
|
|
Packit |
875988 |
(NULL != strchr (header, '\n')) ||
|
|
Packit |
875988 |
(NULL != strchr (content, '\t')) ||
|
|
Packit |
875988 |
(NULL != strchr (content, '\r')) ||
|
|
Packit |
875988 |
(NULL != strchr (content, '\n')) )
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header))))
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
if (NULL == (hdr->header = strdup (header)))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (hdr);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (NULL == (hdr->value = strdup (content)))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (hdr->header);
|
|
Packit |
875988 |
free (hdr);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
hdr->kind = kind;
|
|
Packit |
875988 |
hdr->next = response->first_header;
|
|
Packit |
875988 |
response->first_header = hdr;
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Add a header line to the response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response response to add a header to
|
|
Packit |
875988 |
* @param header the header to add
|
|
Packit |
875988 |
* @param content value to add
|
|
Packit |
875988 |
* @return #MHD_NO on error (i.e. invalid header or content format).
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int
|
|
Packit |
875988 |
MHD_add_response_header (struct MHD_Response *response,
|
|
Packit |
875988 |
const char *header,
|
|
Packit |
875988 |
const char *content)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return add_response_entry (response,
|
|
Packit |
875988 |
MHD_HEADER_KIND,
|
|
Packit |
875988 |
header,
|
|
Packit |
875988 |
content);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Add a footer line to the response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response response to remove a header from
|
|
Packit |
875988 |
* @param footer the footer to delete
|
|
Packit |
875988 |
* @param content value to delete
|
|
Packit |
875988 |
* @return #MHD_NO on error (i.e. invalid footer or content format).
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int
|
|
Packit |
875988 |
MHD_add_response_footer (struct MHD_Response *response,
|
|
Packit |
875988 |
const char *footer,
|
|
Packit |
875988 |
const char *content)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return add_response_entry (response,
|
|
Packit |
875988 |
MHD_FOOTER_KIND,
|
|
Packit |
875988 |
footer,
|
|
Packit |
875988 |
content);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Delete a header (or footer) line from the response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response response to remove a header from
|
|
Packit |
875988 |
* @param header the header to delete
|
|
Packit |
875988 |
* @param content value to delete
|
|
Packit |
875988 |
* @return #MHD_NO on error (no such header known)
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int
|
|
Packit |
875988 |
MHD_del_response_header (struct MHD_Response *response,
|
|
Packit |
875988 |
const char *header,
|
|
Packit |
875988 |
const char *content)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_HTTP_Header *pos;
|
|
Packit |
875988 |
struct MHD_HTTP_Header *prev;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ( (NULL == header) ||
|
|
Packit |
875988 |
(NULL == content) )
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
prev = NULL;
|
|
Packit |
875988 |
pos = response->first_header;
|
|
Packit |
875988 |
while (NULL != pos)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if ((0 == strcmp (header,
|
|
Packit |
875988 |
pos->header)) &&
|
|
Packit |
875988 |
(0 == strcmp (content,
|
|
Packit |
875988 |
pos->value)))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (pos->header);
|
|
Packit |
875988 |
free (pos->value);
|
|
Packit |
875988 |
if (NULL == prev)
|
|
Packit |
875988 |
response->first_header = pos->next;
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
prev->next = pos->next;
|
|
Packit |
875988 |
free (pos);
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
prev = pos;
|
|
Packit |
875988 |
pos = pos->next;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Get all of the headers (and footers) added to a response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response response to query
|
|
Packit |
875988 |
* @param iterator callback to call on each header;
|
|
Packit |
875988 |
* maybe NULL (then just count headers)
|
|
Packit |
875988 |
* @param iterator_cls extra argument to @a iterator
|
|
Packit |
875988 |
* @return number of entries iterated over
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int
|
|
Packit |
875988 |
MHD_get_response_headers (struct MHD_Response *response,
|
|
Packit |
875988 |
MHD_KeyValueIterator iterator,
|
|
Packit |
875988 |
void *iterator_cls)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
int numHeaders = 0;
|
|
Packit |
875988 |
struct MHD_HTTP_Header *pos;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
for (pos = response->first_header;
|
|
Packit |
875988 |
NULL != pos;
|
|
Packit |
875988 |
pos = pos->next)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
numHeaders++;
|
|
Packit |
875988 |
if ((NULL != iterator) &&
|
|
Packit |
875988 |
(MHD_YES != iterator (iterator_cls,
|
|
Packit |
875988 |
pos->kind,
|
|
Packit |
875988 |
pos->header,
|
|
Packit |
875988 |
pos->value)))
|
|
Packit |
875988 |
break;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return numHeaders;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Get a particular header (or footer) from the response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response response to query
|
|
Packit |
875988 |
* @param key which header to get
|
|
Packit |
875988 |
* @return NULL if header does not exist
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
const char *
|
|
Packit |
875988 |
MHD_get_response_header (struct MHD_Response *response,
|
|
Packit |
875988 |
const char *key)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_HTTP_Header *pos;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == key)
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
for (pos = response->first_header;
|
|
Packit |
875988 |
NULL != pos;
|
|
Packit |
875988 |
pos = pos->next)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if ( MHD_str_equal_caseless_ (pos->header, key) )
|
|
Packit |
875988 |
return pos->value;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Check whether response header contains particular token.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* Token could be surrounded by spaces and tabs and delimited by comma.
|
|
Packit |
875988 |
* Case-insensitive match used for header names and tokens.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response the response to query
|
|
Packit |
875988 |
* @param key header name
|
|
Packit |
875988 |
* @param token the token to find
|
|
Packit |
875988 |
* @param token_len the length of token, not including optional
|
|
Packit |
875988 |
* terminating null-character.
|
|
Packit |
875988 |
* @return true if token is found in specified header,
|
|
Packit |
875988 |
* false otherwise
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
bool
|
|
Packit |
875988 |
MHD_check_response_header_token_ci (const struct MHD_Response *response,
|
|
Packit |
875988 |
const char *key,
|
|
Packit |
875988 |
const char *token,
|
|
Packit |
875988 |
size_t token_len)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_HTTP_Header *pos;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ( (NULL == key) ||
|
|
Packit |
875988 |
('\0' == key[0]) ||
|
|
Packit |
875988 |
(NULL == token) ||
|
|
Packit |
875988 |
('\0' == token[0]) )
|
|
Packit |
875988 |
return false;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
for (pos = response->first_header;
|
|
Packit |
875988 |
NULL != pos;
|
|
Packit |
875988 |
pos = pos->next)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if ( (pos->kind == MHD_HEADER_KIND) &&
|
|
Packit |
875988 |
MHD_str_equal_caseless_ (pos->header,
|
|
Packit |
875988 |
key) &&
|
|
Packit |
875988 |
MHD_str_has_token_caseless_ (pos->value,
|
|
Packit |
875988 |
token,
|
|
Packit |
875988 |
token_len) )
|
|
Packit |
875988 |
return true;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return false;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a response object. The response object can be extended with
|
|
Packit |
875988 |
* header information and then be used any number of times.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param size size of the data portion of the response, #MHD_SIZE_UNKNOWN for unknown
|
|
Packit |
875988 |
* @param block_size preferred block size for querying crc (advisory only,
|
|
Packit |
875988 |
* MHD may still call @a crc using smaller chunks); this
|
|
Packit |
875988 |
* is essentially the buffer size used for IO, clients
|
|
Packit |
875988 |
* should pick a value that is appropriate for IO and
|
|
Packit |
875988 |
* memory performance requirements
|
|
Packit |
875988 |
* @param crc callback to use to obtain response data
|
|
Packit |
875988 |
* @param crc_cls extra argument to @a crc
|
|
Packit |
875988 |
* @param crfc callback to call to free @a crc_cls resources
|
|
Packit |
875988 |
* @return NULL on error (i.e. invalid arguments, out of memory)
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MHD_Response *
|
|
Packit |
875988 |
MHD_create_response_from_callback (uint64_t size,
|
|
Packit |
875988 |
size_t block_size,
|
|
Packit |
875988 |
MHD_ContentReaderCallback crc,
|
|
Packit |
875988 |
void *crc_cls,
|
|
Packit |
875988 |
MHD_ContentReaderFreeCallback crfc)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Response *response;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ((NULL == crc) || (0 == block_size))
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
if (NULL == (response = MHD_calloc_ (1, sizeof (struct MHD_Response) + block_size)))
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
response->fd = -1;
|
|
Packit |
875988 |
response->data = (void *) &response[1];
|
|
Packit |
875988 |
response->data_buffer_size = block_size;
|
|
Packit |
875988 |
if (! MHD_mutex_init_ (&response->mutex))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (response);
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
response->crc = crc;
|
|
Packit |
875988 |
response->crfc = crfc;
|
|
Packit |
875988 |
response->crc_cls = crc_cls;
|
|
Packit |
875988 |
response->reference_count = 1;
|
|
Packit |
875988 |
response->total_size = size;
|
|
Packit |
875988 |
return response;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Set special flags and options for a response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response the response to modify
|
|
Packit |
875988 |
* @param flags to set for the response
|
|
Packit |
875988 |
* @param ... #MHD_RO_END terminated list of options
|
|
Packit |
875988 |
* @return #MHD_YES on success, #MHD_NO on error
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int
|
|
Packit |
875988 |
MHD_set_response_options (struct MHD_Response *response,
|
|
Packit |
875988 |
enum MHD_ResponseFlags flags,
|
|
Packit |
875988 |
...)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
va_list ap;
|
|
Packit |
875988 |
int ret;
|
|
Packit |
875988 |
enum MHD_ResponseOptions ro;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
ret = MHD_YES;
|
|
Packit |
875988 |
response->flags = flags;
|
|
Packit |
875988 |
va_start (ap, flags);
|
|
Packit |
875988 |
while (MHD_RO_END != (ro = va_arg (ap, enum MHD_ResponseOptions)))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
switch (ro)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
default:
|
|
Packit |
875988 |
ret = MHD_NO;
|
|
Packit |
875988 |
break;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
va_end (ap);
|
|
Packit |
875988 |
return ret;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Given a file descriptor, read data from the file
|
|
Packit |
875988 |
* to generate the response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param cls pointer to the response
|
|
Packit |
875988 |
* @param pos offset in the file to access
|
|
Packit |
875988 |
* @param buf where to write the data
|
|
Packit |
875988 |
* @param max number of bytes to write at most
|
|
Packit |
875988 |
* @return number of bytes written
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static ssize_t
|
|
Packit |
875988 |
file_reader (void *cls,
|
|
Packit |
875988 |
uint64_t pos,
|
|
Packit |
875988 |
char *buf,
|
|
Packit |
875988 |
size_t max)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Response *response = cls;
|
|
Packit |
875988 |
#if !defined(_WIN32) || defined(__CYGWIN__)
|
|
Packit |
875988 |
ssize_t n;
|
|
Packit |
875988 |
#else /* _WIN32 && !__CYGWIN__ */
|
|
Packit |
875988 |
const HANDLE fh = (HANDLE) _get_osfhandle (response->fd);
|
|
Packit |
875988 |
#endif /* _WIN32 && !__CYGWIN__ */
|
|
Packit |
875988 |
const int64_t offset64 = (int64_t)(pos + response->fd_off);
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (offset64 < 0)
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#if !defined(_WIN32) || defined(__CYGWIN__)
|
|
Packit |
875988 |
if (max > SSIZE_MAX)
|
|
Packit |
875988 |
max = SSIZE_MAX; /* Clamp to maximum return value. */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#if defined(HAVE_PREAD64)
|
|
Packit |
875988 |
n = pread64(response->fd, buf, max, offset64);
|
|
Packit |
875988 |
#elif defined(HAVE_PREAD)
|
|
Packit |
875988 |
if ( (sizeof(off_t) < sizeof (uint64_t)) &&
|
|
Packit |
875988 |
(offset64 > (uint64_t)INT32_MAX) )
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_WITH_ERROR; /* Read at required position is not possible. */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
n = pread(response->fd, buf, max, (off_t) offset64);
|
|
Packit |
875988 |
#else /* ! HAVE_PREAD */
|
|
Packit |
875988 |
#if defined(HAVE_LSEEK64)
|
|
Packit |
875988 |
if (lseek64 (response->fd,
|
|
Packit |
875988 |
offset64,
|
|
Packit |
875988 |
SEEK_SET) != offset64)
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
|
|
Packit |
875988 |
#else /* ! HAVE_LSEEK64 */
|
|
Packit |
875988 |
if ( (sizeof(off_t) < sizeof (uint64_t)) &&
|
|
Packit |
875988 |
(offset64 > (uint64_t)INT32_MAX) )
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (lseek (response->fd,
|
|
Packit |
875988 |
(off_t) offset64,
|
|
Packit |
875988 |
SEEK_SET) != (off_t) offset64)
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
|
|
Packit |
875988 |
#endif /* ! HAVE_LSEEK64 */
|
|
Packit |
875988 |
n = read (response->fd,
|
|
Packit |
875988 |
buf,
|
|
Packit |
875988 |
max);
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#endif /* ! HAVE_PREAD */
|
|
Packit |
875988 |
if (0 == n)
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_OF_STREAM;
|
|
Packit |
875988 |
if (n < 0)
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_WITH_ERROR;
|
|
Packit |
875988 |
return n;
|
|
Packit |
875988 |
#else /* _WIN32 && !__CYGWIN__ */
|
|
Packit |
875988 |
if (INVALID_HANDLE_VALUE == fh)
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_WITH_ERROR; /* Value of 'response->fd' is not valid. */
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
OVERLAPPED f_ol = {0, 0, {{0, 0}}, 0}; /* Initialize to zero. */
|
|
Packit |
875988 |
ULARGE_INTEGER pos_uli;
|
|
Packit |
875988 |
DWORD toRead = (max > INT32_MAX) ? INT32_MAX : (DWORD) max;
|
|
Packit |
875988 |
DWORD resRead;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
pos_uli.QuadPart = (uint64_t) offset64; /* Simple transformation 64bit -> 2x32bit. */
|
|
Packit |
875988 |
f_ol.Offset = pos_uli.LowPart;
|
|
Packit |
875988 |
f_ol.OffsetHigh = pos_uli.HighPart;
|
|
Packit |
875988 |
if (! ReadFile(fh, (void*)buf, toRead, &resRead, &f_ol))
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_WITH_ERROR; /* Read error. */
|
|
Packit |
875988 |
if (0 == resRead)
|
|
Packit |
875988 |
return MHD_CONTENT_READER_END_OF_STREAM;
|
|
Packit |
875988 |
return (ssize_t) resRead;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#endif /* _WIN32 && !__CYGWIN__ */
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Destroy file reader context. Closes the file
|
|
Packit |
875988 |
* descriptor.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param cls pointer to file descriptor
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
free_callback (void *cls)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Response *response = cls;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
(void) close (response->fd);
|
|
Packit |
875988 |
response->fd = -1;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#undef MHD_create_response_from_fd_at_offset
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a response object. The response object can be extended with
|
|
Packit |
875988 |
* header information and then be used any number of times.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param size size of the data portion of the response
|
|
Packit |
875988 |
* @param fd file descriptor referring to a file on disk with the
|
|
Packit |
875988 |
* data; will be closed when response is destroyed;
|
|
Packit |
875988 |
* fd should be in 'blocking' mode
|
|
Packit |
875988 |
* @param offset offset to start reading from in the file;
|
|
Packit |
875988 |
* Be careful! `off_t` may have been compiled to be a
|
|
Packit |
875988 |
* 64-bit variable for MHD, in which case your application
|
|
Packit |
875988 |
* also has to be compiled using the same options! Read
|
|
Packit |
875988 |
* the MHD manual for more details.
|
|
Packit |
875988 |
* @return NULL on error (i.e. invalid arguments, out of memory)
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MHD_Response *
|
|
Packit |
875988 |
MHD_create_response_from_fd_at_offset (size_t size,
|
|
Packit |
875988 |
int fd,
|
|
Packit |
875988 |
off_t offset)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return MHD_create_response_from_fd_at_offset64 (size,
|
|
Packit |
875988 |
fd,
|
|
Packit |
875988 |
offset);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a response object. The response object can be extended with
|
|
Packit |
875988 |
* header information and then be used any number of times.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param size size of the data portion of the response;
|
|
Packit |
875988 |
* sizes larger than 2 GiB may be not supported by OS or
|
|
Packit |
875988 |
* MHD build; see ::MHD_FEATURE_LARGE_FILE
|
|
Packit |
875988 |
* @param fd file descriptor referring to a file on disk with the
|
|
Packit |
875988 |
* data; will be closed when response is destroyed;
|
|
Packit |
875988 |
* fd should be in 'blocking' mode
|
|
Packit |
875988 |
* @param offset offset to start reading from in the file;
|
|
Packit |
875988 |
* reading file beyond 2 GiB may be not supported by OS or
|
|
Packit |
875988 |
* MHD build; see ::MHD_FEATURE_LARGE_FILE
|
|
Packit |
875988 |
* @return NULL on error (i.e. invalid arguments, out of memory)
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
_MHD_EXTERN struct MHD_Response *
|
|
Packit |
875988 |
MHD_create_response_from_fd_at_offset64 (uint64_t size,
|
|
Packit |
875988 |
int fd,
|
|
Packit |
875988 |
uint64_t offset)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Response *response;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#if !defined(HAVE___LSEEKI64) && !defined(HAVE_LSEEK64)
|
|
Packit |
875988 |
if ( (sizeof(uint64_t) > sizeof(off_t)) &&
|
|
Packit |
875988 |
( (size > (uint64_t)INT32_MAX) ||
|
|
Packit |
875988 |
(offset > (uint64_t)INT32_MAX) ||
|
|
Packit |
875988 |
((size + offset) >= (uint64_t)INT32_MAX) ) )
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
if ( ((int64_t)size < 0) ||
|
|
Packit |
875988 |
((int64_t)offset < 0) ||
|
|
Packit |
875988 |
((int64_t)(size + offset) < 0) )
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
response = MHD_create_response_from_callback (size,
|
|
Packit |
875988 |
4 * 1024,
|
|
Packit |
875988 |
&file_reader,
|
|
Packit |
875988 |
NULL,
|
|
Packit |
875988 |
&free_callback);
|
|
Packit |
875988 |
if (NULL == response)
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
response->fd = fd;
|
|
Packit |
875988 |
response->fd_off = offset;
|
|
Packit |
875988 |
response->crc_cls = response;
|
|
Packit |
875988 |
return response;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a response object. The response object can be extended with
|
|
Packit |
875988 |
* header information and then be used any number of times.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param size size of the data portion of the response
|
|
Packit |
875988 |
* @param fd file descriptor referring to a file on disk with the data
|
|
Packit |
875988 |
* @return NULL on error (i.e. invalid arguments, out of memory)
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MHD_Response *
|
|
Packit |
875988 |
MHD_create_response_from_fd (size_t size,
|
|
Packit |
875988 |
int fd)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return MHD_create_response_from_fd_at_offset64 (size,
|
|
Packit |
875988 |
fd,
|
|
Packit |
875988 |
0);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a response object. The response object can be extended with
|
|
Packit |
875988 |
* header information and then be used any number of times.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param size size of the data portion of the response;
|
|
Packit |
875988 |
* sizes larger than 2 GiB may be not supported by OS or
|
|
Packit |
875988 |
* MHD build; see ::MHD_FEATURE_LARGE_FILE
|
|
Packit |
875988 |
* @param fd file descriptor referring to a file on disk with the
|
|
Packit |
875988 |
* data; will be closed when response is destroyed;
|
|
Packit |
875988 |
* fd should be in 'blocking' mode
|
|
Packit |
875988 |
* @return NULL on error (i.e. invalid arguments, out of memory)
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
_MHD_EXTERN struct MHD_Response *
|
|
Packit |
875988 |
MHD_create_response_from_fd64 (uint64_t size,
|
|
Packit |
875988 |
int fd)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return MHD_create_response_from_fd_at_offset64 (size,
|
|
Packit |
875988 |
fd,
|
|
Packit |
875988 |
0);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a response object. The response object can be extended with
|
|
Packit |
875988 |
* header information and then be used any number of times.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param size size of the @a data portion of the response
|
|
Packit |
875988 |
* @param data the data itself
|
|
Packit |
875988 |
* @param must_free libmicrohttpd should free data when done
|
|
Packit |
875988 |
* @param must_copy libmicrohttpd must make a copy of @a data
|
|
Packit |
875988 |
* right away, the data maybe released anytime after
|
|
Packit |
875988 |
* this call returns
|
|
Packit |
875988 |
* @return NULL on error (i.e. invalid arguments, out of memory)
|
|
Packit |
875988 |
* @deprecated use #MHD_create_response_from_buffer instead
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MHD_Response *
|
|
Packit |
875988 |
MHD_create_response_from_data (size_t size,
|
|
Packit |
875988 |
void *data,
|
|
Packit |
875988 |
int must_free,
|
|
Packit |
875988 |
int must_copy)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Response *response;
|
|
Packit |
875988 |
void *tmp;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ((NULL == data) && (size > 0))
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
if (NULL == (response = MHD_calloc_ (1, sizeof (struct MHD_Response))))
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
response->fd = -1;
|
|
Packit |
875988 |
if (! MHD_mutex_init_ (&response->mutex))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (response);
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if ((must_copy) && (size > 0))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (NULL == (tmp = malloc (size)))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
MHD_mutex_destroy_chk_ (&response->mutex);
|
|
Packit |
875988 |
free (response);
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
memcpy (tmp, data, size);
|
|
Packit |
875988 |
must_free = MHD_YES;
|
|
Packit |
875988 |
data = tmp;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (must_free)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
response->crfc = &fre;;
|
|
Packit |
875988 |
response->crc_cls = data;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
response->reference_count = 1;
|
|
Packit |
875988 |
response->total_size = size;
|
|
Packit |
875988 |
response->data = data;
|
|
Packit |
875988 |
response->data_size = size;
|
|
Packit |
875988 |
return response;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a response object. The response object can be extended with
|
|
Packit |
875988 |
* header information and then be used any number of times.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param size size of the data portion of the response
|
|
Packit |
875988 |
* @param buffer size bytes containing the response's data portion
|
|
Packit |
875988 |
* @param mode flags for buffer management
|
|
Packit |
875988 |
* @return NULL on error (i.e. invalid arguments, out of memory)
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MHD_Response *
|
|
Packit |
875988 |
MHD_create_response_from_buffer (size_t size,
|
|
Packit |
875988 |
void *buffer,
|
|
Packit |
875988 |
enum MHD_ResponseMemoryMode mode)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return MHD_create_response_from_data (size,
|
|
Packit |
875988 |
buffer,
|
|
Packit |
875988 |
mode == MHD_RESPMEM_MUST_FREE,
|
|
Packit |
875988 |
mode == MHD_RESPMEM_MUST_COPY);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#ifdef UPGRADE_SUPPORT
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* This connection-specific callback is provided by MHD to
|
|
Packit |
875988 |
* applications (unusual) during the #MHD_UpgradeHandler.
|
|
Packit |
875988 |
* It allows applications to perform 'special' actions on
|
|
Packit |
875988 |
* the underlying socket from the upgrade.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param urh the handle identifying the connection to perform
|
|
Packit |
875988 |
* the upgrade @a action on.
|
|
Packit |
875988 |
* @param action which action should be performed
|
|
Packit |
875988 |
* @param ... arguments to the action (depends on the action)
|
|
Packit |
875988 |
* @return #MHD_NO on error, #MHD_YES on success
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
_MHD_EXTERN int
|
|
Packit |
875988 |
MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh,
|
|
Packit |
875988 |
enum MHD_UpgradeAction action,
|
|
Packit |
875988 |
...)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Connection *connection;
|
|
Packit |
875988 |
struct MHD_Daemon *daemon;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == urh)
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
connection = urh->connection;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Precaution checks on external data. */
|
|
Packit |
875988 |
if (NULL == connection)
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
daemon = connection->daemon;
|
|
Packit |
875988 |
if (NULL == daemon)
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
switch (action)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
case MHD_UPGRADE_ACTION_CLOSE:
|
|
Packit |
875988 |
if (urh->was_closed)
|
|
Packit |
875988 |
return MHD_NO; /* Already closed. */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* transition to special 'closed' state for start of cleanup */
|
|
Packit |
875988 |
#ifdef HTTPS_SUPPORT
|
|
Packit |
875988 |
if (0 != (daemon->options & MHD_USE_TLS) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* signal that app is done by shutdown() of 'app' socket */
|
|
Packit |
875988 |
/* Application will not use anyway this socket after this command. */
|
|
Packit |
875988 |
shutdown (urh->app.socket,
|
|
Packit |
875988 |
SHUT_RDWR);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#endif /* HTTPS_SUPPORT */
|
|
Packit |
875988 |
mhd_assert (MHD_CONNECTION_UPGRADE == connection->state);
|
|
Packit |
875988 |
urh->was_closed = true;
|
|
Packit |
875988 |
/* As soon as connection will be marked with BOTH
|
|
Packit |
875988 |
* 'urh->was_closed' AND 'urh->clean_ready', it will
|
|
Packit |
875988 |
* be moved to cleanup list by MHD_resume_connection(). */
|
|
Packit |
875988 |
MHD_resume_connection (connection);
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
default:
|
|
Packit |
875988 |
/* we don't understand this one */
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* We are done sending the header of a given response to the client.
|
|
Packit |
875988 |
* Now it is time to perform the upgrade and hand over the connection
|
|
Packit |
875988 |
* to the application.
|
|
Packit |
875988 |
* @remark To be called only from thread that process connection's
|
|
Packit |
875988 |
* recv(), send() and response. Must be called right after sending
|
|
Packit |
875988 |
* response headers.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response the response that was created for an upgrade
|
|
Packit |
875988 |
* @param connection the specific connection we are upgrading
|
|
Packit |
875988 |
* @return #MHD_YES on success, #MHD_NO on failure (will cause
|
|
Packit |
875988 |
* connection to be closed)
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int
|
|
Packit |
875988 |
MHD_response_execute_upgrade_ (struct MHD_Response *response,
|
|
Packit |
875988 |
struct MHD_Connection *connection)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Daemon *daemon = connection->daemon;
|
|
Packit |
875988 |
struct MHD_UpgradeResponseHandle *urh;
|
|
Packit |
875988 |
size_t rbo;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (0 == (daemon->options & MHD_ALLOW_UPGRADE))
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL ==
|
|
Packit |
875988 |
MHD_get_response_header (response,
|
|
Packit |
875988 |
MHD_HTTP_HEADER_UPGRADE))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Invalid response for upgrade: application failed to set the 'Upgrade' header!\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
urh = MHD_calloc_ (1, sizeof (struct MHD_UpgradeResponseHandle));
|
|
Packit |
875988 |
if (NULL == urh)
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
urh->connection = connection;
|
|
Packit |
875988 |
rbo = connection->read_buffer_offset;
|
|
Packit |
875988 |
connection->read_buffer_offset = 0;
|
|
Packit |
875988 |
#ifdef HTTPS_SUPPORT
|
|
Packit |
875988 |
if (0 != (daemon->options & MHD_USE_TLS) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MemoryPool *pool;
|
|
Packit |
875988 |
size_t avail;
|
|
Packit |
875988 |
char *buf;
|
|
Packit |
875988 |
MHD_socket sv[2];
|
|
Packit |
875988 |
#if defined(MHD_socket_nosignal_) || !defined(MHD_socket_pair_nblk_)
|
|
Packit |
875988 |
int res1;
|
|
Packit |
875988 |
int res2;
|
|
Packit |
875988 |
#endif /* MHD_socket_nosignal_ || !MHD_socket_pair_nblk_ */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#ifdef MHD_socket_pair_nblk_
|
|
Packit |
875988 |
if (! MHD_socket_pair_nblk_ (sv))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (urh);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#else /* !MHD_socket_pair_nblk_ */
|
|
Packit |
875988 |
if (! MHD_socket_pair_ (sv))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (urh);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
res1 = MHD_socket_nonblocking_(sv[0]);
|
|
Packit |
875988 |
res2 = MHD_socket_nonblocking_(sv[1]);
|
|
Packit |
875988 |
if ( (! res1) || (! res2) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Failed to make loopback sockets non-blocking.\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
if (! res2)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* Socketpair cannot be used. */
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[0]);
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[1]);
|
|
Packit |
875988 |
free (urh);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#endif /* !MHD_socket_pair_nblk_ */
|
|
Packit |
875988 |
#ifdef MHD_socket_nosignal_
|
|
Packit |
875988 |
res1 = MHD_socket_nosignal_(sv[0]);
|
|
Packit |
875988 |
res2 = MHD_socket_nosignal_(sv[1]);
|
|
Packit |
875988 |
if ( (! res1) || (! res2) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Failed to set SO_NOSIGPIPE on loopback sockets.\n"));
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
#ifndef MSG_NOSIGNAL
|
|
Packit |
875988 |
if (!res2)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* Socketpair cannot be used. */
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[0]);
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[1]);
|
|
Packit |
875988 |
free (urh);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#endif /* ! MSG_NOSIGNAL */
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#endif /* MHD_socket_nosignal_ */
|
|
Packit |
875988 |
if ( (! MHD_SCKT_FD_FITS_FDSET_ (sv[1],
|
|
Packit |
875988 |
NULL)) &&
|
|
Packit |
875988 |
(0 == (daemon->options & (MHD_USE_POLL | MHD_USE_EPOLL))) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Socketpair descriptor larger than FD_SETSIZE: %d > %d\n"),
|
|
Packit |
875988 |
(int) sv[1],
|
|
Packit |
875988 |
(int) FD_SETSIZE);
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[0]);
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[1]);
|
|
Packit |
875988 |
free (urh);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
urh->app.socket = sv[0];
|
|
Packit |
875988 |
urh->app.urh = urh;
|
|
Packit |
875988 |
urh->app.celi = MHD_EPOLL_STATE_UNREADY;
|
|
Packit |
875988 |
urh->mhd.socket = sv[1];
|
|
Packit |
875988 |
urh->mhd.urh = urh;
|
|
Packit |
875988 |
urh->mhd.celi = MHD_EPOLL_STATE_UNREADY;
|
|
Packit |
875988 |
pool = connection->pool;
|
|
Packit |
875988 |
avail = MHD_pool_get_free (pool);
|
|
Packit |
875988 |
if (avail < RESERVE_EBUF_SIZE)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* connection's pool is totally at the limit,
|
|
Packit |
875988 |
use our 'emergency' buffer of #RESERVE_EBUF_SIZE bytes. */
|
|
Packit |
875988 |
avail = RESERVE_EBUF_SIZE;
|
|
Packit |
875988 |
buf = urh->e_buf;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* Normal case: grab all remaining memory from the
|
|
Packit |
875988 |
connection's pool for the IO buffers; the connection
|
|
Packit |
875988 |
certainly won't need it anymore as we've upgraded
|
|
Packit |
875988 |
to another protocol. */
|
|
Packit |
875988 |
buf = MHD_pool_allocate (pool,
|
|
Packit |
875988 |
avail,
|
|
Packit |
875988 |
MHD_NO);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* use half the buffer for inbound, half for outbound */
|
|
Packit |
875988 |
urh->in_buffer_size = avail / 2;
|
|
Packit |
875988 |
urh->out_buffer_size = avail - urh->in_buffer_size;
|
|
Packit |
875988 |
urh->in_buffer = buf;
|
|
Packit |
875988 |
urh->out_buffer = &buf[urh->in_buffer_size];
|
|
Packit |
875988 |
#ifdef EPOLL_SUPPORT
|
|
Packit |
875988 |
/* Launch IO processing by the event loop */
|
|
Packit |
875988 |
if (0 != (daemon->options & MHD_USE_EPOLL))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* We're running with epoll(), need to add the sockets
|
|
Packit |
875988 |
to the event set of the daemon's `epoll_upgrade_fd` */
|
|
Packit |
875988 |
struct epoll_event event;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
mhd_assert (-1 != daemon->epoll_upgrade_fd);
|
|
Packit |
875988 |
/* First, add network socket */
|
|
Packit |
875988 |
event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
|
|
Packit |
875988 |
event.data.ptr = &urh->app;
|
|
Packit |
875988 |
if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
|
|
Packit |
875988 |
EPOLL_CTL_ADD,
|
|
Packit |
875988 |
connection->socket_fd,
|
|
Packit |
875988 |
&event))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Call to epoll_ctl failed: %s\n"),
|
|
Packit |
875988 |
MHD_socket_last_strerr_ ());
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[0]);
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[1]);
|
|
Packit |
875988 |
free (urh);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Second, add our end of the UNIX socketpair() */
|
|
Packit |
875988 |
event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
|
|
Packit |
875988 |
event.data.ptr = &urh->mhd;
|
|
Packit |
875988 |
if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
|
|
Packit |
875988 |
EPOLL_CTL_ADD,
|
|
Packit |
875988 |
urh->mhd.socket,
|
|
Packit |
875988 |
&event))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
event.events = EPOLLIN | EPOLLOUT | EPOLLPRI;
|
|
Packit |
875988 |
event.data.ptr = &urh->app;
|
|
Packit |
875988 |
if (0 != epoll_ctl (daemon->epoll_upgrade_fd,
|
|
Packit |
875988 |
EPOLL_CTL_DEL,
|
|
Packit |
875988 |
connection->socket_fd,
|
|
Packit |
875988 |
&event))
|
|
Packit |
875988 |
MHD_PANIC (_("Error cleaning up while handling epoll error"));
|
|
Packit |
875988 |
#ifdef HAVE_MESSAGES
|
|
Packit |
875988 |
MHD_DLOG (daemon,
|
|
Packit |
875988 |
_("Call to epoll_ctl failed: %s\n"),
|
|
Packit |
875988 |
MHD_socket_last_strerr_ ());
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[0]);
|
|
Packit |
875988 |
MHD_socket_close_chk_ (sv[1]);
|
|
Packit |
875988 |
free (urh);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
EDLL_insert (daemon->eready_urh_head,
|
|
Packit |
875988 |
daemon->eready_urh_tail,
|
|
Packit |
875988 |
urh);
|
|
Packit |
875988 |
urh->in_eready_list = true;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#endif /* EPOLL_SUPPORT */
|
|
Packit |
875988 |
if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* This takes care of further processing for most event loops:
|
|
Packit |
875988 |
simply add to DLL for bi-direcitonal processing */
|
|
Packit |
875988 |
DLL_insert (daemon->urh_head,
|
|
Packit |
875988 |
daemon->urh_tail,
|
|
Packit |
875988 |
urh);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* In thread-per-connection mode, thread will switch to forwarding once
|
|
Packit |
875988 |
* connection.urh is not NULL and connection.state == MHD_CONNECTION_UPGRADE.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
urh->app.socket = MHD_INVALID_SOCKET;
|
|
Packit |
875988 |
urh->mhd.socket = MHD_INVALID_SOCKET;
|
|
Packit |
875988 |
/* Non-TLS connection do not hold any additional resources. */
|
|
Packit |
875988 |
urh->clean_ready = true;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#else /* ! HTTPS_SUPPORT */
|
|
Packit |
875988 |
urh->clean_ready = true;
|
|
Packit |
875988 |
#endif /* ! HTTPS_SUPPORT */
|
|
Packit |
875988 |
connection->urh = urh;
|
|
Packit |
875988 |
/* As far as MHD's event loops are concerned, this connection is
|
|
Packit |
875988 |
suspended; it will be resumed once application is done by the
|
|
Packit |
875988 |
#MHD_upgrade_action() function */
|
|
Packit |
875988 |
internal_suspend_connection_ (connection);
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* hand over socket to application */
|
|
Packit |
875988 |
response->upgrade_handler (response->upgrade_handler_cls,
|
|
Packit |
875988 |
connection,
|
|
Packit |
875988 |
connection->client_context,
|
|
Packit |
875988 |
connection->read_buffer,
|
|
Packit |
875988 |
rbo,
|
|
Packit |
875988 |
#ifdef HTTPS_SUPPORT
|
|
Packit |
875988 |
(0 == (daemon->options & MHD_USE_TLS) ) ?
|
|
Packit |
875988 |
connection->socket_fd : urh->app.socket,
|
|
Packit |
875988 |
#else /* ! HTTPS_SUPPORT */
|
|
Packit |
875988 |
connection->socket_fd,
|
|
Packit |
875988 |
#endif /* ! HTTPS_SUPPORT */
|
|
Packit |
875988 |
urh);
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a response object that can be used for 101 UPGRADE
|
|
Packit |
875988 |
* responses, for example to implement WebSockets. After sending the
|
|
Packit |
875988 |
* response, control over the data stream is given to the callback (which
|
|
Packit |
875988 |
* can then, for example, start some bi-directional communication).
|
|
Packit |
875988 |
* If the response is queued for multiple connections, the callback
|
|
Packit |
875988 |
* will be called for each connection. The callback
|
|
Packit |
875988 |
* will ONLY be called after the response header was successfully passed
|
|
Packit |
875988 |
* to the OS; if there are communication errors before, the usual MHD
|
|
Packit |
875988 |
* connection error handling code will be performed.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* Setting the correct HTTP code (i.e. MHD_HTTP_SWITCHING_PROTOCOLS)
|
|
Packit |
875988 |
* and setting correct HTTP headers for the upgrade must be done
|
|
Packit |
875988 |
* manually (this way, it is possible to implement most existing
|
|
Packit |
875988 |
* WebSocket versions using this API; in fact, this API might be useful
|
|
Packit |
875988 |
* for any protocol switch, not just WebSockets). Note that
|
|
Packit |
875988 |
* draft-ietf-hybi-thewebsocketprotocol-00 cannot be implemented this
|
|
Packit |
875988 |
* way as the header "HTTP/1.1 101 WebSocket Protocol Handshake"
|
|
Packit |
875988 |
* cannot be generated; instead, MHD will always produce "HTTP/1.1 101
|
|
Packit |
875988 |
* Switching Protocols" (if the response code 101 is used).
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* As usual, the response object can be extended with header
|
|
Packit |
875988 |
* information and then be used any number of times (as long as the
|
|
Packit |
875988 |
* header information is not connection-specific).
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param upgrade_handler function to call with the 'upgraded' socket
|
|
Packit |
875988 |
* @param upgrade_handler_cls closure for @a upgrade_handler
|
|
Packit |
875988 |
* @return NULL on error (i.e. invalid arguments, out of memory)
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
_MHD_EXTERN struct MHD_Response *
|
|
Packit |
875988 |
MHD_create_response_for_upgrade (MHD_UpgradeHandler upgrade_handler,
|
|
Packit |
875988 |
void *upgrade_handler_cls)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Response *response;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == upgrade_handler)
|
|
Packit |
875988 |
return NULL; /* invalid request */
|
|
Packit |
875988 |
response = MHD_calloc_ (1, sizeof (struct MHD_Response));
|
|
Packit |
875988 |
if (NULL == response)
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
if (! MHD_mutex_init_ (&response->mutex))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (response);
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
response->upgrade_handler = upgrade_handler;
|
|
Packit |
875988 |
response->upgrade_handler_cls = upgrade_handler_cls;
|
|
Packit |
875988 |
response->total_size = MHD_SIZE_UNKNOWN;
|
|
Packit |
875988 |
response->reference_count = 1;
|
|
Packit |
875988 |
if (MHD_NO ==
|
|
Packit |
875988 |
MHD_add_response_header (response,
|
|
Packit |
875988 |
MHD_HTTP_HEADER_CONNECTION,
|
|
Packit |
875988 |
"Upgrade"))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
MHD_destroy_response (response);
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return response;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#endif /* UPGRADE_SUPPORT */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Destroy a response object and associated resources. Note that
|
|
Packit |
875988 |
* libmicrohttpd may keep some of the resources around if the response
|
|
Packit |
875988 |
* is still in the queue for some clients, so the memory may not
|
|
Packit |
875988 |
* necessarily be freed immediately.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response response to destroy
|
|
Packit |
875988 |
* @ingroup response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
void
|
|
Packit |
875988 |
MHD_destroy_response (struct MHD_Response *response)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_HTTP_Header *pos;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == response)
|
|
Packit |
875988 |
return;
|
|
Packit |
875988 |
MHD_mutex_lock_chk_ (&response->mutex);
|
|
Packit |
875988 |
if (0 != --(response->reference_count))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
MHD_mutex_unlock_chk_ (&response->mutex);
|
|
Packit |
875988 |
return;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
MHD_mutex_unlock_chk_ (&response->mutex);
|
|
Packit |
875988 |
MHD_mutex_destroy_chk_ (&response->mutex);
|
|
Packit |
875988 |
if (NULL != response->crfc)
|
|
Packit |
875988 |
response->crfc (response->crc_cls);
|
|
Packit |
875988 |
while (NULL != response->first_header)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
pos = response->first_header;
|
|
Packit |
875988 |
response->first_header = pos->next;
|
|
Packit |
875988 |
free (pos->header);
|
|
Packit |
875988 |
free (pos->value);
|
|
Packit |
875988 |
free (pos);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
free (response);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Increments the reference counter for the @a response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response object to modify
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
void
|
|
Packit |
875988 |
MHD_increment_response_rc (struct MHD_Response *response)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
MHD_mutex_lock_chk_ (&response->mutex);
|
|
Packit |
875988 |
(response->reference_count)++;
|
|
Packit |
875988 |
MHD_mutex_unlock_chk_ (&response->mutex);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* end of response.c */
|