1
0
mirror of https://github.com/lammertb/libhttp.git synced 2025-08-06 05:02:40 +03:00

Better error handling at startup

This commit is contained in:
lammertb
2016-12-27 10:42:35 +01:00
parent 2b9add7116
commit 1c2467e587
5 changed files with 43 additions and 33 deletions

View File

@@ -310,7 +310,6 @@ struct httplib_callbacks {
Return: Return:
web server context, or NULL on error. */ web server context, or NULL on error. */
LIBHTTP_API struct httplib_context *httplib_start(const struct httplib_callbacks *callbacks, void *user_data, const char **configuration_options);
/* httplib_request_handler /* httplib_request_handler
@@ -985,6 +984,7 @@ LIBHTTP_API int httplib_remove( const char *path );
LIBHTTP_API void httplib_send_file( struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers ); LIBHTTP_API void httplib_send_file( struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers );
LIBHTTP_API void httplib_set_alloc_callback_func( httplib_alloc_callback_func log_func ); LIBHTTP_API void httplib_set_alloc_callback_func( httplib_alloc_callback_func log_func );
LIBHTTP_API void httplib_set_user_connection_data( struct httplib_connection *conn, void *data ); LIBHTTP_API void httplib_set_user_connection_data( struct httplib_connection *conn, void *data );
LIBHTTP_API struct httplib_context * httplib_start(const struct httplib_callbacks *callbacks, void *user_data, const char **configuration_options, char *ebuf, size_t ebuf_len );
LIBHTTP_API void httplib_stop( struct httplib_context *ctx ); LIBHTTP_API void httplib_stop( struct httplib_context *ctx );
LIBHTTP_API int httplib_strcasecmp( const char *s1, const char *s2 ); LIBHTTP_API int httplib_strcasecmp( const char *s1, const char *s2 );
LIBHTTP_API const char * httplib_strcasestr( const char *big_str, const char *small_str ); LIBHTTP_API const char * httplib_strcasestr( const char *big_str, const char *small_str );

View File

@@ -48,7 +48,7 @@ void httplib_cry( const struct httplib_context *ctx, const struct httplib_connec
va_end( ap ); va_end( ap );
buf[sizeof(buf)-1] = 0; buf[sizeof(buf)-1] = 0;
if ( conn == NULL || ctx == NULL ) return; if ( ctx == NULL ) return;
/* /*
* Do not lock when getting the callback value, here and below. * Do not lock when getting the callback value, here and below.
@@ -56,7 +56,7 @@ void httplib_cry( const struct httplib_context *ctx, const struct httplib_connec
* same way string option can. * same way string option can.
*/ */
if ( ctx->callbacks.log_message == NULL || ctx->callbacks.log_message( conn, buf ) == 0 ) { if ( conn == NULL || ctx->callbacks.log_message == NULL || ctx->callbacks.log_message( conn, buf ) == 0 ) {
if ( ctx->cfg[ERROR_LOG_FILE] != NULL ) { if ( ctx->cfg[ERROR_LOG_FILE] != NULL ) {
@@ -70,10 +70,10 @@ void httplib_cry( const struct httplib_context *ctx, const struct httplib_connec
flockfile( fi.fp ); flockfile( fi.fp );
timestamp = time( NULL ); timestamp = time( NULL );
XX_httplib_sockaddr_to_string( src_addr, sizeof(src_addr), &conn->client.rsa ); if ( conn != NULL ) XX_httplib_sockaddr_to_string( src_addr, sizeof(src_addr), &conn->client.rsa );
fprintf( fi.fp, "[%010lu] [error] [client %s] ", (unsigned long)timestamp, src_addr ); fprintf( fi.fp, "[%010lu] [error] [client %s] ", (unsigned long)timestamp, src_addr );
if ( conn->request_info.request_method != NULL ) { if ( conn != NULL && conn->request_info.request_method != NULL ) {
fprintf( fi.fp, "%s %s: ", conn->request_info.request_method, conn->request_info.request_uri ); fprintf( fi.fp, "%s %s: ", conn->request_info.request_method, conn->request_info.request_uri );
} }

View File

@@ -70,7 +70,7 @@ int XX_httplib_set_ports_option( struct httplib_context *ctx ) {
ports_total++; ports_total++;
if ( ! parse_port_string( & vec, & so, & ip_version ) ) { if ( ! parse_port_string( &vec, &so, &ip_version ) ) {
httplib_cry( ctx, NULL, httplib_cry( ctx, NULL,
"%.*s: invalid port spec (entry %i). Expecting list of: %s", "%.*s: invalid port spec (entry %i). Expecting list of: %s",

View File

@@ -31,17 +31,17 @@
#include "httplib_string.h" #include "httplib_string.h"
#include "httplib_utils.h" #include "httplib_utils.h"
static struct httplib_context * cleanup( struct httplib_context *ctx, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); static struct httplib_context * cleanup( struct httplib_context *ctx, char *ebuf, size_t ebuf_len, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(4, 5);
/* /*
* struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options ); * struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options, char *ebuf, size_t ebuf_len );
* *
* The function httplib_start() functions as the main entry point for the LibHTTP * The function httplib_start() functions as the main entry point for the LibHTTP
* server. The function starts all threads and when finished returns the * server. The function starts all threads and when finished returns the
* context to the running server for future reference. * context to the running server for future reference.
*/ */
struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options ) { struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options, char *ebuf, size_t ebuf_len ) {
struct httplib_context *ctx; struct httplib_context *ctx;
const char *name; const char *name;
@@ -53,13 +53,19 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
void (*exit_callback)(const struct httplib_context *ctx) = NULL; void (*exit_callback)(const struct httplib_context *ctx) = NULL;
struct httplib_workerTLS tls; struct httplib_workerTLS tls;
if ( ebuf != NULL && ebuf_len > 0 ) ebuf[0] = '\0';
#if defined(_WIN32) #if defined(_WIN32)
WSADATA data; WSADATA data;
WSAStartup(MAKEWORD(2, 2), &data); WSAStartup(MAKEWORD(2, 2), &data);
#endif /* _WIN32 */ #endif /* _WIN32 */
ctx = httplib_calloc( 1, sizeof(*ctx) ); ctx = httplib_calloc( 1, sizeof(*ctx) );
if ( ctx == NULL ) return NULL; if ( ctx == NULL ) {
if ( ebuf != NULL && ebuf_len > 0 ) snprintf( ebuf, ebuf_len, "No memory for CTX structure" );
return NULL;
}
/* /*
* Random number generator will initialize at the first call * Random number generator will initialize at the first call
@@ -87,6 +93,8 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
httplib_cry( ctx, NULL, "Cannot initialize thread local storage" ); httplib_cry( ctx, NULL, "Cannot initialize thread local storage" );
httplib_free( ctx ); httplib_free( ctx );
if ( ebuf != NULL && ebuf_len > 0 ) snprintf( ebuf, ebuf_len, "Cannot create pthread key" );
return NULL; return NULL;
} }
} }
@@ -104,12 +112,12 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
#endif #endif
httplib_pthread_setspecific( XX_httplib_sTlsKey, & tls ); httplib_pthread_setspecific( XX_httplib_sTlsKey, & tls );
if ( httplib_pthread_mutex_init( & ctx->thread_mutex, &XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, "Cannot initialize thread mutex" ); if ( httplib_pthread_mutex_init( & ctx->thread_mutex, &XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize thread mutex" );
#if !defined(ALTERNATIVE_QUEUE) #if !defined(ALTERNATIVE_QUEUE)
if ( httplib_pthread_cond_init( & ctx->sq_empty, NULL ) ) return cleanup( ctx, "Cannot initialize empty queue condition" ); if ( httplib_pthread_cond_init( & ctx->sq_empty, NULL ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize empty queue condition" );
if ( httplib_pthread_cond_init( & ctx->sq_full, NULL ) ) return cleanup( ctx, "Cannot initialize full queue condition" ); if ( httplib_pthread_cond_init( & ctx->sq_full, NULL ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize full queue condition" );
#endif #endif
if ( httplib_pthread_mutex_init( & ctx->nonce_mutex, & XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, "Cannot initialize nonce mutex" ); if ( httplib_pthread_mutex_init( & ctx->nonce_mutex, & XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize nonce mutex" );
if ( callbacks != NULL ) { if ( callbacks != NULL ) {
@@ -124,8 +132,8 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
while ( options && (name = *options++) != NULL ) { while ( options && (name = *options++) != NULL ) {
idx = XX_httplib_get_option_index( name ); idx = XX_httplib_get_option_index( name );
if ( idx == -1 ) return cleanup( ctx, "Invalid option: %s", name ); if ( idx == -1 ) return cleanup( ctx, ebuf, ebuf_len, "Invalid option: %s", name );
if ( (value = *options++) == NULL ) return cleanup( ctx , "%s: option value cannot be NULL", name ); if ( (value = *options++) == NULL ) return cleanup( ctx, ebuf, ebuf_len, "%s: option value cannot be NULL", name );
if ( ctx->cfg[idx] != NULL ) { if ( ctx->cfg[idx] != NULL ) {
@@ -153,13 +161,13 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
* be initialized before listening ports. UID must be set last. * be initialized before listening ports. UID must be set last.
*/ */
if ( ! XX_httplib_set_gpass_option( ctx ) ) return cleanup( ctx, "Error setting gpass option" ); if ( ! XX_httplib_set_gpass_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting gpass option" );
#if !defined(NO_SSL) #if !defined(NO_SSL)
if ( ! XX_httplib_set_ssl_option( ctx ) ) return cleanup( ctx, "Error setting SSL option" ); if ( ! XX_httplib_set_ssl_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting SSL option" );
#endif #endif
if ( ! XX_httplib_set_ports_option( ctx ) ) return cleanup( ctx, "Error setting ports option" ); if ( ! XX_httplib_set_ports_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting ports option" );
if ( ! XX_httplib_set_uid_option( ctx ) ) return cleanup( ctx, "Error setting UID option" ); if ( ! XX_httplib_set_uid_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting UID option" );
if ( ! XX_httplib_set_acl_option( ctx ) ) return cleanup( ctx, "Error setting ACL option" ); if ( ! XX_httplib_set_acl_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting ACL option" );
#if !defined(_WIN32) #if !defined(_WIN32)
@@ -172,36 +180,36 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
#endif /* !_WIN32 */ #endif /* !_WIN32 */
if ( ctx->cfg[NUM_THREADS] == NULL ) return cleanup( ctx, "No worker thread number specified" ); if ( ctx->cfg[NUM_THREADS] == NULL ) return cleanup( ctx, ebuf, ebuf_len, "No worker thread number specified" );
workerthreadcount = atoi( ctx->cfg[NUM_THREADS] ); workerthreadcount = atoi( ctx->cfg[NUM_THREADS] );
if ( workerthreadcount > MAX_WORKER_THREADS ) return cleanup( ctx, "Too many worker threads" ); if ( workerthreadcount > MAX_WORKER_THREADS ) return cleanup( ctx, ebuf, ebuf_len, "Too many worker threads" );
if ( workerthreadcount > 0 ) { if ( workerthreadcount > 0 ) {
ctx->cfg_worker_threads = (unsigned int)(workerthreadcount); ctx->cfg_worker_threads = (unsigned int)(workerthreadcount);
ctx->workerthreadids = httplib_calloc( ctx->cfg_worker_threads, sizeof(pthread_t) ); ctx->workerthreadids = httplib_calloc( ctx->cfg_worker_threads, sizeof(pthread_t) );
if ( ctx->workerthreadids == NULL ) return cleanup( ctx, "Not enough memory for worker thread ID array" ); if ( ctx->workerthreadids == NULL ) return cleanup( ctx, ebuf, ebuf_len, "Not enough memory for worker thread ID array" );
#if defined(ALTERNATIVE_QUEUE) #if defined(ALTERNATIVE_QUEUE)
ctx->client_wait_events = httplib_calloc( sizeof(ctx->client_wait_events[0]), ctx->cfg_worker_threads ); ctx->client_wait_events = httplib_calloc( sizeof(ctx->client_wait_events[0]), ctx->cfg_worker_threads );
if ( ctx->client_wait_events == NULL ) return cleanup( ctx, "Not enough memory for worker event array" ); if ( ctx->client_wait_events == NULL ) return cleanup( ctx, ebuf, ebuf_len, "Not enough memory for worker event array" );
ctx->client_socks = httplib_calloc( sizeof(ctx->client_socks[0]), ctx->cfg_worker_threads ); ctx->client_socks = httplib_calloc( sizeof(ctx->client_socks[0]), ctx->cfg_worker_threads );
if ( ctx->client_socks == NULL ) return cleanup( ctx, "Not enough memory for worker socket array" ); if ( ctx->client_socks == NULL ) return cleanup( ctx, ebuf, ebuf_len, "Not enough memory for worker socket array" );
for (i=0; i<ctx->cfg_worker_threads; i++) { for (i=0; i<ctx->cfg_worker_threads; i++) {
ctx->client_wait_events[i] = event_create(); ctx->client_wait_events[i] = event_create();
if ( ctx->client_wait_events[i] == 0 ) return cleanup( ctx, "Error creating worker event %u", i ); if ( ctx->client_wait_events[i] == 0 ) return cleanup( ctx, ebuf, ebuf_len, "Error creating worker event %u", i );
} }
#endif #endif
} }
#if defined(USE_TIMERS) #if defined(USE_TIMERS)
if ( timers_init( ctx ) != 0 ) return cleanup( ctx, "Error creating timers" ); if ( timers_init( ctx ) != 0 ) return cleanup( ctx, ebuf, ebuf_len, "Error creating timers" );
#endif #endif
/* /*
@@ -244,7 +252,7 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
if ( i > 0 ) httplib_cry( ctx, NULL, "Cannot start worker thread %i: error %ld", i + 1, (long)ERRNO ); if ( i > 0 ) httplib_cry( ctx, NULL, "Cannot start worker thread %i: error %ld", i + 1, (long)ERRNO );
else return cleanup( ctx, "Cannot create threads: error %ld", (long)ERRNO ); else return cleanup( ctx, ebuf, ebuf_len, "Cannot create threads: error %ld", (long)ERRNO );
break; break;
} }
@@ -259,14 +267,14 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
/* /*
* static struct httplib_context *cleanup( struct httplib_context *ctx, const char *fmt, ... ); * static struct httplib_context *cleanup( struct httplib_context *ctx, char *ebuf, size_t ebuf_len, const char *fmt, ... );
* *
* The function cleanup() is called to do some cleanup work when an error * The function cleanup() is called to do some cleanup work when an error
* occured initializing a context. The function returns NULL which is then * occured initializing a context. The function returns NULL which is then
* further returned to the calling party. * further returned to the calling party.
*/ */
static struct httplib_context *cleanup( struct httplib_context *ctx, const char *fmt, ... ) { static struct httplib_context *cleanup( struct httplib_context *ctx, char *ebuf, size_t ebuf_len, const char *fmt, ... ) {
va_list ap; va_list ap;
char buf[MG_BUF_LEN]; char buf[MG_BUF_LEN];
@@ -276,7 +284,9 @@ static struct httplib_context *cleanup( struct httplib_context *ctx, const char
va_end( ap ); va_end( ap );
buf[sizeof(buf)-1] = 0; buf[sizeof(buf)-1] = 0;
httplib_cry(ctx, NULL, "%s", buf ); if ( ebuf != NULL && ebuf_len > 0 ) snprintf( ebuf, ebuf_len, "%s", buf );
httplib_cry( ctx, NULL, "%s", buf );
if ( ctx != NULL ) XX_httplib_free_context( ctx ); if ( ctx != NULL ) XX_httplib_free_context( ctx );
httplib_pthread_setspecific( XX_httplib_sTlsKey, NULL ); httplib_pthread_setspecific( XX_httplib_sTlsKey, NULL );

View File

@@ -869,7 +869,7 @@ static void start_libhttp(int argc, char *argv[]) {
/* Start LibHTTP */ /* Start LibHTTP */
memset(&callbacks, 0, sizeof(callbacks)); memset(&callbacks, 0, sizeof(callbacks));
callbacks.log_message = &log_message; callbacks.log_message = &log_message;
g_ctx = httplib_start(&callbacks, &g_user_data, (const char **)options); g_ctx = httplib_start(&callbacks, &g_user_data, (const char **)options, NULL, 0 );
/* httplib_start copies all options to an internal buffer. /* httplib_start copies all options to an internal buffer.
* The options data field here is not required anymore. */ * The options data field here is not required anymore. */