mirror of
https://github.com/lammertb/libhttp.git
synced 2025-08-09 03:22:45 +03:00
Improved error and memory handling
This commit is contained in:
@@ -904,8 +904,8 @@ 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_client( struct httplib_context *ctx, const char *host, int port, int use_ssl );
|
||||
LIBHTTP_API struct httplib_connection * httplib_connect_client_secure( struct httplib_context *ctx, const struct httplib_client_options *client_options );
|
||||
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_callbacks *callbacks, 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);
|
||||
|
@@ -30,7 +30,7 @@
|
||||
#include "httplib_ssl.h"
|
||||
#include "httplib_string.h"
|
||||
|
||||
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_connection * httplib_connect_client_impl( struct httplib_context *ctx, const struct httplib_client_options *client_options, int use_ssl );
|
||||
|
||||
/*
|
||||
* 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 );
|
||||
@@ -40,20 +40,20 @@ static struct httplib_connection * httplib_connect_client_impl( struct httplib_c
|
||||
* information, or NULL if an error occured.
|
||||
*/
|
||||
|
||||
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_client_secure( struct httplib_context *ctx, const struct httplib_client_options *client_options ) {
|
||||
|
||||
return httplib_connect_client_impl( ctx, client_options, 1, error_buffer, error_buffer_size );
|
||||
return httplib_connect_client_impl( ctx, client_options, true );
|
||||
|
||||
} /* httplib_connect_client_secure */
|
||||
|
||||
/*
|
||||
* 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_connection *httplib_connect_client( struct httplib_context *ctx, const char *host, int port, int use_ssl );
|
||||
*
|
||||
* 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( struct httplib_context *ctx, 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 ) {
|
||||
|
||||
struct httplib_client_options opts;
|
||||
|
||||
@@ -61,20 +61,20 @@ struct httplib_connection *httplib_connect_client( struct httplib_context *ctx,
|
||||
opts.host = host;
|
||||
opts.port = port;
|
||||
|
||||
return httplib_connect_client_impl( ctx, &opts, use_ssl, error_buffer, error_buffer_size );
|
||||
return httplib_connect_client_impl( ctx, &opts, use_ssl );
|
||||
|
||||
} /* httplib_connect_client */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 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_connection *httplib_connect_client_impl( struct httplib_context *ctx, const struct httplib_client_options *client_options, int use_ssl );
|
||||
*
|
||||
* 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( struct httplib_context *ctx, 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 ) {
|
||||
|
||||
struct httplib_connection *conn;
|
||||
SOCKET sock;
|
||||
@@ -85,18 +85,18 @@ static struct httplib_connection *httplib_connect_client_impl( struct httplib_co
|
||||
|
||||
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 ( ! XX_httplib_connect_socket( ctx, client_options->host, client_options->port, use_ssl, &sock, &sa ) ) return NULL;
|
||||
|
||||
if ( (conn = httplib_calloc( 1, sizeof(*conn) + MAX_REQUEST_SIZE )) == NULL ) {
|
||||
|
||||
XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "calloc(): %s", httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, NULL, "%s (%u): calloc(): %s", __func__, __LINE__, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
|
||||
closesocket( sock );
|
||||
}
|
||||
#ifndef NO_SSL
|
||||
|
||||
else if ( use_ssl && (conn->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL ) {
|
||||
|
||||
XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "SSL_CTX_new error" );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s (%u): SSL_CTX_new error", __func__, __LINE__ );
|
||||
closesocket( sock );
|
||||
conn = httplib_free( conn );
|
||||
}
|
||||
@@ -113,7 +113,7 @@ static struct httplib_connection *httplib_connect_client_impl( struct httplib_co
|
||||
conn->client.sock = sock;
|
||||
conn->client.lsa = sa;
|
||||
|
||||
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 ) );
|
||||
if ( getsockname( sock, psa, &len ) != 0 ) httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s (%u): getsockname() failed: %s", __func__, __LINE__, 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 );
|
||||
@@ -137,7 +137,7 @@ static struct httplib_connection *httplib_connect_client_impl( struct httplib_co
|
||||
|
||||
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" );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s (%u): can not use SSL client certificate", __func__, __LINE__ );
|
||||
SSL_CTX_free( conn->client_ssl_ctx );
|
||||
closesocket( sock );
|
||||
conn = httplib_free( conn );
|
||||
@@ -154,7 +154,7 @@ static struct httplib_connection *httplib_connect_client_impl( struct httplib_co
|
||||
|
||||
if ( ! XX_httplib_sslize( conn, conn->client_ssl_ctx, SSL_connect ) ) {
|
||||
|
||||
XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "SSL connection error" );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s (%u): SSL connection error", __func__, __LINE__ );
|
||||
SSL_CTX_free( conn->client_ssl_ctx );
|
||||
closesocket( sock );
|
||||
conn = httplib_free( conn );
|
||||
|
@@ -41,26 +41,26 @@
|
||||
* has been established.
|
||||
*/
|
||||
|
||||
bool XX_httplib_connect_socket( const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, SOCKET *sock, union usa *sa ) {
|
||||
bool XX_httplib_connect_socket( struct httplib_context *ctx, const char *host, int port, int use_ssl, SOCKET *sock, union usa *sa ) {
|
||||
|
||||
int ip_ver;
|
||||
char error_string[ERROR_STRING_LEN];
|
||||
|
||||
if ( ctx == NULL ) return false;
|
||||
|
||||
ip_ver = 0;
|
||||
*sock = INVALID_SOCKET;
|
||||
memset( sa, 0, sizeof(*sa) );
|
||||
|
||||
if ( ebuf_len > 0 ) *ebuf = 0;
|
||||
|
||||
if ( host == NULL ) {
|
||||
|
||||
XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "%s", "NULL host" );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, NULL, "%s (%u): NULL host", __func__, __LINE__ );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( port < 0 || ! XX_httplib_is_valid_port( (unsigned)port) ) {
|
||||
|
||||
XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "%s", "invalid port" );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, NULL, "%s (%u): invalid port", __func__, __LINE__ );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ bool XX_httplib_connect_socket( const char *host, int port, int use_ssl, char *e
|
||||
|
||||
if ( use_ssl && SSLv23_client_method == NULL ) {
|
||||
|
||||
XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "%s", "SSL is not initialized" );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, NULL, "%s (%u): SSL is not initialized", __func__, __LINE__ );
|
||||
return false;
|
||||
}
|
||||
#else /* NO_SSL */
|
||||
@@ -112,7 +112,7 @@ bool XX_httplib_connect_socket( const char *host, int port, int use_ssl, char *e
|
||||
|
||||
if ( ip_ver == 0 ) {
|
||||
|
||||
XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "%s", "host not found" );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, NULL, "%s (%u): host not found", __func__, __LINE__ );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -121,8 +121,8 @@ bool XX_httplib_connect_socket( const char *host, int port, int use_ssl, char *e
|
||||
|
||||
if ( *sock == INVALID_SOCKET ) {
|
||||
|
||||
XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "socket(): %s", httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
|
||||
return 0;
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, NULL, "%s (%u): socket(): %s", __func__, __LINE__, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
XX_httplib_set_close_on_exec( *sock );
|
||||
@@ -134,7 +134,7 @@ bool XX_httplib_connect_socket( const char *host, int port, int use_ssl, char *e
|
||||
* Not connected
|
||||
*/
|
||||
|
||||
XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "connect(%s:%d): %s", host, port, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, NULL, "%s (%u): connect(%s:%d): %s", __func__, __LINE__, host, port, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
|
||||
closesocket( *sock );
|
||||
*sock = INVALID_SOCKET;
|
||||
|
||||
|
@@ -43,7 +43,13 @@ struct httplib_connection *httplib_connect_websocket_client( struct httplib_cont
|
||||
static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw==";
|
||||
const char *handshake_req;
|
||||
|
||||
conn = NULL;
|
||||
if ( ctx == NULL ) return NULL;
|
||||
|
||||
if ( ctx->status != CTX_STATUS_TERMINATED ) {
|
||||
|
||||
httplib_cry( DEBUG_LEVEL_CRASH, ctx, NULL, "%s (%u): client context not in terminated state", __func__, __LINE__ );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( origin != NULL ) handshake_req = "GET %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
@@ -67,23 +73,16 @@ struct httplib_connection *httplib_connect_websocket_client( struct httplib_cont
|
||||
*/
|
||||
|
||||
conn = httplib_download( ctx, host, port, use_ssl, error_buffer, error_buffer_size, handshake_req, path, host, magic, origin );
|
||||
if ( conn == NULL ) {
|
||||
|
||||
/*
|
||||
* Connection object will be null if something goes wrong
|
||||
*/
|
||||
|
||||
if ( conn == NULL || strcmp( conn->request_info.request_uri, "101" ) ) {
|
||||
|
||||
if ( ! *error_buffer ) {
|
||||
|
||||
/*
|
||||
* if there is a connection, but it did not return 101,
|
||||
* error_buffer is not yet set
|
||||
*/
|
||||
|
||||
XX_httplib_snprintf( conn, NULL, error_buffer, error_buffer_size, "Unexpected server reply" );
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, NULL, "%s (%u): Init of download failed", __func__, __LINE__ );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( strcmp( conn->request_info.request_uri, "101" ) ) {
|
||||
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s (%u): unexpected server reply \"%s\"", __func__, __LINE__, conn->request_info.request_uri );
|
||||
|
||||
conn = httplib_free( conn );
|
||||
return NULL;
|
||||
}
|
||||
@@ -95,6 +94,8 @@ struct httplib_connection *httplib_connect_websocket_client( struct httplib_cont
|
||||
|
||||
if ( ctx->workerthreadids == NULL ) {
|
||||
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s (%u): out of memory allocating worker thread IDs", __func__, __LINE__ );
|
||||
|
||||
ctx->num_threads = 0;
|
||||
ctx->user_data = NULL;
|
||||
conn = httplib_free( conn );
|
||||
@@ -106,6 +107,8 @@ struct httplib_connection *httplib_connect_websocket_client( struct httplib_cont
|
||||
|
||||
if ( thread_data == NULL ) {
|
||||
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s (%u): out of memory allocating thread data", __func__, __LINE__ );
|
||||
|
||||
ctx->workerthreadids = httplib_free( ctx->workerthreadids );
|
||||
ctx->num_threads = 0;
|
||||
ctx->user_data = NULL;
|
||||
@@ -127,11 +130,13 @@ struct httplib_connection *httplib_connect_websocket_client( struct httplib_cont
|
||||
|
||||
if ( XX_httplib_start_thread_with_id( XX_httplib_websocket_client_thread, thread_data, ctx->workerthreadids) != 0 ) {
|
||||
|
||||
httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s (%u): thread failed to start", __func__, __LINE__ );
|
||||
|
||||
thread_data = httplib_free( thread_data );
|
||||
ctx->workerthreadids = httplib_free( ctx->workerthreadids );
|
||||
conn = httplib_free( conn );
|
||||
ctx->num_threads = 0;
|
||||
ctx->user_data = NULL;
|
||||
conn = httplib_free( conn );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -54,6 +54,7 @@ struct httplib_context *httplib_create_client_context( const struct httplib_call
|
||||
|
||||
ctx->callbacks.exit_context = exit_callback;
|
||||
ctx->ctx_type = CTX_TYPE_CLIENT;
|
||||
ctx->status = CTX_STATUS_TERMINATED;
|
||||
|
||||
return ctx;
|
||||
|
||||
|
@@ -38,6 +38,7 @@ void httplib_destroy_client_context( struct httplib_context *ctx ) {
|
||||
|
||||
XX_httplib_free_config_options( ctx );
|
||||
|
||||
ctx->workerthreadids = httplib_free( ctx->workerthreadids );
|
||||
ctx = httplib_free( ctx );
|
||||
|
||||
} /* httplib_destroy_client_context */
|
||||
|
@@ -47,13 +47,13 @@ struct httplib_connection * httplib_download( struct httplib_context *ctx, const
|
||||
va_start( ap, fmt );
|
||||
ebuf[0] = '\0';
|
||||
|
||||
conn = httplib_connect_client( ctx, host, port, use_ssl, ebuf, ebuf_len );
|
||||
conn = httplib_connect_client( ctx, host, port, use_ssl );
|
||||
|
||||
if ( conn != NULL ) {
|
||||
|
||||
i = XX_httplib_vprintf( conn, fmt, ap );
|
||||
|
||||
if (i <= 0) XX_httplib_snprintf( conn, NULL, ebuf, ebuf_len, "%s", "Error sending request" );
|
||||
if ( i <= 0 ) httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s (%d): error sending request", __func__, __LINE__ );
|
||||
|
||||
else {
|
||||
XX_httplib_getreq( conn, ebuf, ebuf_len, &reqerr );
|
||||
@@ -67,11 +67,13 @@ struct httplib_connection * httplib_download( struct httplib_context *ctx, const
|
||||
}
|
||||
}
|
||||
|
||||
else i = 0;
|
||||
|
||||
/*
|
||||
* if an error occured, close the connection
|
||||
*/
|
||||
|
||||
if ( ebuf[0] != '\0' && conn != NULL ) {
|
||||
if ( i <= 0 && conn != NULL ) {
|
||||
|
||||
httplib_close_connection( conn );
|
||||
conn = NULL;
|
||||
|
@@ -797,7 +797,7 @@ void XX_httplib_close_all_listening_sockets( struct httplib_context *ctx );
|
||||
void XX_httplib_close_connection( struct httplib_connection *conn );
|
||||
void XX_httplib_close_socket_gracefully( struct httplib_connection *conn );
|
||||
int WINCDECL XX_httplib_compare_dir_entries( const void *p1, const void *p2 );
|
||||
bool XX_httplib_connect_socket( const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, SOCKET *sock, union usa *sa );
|
||||
bool XX_httplib_connect_socket( struct httplib_context *ctx, const char *host, int port, int use_ssl, SOCKET *sock, union usa *sa );
|
||||
void XX_httplib_construct_etag( char *buf, size_t buf_len, const struct file *filep );
|
||||
int XX_httplib_consume_socket( struct httplib_context *ctx, struct socket *sp, int thread_index );
|
||||
void XX_httplib_delete_file( struct httplib_connection *conn, const char *path );
|
||||
|
@@ -39,24 +39,24 @@ LIBHTTP_THREAD XX_httplib_websocket_client_thread( void *data ) {
|
||||
struct websocket_client_thread_data *cdata;
|
||||
|
||||
cdata = data;
|
||||
if ( cdata == NULL || cdata->conn == NULL || cdata->conn->ctx == NULL ) return LIBHTTP_THREAD_RETNULL;
|
||||
|
||||
cdata->conn->ctx->status = CTX_STATUS_RUNNING;
|
||||
|
||||
XX_httplib_set_thread_name( "ws-client" );
|
||||
|
||||
if ( cdata->conn->ctx != NULL ) {
|
||||
|
||||
/*
|
||||
* 3 indicates a websocket client thread
|
||||
* TODO: check if conn->ctx can be set
|
||||
*/
|
||||
|
||||
if ( cdata->conn->ctx->callbacks.init_thread != NULL ) cdata->conn->ctx->callbacks.init_thread( cdata->conn->ctx, 3 );
|
||||
}
|
||||
|
||||
XX_httplib_read_websocket( cdata->conn, cdata->data_handler, cdata->callback_data );
|
||||
|
||||
if ( cdata->close_handler != NULL ) cdata->close_handler( cdata->conn, cdata->callback_data );
|
||||
|
||||
cdata->conn->ctx->workerthreadids = httplib_free( cdata->conn->ctx->workerthreadids );
|
||||
cdata->conn = httplib_free( cdata->conn );
|
||||
cdata = httplib_free( cdata );
|
||||
cdata->conn->ctx->user_data = NULL;
|
||||
cdata->conn->ctx->num_threads = 0;
|
||||
cdata->conn->ctx->status = CTX_STATUS_TERMINATED;
|
||||
|
||||
return LIBHTTP_THREAD_RETNULL;
|
||||
|
||||
|
Reference in New Issue
Block a user