/*
This file is part of libhttpserver
Copyright (C) 2011, 2012, 2013, 2014, 2015 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(__MINGW32__) || defined(__CYGWIN32__)
#include
#define _WINDOWS
#else
#include
#endif
#include
#include
#include
#include
#include "gettext.h"
#include "http_utils.hpp"
#include "http_resource.hpp"
#include "http_response.hpp"
#include "http_request.hpp"
#include "http_response_builder.hpp"
#include "details/http_endpoint.hpp"
#include "string_utilities.hpp"
#include "create_webserver.hpp"
#include "details/comet_manager.hpp"
#include "webserver.hpp"
#include "details/modded_request.hpp"
#include "details/cache_entry.hpp"
#define _REENTRANT 1
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 02000000
#endif
#define NEW_OR_MOVE(TYPE, VALUE) new TYPE(VALUE)
using namespace std;
namespace httpserver
{
namespace details
{
struct daemon_item
{
webserver* ws;
struct MHD_Daemon* daemon;
daemon_item(webserver* ws, struct MHD_Daemon* daemon):
ws(ws),
daemon(daemon)
{
}
~daemon_item()
{
MHD_stop_daemon (this->daemon);
}
};
}
using namespace http;
int 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*);
size_t internal_unescaper(void*, char*);
struct compare_value
{
bool operator() (const std::pair& left,
const std::pair& right
) const
{
return left.second < right.second;
}
};
#ifndef __MINGW32__
static void catcher (int sig)
{
}
#endif
static void ignore_sigpipe ()
{
//Mingw doesn't implement SIGPIPE
#ifndef __MINGW32__
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,
gettext("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),
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),
comet_enabled(params._comet_enabled),
single_resource(params._single_resource),
not_found_resource(params._not_found_resource),
method_not_allowed_resource(params._method_not_allowed_resource),
method_not_acceptable_resource(params._method_not_acceptable_resource),
internal_error_resource(params._internal_error_resource),
next_to_choose(0),
internal_comet_manager(new details::comet_manager())
{
if(single_resource != 0x0)
this->single_resource = true;
else
this->single_resource = false;
ignore_sigpipe();
pthread_mutex_init(&mutexwait, NULL);
pthread_rwlock_init(&runguard, NULL);
pthread_cond_init(&mutexcond, NULL);
pthread_rwlock_init(&cache_guard, NULL);
}
webserver::~webserver()
{
this->stop();
pthread_mutex_destroy(&mutexwait);
pthread_rwlock_destroy(&runguard);
pthread_rwlock_destroy(&cache_guard);
pthread_cond_destroy(&mutexcond);
delete internal_comet_manager;
}
void webserver::sweet_kill()
{
this->stop();
}
void webserver::request_completed (
void *cls,
struct MHD_Connection *connection,
void **con_cls,
enum MHD_RequestTerminationCode toe
)
{
details::modded_request* mr = static_cast(*con_cls);
if (mr == 0x0) return;
if (mr->ws != 0x0) mr->ws->internal_comet_manager->complete_request(mr->dhrs->connection_id);
delete mr;
mr = 0x0;
}
bool webserver::register_resource(const std::string& resource, http_resource* hrm, bool family)
{
details::http_endpoint idx(resource, family, true, regex_checking);
pair