mirror of
https://github.com/lammertb/libhttp.git
synced 2025-08-06 05:02:40 +03:00
More functional error logging
This commit is contained in:
@@ -27,6 +27,10 @@
|
|||||||
|
|
||||||
#define LIBHTTP_VERSION "1.9"
|
#define LIBHTTP_VERSION "1.9"
|
||||||
|
|
||||||
|
#ifndef UNUSED_PARAMETER
|
||||||
|
#define UNUSED_PARAMETER(x) (void)(x)
|
||||||
|
#endif /* UNUSED_PARAMETER */
|
||||||
|
|
||||||
#ifndef LIBHTTP_API
|
#ifndef LIBHTTP_API
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#if defined(LIBHTTP_DLL_EXPORTS)
|
#if defined(LIBHTTP_DLL_EXPORTS)
|
||||||
@@ -209,10 +213,7 @@ struct httplib_callbacks {
|
|||||||
|
|
||||||
/* Called when LibHTTP has finished processing request. */
|
/* Called when LibHTTP has finished processing request. */
|
||||||
void (*end_request)(const struct httplib_connection *, int reply_status_code);
|
void (*end_request)(const struct httplib_connection *, int reply_status_code);
|
||||||
|
int (*log_message)( const struct httplib_context *ctx, const struct httplib_connection * conn, const char *message );
|
||||||
/* Called when LibHTTP is about to log a message. If callback returns
|
|
||||||
non-zero, LibHTTP does not log anything. */
|
|
||||||
int (*log_message)(const struct httplib_connection *, const char *message);
|
|
||||||
|
|
||||||
/* Called when LibHTTP is about to log access. If callback returns
|
/* Called when LibHTTP is about to log access. If callback returns
|
||||||
non-zero, LibHTTP does not log anything. */
|
non-zero, LibHTTP does not log anything. */
|
||||||
@@ -468,10 +469,6 @@ struct httplib_server_ports {
|
|||||||
int port; /* port number */
|
int port; /* port number */
|
||||||
bool has_ssl; /* https port: 0 = no, 1 = yes */
|
bool has_ssl; /* https port: 0 = no, 1 = yes */
|
||||||
bool has_redirect; /* redirect all requests: 0 = no, 1 = yes */
|
bool has_redirect; /* redirect all requests: 0 = no, 1 = yes */
|
||||||
int _reserved1;
|
|
||||||
int _reserved2;
|
|
||||||
int _reserved3;
|
|
||||||
int _reserved4;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -815,7 +812,6 @@ typedef LIBHTTP_THREAD_TYPE (LIBHTTP_THREAD_CALLING_CONV *httplib_thread_func_t)
|
|||||||
LIBHTTP_API int httplib_start_thread(httplib_thread_func_t f, void *p);
|
LIBHTTP_API int httplib_start_thread(httplib_thread_func_t f, void *p);
|
||||||
|
|
||||||
|
|
||||||
LIBHTTP_API const char * httplib_get_builtin_mime_type( const char *file_name );
|
|
||||||
|
|
||||||
|
|
||||||
/* Get text representation of HTTP status code. */
|
/* Get text representation of HTTP status code. */
|
||||||
@@ -905,8 +901,7 @@ struct httplib_client_options {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
LIBHTTP_API struct httplib_connection *
|
LIBHTTP_API struct httplib_connection *httplib_connect_client_secure(const struct httplib_client_options *client_options, char *error_buffer, size_t error_buffer_size);
|
||||||
httplib_connect_client_secure(const struct httplib_client_options *client_options, char *error_buffer, size_t error_buffer_size);
|
|
||||||
|
|
||||||
|
|
||||||
enum { TIMEOUT_INFINITE = -1 };
|
enum { TIMEOUT_INFINITE = -1 };
|
||||||
@@ -926,73 +921,63 @@ enum { TIMEOUT_INFINITE = -1 };
|
|||||||
LIBHTTP_API int httplib_get_response(struct httplib_connection *conn, char *ebuf, size_t ebuf_len, int timeout);
|
LIBHTTP_API int httplib_get_response(struct httplib_connection *conn, char *ebuf, size_t ebuf_len, int timeout);
|
||||||
|
|
||||||
|
|
||||||
/* Check which features where set when LibHTTP has been compiled.
|
|
||||||
Parameters:
|
|
||||||
feature: specifies which feature should be checked
|
|
||||||
2 support HTTPS (NO_SSL not set)
|
|
||||||
4 support CGI (NO_CGI not set)
|
|
||||||
The result is undefined for all other feature values.
|
|
||||||
|
|
||||||
Return:
|
|
||||||
If feature is available > 0
|
|
||||||
If feature is not available = 0
|
|
||||||
*/
|
|
||||||
LIBHTTP_API unsigned httplib_check_feature(unsigned feature);
|
|
||||||
|
|
||||||
typedef void (*httplib_alloc_callback_func)( const char *file, unsigned line, const char *action, int64_t current_bytes, int64_t total_blocks, int64_t total_bytes );
|
typedef void (*httplib_alloc_callback_func)( const char *file, unsigned line, const char *action, int64_t current_bytes, int64_t total_blocks, int64_t total_bytes );
|
||||||
|
|
||||||
#define httplib_calloc(a, b) XX_httplib_calloc_ex(a, b, __FILE__, __LINE__)
|
#define httplib_calloc(a, b) XX_httplib_calloc_ex(a, b, __FILE__, __LINE__)
|
||||||
#define httplib_free(a) XX_httplib_free_ex(a, __FILE__, __LINE__)
|
#define httplib_free(a) XX_httplib_free_ex(a, __FILE__, __LINE__)
|
||||||
#define httplib_malloc(a) XX_httplib_malloc_ex(a, __FILE__, __LINE__)
|
#define httplib_malloc(a) XX_httplib_malloc_ex(a, __FILE__, __LINE__)
|
||||||
#define httplib_realloc(a, b) XX_httplib_realloc_ex(a, b, __FILE__, __LINE__)
|
#define httplib_realloc(a, b) XX_httplib_realloc_ex(a, b, __FILE__, __LINE__)
|
||||||
|
|
||||||
LIBHTTP_API void * XX_httplib_calloc_ex( size_t count, size_t size, const char *file, unsigned line );
|
LIBHTTP_API void * XX_httplib_calloc_ex( size_t count, size_t size, const char *file, unsigned line );
|
||||||
LIBHTTP_API void XX_httplib_free_ex( void *memory, const char *file, unsigned line );
|
LIBHTTP_API void XX_httplib_free_ex( void *memory, const char *file, unsigned line );
|
||||||
LIBHTTP_API void * XX_httplib_malloc_ex( size_t size, const char *file, unsigned line );
|
LIBHTTP_API void * XX_httplib_malloc_ex( size_t size, const char *file, unsigned line );
|
||||||
LIBHTTP_API void * XX_httplib_realloc_ex( void *memory, size_t newsize, const char *file, unsigned line );
|
LIBHTTP_API void * XX_httplib_realloc_ex( void *memory, size_t newsize, const char *file, unsigned line );
|
||||||
|
|
||||||
LIBHTTP_API int httplib_atomic_dec( volatile int *addr );
|
LIBHTTP_API int httplib_atomic_dec( volatile int *addr );
|
||||||
LIBHTTP_API int httplib_atomic_inc( volatile int *addr );
|
LIBHTTP_API int httplib_atomic_inc( volatile int *addr );
|
||||||
LIBHTTP_API int httplib_base64_encode( const unsigned char *src, int src_len, char *dst, int dst_len );
|
LIBHTTP_API int httplib_base64_encode( const unsigned char *src, int src_len, char *dst, int dst_len );
|
||||||
LIBHTTP_API int httplib_closedir( DIR *dir );
|
LIBHTTP_API unsigned httplib_check_feature( unsigned feature );
|
||||||
LIBHTTP_API void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(3, 4);
|
LIBHTTP_API int httplib_closedir( DIR *dir );
|
||||||
LIBHTTP_API uint64_t httplib_get_random( void );
|
LIBHTTP_API void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(3, 4);
|
||||||
LIBHTTP_API void * httplib_get_user_connection_data( const struct httplib_connection *conn );
|
LIBHTTP_API const char * httplib_get_builtin_mime_type( const char *file_name );
|
||||||
LIBHTTP_API int httplib_kill( pid_t pid, int sig_num );
|
LIBHTTP_API uint64_t httplib_get_random( void );
|
||||||
LIBHTTP_API int httplib_mkdir( const char *path, int mode );
|
LIBHTTP_API void * httplib_get_user_connection_data( const struct httplib_connection *conn );
|
||||||
LIBHTTP_API DIR * httplib_opendir( const char *name );
|
LIBHTTP_API int httplib_kill( pid_t pid, int sig_num );
|
||||||
LIBHTTP_API int httplib_poll( struct pollfd *pfd, unsigned int nfds, int timeout );
|
LIBHTTP_API int httplib_mkdir( const char *path, int mode );
|
||||||
LIBHTTP_API int httplib_pthread_cond_broadcast( pthread_cond_t *cv );
|
LIBHTTP_API DIR * httplib_opendir( const char *name );
|
||||||
LIBHTTP_API int httplib_pthread_cond_destroy( pthread_cond_t *cv );
|
LIBHTTP_API int httplib_poll( struct pollfd *pfd, unsigned int nfds, int timeout );
|
||||||
LIBHTTP_API int httplib_pthread_cond_init( pthread_cond_t *cv, const pthread_condattr_t *attr );
|
LIBHTTP_API int httplib_pthread_cond_broadcast( pthread_cond_t *cv );
|
||||||
LIBHTTP_API int httplib_pthread_cond_signal( pthread_cond_t *cv );
|
LIBHTTP_API int httplib_pthread_cond_destroy( pthread_cond_t *cv );
|
||||||
LIBHTTP_API int httplib_pthread_cond_timedwait( pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec *abstime );
|
LIBHTTP_API int httplib_pthread_cond_init( pthread_cond_t *cv, const pthread_condattr_t *attr );
|
||||||
LIBHTTP_API int httplib_pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mutex );
|
LIBHTTP_API int httplib_pthread_cond_signal( pthread_cond_t *cv );
|
||||||
LIBHTTP_API void * httplib_pthread_getspecific( pthread_key_t key );
|
LIBHTTP_API int httplib_pthread_cond_timedwait( pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec *abstime );
|
||||||
LIBHTTP_API int httplib_pthread_join( pthread_t thread, void **value_ptr );
|
LIBHTTP_API int httplib_pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mutex );
|
||||||
LIBHTTP_API int httplib_pthread_key_create( pthread_key_t *key, void (*destructor)(void *) );
|
LIBHTTP_API void * httplib_pthread_getspecific( pthread_key_t key );
|
||||||
LIBHTTP_API int httplib_pthread_key_delete( pthread_key_t key );
|
LIBHTTP_API int httplib_pthread_join( pthread_t thread, void **value_ptr );
|
||||||
LIBHTTP_API int httplib_pthread_mutex_destroy( pthread_mutex_t *mutex );
|
LIBHTTP_API int httplib_pthread_key_create( pthread_key_t *key, void (*destructor)(void *) );
|
||||||
LIBHTTP_API int httplib_pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutexattr_t *attr );
|
LIBHTTP_API int httplib_pthread_key_delete( pthread_key_t key );
|
||||||
LIBHTTP_API int httplib_pthread_mutex_lock( pthread_mutex_t *mutex );
|
LIBHTTP_API int httplib_pthread_mutex_destroy( pthread_mutex_t *mutex );
|
||||||
LIBHTTP_API int httplib_pthread_mutex_trylock( pthread_mutex_t *mutex );
|
LIBHTTP_API int httplib_pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutexattr_t *attr );
|
||||||
LIBHTTP_API int httplib_pthread_mutex_unlock( pthread_mutex_t *mutex );
|
LIBHTTP_API int httplib_pthread_mutex_lock( pthread_mutex_t *mutex );
|
||||||
LIBHTTP_API pthread_t httplib_pthread_self( void );
|
LIBHTTP_API int httplib_pthread_mutex_trylock( pthread_mutex_t *mutex );
|
||||||
LIBHTTP_API int httplib_pthread_setspecific( pthread_key_t key, void *value );
|
LIBHTTP_API int httplib_pthread_mutex_unlock( pthread_mutex_t *mutex );
|
||||||
LIBHTTP_API struct dirent * httplib_readdir( DIR *dir );
|
LIBHTTP_API pthread_t httplib_pthread_self( void );
|
||||||
LIBHTTP_API int httplib_remove( const char *path );
|
LIBHTTP_API int httplib_pthread_setspecific( pthread_key_t key, void *value );
|
||||||
LIBHTTP_API void httplib_send_file( struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers );
|
LIBHTTP_API struct dirent * httplib_readdir( DIR *dir );
|
||||||
LIBHTTP_API void httplib_set_alloc_callback_func( httplib_alloc_callback_func log_func );
|
LIBHTTP_API int httplib_remove( const char *path );
|
||||||
LIBHTTP_API void httplib_set_user_connection_data( struct httplib_connection *conn, void *data );
|
LIBHTTP_API void httplib_send_file( struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers );
|
||||||
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_set_alloc_callback_func( httplib_alloc_callback_func log_func );
|
||||||
LIBHTTP_API void httplib_stop( struct httplib_context *ctx );
|
LIBHTTP_API void httplib_set_user_connection_data( struct httplib_connection *conn, void *data );
|
||||||
LIBHTTP_API int httplib_strcasecmp( const char *s1, const char *s2 );
|
LIBHTTP_API struct httplib_context * httplib_start(const struct httplib_callbacks *callbacks, void *user_data, const char **configuration_options );
|
||||||
LIBHTTP_API const char * httplib_strcasestr( const char *big_str, const char *small_str );
|
LIBHTTP_API void httplib_stop( struct httplib_context *ctx );
|
||||||
LIBHTTP_API char * httplib_strdup( const char *str );
|
LIBHTTP_API int httplib_strcasecmp( const char *s1, const char *s2 );
|
||||||
LIBHTTP_API void httplib_strlcpy( char *dst, const char *src, size_t len );
|
LIBHTTP_API const char * httplib_strcasestr( const char *big_str, const char *small_str );
|
||||||
LIBHTTP_API int httplib_strncasecmp( const char *s1, const char *s2, size_t len );
|
LIBHTTP_API char * httplib_strdup( const char *str );
|
||||||
LIBHTTP_API char * httplib_strndup( const char *str, size_t len );
|
LIBHTTP_API void httplib_strlcpy( char *dst, const char *src, size_t len );
|
||||||
LIBHTTP_API const char * httplib_version( void );
|
LIBHTTP_API int httplib_strncasecmp( const char *s1, const char *s2, size_t len );
|
||||||
|
LIBHTTP_API char * httplib_strndup( const char *str, size_t len );
|
||||||
|
LIBHTTP_API const char * httplib_version( void );
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@@ -20,9 +20,6 @@
|
|||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*
|
|
||||||
* ============
|
|
||||||
* Release: 2.0
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "httplib_main.h"
|
#include "httplib_main.h"
|
||||||
@@ -32,7 +29,8 @@
|
|||||||
* void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, const char *fmt, ... );
|
* void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, const char *fmt, ... );
|
||||||
*
|
*
|
||||||
* The function httplib_cry() prints a formatted error message to the opened
|
* The function httplib_cry() prints a formatted error message to the opened
|
||||||
* error log stream.
|
* error log stream. It first tries to use a user supplied error handler. If
|
||||||
|
* that doesn't work, the alternative is to write to an error log file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, const char *fmt, ... ) {
|
void httplib_cry( const struct httplib_context *ctx, const struct httplib_connection *conn, const char *fmt, ... ) {
|
||||||
@@ -43,47 +41,70 @@ void httplib_cry( const struct httplib_context *ctx, const struct httplib_connec
|
|||||||
struct file fi;
|
struct file fi;
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we have a context. Without a context there is no callback
|
||||||
|
* and also other important information like the path to the error file
|
||||||
|
* is missing. No need to continue if that information cannot be
|
||||||
|
* retrieved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ctx == NULL ) return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gather all the information from the parameters of this function and
|
||||||
|
* create a NULL terminated string buffer with the error message.
|
||||||
|
*/
|
||||||
|
|
||||||
va_start( ap, fmt );
|
va_start( ap, fmt );
|
||||||
vsnprintf_impl( buf, sizeof(buf), fmt, ap );
|
vsnprintf_impl( buf, sizeof(buf), fmt, ap );
|
||||||
va_end( ap );
|
va_end( ap );
|
||||||
buf[sizeof(buf)-1] = 0;
|
buf[sizeof(buf)-1] = 0;
|
||||||
|
|
||||||
if ( ctx == NULL ) return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not lock when getting the callback value, here and below.
|
* Let's first try to use the user's custom error handler callback. If
|
||||||
* I suppose this is fine, since function cannot disappear in the
|
* that succeeds, there is no need for us to do our own error
|
||||||
* same way string option can.
|
* processing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( conn == NULL || ctx->callbacks.log_message == NULL || ctx->callbacks.log_message( conn, buf ) == 0 ) {
|
if ( ctx->callbacks.log_message != NULL && ctx->callbacks.log_message( ctx, conn, buf ) != 0 ) return;
|
||||||
|
|
||||||
if ( ctx->cfg[ERROR_LOG_FILE] != NULL ) {
|
/*
|
||||||
|
* We now try to open the error log file. If this succeeds the error is
|
||||||
|
* appended to the file. On failure there is no way to log the message
|
||||||
|
* without disrupting the user's flow of control so we just return and
|
||||||
|
* logging anything. This is IMHO better than printing to stderr which
|
||||||
|
* may not even be available on all platforms (Windows etc).
|
||||||
|
*/
|
||||||
|
|
||||||
if ( XX_httplib_fopen( conn, ctx->cfg[ERROR_LOG_FILE], "a+", &fi ) == 0 ) fi.fp = NULL;
|
if ( ctx->cfg[ERROR_LOG_FILE] == NULL ) return;
|
||||||
}
|
if ( ! XX_httplib_fopen( conn, ctx->cfg[ERROR_LOG_FILE], "a+", &fi ) ) return;
|
||||||
|
|
||||||
else fi.fp = NULL;
|
|
||||||
|
|
||||||
if ( fi.fp != NULL ) {
|
/*
|
||||||
|
* We now have an open FILE stream pointer in fi.fp and can dump the
|
||||||
|
* message in that file. Note though, that some information might not
|
||||||
|
* be available for logging if the message has no connection, so some
|
||||||
|
* information is skipped if the 'conn' parameter is NULL.
|
||||||
|
*
|
||||||
|
* Just to be sure that no other process is writing to the same file,
|
||||||
|
* we use locking around this operation.
|
||||||
|
*/
|
||||||
|
|
||||||
flockfile( fi.fp );
|
flockfile( fi.fp );
|
||||||
timestamp = time( NULL );
|
timestamp = time( NULL );
|
||||||
|
|
||||||
if ( conn != 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 != NULL && 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 );
|
||||||
}
|
|
||||||
|
|
||||||
fprintf( fi.fp, "%s", buf );
|
|
||||||
fputc( '\n', fi.fp );
|
|
||||||
fflush( fi.fp );
|
|
||||||
funlockfile( fi.fp );
|
|
||||||
XX_httplib_fclose( &fi );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf( fi.fp, "%s", buf );
|
||||||
|
fputc( '\n', fi.fp );
|
||||||
|
fflush( fi.fp );
|
||||||
|
|
||||||
|
funlockfile( fi.fp );
|
||||||
|
XX_httplib_fclose( &fi );
|
||||||
|
|
||||||
} /* httplib_cry */
|
} /* httplib_cry */
|
||||||
|
@@ -24,10 +24,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef UNUSED_PARAMETER
|
|
||||||
#define UNUSED_PARAMETER(x) (void)(x)
|
|
||||||
#endif /* UNUSED_PARAMETER */
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
#if !defined(_CRT_SECURE_NO_WARNINGS)
|
#if !defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
@@ -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, char *ebuf, size_t ebuf_len, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(4, 5);
|
static struct httplib_context * cleanup( struct httplib_context *ctx, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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 *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options );
|
||||||
*
|
*
|
||||||
* 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, char *ebuf, size_t ebuf_len ) {
|
struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const char **options ) {
|
||||||
|
|
||||||
struct httplib_context *ctx;
|
struct httplib_context *ctx;
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -50,21 +50,50 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
|
|||||||
int idx;
|
int idx;
|
||||||
int workerthreadcount;
|
int workerthreadcount;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
void (*exit_callback)(const struct httplib_context *ctx) = NULL;
|
void (*exit_callback)(const struct httplib_context *ctx);
|
||||||
struct httplib_workerTLS tls;
|
struct httplib_workerTLS tls;
|
||||||
|
|
||||||
if ( ebuf != NULL && ebuf_len > 0 ) ebuf[0] = '\0';
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Yes, this is Windows and nothing works out of the box. We first have
|
||||||
|
* to initialize socket communications by telling Windows which socket
|
||||||
|
* version we want to use. 2.2 in this case.
|
||||||
|
*/
|
||||||
|
|
||||||
WSADATA data;
|
WSADATA data;
|
||||||
WSAStartup(MAKEWORD(2, 2), &data);
|
WSAStartup( MAKEWORD(2, 2), &data );
|
||||||
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
ctx = httplib_calloc( 1, sizeof(*ctx) );
|
/*
|
||||||
if ( ctx == NULL ) {
|
* No memory for the ctx structure is the only error which we
|
||||||
|
* don't log through httplib_cry() for the simple reason that we do not
|
||||||
if ( ebuf != NULL && ebuf_len > 0 ) snprintf( ebuf, ebuf_len, "No memory for CTX structure" );
|
* have enough configured yet to make that function working. Having an
|
||||||
return NULL;
|
* OOM in this state of the process though should be noticed by the
|
||||||
|
* calling process in other parts of their execution anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exit_callback = NULL;
|
||||||
|
ctx = httplib_calloc( 1, sizeof(*ctx) );
|
||||||
|
|
||||||
|
if ( ctx == NULL ) return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup callback functions very early. This is necessary to make the
|
||||||
|
* log_message() callback function available in case an error occurs.
|
||||||
|
*
|
||||||
|
* We first set the exit_context() callback to NULL becasue no proper
|
||||||
|
* context is available yet and we do not want to mess up things if the
|
||||||
|
* function exits and that callback is given a half-decent structure to
|
||||||
|
* work on and without a call to init_context() before.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( callbacks != NULL ) {
|
||||||
|
|
||||||
|
ctx->callbacks = *callbacks;
|
||||||
|
exit_callback = callbacks->exit_context;
|
||||||
|
ctx->callbacks.exit_context = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -93,15 +122,16 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
/* TODO (low): istead of sleeping, check if XX_httplib_sTlsKey is already
|
/*
|
||||||
* initialized. */
|
* TODO (low): istead of sleeping, check if XX_httplib_sTlsKey is already
|
||||||
|
* initialized.
|
||||||
|
*/
|
||||||
|
|
||||||
httplib_sleep( 1 );
|
httplib_sleep( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,19 +142,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, ebuf, ebuf_len, "Cannot initialize thread mutex" );
|
if ( httplib_pthread_mutex_init( & ctx->thread_mutex, &XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, "Cannot initialize thread mutex" );
|
||||||
#if !defined(ALTERNATIVE_QUEUE)
|
#if !defined(ALTERNATIVE_QUEUE)
|
||||||
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_empty, NULL ) ) return cleanup( ctx, "Cannot initialize empty queue condition" );
|
||||||
if ( httplib_pthread_cond_init( & ctx->sq_full, NULL ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize full queue condition" );
|
if ( httplib_pthread_cond_init( & ctx->sq_full, NULL ) ) return cleanup( ctx, "Cannot initialize full queue condition" );
|
||||||
#endif
|
#endif
|
||||||
if ( httplib_pthread_mutex_init( & ctx->nonce_mutex, & XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, ebuf, ebuf_len, "Cannot initialize nonce mutex" );
|
if ( httplib_pthread_mutex_init( & ctx->nonce_mutex, & XX_httplib_pthread_mutex_attr ) ) return cleanup( ctx, "Cannot initialize nonce mutex" );
|
||||||
|
|
||||||
if ( callbacks != NULL ) {
|
|
||||||
|
|
||||||
ctx->callbacks = *callbacks;
|
|
||||||
exit_callback = callbacks->exit_context;
|
|
||||||
ctx->callbacks.exit_context = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->user_data = user_data;
|
ctx->user_data = user_data;
|
||||||
ctx->handlers = NULL;
|
ctx->handlers = NULL;
|
||||||
@@ -132,8 +155,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, ebuf, ebuf_len, "Invalid option: %s", name );
|
if ( idx == -1 ) return cleanup( ctx, "Invalid option: %s", name );
|
||||||
if ( (value = *options++) == NULL ) return cleanup( ctx, ebuf, ebuf_len, "%s: option value cannot be NULL", name );
|
if ( (value = *options++) == NULL ) return cleanup( ctx, "%s: option value cannot be NULL", name );
|
||||||
|
|
||||||
if ( ctx->cfg[idx] != NULL ) {
|
if ( ctx->cfg[idx] != NULL ) {
|
||||||
|
|
||||||
@@ -161,13 +184,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, ebuf, ebuf_len, "Error setting gpass option" );
|
if ( ! XX_httplib_set_gpass_option( ctx ) ) return cleanup( ctx, "Error setting gpass option" );
|
||||||
#if !defined(NO_SSL)
|
#if !defined(NO_SSL)
|
||||||
if ( ! XX_httplib_set_ssl_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting SSL option" );
|
if ( ! XX_httplib_set_ssl_option( ctx ) ) return cleanup( ctx, "Error setting SSL option" );
|
||||||
#endif
|
#endif
|
||||||
if ( ! XX_httplib_set_ports_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting ports option" );
|
if ( ! XX_httplib_set_ports_option( ctx ) ) return cleanup( ctx, "Error setting ports option" );
|
||||||
if ( ! XX_httplib_set_uid_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting UID option" );
|
if ( ! XX_httplib_set_uid_option( ctx ) ) return cleanup( ctx, "Error setting UID option" );
|
||||||
if ( ! XX_httplib_set_acl_option( ctx ) ) return cleanup( ctx, ebuf, ebuf_len, "Error setting ACL option" );
|
if ( ! XX_httplib_set_acl_option( ctx ) ) return cleanup( ctx, "Error setting ACL option" );
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
|
|
||||||
@@ -180,40 +203,43 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
|
|||||||
|
|
||||||
#endif /* !_WIN32 */
|
#endif /* !_WIN32 */
|
||||||
|
|
||||||
if ( ctx->cfg[NUM_THREADS] == NULL ) return cleanup( ctx, ebuf, ebuf_len, "No worker thread number specified" );
|
if ( ctx->cfg[NUM_THREADS] == NULL ) return cleanup( ctx, "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, ebuf, ebuf_len, "Too many worker threads" );
|
if ( workerthreadcount > MAX_WORKER_THREADS ) return cleanup( ctx, "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, ebuf, ebuf_len, "Not enough memory for worker thread ID array" );
|
if ( ctx->workerthreadids == NULL ) return cleanup( ctx, "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, ebuf, ebuf_len, "Not enough memory for worker event array" );
|
if ( ctx->client_wait_events == NULL ) return cleanup( ctx, "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, ebuf, ebuf_len, "Not enough memory for worker socket array" );
|
if ( ctx->client_socks == NULL ) return cleanup( ctx, "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, ebuf, ebuf_len, "Error creating worker event %u", i );
|
if ( ctx->client_wait_events[i] == 0 ) return cleanup( ctx, "Error creating worker event %u", i );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_TIMERS)
|
#if defined(USE_TIMERS)
|
||||||
if ( timers_init( ctx ) != 0 ) return cleanup( ctx, ebuf, ebuf_len, "Error creating timers" );
|
if ( timers_init( ctx ) != 0 ) return cleanup( ctx, "Error creating timers" );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Context has been created - init user libraries
|
* Context has been created - init user libraries
|
||||||
|
*
|
||||||
|
* Context has been properly setup. It is now safe to use exit_context
|
||||||
|
* in case the system needs a shutdown.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( ctx->callbacks.init_context != NULL ) ctx->callbacks.init_context( ctx );
|
if ( ctx->callbacks.init_context != NULL ) ctx->callbacks.init_context( ctx );
|
||||||
@@ -252,7 +278,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, ebuf, ebuf_len, "Cannot create threads: error %ld", (long)ERRNO );
|
else return cleanup( ctx, "Cannot create threads: error %ld", (long)ERRNO );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -267,14 +293,14 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* static struct httplib_context *cleanup( struct httplib_context *ctx, char *ebuf, size_t ebuf_len, const char *fmt, ... );
|
* static struct httplib_context *cleanup( struct httplib_context *ctx, 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, char *ebuf, size_t ebuf_len, const char *fmt, ... ) {
|
static struct httplib_context *cleanup( struct httplib_context *ctx, const char *fmt, ... ) {
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char buf[MG_BUF_LEN];
|
char buf[MG_BUF_LEN];
|
||||||
@@ -284,8 +310,6 @@ static struct httplib_context *cleanup( struct httplib_context *ctx, char *ebuf,
|
|||||||
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 );
|
||||||
|
19
src/main.c
19
src/main.c
@@ -606,19 +606,20 @@ static void init_server_name(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int log_message(const struct httplib_connection *conn, const char *message) {
|
static int log_message( const struct httplib_context *ctx, const struct httplib_connection *conn, const char *message ) {
|
||||||
|
|
||||||
const struct httplib_context *ctx = httplib_get_context(conn);
|
struct tuser_data *ud;
|
||||||
struct tuser_data *ud = (struct tuser_data *)httplib_get_user_data(ctx);
|
|
||||||
|
|
||||||
fprintf(stderr, "%s\n", message);
|
UNUSED_PARAMETER(conn);
|
||||||
|
|
||||||
if (ud->first_message == NULL) {
|
fprintf( stderr, "%s\n", message );
|
||||||
ud->first_message = sdup(message);
|
|
||||||
}
|
ud = httplib_get_user_data( ctx );
|
||||||
|
if ( ud != NULL && ud->first_message == NULL ) ud->first_message = sdup( message );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
} /* log_message */
|
||||||
|
|
||||||
|
|
||||||
static int is_path_absolute(const char *path) {
|
static int is_path_absolute(const char *path) {
|
||||||
@@ -869,7 +870,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, NULL, 0 );
|
g_ctx = httplib_start(&callbacks, &g_user_data, (const char **)options );
|
||||||
|
|
||||||
/* 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