From f5e401578b6ab8b44e12cd96696eb7e55f9c65bd Mon Sep 17 00:00:00 2001 From: Lammert Bies Date: Sat, 31 Dec 2016 21:32:02 +0100 Subject: [PATCH] Client contexts are now real, not fake --- Makefile | 45 +- include/libhttp.h | 28 +- src/httplib_abort_start.c | 56 ++ src/httplib_connect_client.c | 29 +- src/httplib_connect_websocket_client.c | 53 +- src/httplib_create_client_context.c | 46 ++ src/httplib_destroy_client_context.c | 41 ++ src/httplib_download.c | 6 +- src/httplib_free_config_options.c | 62 +++ src/httplib_free_context.c | 30 +- src/httplib_init_options.c | 118 +++++ src/httplib_main.h | 6 + src/httplib_process_options.c | 338 ++++++++++++ src/httplib_pthread.h | 1 - src/httplib_ssl.h | 1 - src/httplib_start.c | 498 +----------------- src/httplib_stop.c | 4 - src/httplib_system_exit.c | 49 ++ ...config_options.c => httplib_system_init.c} | 31 +- 19 files changed, 845 insertions(+), 597 deletions(-) create mode 100644 src/httplib_abort_start.c create mode 100644 src/httplib_create_client_context.c create mode 100644 src/httplib_destroy_client_context.c create mode 100644 src/httplib_free_config_options.c create mode 100644 src/httplib_init_options.c create mode 100644 src/httplib_process_options.c create mode 100644 src/httplib_system_exit.c rename src/{httplib_config_options.c => httplib_system_init.c} (72%) diff --git a/Makefile b/Makefile index 838470f2..201ea623 100644 --- a/Makefile +++ b/Makefile @@ -189,6 +189,7 @@ OBJLIST = \ ${OBJDIR}extern_md5${OBJEXT} \ ${OBJDIR}extern_sha1${OBJEXT} \ ${OBJDIR}extern_ssl_lut${OBJEXT} \ + ${OBJDIR}httplib_abort_start${OBJEXT} \ ${OBJDIR}httplib_accept_new_connection${OBJEXT} \ ${OBJDIR}httplib_addenv${OBJEXT} \ ${OBJDIR}httplib_atomic_dec${OBJEXT} \ @@ -204,14 +205,15 @@ OBJLIST = \ ${OBJDIR}httplib_close_socket_gracefully${OBJEXT} \ ${OBJDIR}httplib_closedir${OBJEXT} \ ${OBJDIR}httplib_compare_dir_entries${OBJEXT} \ - ${OBJDIR}httplib_config_options${OBJEXT} \ ${OBJDIR}httplib_connect_client${OBJEXT} \ ${OBJDIR}httplib_connect_socket${OBJEXT} \ ${OBJDIR}httplib_connect_websocket_client${OBJEXT} \ ${OBJDIR}httplib_construct_etag${OBJEXT} \ ${OBJDIR}httplib_consume_socket${OBJEXT} \ + ${OBJDIR}httplib_create_client_context${OBJEXT} \ ${OBJDIR}httplib_cry${OBJEXT} \ ${OBJDIR}httplib_delete_file${OBJEXT} \ + ${OBJDIR}httplib_destroy_client_context${OBJEXT} \ ${OBJDIR}httplib_difftimespec${OBJEXT} \ ${OBJDIR}httplib_dir_scan_callback${OBJEXT} \ ${OBJDIR}httplib_discard_unread_request_data${OBJEXT} \ @@ -223,6 +225,7 @@ OBJLIST = \ ${OBJDIR}httplib_fgets${OBJEXT} \ ${OBJDIR}httplib_fopen${OBJEXT} \ ${OBJDIR}httplib_forward_body_data${OBJEXT} \ + ${OBJDIR}httplib_free_config_options${OBJEXT} \ ${OBJDIR}httplib_free_context${OBJEXT} \ ${OBJDIR}httplib_get_builtin_mime_type${OBJEXT} \ ${OBJDIR}httplib_get_context${OBJEXT} \ @@ -260,6 +263,7 @@ OBJLIST = \ ${OBJDIR}httplib_handle_websocket_request${OBJEXT} \ ${OBJDIR}httplib_header_has_option${OBJEXT} \ ${OBJDIR}httplib_inet_pton${OBJEXT} \ + ${OBJDIR}httplib_init_options${OBJEXT} \ ${OBJDIR}httplib_initialize_ssl${OBJEXT} \ ${OBJDIR}httplib_interpret_uri${OBJEXT} \ ${OBJDIR}httplib_is_authorized_for_put${OBJEXT} \ @@ -270,6 +274,7 @@ OBJLIST = \ ${OBJDIR}httplib_is_valid_http_method${OBJEXT} \ ${OBJDIR}httplib_is_valid_port${OBJEXT} \ ${OBJDIR}httplib_is_websocket_protocol${OBJEXT} \ + ${OBJDIR}httplib_process_options${OBJEXT} \ ${OBJDIR}httplib_pthread_join${OBJEXT} \ ${OBJDIR}httplib_kill${OBJEXT} \ ${OBJDIR}httplib_load_dll${OBJEXT} \ @@ -375,6 +380,8 @@ OBJLIST = \ ${OBJDIR}httplib_strndup${OBJEXT} \ ${OBJDIR}httplib_substitute_index_file${OBJEXT} \ ${OBJDIR}httplib_suggest_connection_header${OBJEXT} \ + ${OBJDIR}httplib_system_exit${OBJEXT} \ + ${OBJDIR}httplib_system_init${OBJEXT} \ ${OBJDIR}httplib_timer${OBJEXT} \ ${OBJDIR}httplib_tls_dtor${OBJEXT} \ ${OBJDIR}httplib_uninitialize_ssl${OBJEXT} \ @@ -448,6 +455,10 @@ ${OBJDIR}extern_ssl_lut${OBJEXT} : ${SRCDIR}extern_ssl_lut.c \ ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h +${OBJDIR}httplib_abort_start${OBJEXT} : ${SRCDIR}httplib_abort_start.c \ + ${SRCDIR}httplib_main.h \ + ${INCDIR}libhttp.h + ${OBJDIR}httplib_accept_new_connection${OBJEXT} : ${SRCDIR}httplib_accept_new_connection.c \ ${SRCDIR}httplib_ssl.h \ ${SRCDIR}httplib_main.h \ @@ -517,10 +528,6 @@ ${OBJDIR}httplib_compare_dir_entries${OBJEXT} : ${SRCDIR}httplib_compare_dir_ ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h -${OBJDIR}httplib_config_options${OBJEXT} : ${SRCDIR}httplib_config_options.c \ - ${SRCDIR}httplib_main.h \ - ${INCDIR}libhttp.h - ${OBJDIR}httplib_connect_client${OBJEXT} : ${SRCDIR}httplib_connect_client.c \ ${SRCDIR}httplib_pthread.h \ ${SRCDIR}httplib_ssl.h \ @@ -550,6 +557,10 @@ ${OBJDIR}httplib_consume_socket${OBJEXT} : ${SRCDIR}httplib_consume_socket.c ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h +${OBJDIR}httplib_create_client_context${OBJEXT} : ${SRCDIR}httplib_create_client_context.c \ + ${SRCDIR}httplib_main.h \ + ${INCDIR}libhttp.h + ${OBJDIR}httplib_cry${OBJEXT} : ${SRCDIR}httplib_cry.c \ ${SRCDIR}httplib_ssl.h \ ${SRCDIR}httplib_main.h \ @@ -559,6 +570,10 @@ ${OBJDIR}httplib_delete_file${OBJEXT} : ${SRCDIR}httplib_delete_file.c \ ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h +${OBJDIR}httplib_destroy_client_context${OBJEXT} : ${SRCDIR}httplib_destroy_client_context.c \ + ${SRCDIR}httplib_main.h \ + ${INCDIR}libhttp.h + ${OBJDIR}httplib_difftimespec${OBJEXT} : ${SRCDIR}httplib_difftimespec.c \ ${SRCDIR}httplib_utils.h \ ${SRCDIR}httplib_main.h \ @@ -606,6 +621,10 @@ ${OBJDIR}httplib_forward_body_data${OBJEXT} : ${SRCDIR}httplib_forward_body_d ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h +${OBJDIR}httplib_free_config_options${OBJEXT} : ${SRCDIR}httplib_free_config_options.c \ + ${SRCDIR}httplib_main.h \ + ${INCDIR}libhttp.h + ${OBJDIR}httplib_free_context${OBJEXT} : ${SRCDIR}httplib_free_context.c \ ${SRCDIR}httplib_pthread.h \ ${SRCDIR}httplib_ssl.h \ @@ -776,6 +795,10 @@ ${OBJDIR}httplib_inet_pton${OBJEXT} : ${SRCDIR}httplib_inet_pton.c \ ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h +${OBJDIR}httplib_init_options${OBJEXT} : ${SRCDIR}httplib_init_options.c \ + ${SRCDIR}httplib_main.h \ + ${INCDIR}libhttp.h + ${OBJDIR}httplib_initialize_ssl${OBJEXT} : ${SRCDIR}httplib_initialize_ssl.c \ ${SRCDIR}httplib_pthread.h \ ${SRCDIR}httplib_ssl.h \ @@ -821,6 +844,10 @@ ${OBJDIR}httplib_is_websocket_protocol${OBJEXT} : ${SRCDIR}httplib_is_websock ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h +${OBJDIR}httplib_process_options${OBJEXT} : ${SRCDIR}httplib_process_options.c \ + ${SRCDIR}httplib_main.h \ + ${INCDIR}libhttp.h + ${OBJDIR}httplib_pthread_join${OBJEXT} : ${SRCDIR}httplib_pthread_join.c \ ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h @@ -1303,6 +1330,14 @@ ${OBJDIR}httplib_substitute_index_file${OBJEXT} : ${SRCDIR}httplib_substitute ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h +${OBJDIR}httplib_system_exit${OBJEXT} : ${SRCDIR}httplib_system_exit.c \ + ${SRCDIR}httplib_main.h \ + ${INCDIR}libhttp.h + +${OBJDIR}httplib_system_init${OBJEXT} : ${SRCDIR}httplib_system_init.c \ + ${SRCDIR}httplib_main.h \ + ${INCDIR}libhttp.h + ${OBJDIR}httplib_suggest_connection_header${OBJEXT} : ${SRCDIR}httplib_suggest_connection_header.c \ ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h diff --git a/include/libhttp.h b/include/libhttp.h index 97455521..2168ec90 100644 --- a/include/libhttp.h +++ b/include/libhttp.h @@ -667,14 +667,6 @@ LIBHTTP_API int httplib_get_cookie(const char *cookie, const char *var_name, cha conn = httplib_download("google.com", 80, 0, ebuf, sizeof(ebuf), "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n"); */ -LIBHTTP_API struct httplib_connection * -httplib_download(const char *host, - int port, - int use_ssl, - char *error_buffer, - size_t error_buffer_size, - PRINTF_FORMAT_STRING(const char *request_fmt), - ...) PRINTF_ARGS(6, 7); /* Close the connection opened by httplib_download(). */ @@ -841,16 +833,6 @@ LIBHTTP_API char *httplib_md5(char buf[33], ...); On success, valid httplib_connection object. On error, NULL. Se error_buffer for details. */ -LIBHTTP_API struct httplib_connection *httplib_connect_websocket_client( const char *host, - int port, - int use_ssl, - char *error_buffer, - size_t error_buffer_size, - const char *path, - const char *origin, - httplib_websocket_data_handler data_func, - httplib_websocket_close_handler close_func, - void *user_data); /* Connect to a TCP server as a client (can be used to connect to a HTTP server) @@ -865,7 +847,6 @@ LIBHTTP_API struct httplib_connection *httplib_connect_websocket_client( const c On success, valid httplib_connection object. On error, NULL. Se error_buffer for details. */ -LIBHTTP_API struct httplib_connection *httplib_connect_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size); struct httplib_client_options { @@ -877,7 +858,6 @@ struct httplib_client_options { }; -LIBHTTP_API struct httplib_connection *httplib_connect_client_secure(const struct httplib_client_options *client_options, char *error_buffer, size_t error_buffer_size); enum debug_level_t { @@ -924,7 +904,13 @@ 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 unsigned httplib_check_feature( unsigned feature ); LIBHTTP_API int httplib_closedir( DIR *dir ); +LIBHTTP_API struct httplib_connection * httplib_connect_client( struct httplib_context *ctx, const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size ); +LIBHTTP_API struct httplib_connection * httplib_connect_client_secure( struct httplib_context *ctx, const struct httplib_client_options *client_options, char *error_buffer, size_t error_buffer_size ); +LIBHTTP_API struct httplib_connection * httplib_connect_websocket_client( struct httplib_context *ctx, const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, httplib_websocket_data_handler data_func, httplib_websocket_close_handler close_func, void *user_data ); +LIBHTTP_API struct httplib_context * httplib_create_client_context( const struct httplib_option_t *options ); LIBHTTP_API void httplib_cry( enum debug_level_t debug_level, const struct httplib_context *ctx, const struct httplib_connection *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(4, 5); +LIBHTTP_API void httplib_destroy_client_context( struct httplib_context *ctx ); +LIBHTTP_API struct httplib_connection * httplib_download( struct httplib_context *ctx, const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, PRINTF_FORMAT_STRING(const char *request_fmt), ...) PRINTF_ARGS(7, 8); LIBHTTP_API char * httplib_error_string( int error_code, char *buf, size_t buf_len ); LIBHTTP_API const char * httplib_get_builtin_mime_type( const char *file_name ); LIBHTTP_API enum debug_level_t httplib_get_debug_level( struct httplib_context *ctx ); @@ -967,6 +953,8 @@ LIBHTTP_API char * httplib_strdup( const char *str ); LIBHTTP_API void httplib_strlcpy( char *dst, const char *src, size_t len ); 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 int httplib_system_exit( void ); +LIBHTTP_API int httplib_system_init( void ); LIBHTTP_API const char * httplib_version( void ); #ifdef __cplusplus diff --git a/src/httplib_abort_start.c b/src/httplib_abort_start.c new file mode 100644 index 00000000..8ecd54a5 --- /dev/null +++ b/src/httplib_abort_start.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 Lammert Bies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * 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 + * THE SOFTWARE. + */ + +#include "httplib_main.h" + +/* + * struct httplib_context *XX_httplib_abort_start( struct httplib_context *ctx, const char *fmt, ... ); + * + * The function XX_httplib_abort_start() is called to do some cleanup work when + * an error occured initializing a context. The function returns NULL which is + * then further returned to the calling party. + */ + +struct httplib_context *XX_httplib_abort_start( struct httplib_context *ctx, const char *fmt, ... ) { + + va_list ap; + char buf[MG_BUF_LEN]; + + if ( ctx == NULL ) return NULL; + + if ( fmt != NULL ) { + + va_start( ap, fmt ); + vsnprintf_impl( buf, sizeof(buf), fmt, ap ); + va_end( ap ); + buf[sizeof(buf)-1] = 0; + + httplib_cry( DEBUG_LEVEL_CRASH, ctx, NULL, "%s", buf ); + } + + XX_httplib_free_context( ctx ); + + httplib_pthread_setspecific( XX_httplib_sTlsKey, NULL ); + + return NULL; + +} /* XX_httplib_abort_start */ diff --git a/src/httplib_connect_client.c b/src/httplib_connect_client.c index 8b9065c6..01e69a5a 100644 --- a/src/httplib_connect_client.c +++ b/src/httplib_connect_client.c @@ -30,30 +30,30 @@ #include "httplib_ssl.h" #include "httplib_string.h" -static struct httplib_connection * httplib_connect_client_impl( const struct httplib_client_options *client_options, int use_ssl, char *ebuf, size_t ebuf_len ); +static struct httplib_connection * httplib_connect_client_impl( struct httplib_context *ctx, const struct httplib_client_options *client_options, int use_ssl, char *ebuf, size_t ebuf_len ); /* - * struct httplib_connection *httplib_connect_client_secure( const struct httplib_client_options *client options, char *error buffer, size_t error_buffer_size ); + * struct httplib_connection *httplib_connect_client_secure( struct httplib_context_*ctx, const struct httplib_client_options *client options, char *error buffer, size_t error_buffer_size ); * * The function httplib_connect_client_secure() creates a secure connection as a * client to a remote server and returns a pointer to the connection * information, or NULL if an error occured. */ -LIBHTTP_API struct httplib_connection *httplib_connect_client_secure( const struct httplib_client_options *client_options, char *error_buffer, size_t error_buffer_size ) { +LIBHTTP_API struct httplib_connection *httplib_connect_client_secure( struct httplib_context *ctx, const struct httplib_client_options *client_options, char *error_buffer, size_t error_buffer_size ) { - return httplib_connect_client_impl( client_options, 1, error_buffer, error_buffer_size ); + return httplib_connect_client_impl( ctx, client_options, 1, error_buffer, error_buffer_size ); } /* httplib_connect_client_secure */ /* - * struct httplib_connection *httplib_connect_client( const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size ); + * struct httplib_connection *httplib_connect_client( struct httplib_context *ctx, const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size ); * * The function httplib_connect_client() connects to a remote server as a client * with the options of the connection provided as parameters. */ -struct httplib_connection * httplib_connect_client( const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size ) { +struct httplib_connection *httplib_connect_client( struct httplib_context *ctx, const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size ) { struct httplib_client_options opts; @@ -61,22 +61,21 @@ struct httplib_connection * httplib_connect_client( const char *host, int port, opts.host = host; opts.port = port; - return httplib_connect_client_impl( &opts, use_ssl, error_buffer, error_buffer_size ); + return httplib_connect_client_impl( ctx, &opts, use_ssl, error_buffer, error_buffer_size ); } /* httplib_connect_client */ /* - * static struct httplib_connection *httplib_connect_client_impl( const struct httplib_client_options *client_options, int use_ssl, char *ebuf, size_t ebuf_len ); + * static struct httplib_connection *httplib_connect_client_impl( struct httplib_context *ctx, const struct httplib_client_options *client_options, int use_ssl, char *ebuf, size_t ebuf_len ); * * The function httplib_connect_client_impl() is the background function doing the * heavy lifting to make connections as a client to remote servers. */ -static struct httplib_connection *httplib_connect_client_impl( const struct httplib_client_options *client_options, int use_ssl, char *ebuf, size_t ebuf_len ) { +static struct httplib_connection *httplib_connect_client_impl( struct httplib_context *ctx, const struct httplib_client_options *client_options, int use_ssl, char *ebuf, size_t ebuf_len ) { - static struct httplib_context fake_ctx; struct httplib_connection *conn; SOCKET sock; union usa sa; @@ -84,6 +83,8 @@ static struct httplib_connection *httplib_connect_client_impl( const struct http struct sockaddr *psa; char error_string[ERROR_STRING_LEN]; + if ( ctx == NULL ) return NULL; + if ( ! XX_httplib_connect_socket( client_options->host, client_options->port, use_ssl, ebuf, ebuf_len, &sock, &sa ) ) return NULL; if ( (conn = httplib_calloc( 1, sizeof(*conn) + MAX_REQUEST_SIZE )) == NULL ) { @@ -108,11 +109,11 @@ static struct httplib_connection *httplib_connect_client_impl( const struct http conn->buf_size = MAX_REQUEST_SIZE; conn->buf = (char *)(conn + 1); - conn->ctx = &fake_ctx; + conn->ctx = ctx; conn->client.sock = sock; conn->client.lsa = sa; - if ( getsockname( sock, psa, &len ) != 0 ) httplib_cry( DEBUG_LEVEL_ERROR, &fake_ctx, conn, "%s: getsockname() failed: %s", __func__, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) ); + if ( getsockname( sock, psa, &len ) != 0 ) httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s: getsockname() failed: %s", __func__, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) ); conn->client.has_ssl = (use_ssl) ? true : false; httplib_pthread_mutex_init( &conn->mutex, &XX_httplib_pthread_mutex_attr ); @@ -120,7 +121,7 @@ static struct httplib_connection *httplib_connect_client_impl( const struct http #ifndef NO_SSL if ( use_ssl ) { - fake_ctx.ssl_ctx = conn->client_ssl_ctx; + ctx->ssl_ctx = conn->client_ssl_ctx; /* * TODO: Check ssl_verify_peer and ssl_ca_path here. @@ -134,7 +135,7 @@ static struct httplib_connection *httplib_connect_client_impl( const struct http if ( client_options->client_cert ) { - if ( ! XX_httplib_ssl_use_pem_file( &fake_ctx, client_options->client_cert ) ) { + if ( ! XX_httplib_ssl_use_pem_file( ctx, client_options->client_cert ) ) { XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "Can not use SSL client certificate" ); SSL_CTX_free( conn->client_ssl_ctx ); diff --git a/src/httplib_connect_websocket_client.c b/src/httplib_connect_websocket_client.c index 76f858d0..823d824e 100644 --- a/src/httplib_connect_websocket_client.c +++ b/src/httplib_connect_websocket_client.c @@ -36,16 +36,14 @@ * returned, otherwise NULL. */ -struct httplib_connection *httplib_connect_websocket_client( const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, httplib_websocket_data_handler data_func, httplib_websocket_close_handler close_func, void *user_data ) { +struct httplib_connection *httplib_connect_websocket_client( struct httplib_context *ctx, const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, httplib_websocket_data_handler data_func, httplib_websocket_close_handler close_func, void *user_data ) { struct httplib_connection *conn; - struct httplib_context *newctx; struct websocket_client_thread_data *thread_data; static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw=="; const char *handshake_req; - conn = NULL; - newctx = NULL; + conn = NULL; if ( origin != NULL ) handshake_req = "GET %s HTTP/1.1\r\n" "Host: %s\r\n" @@ -68,7 +66,7 @@ struct httplib_connection *httplib_connect_websocket_client( const char *host, i * Establish the client connection and request upgrade */ - conn = httplib_download( host, port, use_ssl, error_buffer, error_buffer_size, handshake_req, path, host, magic, origin ); + conn = httplib_download( ctx, host, port, use_ssl, error_buffer, error_buffer_size, handshake_req, path, host, magic, origin ); /* * Connection object will be null if something goes wrong @@ -90,36 +88,28 @@ struct httplib_connection *httplib_connect_websocket_client( const char *host, i return NULL; } - /* - * For client connections, httplib_context is fake. Since we need to set a - * callback function, we need to create a copy and modify it. - */ + ctx->user_data = user_data; + ctx->ctx_type = CTX_TYPE_CLIENT; + ctx->num_threads = 1; /* one worker thread will be created */ + ctx->workerthreadids = httplib_calloc( ctx->num_threads, sizeof(pthread_t) ); - newctx = httplib_malloc( sizeof(struct httplib_context) ); - if ( newctx == NULL ) { conn = httplib_free( conn ); return NULL; } + if ( ctx->workerthreadids == NULL ) { - *newctx = *conn->ctx; - newctx->user_data = user_data; - newctx->ctx_type = CTX_TYPE_CLIENT; - newctx->num_threads = 1; /* one worker thread will be created */ - newctx->workerthreadids = httplib_calloc( newctx->num_threads, sizeof(pthread_t) ); - - if ( newctx->workerthreadids == NULL ) { - - newctx = httplib_free( newctx ); - conn = httplib_free( conn ); + ctx->num_threads = 0; + ctx->user_data = NULL; + conn = httplib_free( conn ); return NULL; } - conn->ctx = newctx; - thread_data = httplib_calloc( sizeof(struct websocket_client_thread_data), 1 ); + thread_data = httplib_calloc( sizeof(struct websocket_client_thread_data), 1 ); if ( thread_data == NULL ) { - newctx->workerthreadids = httplib_free( newctx->workerthreadids ); - newctx = httplib_free( newctx ); - conn = httplib_free( conn ); + ctx->workerthreadids = httplib_free( ctx->workerthreadids ); + ctx->num_threads = 0; + ctx->user_data = NULL; + conn = httplib_free( conn ); return NULL; } @@ -135,12 +125,13 @@ struct httplib_connection *httplib_connect_websocket_client( const char *host, i * called on the client connection */ - if ( XX_httplib_start_thread_with_id( XX_httplib_websocket_client_thread, thread_data, newctx->workerthreadids) != 0 ) { + if ( XX_httplib_start_thread_with_id( XX_httplib_websocket_client_thread, thread_data, ctx->workerthreadids) != 0 ) { - thread_data = httplib_free( thread_data ); - newctx->workerthreadids = httplib_free( newctx->workerthreadids ); - newctx = httplib_free( newctx ); - conn = httplib_free( conn ); + thread_data = httplib_free( thread_data ); + ctx->workerthreadids = httplib_free( ctx->workerthreadids ); + ctx->num_threads = 0; + ctx->user_data = NULL; + conn = httplib_free( conn ); return NULL; } diff --git a/src/httplib_create_client_context.c b/src/httplib_create_client_context.c new file mode 100644 index 00000000..79c955f4 --- /dev/null +++ b/src/httplib_create_client_context.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 Lammert Bies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * 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 + * THE SOFTWARE. + */ + +#include "httplib_main.h" + +/* + * struct httplib_context *httplib_create_client_context( const struct httplib_option_t *options ); + * + * The function httplib_create_client_context() creates a context to be used + * for one simultaneous client connection. It is not possible to use one client + * context for multiple connections at the same time, because the contect + * contains SSL context information which is specific for one connection. + */ + +struct httplib_context *httplib_create_client_context( const struct httplib_option_t *options ) { + + struct httplib_context *ctx; + + ctx = httplib_calloc( 1, sizeof(struct httplib_context) ); + if ( ctx == NULL ) return NULL; + + if ( XX_httplib_init_options( ctx ) ) return NULL; + if ( XX_httplib_process_options( ctx, options ) ) return NULL; + + return ctx; + +} /* httplib_create_client_context */ diff --git a/src/httplib_destroy_client_context.c b/src/httplib_destroy_client_context.c new file mode 100644 index 00000000..f6cb58b1 --- /dev/null +++ b/src/httplib_destroy_client_context.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Lammert Bies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * 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 + * THE SOFTWARE. + */ + +#include "httplib_main.h" + +/* + * void httplib_destroy_client_context( struct httplib_context *ctx ); + * + * The function httplib_destroy_client_context() destroys the context for a + * client connection. This function should not be called for server contexts. + * Use httplib_stop() for server contexts instead. + */ + +void httplib_destroy_client_context( struct httplib_context *ctx ) { + + if ( ctx == NULL ) return; + + XX_httplib_free_config_options( ctx ); + + httplib_free( ctx ); + +} /* httplib_destroy_client_context */ diff --git a/src/httplib_download.c b/src/httplib_download.c index 71f3c576..e618ddbc 100644 --- a/src/httplib_download.c +++ b/src/httplib_download.c @@ -35,17 +35,19 @@ * and returns a pointer to the connection on success, or NULL on error. */ -struct httplib_connection * httplib_download( const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt, ... ) { +struct httplib_connection * httplib_download( struct httplib_context *ctx, const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt, ... ) { struct httplib_connection *conn; va_list ap; int i; int reqerr; + if ( ctx == NULL ) return NULL; + va_start( ap, fmt ); ebuf[0] = '\0'; - conn = httplib_connect_client( host, port, use_ssl, ebuf, ebuf_len ); + conn = httplib_connect_client( ctx, host, port, use_ssl, ebuf, ebuf_len ); if ( conn != NULL ) { diff --git a/src/httplib_free_config_options.c b/src/httplib_free_config_options.c new file mode 100644 index 00000000..37d6245e --- /dev/null +++ b/src/httplib_free_config_options.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 Lammert Bies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * 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 + * THE SOFTWARE. + */ + +#include "httplib_main.h" + +/* + * void XX_httplib_free_config_options( struct htptlib_context *ctx ); + * + * The function XX_httplib_free_config_options() returns all the from the heap + * allocated space to store config options back to the heap. + */ + +void XX_httplib_free_config_options( struct httplib_context *ctx ) { + + if ( ctx == NULL ) return; + + ctx->access_control_allow_origin = httplib_free( ctx->access_control_allow_origin ); + ctx->access_control_list = httplib_free( ctx->access_control_list ); + ctx->access_log_file = httplib_free( ctx->access_log_file ); + ctx->authentication_domain = httplib_free( ctx->authentication_domain ); + ctx->cgi_environment = httplib_free( ctx->cgi_environment ); + ctx->cgi_interpreter = httplib_free( ctx->cgi_interpreter ); + ctx->document_root = httplib_free( ctx->document_root ); + ctx->error_log_file = httplib_free( ctx->error_log_file ); + ctx->error_pages = httplib_free( ctx->error_pages ); + ctx->extra_mime_types = httplib_free( ctx->extra_mime_types ); + ctx->global_auth_file = httplib_free( ctx->global_auth_file ); + ctx->hide_file_pattern = httplib_free( ctx->hide_file_pattern ); + ctx->index_files = httplib_free( ctx->index_files ); + ctx->listening_ports = httplib_free( ctx->listening_ports ); + ctx->protect_uri = httplib_free( ctx->protect_uri ); + ctx->put_delete_auth_file = httplib_free( ctx->put_delete_auth_file ); + ctx->run_as_user = httplib_free( ctx->run_as_user ); + ctx->ssi_pattern = httplib_free( ctx->ssi_pattern ); + ctx->ssl_ca_file = httplib_free( ctx->ssl_ca_file ); + ctx->ssl_ca_path = httplib_free( ctx->ssl_ca_path ); + ctx->ssl_certificate = httplib_free( ctx->ssl_certificate ); + ctx->ssl_cipher_list = httplib_free( ctx->ssl_cipher_list ); + ctx->throttle = httplib_free( ctx->throttle ); + ctx->url_rewrite_patterns = httplib_free( ctx->url_rewrite_patterns ); + ctx->websocket_root = httplib_free( ctx->websocket_root ); + +} /* XX_httplib_free_config_options */ diff --git a/src/httplib_free_context.c b/src/httplib_free_context.c index 9a311370..b7d03557 100644 --- a/src/httplib_free_context.c +++ b/src/httplib_free_context.c @@ -74,35 +74,7 @@ void XX_httplib_free_context( struct httplib_context *ctx ) { timers_exit( ctx ); #endif - /* - * Deallocate config parameters - */ - - ctx->access_control_allow_origin = httplib_free( ctx->access_control_allow_origin ); - ctx->access_control_list = httplib_free( ctx->access_control_list ); - ctx->access_log_file = httplib_free( ctx->access_log_file ); - ctx->authentication_domain = httplib_free( ctx->authentication_domain ); - ctx->cgi_environment = httplib_free( ctx->cgi_environment ); - ctx->cgi_interpreter = httplib_free( ctx->cgi_interpreter ); - ctx->document_root = httplib_free( ctx->document_root ); - ctx->error_log_file = httplib_free( ctx->error_log_file ); - ctx->error_pages = httplib_free( ctx->error_pages ); - ctx->extra_mime_types = httplib_free( ctx->extra_mime_types ); - ctx->global_auth_file = httplib_free( ctx->global_auth_file ); - ctx->hide_file_pattern = httplib_free( ctx->hide_file_pattern ); - ctx->index_files = httplib_free( ctx->index_files ); - ctx->listening_ports = httplib_free( ctx->listening_ports ); - ctx->protect_uri = httplib_free( ctx->protect_uri ); - ctx->put_delete_auth_file = httplib_free( ctx->put_delete_auth_file ); - ctx->run_as_user = httplib_free( ctx->run_as_user ); - ctx->ssi_pattern = httplib_free( ctx->ssi_pattern ); - ctx->ssl_ca_file = httplib_free( ctx->ssl_ca_file ); - ctx->ssl_ca_path = httplib_free( ctx->ssl_ca_path ); - ctx->ssl_certificate = httplib_free( ctx->ssl_certificate ); - ctx->ssl_cipher_list = httplib_free( ctx->ssl_cipher_list ); - ctx->throttle = httplib_free( ctx->throttle ); - ctx->url_rewrite_patterns = httplib_free( ctx->url_rewrite_patterns ); - ctx->websocket_root = httplib_free( ctx->websocket_root ); + XX_httplib_free_config_options( ctx ); /* * Deallocate request handlers diff --git a/src/httplib_init_options.c b/src/httplib_init_options.c new file mode 100644 index 00000000..86391b66 --- /dev/null +++ b/src/httplib_init_options.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2016 Lammert Bies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * 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 + * THE SOFTWARE. + */ + +#include "httplib_main.h" + +/* + * bool XX_httplib_init_options( struct httplib_context *ctx ); + * + * The function XX_httplib_init_options() sets the options of a newly created + * context to reasonablei default values. When succesful, the function returns + * false. Otherwise true is returned, and the function already performed a + * cleanup. + */ + +bool XX_httplib_init_options( struct httplib_context *ctx ) { + + if ( ctx == NULL ) return true; + + ctx->access_control_allow_origin = NULL; + ctx->access_control_list = NULL; + ctx->access_log_file = NULL; + ctx->allow_sendfile_call = true; + ctx->authentication_domain = NULL; + ctx->cgi_environment = NULL; + ctx->cgi_interpreter = NULL; + ctx->cgi_pattern = NULL; + ctx->debug_level = DEBUG_LEVEL_WARNING; + ctx->decode_url = true; + ctx->document_root = NULL; + ctx->enable_directory_listing = true; + ctx->enable_keep_alive = false; + ctx->error_log_file = NULL; + ctx->error_pages = NULL; + ctx->extra_mime_types = NULL; + ctx->global_auth_file = NULL; + ctx->hide_file_pattern = NULL; + ctx->index_files = NULL; + ctx->listening_ports = NULL; + ctx->num_threads = 50; + ctx->protect_uri = NULL; + ctx->put_delete_auth_file = NULL; + ctx->request_timeout = 30000; + ctx->run_as_user = NULL; + ctx->ssi_pattern = NULL; + ctx->ssl_ca_file = NULL; + ctx->ssl_ca_path = NULL; + ctx->ssl_certificate = NULL; + ctx->ssl_cipher_list = NULL; + ctx->ssl_protocol_version = 0; + ctx->ssl_short_trust = false; + ctx->ssl_verify_depth = 9; + ctx->ssl_verify_paths = true; + ctx->ssl_verify_peer = false; + ctx->static_file_max_age = 0; + ctx->throttle = NULL; + ctx->tcp_nodelay = false; + ctx->url_rewrite_patterns = NULL; + ctx->websocket_root = NULL; + ctx->websocket_timeout = 30000; + + if ( (ctx->access_control_allow_origin = httplib_strdup( "*" )) == NULL ) { + + XX_httplib_abort_start( ctx, "Out of memory creating context allocating \"access_control_allow_origin\"" ); + return true; + } + + if ( (ctx->authentication_domain = httplib_strdup( "example.com" )) == NULL ) { + + XX_httplib_abort_start( ctx, "Out of memory creating context allocating \"authentication_domain\"" ); + return true; + } + + if ( (ctx->cgi_pattern = httplib_strdup( "**.cgi$|**.pl$|**.php$" )) == NULL ) { + + XX_httplib_abort_start( ctx, "Out of memory creating context allocating \"cgi_pattern\"" ); + return true; + } + + if ( (ctx->index_files = httplib_strdup( "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php" )) == NULL ) { + + XX_httplib_abort_start( ctx, "Out of memory creating context allocating \"index_files\"" ); + return true; + } + + if ( (ctx->listening_ports = httplib_strdup( "8080" )) == NULL ) { + + XX_httplib_abort_start( ctx, "Out of memory creating context allocating \"listening_ports\"" ); + return true; + } + + if ( (ctx->ssi_pattern = httplib_strdup( "**.shtml$|**.shtm$" )) == NULL ) { + + XX_httplib_abort_start( ctx, "Out of memory creating context allocating \"ssi_pattern\"" ); + return true; + } + + return false; + +} /* XX_httplib_init_options */ diff --git a/src/httplib_main.h b/src/httplib_main.h index 955f9d62..07c318c9 100644 --- a/src/httplib_main.h +++ b/src/httplib_main.h @@ -786,6 +786,7 @@ void SHA1Final( unsigned char digest[20], SHA1_CTX *context ); void SHA1Init( SHA1_CTX *context ); void SHA1Update( SHA1_CTX *context, const unsigned char *data, uint32_t len ); +struct httplib_context *XX_httplib_abort_start( struct httplib_context *ctx, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); void XX_httplib_accept_new_connection( const struct socket *listener, struct httplib_context *ctx ); bool XX_httplib_authorize( struct httplib_connection *conn, struct file *filep ); const char * XX_httplib_builtin_mime_ext( int index ); @@ -808,6 +809,7 @@ void XX_httplib_fclose_on_exec( struct file *filep, struct httplib_connection const char * XX_httplib_fgets( char *buf, size_t size, struct file *filep, char **p ); bool XX_httplib_fopen( const struct httplib_connection *conn, const char *path, const char *mode, struct file *filep ); bool XX_httplib_forward_body_data( struct httplib_connection *conn, FILE *fp, SOCKET sock, SSL *ssl ); +void XX_httplib_free_config_options( struct httplib_context *ctx ); void XX_httplib_free_context( struct httplib_context *ctx ); const char * XX_httplib_get_header( const struct httplib_request_info *ri, const char *name ); void XX_httplib_get_mime_type( struct httplib_context *ctx, const char *path, struct vec *vec ); @@ -828,6 +830,7 @@ void XX_httplib_handle_ssi_file_request( struct httplib_connection *conn, cons void XX_httplib_handle_static_file_request( struct httplib_connection *conn, const char *path, struct file *filep, const char *mime_type, const char *additional_headers ); void XX_httplib_handle_websocket_request( struct httplib_connection *conn, const char *path, int is_callback_resource, httplib_websocket_connect_handler ws_connect_handler, httplib_websocket_ready_handler ws_ready_handler, httplib_websocket_data_handler ws_data_handler, httplib_websocket_close_handler ws_close_handler, void *cbData ); bool XX_httplib_header_has_option( const char *header, const char *option ); +bool XX_httplib_init_options( struct httplib_context *ctx ); void XX_httplib_interpret_uri( struct httplib_connection *conn, char *filename, size_t filename_buf_len, struct file *filep, bool *is_found, bool *is_script_resource, bool *is_websocket_request, bool *is_put_or_delete_request ); bool XX_httplib_is_authorized_for_put( struct httplib_connection *conn ); bool XX_httplib_is_file_in_memory( const struct httplib_connection *conn, const char *path, struct file *filep ); @@ -857,6 +860,7 @@ void XX_httplib_path_to_unicode( const char *path, wchar_t *wbuf, size_t wbuf_ void XX_httplib_prepare_cgi_environment( struct httplib_connection *conn, const char *prog, struct cgi_environment *env ); void XX_httplib_print_dir_entry( struct de *de ); void XX_httplib_process_new_connection( struct httplib_connection *conn ); +bool XX_httplib_process_options( struct httplib_context *ctx, const struct httplib_option_t *options ); void XX_httplib_produce_socket( struct httplib_context *ctx, const struct socket *sp ); int XX_httplib_pull( FILE *fp, struct httplib_connection *conn, char *buf, int len, double timeout ); int XX_httplib_pull_all( FILE *fp, struct httplib_connection *conn, char *buf, int len ); @@ -929,3 +933,5 @@ extern pthread_mutexattr_t XX_httplib_pthread_mutex_attr; #endif /* _WIN32 */ extern const struct uriprot_tp XX_httplib_abs_uri_protocols[]; +extern int XX_httplib_sTlsInit; +extern pthread_key_t XX_httplib_sTlsKey; diff --git a/src/httplib_process_options.c b/src/httplib_process_options.c new file mode 100644 index 00000000..cbdf30a9 --- /dev/null +++ b/src/httplib_process_options.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2016 Lammert Bies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * 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 + * THE SOFTWARE. + */ + +#include "httplib_main.h" + +static bool check_bool( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, bool *config ); +static bool check_dbg( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, enum debug_level_t *config ); +static bool check_dir( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); +static bool check_file( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); +static bool check_int( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, int *config, int minval, int maxval ); +static bool check_patt( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); +static bool check_str( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); + +/* + * bool XX_httplib_process_options( struct httplib_context *ctx, const struct httplib_option_t *options ); + * + * The function process_options() processes the user supplied options and adds + * them to the central option list of the context. If en error occurs, the + * function returns true, otherwise FALSE is returned. In case of an error all + * cleanup is already done before returning and an error message has been + * generated. + */ + +bool XX_httplib_process_options( struct httplib_context *ctx, const struct httplib_option_t *options ) { + + if ( ctx == NULL ) return true; + + while ( options != NULL && options->name != NULL ) { + + if ( check_str( ctx, options, "access_control_allow_origin", & ctx->access_control_allow_origin ) ) return true; + if ( check_str( ctx, options, "access_control_list", & ctx->access_control_list ) ) return true; + if ( check_file( ctx, options, "access_log_file", & ctx->access_log_file ) ) return true; + if ( check_bool( ctx, options, "allow_sendfile_call", & ctx->allow_sendfile_call ) ) return true; + if ( check_str( ctx, options, "authentication_domain", & ctx->authentication_domain ) ) return true; + if ( check_str( ctx, options, "cgi_environment", & ctx->cgi_environment ) ) return true; + if ( check_file( ctx, options, "cgi_interpreter", & ctx->cgi_interpreter ) ) return true; + if ( check_patt( ctx, options, "cgi_pattern", & ctx->cgi_pattern ) ) return true; + if ( check_dbg( ctx, options, "debug_level", & ctx->debug_level ) ) return true; + if ( check_bool( ctx, options, "decode_url", & ctx->decode_url ) ) return true; + if ( check_dir( ctx, options, "document_root", & ctx->document_root ) ) return true; + if ( check_bool( ctx, options, "enable_directory_listing", & ctx->enable_directory_listing ) ) return true; + if ( check_bool( ctx, options, "enable_keep_alive", & ctx->enable_keep_alive ) ) return true; + if ( check_file( ctx, options, "error_log_file", & ctx->error_log_file ) ) return true; + if ( check_dir( ctx, options, "error_pages", & ctx->error_pages ) ) return true; + if ( check_str( ctx, options, "extra_mime_types", & ctx->extra_mime_types ) ) return true; + if ( check_file( ctx, options, "global_auth_file", & ctx->global_auth_file ) ) return true; + if ( check_patt( ctx, options, "hide_file_pattern", & ctx->hide_file_pattern ) ) return true; + if ( check_str( ctx, options, "index_files", & ctx->index_files ) ) return true; + if ( check_str( ctx, options, "listening_ports", & ctx->listening_ports ) ) return true; + if ( check_int( ctx, options, "num_threads", & ctx->num_threads, 1, INT_MAX ) ) return true; + if ( check_str( ctx, options, "protect_uri", & ctx->protect_uri ) ) return true; + if ( check_file( ctx, options, "put_delete_auth_file", & ctx->put_delete_auth_file ) ) return true; + if ( check_int( ctx, options, "request_timeout", & ctx->request_timeout, 0, INT_MAX ) ) return true; + if ( check_str( ctx, options, "run_as_user", & ctx->run_as_user ) ) return true; + if ( check_patt( ctx, options, "ssi_pattern", & ctx->ssi_pattern ) ) return true; + if ( check_file( ctx, options, "ssl_ca_file", & ctx->ssl_ca_file ) ) return true; + if ( check_dir( ctx, options, "ssl_ca_path", & ctx->ssl_ca_path ) ) return true; + if ( check_file( ctx, options, "ssl_certificate", & ctx->ssl_certificate ) ) return true; + if ( check_str( ctx, options, "ssl_cipher_list", & ctx->ssl_cipher_list ) ) return true; + if ( check_int( ctx, options, "ssl_protocol_version", & ctx->ssl_protocol_version, 0, 4 ) ) return true; + if ( check_bool( ctx, options, "ssl_short_trust", & ctx->ssl_short_trust ) ) return true; + if ( check_int( ctx, options, "ssl_verify_depth", & ctx->ssl_verify_depth, 0, 9 ) ) return true; + if ( check_bool( ctx, options, "ssl_verify_paths", & ctx->ssl_verify_paths ) ) return true; + if ( check_bool( ctx, options, "ssl_verify_peer", & ctx->ssl_verify_peer ) ) return true; + if ( check_int( ctx, options, "static_file_max_age", & ctx->static_file_max_age, 0, INT_MAX ) ) return true; + if ( check_str( ctx, options, "throttle", & ctx->throttle ) ) return true; + if ( check_bool( ctx, options, "tcp_nodelay", & ctx->tcp_nodelay ) ) return true; + if ( check_str( ctx, options, "url_rewrite_patterns", & ctx->url_rewrite_patterns ) ) return true; + if ( check_dir( ctx, options, "websocket_root", & ctx->websocket_root ) ) return true; + if ( check_int( ctx, options, "websocket_timeout", & ctx->websocket_timeout, 0, INT_MAX ) ) return true; + + /* + * TODO: Currently silently ignoring unrecognized options + */ + + options++; + } + + return false; + +} /* XX_httplib_process_options */ + +/* + * static bool check_bool( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, bool *config ); + * + * The function check_bool() checks if an option is equal to a boolean config + * parameter and stores the value if that is the case. If the value cannot be + * recognized, true is returned and the function performs a complete cleanup. + * If the option name could not be found, the function returns false to + * indicate that the search should go on. If the value could be found, also + * false is returned. + */ + +static bool check_bool( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, bool *config ) { + + if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { + + XX_httplib_abort_start( ctx, "Internal error parsing boolean option" ); + return true; + } + + if ( httplib_strcasecmp( option->name, name ) ) return false; + if ( ! XX_httplib_option_value_to_bool( option->value, config ) ) return false; + + XX_httplib_abort_start( ctx, "Invalid boolean value \"%s\" for option \"%s\"", option->value, option->name ); + return true; + +} /* check_bool */ + +/* + * static bool check_dir( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); + * + * The function check_dir() checks if an option is equal to a directory config + * parameter and stores the value if that is the case. If the value cannot be + * recognized, true is returned and the function performs a complete cleanup. + * If the option name could not be found, the function returns false to + * indicate that the search should go on. IF the value could be found, also + * false is returned. + */ + +static bool check_dir( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ) { + + if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { + + XX_httplib_abort_start( ctx, "Internal error parsing directory option" ); + return true; + } + + if ( httplib_strcasecmp( option->name, name ) ) return false; + + *config = httplib_free( *config ); + + if ( option->value == NULL ) return false; + + *config = httplib_strdup( option->value ); + if ( *config != NULL ) return false; + + XX_httplib_abort_start( ctx, "Out of memory assigning value \"%s\" to option \"%s\"", option->value, option->name ); + return true; + +} /* check_dir */ + +/* + * static bool check_patt( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); + * + * The function check_patt() checks if an option is equal to a pattern config + * parameter and stores the value if that is the case. If the value cannot be + * recognized, true is returned and the function performs a complete cleanup. + * If the option name could not be found, the function returns false to + * indicate that the search should go on. IF the value could be found, also + * false is returned. + */ + +static bool check_patt( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ) { + + if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { + + XX_httplib_abort_start( ctx, "Internal error parsing pattern option" ); + return true; + } + + if ( httplib_strcasecmp( option->name, name ) ) return false; + + *config = httplib_free( *config ); + + if ( option->value == NULL ) return false; + + *config = httplib_strdup( option->value ); + if ( *config != NULL ) return false; + + XX_httplib_abort_start( ctx, "Out of memory assigning value \"%s\" to option \"%s\"", option->value, option->name ); + return true; + +} /* check_patt */ + +/* + * static bool check_file( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); + * + * The function check_file() checks if an option is equal to a filename config + * parameter and stores the value if that is the case. If the value cannot be + * recognized, true is returned and the function performs a complete cleanup. + * If the option name could not be found, the function returns false to + * indicate that the search should go on. IF the value could be found, also + * false is returned. + */ + +static bool check_file( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ) { + + if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { + + XX_httplib_abort_start( ctx, "Internal error parsing file option" ); + return true; + } + + if ( httplib_strcasecmp( option->name, name ) ) return false; + + *config = httplib_free( *config ); + + if ( option->value == NULL ) return false; + + *config = httplib_strdup( option->value ); + if ( *config != NULL ) return false; + + XX_httplib_abort_start( ctx, "Out of memory assigning value \"%s\" to option \"%s\"", option->value, option->name ); + return true; + +} /* check_file */ + +/* + * static bool check_str( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); + * + * The function check_str() checks if an option is equal to a string config + * parameter and stores the value if that is the case. If the value cannot be + * recognized, true is returned and the function performs a complete cleanup. + * If the option name could not be found, the function returns false to + * indicate that the search should go on. IF the value could be found, also + * false is returned. + */ + +static bool check_str( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ) { + + if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { + + XX_httplib_abort_start( ctx, "Internal error parsing string option" ); + return true; + } + + if ( httplib_strcasecmp( option->name, name ) ) return false; + + *config = httplib_free( *config ); + + if ( option->value == NULL ) return false; + + *config = httplib_strdup( option->value ); + if ( *config != NULL ) return false; + + XX_httplib_abort_start( ctx, "Out of memory assigning value \"%s\" to option \"%s\"", option->value, option->name ); + return true; + +} /* check_str */ + +/* + * static bool check_int( struct httplib_context *ctx, const struct httplib_opion_t *option, const char *name, int *config, int minval, int maxval ); + * + * The function check_int() checks in an option is equal to an integer config + * parameter and stores the value if that is the case. If the value cannot be + * recognized, true is returned and the function performs a complete cleanup. + * If the option name could not be found, the function returns false to + * indicate that the search should go on. If the value could be found and is + * valud, also false is returned. + */ + +static bool check_int( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, int *config, int minval, int maxval ) { + + int val; + + if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { + + XX_httplib_abort_start( ctx, "Internal error parsing integer option" ); + return true; + } + + if ( httplib_strcasecmp( option->name, name ) ) return false; + + if ( ! XX_httplib_option_value_to_int( option->value, & val ) ) { + + if ( val < minval ) { XX_httplib_abort_start( ctx, "Integer \"%s\" too small for option \"%s\"", option->value, option->name ); return true; } + if ( val > maxval ) { XX_httplib_abort_start( ctx, "Integer \"%s\" too large for option \"%s\"", option->value, option->name ); return true; } + + *config = val; + return false; + } + + XX_httplib_abort_start( ctx, "Invalid integer value \"%s\" for option \"%s\"", option->value, option->name ); + return true; + +} /* check_int */ + +/* + * static bool check_dbg( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name ); + * + * The function check_dbg() checks if an option is equal to a debug level + * config parameter and stores the value if that is the case. If the value + * cannot be recognized, true is returned and the function performs a complete + * cleanup. If the option name could not be found, the function returns false + * to indicate that the search should go on. If the value could be found and is + * valid, also false is returned. + */ + +static bool check_dbg( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, enum debug_level_t *config ) { + + int val; + + if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { + + XX_httplib_abort_start( ctx, "Internal error parsing debug level option" ); + return true; + } + + if ( httplib_strcasecmp( option->name, name ) ) return false; + + if ( ! XX_httplib_option_value_to_int( option->value, &val ) ) { + + switch ( val ) { + + case DEBUG_LEVEL_NONE : + case DEBUG_LEVEL_CRASH : + case DEBUG_LEVEL_ERROR : + case DEBUG_LEVEL_WARNING : + case DEBUG_LEVEL_INFO : + *config = val; + return false; + } + } + + XX_httplib_abort_start( ctx, "Invalid value \"%s\" for option \"%s\"", option->value, option->name ); + return true; + +} /* check_dbg */ diff --git a/src/httplib_pthread.h b/src/httplib_pthread.h index 8c345626..8737f53f 100644 --- a/src/httplib_pthread.h +++ b/src/httplib_pthread.h @@ -23,5 +23,4 @@ extern pthread_mutex_t * XX_httplib_ssl_mutexes; -extern pthread_key_t XX_httplib_sTlsKey; extern int XX_httplib_thread_idx_max; diff --git a/src/httplib_ssl.h b/src/httplib_ssl.h index d1e85372..f0dbfe96 100644 --- a/src/httplib_ssl.h +++ b/src/httplib_ssl.h @@ -150,6 +150,5 @@ void XX_httplib_uninitialize_ssl( struct httplib_context *ctx ); extern int XX_httplib_cryptolib_users; extern struct ssl_func XX_httplib_crypto_sw[]; extern struct ssl_func XX_httplib_ssl_sw[]; -extern int XX_httplib_sTlsInit; #endif /* NO_SSL */ diff --git a/src/httplib_start.c b/src/httplib_start.c index befd92dd..c1906ce7 100644 --- a/src/httplib_start.c +++ b/src/httplib_start.c @@ -31,16 +31,6 @@ #include "httplib_string.h" #include "httplib_utils.h" -static bool check_bool( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, bool *config ); -static bool check_dbg( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, enum debug_level_t *config ); -static bool check_dir( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); -static bool check_file( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); -static bool check_int( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, int *config, int minval, int maxval ); -static bool check_patt( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); -static bool check_str( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); -static struct httplib_context * cleanup( struct httplib_context *ctx, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); -static bool process_options( struct httplib_context *ctx, const struct httplib_option_t *options ); - /* * struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks, void *user_data, const struct httplib_t *options ); * @@ -56,19 +46,6 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks void (*exit_callback)(const struct httplib_context *ctx); struct httplib_workerTLS tls; -#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; - WSAStartup( MAKEWORD(2, 2), &data ); - -#endif /* _WIN32 */ - /* * 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 @@ -78,7 +55,7 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks */ exit_callback = NULL; - ctx = httplib_calloc( 1, sizeof(*ctx) ); + ctx = httplib_calloc( 1, sizeof(struct httplib_context) ); if ( ctx == NULL ) return NULL; @@ -145,17 +122,18 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks #endif 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 XX_httplib_abort_start( ctx, "Cannot initialize thread mutex" ); #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_full, NULL ) ) return cleanup( ctx, "Cannot initialize full queue condition" ); + if ( httplib_pthread_cond_init( & ctx->sq_empty, NULL ) ) return XX_httplib_abort_start( ctx, "Cannot initialize empty queue condition" ); + if ( httplib_pthread_cond_init( & ctx->sq_full, NULL ) ) return XX_httplib_abort_start( ctx, "Cannot initialize full queue condition" ); #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 XX_httplib_abort_start( ctx, "Cannot initialize nonce mutex" ); ctx->user_data = user_data; ctx->handlers = NULL; - if ( process_options( ctx, options ) ) return NULL; + if ( XX_httplib_init_options( ctx ) ) return NULL; + if ( XX_httplib_process_options( ctx, options ) ) return NULL; XX_httplib_get_system_name( & ctx->systemName ); @@ -164,13 +142,13 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks * 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 XX_httplib_abort_start( ctx, "Error setting gpass option" ); #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 XX_httplib_abort_start( ctx, "Error setting SSL option" ); #endif - if ( ! XX_httplib_set_ports_option( ctx ) ) return cleanup( ctx, "Error setting ports 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, "Error setting ACL option" ); + if ( ! XX_httplib_set_ports_option( ctx ) ) return XX_httplib_abort_start( ctx, "Error setting ports option" ); + if ( ! XX_httplib_set_uid_option( ctx ) ) return XX_httplib_abort_start( ctx, "Error setting UID option" ); + if ( ! XX_httplib_set_acl_option( ctx ) ) return XX_httplib_abort_start( ctx, "Error setting ACL option" ); #if !defined(_WIN32) @@ -183,33 +161,33 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks #endif /* !_WIN32 */ - if ( ctx->num_threads < 1 ) return cleanup( ctx, "No worker thread number specified" ); + if ( ctx->num_threads < 1 ) return XX_httplib_abort_start( ctx, "No worker thread number specified" ); - if ( ctx->num_threads > MAX_WORKER_THREADS ) return cleanup( ctx, "Too many worker threads" ); + if ( ctx->num_threads > MAX_WORKER_THREADS ) return XX_httplib_abort_start( ctx, "Too many worker threads" ); if ( ctx->num_threads > 0 ) { ctx->workerthreadids = httplib_calloc( ctx->num_threads, sizeof(pthread_t) ); - if ( ctx->workerthreadids == NULL ) return cleanup( ctx, "Not enough memory for worker thread ID array" ); + if ( ctx->workerthreadids == NULL ) return XX_httplib_abort_start( ctx, "Not enough memory for worker thread ID array" ); #if defined(ALTERNATIVE_QUEUE) ctx->client_wait_events = httplib_calloc( sizeof(ctx->client_wait_events[0]), ctx->num_threads ); - if ( ctx->client_wait_events == NULL ) return cleanup( ctx, "Not enough memory for worker event array" ); + if ( ctx->client_wait_events == NULL ) return XX_httplib_abort_start( ctx, "Not enough memory for worker event array" ); ctx->client_socks = httplib_calloc( sizeof(ctx->client_socks[0]), ctx->num_threads ); - if ( ctx->client_socks == NULL ) return cleanup( ctx, "Not enough memory for worker socket array" ); + if ( ctx->client_socks == NULL ) return XX_httplib_abort_start( ctx, "Not enough memory for worker socket array" ); for (i=0; inum_threads; i++) { 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 XX_httplib_abort_start( ctx, "Error creating worker event %u", i ); } #endif } #if defined(USE_TIMERS) - if ( timers_init( ctx ) != 0 ) return cleanup( ctx, "Error creating timers" ); + if ( timers_init( ctx ) != 0 ) return XX_httplib_abort_start( ctx, "Error creating timers" ); #endif /* @@ -255,7 +233,7 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks if ( i > 0 ) httplib_cry( DEBUG_LEVEL_ERROR, ctx, NULL, "Cannot start worker thread %i: error %ld", i + 1, (long)ERRNO ); - else return cleanup( ctx, "Cannot create worker threads: error %ld", (long)ERRNO ); + else return XX_httplib_abort_start( ctx, "Cannot create worker threads: error %ld", (long)ERRNO ); break; } @@ -266,439 +244,3 @@ struct httplib_context *httplib_start( const struct httplib_callbacks *callbacks return ctx; } /* httplib_start */ - - - -/* - * static bool process_options( struct httplib_context *ctx, const struct httplib_option_t *options ); - * - * The function process_options() processes the user supplied options and adds - * them to the central option list of the context. If en error occurs, the - * function returns true, otherwise FALSE is returned. In case of an error all - * cleanup is already done before returning and an error message has been - * generated. - */ - -static bool process_options( struct httplib_context *ctx, const struct httplib_option_t *options ) { - - if ( ctx == NULL ) return false; - - ctx->access_control_allow_origin = NULL; - ctx->access_control_list = NULL; - ctx->access_log_file = NULL; - ctx->allow_sendfile_call = true; - ctx->authentication_domain = NULL; - ctx->cgi_environment = NULL; - ctx->cgi_interpreter = NULL; - ctx->cgi_pattern = NULL; - ctx->debug_level = DEBUG_LEVEL_WARNING; - ctx->decode_url = true; - ctx->document_root = NULL; - ctx->enable_directory_listing = true; - ctx->enable_keep_alive = false; - ctx->error_log_file = NULL; - ctx->error_pages = NULL; - ctx->extra_mime_types = NULL; - ctx->global_auth_file = NULL; - ctx->hide_file_pattern = NULL; - ctx->index_files = NULL; - ctx->listening_ports = NULL; - ctx->num_threads = 50; - ctx->protect_uri = NULL; - ctx->put_delete_auth_file = NULL; - ctx->request_timeout = 30000; - ctx->run_as_user = NULL; - ctx->ssi_pattern = NULL; - ctx->ssl_ca_file = NULL; - ctx->ssl_ca_path = NULL; - ctx->ssl_certificate = NULL; - ctx->ssl_cipher_list = NULL; - ctx->ssl_protocol_version = 0; - ctx->ssl_short_trust = false; - ctx->ssl_verify_depth = 9; - ctx->ssl_verify_paths = true; - ctx->ssl_verify_peer = false; - ctx->static_file_max_age = 0; - ctx->throttle = NULL; - ctx->tcp_nodelay = false; - ctx->url_rewrite_patterns = NULL; - ctx->websocket_root = NULL; - ctx->websocket_timeout = 30000; - - if ( (ctx->access_control_allow_origin = httplib_strdup( "*" )) == NULL ) { - - cleanup( ctx, "Out of memory creating context allocating \"access_control_allow_origin\"" ); - return true; - } - - if ( (ctx->authentication_domain = httplib_strdup( "example.com" )) == NULL ) { - - cleanup( ctx, "Out of memory creating context allocating \"authentication_domain\"" ); - return true; - } - - if ( (ctx->cgi_pattern = httplib_strdup( "**.cgi$|**.pl$|**.php$" )) == NULL ) { - - cleanup( ctx, "Out of memory creating context allocating \"cgi_pattern\"" ); - return true; - } - - if ( (ctx->index_files = httplib_strdup( "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php" )) == NULL ) { - - cleanup( ctx, "Out of memory creating context allocating \"index_files\"" ); - return true; - } - - if ( (ctx->listening_ports = httplib_strdup( "8080" )) == NULL ) { - - cleanup( ctx, "Out of memory creating context allocating \"listening_ports\"" ); - return true; - } - - if ( (ctx->ssi_pattern = httplib_strdup( "**.shtml$|**.shtm$" )) == NULL ) { - - cleanup( ctx, "Out of memory creating context allocating \"ssi_pattern\"" ); - return true; - } - - while ( options != NULL && options->name != NULL ) { - - if ( check_str( ctx, options, "access_control_allow_origin", & ctx->access_control_allow_origin ) ) return true; - if ( check_str( ctx, options, "access_control_list", & ctx->access_control_list ) ) return true; - if ( check_file( ctx, options, "access_log_file", & ctx->access_log_file ) ) return true; - if ( check_bool( ctx, options, "allow_sendfile_call", & ctx->allow_sendfile_call ) ) return true; - if ( check_str( ctx, options, "authentication_domain", & ctx->authentication_domain ) ) return true; - if ( check_str( ctx, options, "cgi_environment", & ctx->cgi_environment ) ) return true; - if ( check_file( ctx, options, "cgi_interpreter", & ctx->cgi_interpreter ) ) return true; - if ( check_patt( ctx, options, "cgi_pattern", & ctx->cgi_pattern ) ) return true; - if ( check_dbg( ctx, options, "debug_level", & ctx->debug_level ) ) return true; - if ( check_bool( ctx, options, "decode_url", & ctx->decode_url ) ) return true; - if ( check_dir( ctx, options, "document_root", & ctx->document_root ) ) return true; - if ( check_bool( ctx, options, "enable_directory_listing", & ctx->enable_directory_listing ) ) return true; - if ( check_bool( ctx, options, "enable_keep_alive", & ctx->enable_keep_alive ) ) return true; - if ( check_file( ctx, options, "error_log_file", & ctx->error_log_file ) ) return true; - if ( check_dir( ctx, options, "error_pages", & ctx->error_pages ) ) return true; - if ( check_str( ctx, options, "extra_mime_types", & ctx->extra_mime_types ) ) return true; - if ( check_file( ctx, options, "global_auth_file", & ctx->global_auth_file ) ) return true; - if ( check_patt( ctx, options, "hide_file_pattern", & ctx->hide_file_pattern ) ) return true; - if ( check_str( ctx, options, "index_files", & ctx->index_files ) ) return true; - if ( check_str( ctx, options, "listening_ports", & ctx->listening_ports ) ) return true; - if ( check_int( ctx, options, "num_threads", & ctx->num_threads, 1, INT_MAX ) ) return true; - if ( check_str( ctx, options, "protect_uri", & ctx->protect_uri ) ) return true; - if ( check_file( ctx, options, "put_delete_auth_file", & ctx->put_delete_auth_file ) ) return true; - if ( check_int( ctx, options, "request_timeout", & ctx->request_timeout, 0, INT_MAX ) ) return true; - if ( check_str( ctx, options, "run_as_user", & ctx->run_as_user ) ) return true; - if ( check_patt( ctx, options, "ssi_pattern", & ctx->ssi_pattern ) ) return true; - if ( check_file( ctx, options, "ssl_ca_file", & ctx->ssl_ca_file ) ) return true; - if ( check_dir( ctx, options, "ssl_ca_path", & ctx->ssl_ca_path ) ) return true; - if ( check_file( ctx, options, "ssl_certificate", & ctx->ssl_certificate ) ) return true; - if ( check_str( ctx, options, "ssl_cipher_list", & ctx->ssl_cipher_list ) ) return true; - if ( check_int( ctx, options, "ssl_protocol_version", & ctx->ssl_protocol_version, 0, 4 ) ) return true; - if ( check_bool( ctx, options, "ssl_short_trust", & ctx->ssl_short_trust ) ) return true; - if ( check_int( ctx, options, "ssl_verify_depth", & ctx->ssl_verify_depth, 0, 9 ) ) return true; - if ( check_bool( ctx, options, "ssl_verify_paths", & ctx->ssl_verify_paths ) ) return true; - if ( check_bool( ctx, options, "ssl_verify_peer", & ctx->ssl_verify_peer ) ) return true; - if ( check_int( ctx, options, "static_file_max_age", & ctx->static_file_max_age, 0, INT_MAX ) ) return true; - if ( check_str( ctx, options, "throttle", & ctx->throttle ) ) return true; - if ( check_bool( ctx, options, "tcp_nodelay", & ctx->tcp_nodelay ) ) return true; - if ( check_str( ctx, options, "url_rewrite_patterns", & ctx->url_rewrite_patterns ) ) return true; - if ( check_dir( ctx, options, "websocket_root", & ctx->websocket_root ) ) return true; - if ( check_int( ctx, options, "websocket_timeout", & ctx->websocket_timeout, 0, INT_MAX ) ) return true; - - /* - * TODO: Currently silently ignoring unrecognized options - */ - - options++; - } - - return false; - -} /* process_options */ - - - -/* - * static bool check_bool( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, bool *config ); - * - * The function check_bool() checks if an option is equal to a boolean config - * parameter and stores the value if that is the case. If the value cannot be - * recognized, true is returned and the function performs a complete cleanup. - * If the option name could not be found, the function returns false to - * indicate that the search should go on. If the value could be found, also - * false is returned. - */ - -static bool check_bool( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, bool *config ) { - - if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { - - cleanup( ctx, "Internal error parsing boolean option" ); - return true; - } - - if ( httplib_strcasecmp( option->name, name ) ) return false; - if ( ! XX_httplib_option_value_to_bool( option->value, config ) ) return false; - - cleanup( ctx, "Invalid boolean value \"%s\" for option \"%s\"", option->value, option->name ); - return true; - -} /* check_bool */ - - - -/* - * static bool check_dir( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); - * - * The function check_dir() checks if an option is equal to a directory config - * parameter and stores the value if that is the case. If the value cannot be - * recognized, true is returned and the function performs a complete cleanup. - * If the option name could not be found, the function returns false to - * indicate that the search should go on. IF the value could be found, also - * false is returned. - */ - -static bool check_dir( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ) { - - if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { - - cleanup( ctx, "Internal error parsing directory option" ); - return true; - } - - if ( httplib_strcasecmp( option->name, name ) ) return false; - - *config = httplib_free( *config ); - - if ( option->value == NULL ) return false; - - *config = httplib_strdup( option->value ); - if ( *config != NULL ) return false; - - cleanup( ctx, "Out of memory assigning value \"%s\" to option \"%s\"", option->value, option->name ); - return true; - -} /* check_dir */ - - - -/* - * static bool check_patt( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); - * - * The function check_patt() checks if an option is equal to a pattern config - * parameter and stores the value if that is the case. If the value cannot be - * recognized, true is returned and the function performs a complete cleanup. - * If the option name could not be found, the function returns false to - * indicate that the search should go on. IF the value could be found, also - * false is returned. - */ - -static bool check_patt( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ) { - - if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { - - cleanup( ctx, "Internal error parsing pattern option" ); - return true; - } - - if ( httplib_strcasecmp( option->name, name ) ) return false; - - *config = httplib_free( *config ); - - if ( option->value == NULL ) return false; - - *config = httplib_strdup( option->value ); - if ( *config != NULL ) return false; - - cleanup( ctx, "Out of memory assigning value \"%s\" to option \"%s\"", option->value, option->name ); - return true; - -} /* check_patt */ - - - -/* - * static bool check_file( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); - * - * The function check_file() checks if an option is equal to a filename config - * parameter and stores the value if that is the case. If the value cannot be - * recognized, true is returned and the function performs a complete cleanup. - * If the option name could not be found, the function returns false to - * indicate that the search should go on. IF the value could be found, also - * false is returned. - */ - -static bool check_file( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ) { - - if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { - - cleanup( ctx, "Internal error parsing file option" ); - return true; - } - - if ( httplib_strcasecmp( option->name, name ) ) return false; - - *config = httplib_free( *config ); - - if ( option->value == NULL ) return false; - - *config = httplib_strdup( option->value ); - if ( *config != NULL ) return false; - - cleanup( ctx, "Out of memory assigning value \"%s\" to option \"%s\"", option->value, option->name ); - return true; - -} /* check_file */ - - - -/* - * static bool check_str( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ); - * - * The function check_str() checks if an option is equal to a string config - * parameter and stores the value if that is the case. If the value cannot be - * recognized, true is returned and the function performs a complete cleanup. - * If the option name could not be found, the function returns false to - * indicate that the search should go on. IF the value could be found, also - * false is returned. - */ - -static bool check_str( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, char **config ) { - - if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { - - cleanup( ctx, "Internal error parsing string option" ); - return true; - } - - if ( httplib_strcasecmp( option->name, name ) ) return false; - - *config = httplib_free( *config ); - - if ( option->value == NULL ) return false; - - *config = httplib_strdup( option->value ); - if ( *config != NULL ) return false; - - cleanup( ctx, "Out of memory assigning value \"%s\" to option \"%s\"", option->value, option->name ); - return true; - -} /* check_str */ - - - -/* - * static bool check_int( struct httplib_context *ctx, const struct httplib_opion_t *option, const char *name, int *config, int minval, int maxval ); - * - * The function check_int() checks in an option is equal to an integer config - * parameter and stores the value if that is the case. If the value cannot be - * recognized, true is returned and the function performs a complete cleanup. - * If the option name could not be found, the function returns false to - * indicate that the search should go on. If the value could be found and is - * valud, also false is returned. - */ - -static bool check_int( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, int *config, int minval, int maxval ) { - - int val; - - if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { - - cleanup( ctx, "Internal error parsing integer option" ); - return true; - } - - if ( httplib_strcasecmp( option->name, name ) ) return false; - - if ( ! XX_httplib_option_value_to_int( option->value, & val ) ) { - - if ( val < minval ) { cleanup( ctx, "Integer \"%s\" too small for option \"%s\"", option->value, option->name ); return true; } - if ( val > maxval ) { cleanup( ctx, "Integer \"%s\" too large for option \"%s\"", option->value, option->name ); return true; } - - *config = val; - return false; - } - - cleanup( ctx, "Invalid integer value \"%s\" for option \"%s\"", option->value, option->name ); - return true; - -} /* check_int */ - - - -/* - * static bool check_dbg( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name ); - * - * The function check_dbg() checks if an option is equal to a debug level - * config parameter and stores the value if that is the case. If the value - * cannot be recognized, true is returned and the function performs a complete - * cleanup. If the option name could not be found, the function returns false - * to indicate that the search should go on. If the value could be found and is - * valid, also false is returned. - */ - -static bool check_dbg( struct httplib_context *ctx, const struct httplib_option_t *option, const char *name, enum debug_level_t *config ) { - - int val; - - if ( ctx == NULL || option == NULL || option->name == NULL || name == NULL || config == NULL ) { - - cleanup( ctx, "Internal error parsing debug level option" ); - return true; - } - - if ( httplib_strcasecmp( option->name, name ) ) return false; - - if ( ! XX_httplib_option_value_to_int( option->value, &val ) ) { - - switch ( val ) { - - case DEBUG_LEVEL_NONE : - case DEBUG_LEVEL_CRASH : - case DEBUG_LEVEL_ERROR : - case DEBUG_LEVEL_WARNING : - case DEBUG_LEVEL_INFO : - *config = val; - return false; - } - } - - cleanup( ctx, "Invalid value \"%s\" for option \"%s\"", option->value, option->name ); - return true; - -} /* check_dbg */ - - - -/* - * 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 - * occured initializing a context. The function returns NULL which is then - * further returned to the calling party. - */ - -static struct httplib_context *cleanup( struct httplib_context *ctx, const char *fmt, ... ) { - - va_list ap; - char buf[MG_BUF_LEN]; - - if ( ctx == NULL ) return NULL; - - if ( fmt != NULL ) { - - va_start( ap, fmt ); - vsnprintf_impl( buf, sizeof(buf), fmt, ap ); - va_end( ap ); - buf[sizeof(buf)-1] = 0; - - httplib_cry( DEBUG_LEVEL_CRASH, ctx, NULL, "%s", buf ); - } - - XX_httplib_free_context( ctx ); - - httplib_pthread_setspecific( XX_httplib_sTlsKey, NULL ); - - return NULL; - -} /* cleanup */ diff --git a/src/httplib_stop.c b/src/httplib_stop.c index b0d82553..7600fd2f 100644 --- a/src/httplib_stop.c +++ b/src/httplib_stop.c @@ -69,8 +69,4 @@ void httplib_stop( struct httplib_context *ctx ) { httplib_pthread_join( mt, NULL ); XX_httplib_free_context( ctx ); -#if defined(_WIN32) - WSACleanup(); -#endif /* _WIN32 */ - } /* httplib_stop */ diff --git a/src/httplib_system_exit.c b/src/httplib_system_exit.c new file mode 100644 index 00000000..6d4114be --- /dev/null +++ b/src/httplib_system_exit.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Lammert Bies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * 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 + * THE SOFTWARE. + */ + +#include "httplib_main.h" + +/* + * int httplib_system_exit( void ); + * + * The function httplib_system_exit() is called after all processing with other + * LibHTTP function is completed to deinitialize socket communications. The + * function returns 0 when successful, and -1 if an error occured. + * + * Please note that this function terminates socket communications for all + * threads and it should therefore be called only when all running threads have + * terminated. + */ + +int httplib_system_exit( void ) { + +#if defined(_WIN32) + + return ( WSACleanup() ) ? -1 : 0; + +#else /* _WIN32 */ + + return 0; + +#endif /* _WIN32 */ + +} /* httplib_system_exit */ diff --git a/src/httplib_config_options.c b/src/httplib_system_init.c similarity index 72% rename from src/httplib_config_options.c rename to src/httplib_system_init.c index 2005f94c..9b5555c9 100644 --- a/src/httplib_config_options.c +++ b/src/httplib_system_init.c @@ -1,7 +1,5 @@ /* * Copyright (c) 2016 Lammert Bies - * Copyright (c) 2013-2016 the Civetweb developers - * Copyright (c) 2004-2013 Sergey Lyubka * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,20 +18,29 @@ * 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 * THE SOFTWARE. - * - * ============ - * Release: 2.0 */ #include "httplib_main.h" -/* - * Check if the XX_httplib_config_options and the corresponding enum have - * compatible sizes - */ - /* - * TODO: LJB: Move to test functions + * int httplib_system_init( void ); + * + * The function httplib_system_init() is called before any other LibHTTP + * functions to do some basic initialisation. The function returns 0 when + * successful and -1 if an error occured. */ -// httplib_static_assert((sizeof(XX_httplib_config_options) / sizeof(XX_httplib_config_options[0])) == (NUM_OPTIONS + 1), "XX_httplib_config_options and enum not sync"); +int httplib_system_init( void ) { + +#if defined(_WIN32) + + WSADATA data; + return ( WSAStartup( MAKEWORD(2,2), &data ) ) ? -1 : 0; + +#else /* _WIN32 */ + + return 0; + +#endif /* _WIN32 */ + +} /* httplib_system_init */