mirror of
https://github.com/lammertb/libhttp.git
synced 2025-08-07 16:02:55 +03:00
Better error handling at startup
This commit is contained in:
@@ -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 );
|
||||||
|
@@ -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 );
|
||||||
}
|
}
|
||||||
|
@@ -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,6 +284,8 @@ 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;
|
||||||
|
|
||||||
|
if ( ebuf != NULL && ebuf_len > 0 ) snprintf( ebuf, ebuf_len, "%s", buf );
|
||||||
|
|
||||||
httplib_cry( ctx, NULL, "%s", buf );
|
httplib_cry( ctx, NULL, "%s", buf );
|
||||||
|
|
||||||
if ( ctx != NULL ) XX_httplib_free_context( ctx );
|
if ( ctx != NULL ) XX_httplib_free_context( ctx );
|
||||||
|
@@ -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. */
|
||||||
|
Reference in New Issue
Block a user