/*
This file is part of libhttpserver
Copyright (C) 2011-2019 Sebastiano Merlino
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
*/
#include "httpserver/webserver.hpp"
#if defined(_WIN32) && !defined(__CYGWIN__)
#include
#include
#define _WINDOWS
#else
#if defined(__CYGWIN__)
#include
#endif
#include
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "httpserver/create_webserver.hpp"
#include "httpserver/details/http_endpoint.hpp"
#include "httpserver/details/modded_request.hpp"
#include "httpserver/http_request.hpp"
#include "httpserver/http_resource.hpp"
#include "httpserver/http_response.hpp"
#include "httpserver/http_utils.hpp"
#include "httpserver/string_response.hpp"
struct MHD_Connection;
#define _REENTRANT 1
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 02000000
#endif
#if MHD_VERSION < 0x00097002
typedef int MHD_Result;
#endif
using std::string;
using std::pair;
using std::vector;
using std::map;
using std::set;
using httpserver::http::http_utils;
using httpserver::http::ip_representation;
using httpserver::http::base_unescaper;
namespace httpserver {
MHD_Result policy_callback(void *, const struct sockaddr*, socklen_t);
void error_log(void*, const char*, va_list);
void* uri_log(void*, const char*);
void access_log(webserver*, string);
size_t unescaper_func(void*, struct MHD_Connection*, char*);
struct compare_value {
bool operator() (const std::pair& left, const std::pair& right) const {
return left.second < right.second;
}
};
#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
static void catcher(int) { }
#endif
static void ignore_sigpipe() {
// Mingw doesn't implement SIGPIPE
#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
struct sigaction oldsig;
struct sigaction sig;
sig.sa_handler = &catcher;
sigemptyset(&sig.sa_mask);
#ifdef SA_INTERRUPT
sig.sa_flags = SA_INTERRUPT; /* SunOS */
#else // SA_INTERRUPT
sig.sa_flags = SA_RESTART;
#endif // SA_INTERRUPTT
if (0 != sigaction(SIGPIPE, &sig, &oldsig)) {
fprintf(stderr, "Failed to install SIGPIPE handler: %s\n", strerror(errno));
}
#endif
}
// WEBSERVER
webserver::webserver(const create_webserver& params):
port(params._port),
start_method(params._start_method),
max_threads(params._max_threads),
max_connections(params._max_connections),
memory_limit(params._memory_limit),
content_size_limit(params._content_size_limit),
connection_timeout(params._connection_timeout),
per_IP_connection_limit(params._per_IP_connection_limit),
log_access(params._log_access),
log_error(params._log_error),
validator(params._validator),
unescaper(params._unescaper),
bind_address(params._bind_address),
bind_socket(params._bind_socket),
max_thread_stack_size(params._max_thread_stack_size),
use_ssl(params._use_ssl),
use_ipv6(params._use_ipv6),
use_dual_stack(params._use_dual_stack),
debug(params._debug),
pedantic(params._pedantic),
https_mem_key(params._https_mem_key),
https_mem_cert(params._https_mem_cert),
https_mem_trust(params._https_mem_trust),
https_priorities(params._https_priorities),
cred_type(params._cred_type),
digest_auth_random(params._digest_auth_random),
nonce_nc_size(params._nonce_nc_size),
running(false),
default_policy(params._default_policy),
basic_auth_enabled(params._basic_auth_enabled),
digest_auth_enabled(params._digest_auth_enabled),
regex_checking(params._regex_checking),
ban_system_enabled(params._ban_system_enabled),
post_process_enabled(params._post_process_enabled),
deferred_enabled(params._deferred_enabled),
single_resource(params._single_resource),
tcp_nodelay(params._tcp_nodelay),
not_found_resource(params._not_found_resource),
method_not_allowed_resource(params._method_not_allowed_resource),
internal_error_resource(params._internal_error_resource) {
ignore_sigpipe();
pthread_mutex_init(&mutexwait, nullptr);
pthread_cond_init(&mutexcond, nullptr);
}
webserver::~webserver() {
stop();
pthread_mutex_destroy(&mutexwait);
pthread_cond_destroy(&mutexcond);
}
void webserver::sweet_kill() {
stop();
}
void webserver::request_completed(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe) {
// These parameters are passed to respect the MHD interface, but are not needed here.
std::ignore = cls;
std::ignore = connection;
std::ignore = toe;
details::modded_request* mr = static_cast(*con_cls);
if (mr == nullptr) return;
delete mr;
mr = nullptr;
}
bool webserver::register_resource(const std::string& resource, http_resource* hrm, bool family) {
if (single_resource && ((resource != "" && resource != "/") || !family)) {
throw std::invalid_argument("The resource should be '' or '/' and be marked as family when using a single_resource server");
}
details::http_endpoint idx(resource, family, true, regex_checking);
pair