From 200ff09bbe0b0be3d5a52e09314bba005fcad2b3 Mon Sep 17 00:00:00 2001 From: Lammert Bies Date: Tue, 20 Dec 2016 22:17:46 +0100 Subject: [PATCH] Code cleanup --- src/httplib_authorize.c | 16 +- src/httplib_check_acl.c | 36 +-- src/httplib_check_feature.c | 2 +- src/httplib_close_connection.c | 63 +++-- src/httplib_config_options.c | 8 +- src/httplib_connect_client.c | 91 ++++---- src/httplib_connect_socket.c | 102 +++++---- src/httplib_construct_etag.c | 7 +- src/httplib_consume_socket.c | 41 ++-- src/httplib_cry.c | 79 +++---- src/httplib_delete_file.c | 80 ++++--- src/httplib_difftimespec.c | 16 +- src/httplib_discard_unread_request_data.c | 49 ++-- src/httplib_download.c | 39 ++-- src/httplib_event_queue.c | 85 ++++--- src/httplib_fc.c | 13 +- src/httplib_fclose_on_exec.c | 15 +- src/httplib_fgets.c | 35 +-- src/httplib_free_context.c | 73 ++++-- src/httplib_get_cookie.c | 34 +-- src/httplib_get_first_ssl_listener_index.c | 4 +- src/httplib_get_header.c | 12 +- src/httplib_get_mime_type.c | 27 ++- src/httplib_get_option_index.c | 10 +- src/httplib_get_random.c | 57 +++-- src/httplib_get_rel_url_at_current_server.c | 104 +++++---- src/httplib_get_remote_ip.c | 4 +- src/httplib_get_request_handler.c | 150 +++++++----- src/httplib_get_request_info.c | 2 +- src/httplib_get_request_len.c | 41 ++-- src/httplib_get_response.c | 47 ++-- src/httplib_get_response_code_text.c | 17 +- src/httplib_get_server_ports.c | 31 ++- src/httplib_get_system_name.c | 36 +-- src/httplib_get_uri_type.c | 83 ++++--- src/httplib_get_user_connection_data.c | 8 +- src/httplib_get_valid_options.c | 4 +- src/httplib_get_var.c | 77 ++++--- src/httplib_getreq.c | 138 +++++++---- src/httplib_global_data.c | 2 +- src/httplib_gmt_time_string.c | 13 +- src/httplib_handle_cgi_request.c | 241 ++++++++++++-------- src/httplib_handle_form_request.c | 59 +++-- src/httplib_printf.c | 8 +- src/httplib_pull.c | 74 +++--- src/httplib_put_file.c | 2 +- src/httplib_set_acl_option.c | 2 +- src/httplib_set_auth_handler.c | 2 +- src/httplib_set_gpass_option.c | 14 +- src/httplib_set_uid_option.c | 25 +- 50 files changed, 1330 insertions(+), 848 deletions(-) diff --git a/src/httplib_authorize.c b/src/httplib_authorize.c index b86843e7..66516763 100644 --- a/src/httplib_authorize.c +++ b/src/httplib_authorize.c @@ -22,12 +22,18 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" -/* Authorize against the opened passwords file. Return 1 if authorized. */ +/* + * int XX_httplib_authorize( struct httplib_connection *conn, struct file *filep ); + * + * The function XX_httplib_authorize() authorizes agains the open passwords + * file. It returns 1 if authorized. + */ + int XX_httplib_authorize( struct httplib_connection *conn, struct file *filep ) { struct read_auth_file_struct workdata; @@ -35,12 +41,12 @@ int XX_httplib_authorize( struct httplib_connection *conn, struct file *filep ) if ( conn == NULL || conn->ctx == NULL ) return 0; - memset(&workdata, 0, sizeof(workdata)); + memset( & workdata, 0, sizeof(workdata) ); workdata.conn = conn; - if (!XX_httplib_parse_auth_header(conn, buf, sizeof(buf), &workdata.ah)) return 0; + if ( ! XX_httplib_parse_auth_header( conn, buf, sizeof(buf), &workdata.ah ) ) return 0; workdata.domain = conn->ctx->config[AUTHENTICATION_DOMAIN]; - return XX_httplib_read_auth_file(filep, &workdata); + return XX_httplib_read_auth_file( filep, &workdata ); } /* XX_httplib_authorize */ diff --git a/src/httplib_check_acl.c b/src/httplib_check_acl.c index 1bb1b9a7..cc7eaec2 100644 --- a/src/httplib_check_acl.c +++ b/src/httplib_check_acl.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -43,25 +43,33 @@ int XX_httplib_check_acl( struct httplib_context *ctx, uint32_t remote_ip ) { uint32_t net; uint32_t mask; struct vec vec; + const char *list; - if (ctx) { - const char *list = ctx->config[ACCESS_CONTROL_LIST]; + if ( ctx == NULL ) return -1; - /* If any ACL is set, deny by default */ - allowed = (list == NULL) ? '+' : '-'; + list = ctx->config[ACCESS_CONTROL_LIST]; - while ((list = XX_httplib_next_option(list, &vec, NULL)) != NULL) { - flag = vec.ptr[0]; - if ((flag != '+' && flag != '-') || XX_httplib_parse_net(&vec.ptr[1], &net, &mask) == 0) { - httplib_cry( XX_httplib_fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__); - return -1; - } + /* + * If any ACL is set, deny by default + */ - if (net == (remote_ip & mask)) allowed = flag; + if ( list == NULL ) allowed = '+'; + else allowed = '-'; + + + while ( (list = XX_httplib_next_option( list, & vec, NULL )) != NULL ) { + + flag = vec.ptr[0]; + + if ( (flag != '+' && flag != '-') || XX_httplib_parse_net( &vec.ptr[1], &net, &mask ) == 0 ) { + + httplib_cry( XX_httplib_fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__ ); + return -1; } - return allowed == '+'; + if ( (remote_ip & mask) == net ) allowed = flag; } - return -1; + + return (allowed == '+'); } /* XX_httplib_check_acl */ diff --git a/src/httplib_check_feature.c b/src/httplib_check_feature.c index b9c217bf..64f6eaed 100644 --- a/src/httplib_check_feature.c +++ b/src/httplib_check_feature.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" diff --git a/src/httplib_close_connection.c b/src/httplib_close_connection.c index 63a337d6..d9d32e3a 100644 --- a/src/httplib_close_connection.c +++ b/src/httplib_close_connection.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -41,24 +41,32 @@ void XX_httplib_close_connection( struct httplib_connection *conn ) { if ( conn == NULL || conn->ctx == NULL ) return; - /* call the connection_close callback if assigned */ - if ((conn->ctx->callbacks.connection_close != NULL) && (conn->ctx->context_type == 1)) { - conn->ctx->callbacks.connection_close(conn); - } + /* + * call the connection_close callback if assigned + */ + + if ( conn->ctx->callbacks.connection_close != NULL && conn->ctx->context_type == 1 ) conn->ctx->callbacks.connection_close( conn ); httplib_lock_connection( conn ); conn->must_close = 1; #ifndef NO_SSL - if (conn->ssl != NULL) { - /* Run SSL_shutdown twice to ensure completly close SSL connection + if ( conn->ssl != NULL ) { + + /* + * Run SSL_shutdown twice to ensure completly close SSL connection */ - SSL_shutdown(conn->ssl); - SSL_free(conn->ssl); - /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion: - * https://wiki.openssl.org/index.php/Talk:Library_Initialization */ - ERR_remove_state(0); + + SSL_shutdown( conn->ssl ); + SSL_free( conn->ssl ); + + /* + * Avoid CRYPTO_cleanup_all_ex_data(); See discussion: + * https://wiki.openssl.org/index.php/Talk:Library_Initialization + */ + + ERR_remove_state( 0 ); conn->ssl = NULL; } #endif @@ -84,31 +92,44 @@ void XX_httplib_close_connection( struct httplib_connection *conn ) { void httplib_close_connection( struct httplib_connection *conn ) { - struct httplib_context *client_ctx = NULL; + struct httplib_context *client_ctx; unsigned int i; if ( conn == NULL ) return; if ( conn->ctx->context_type == 2 ) { - client_ctx = conn->ctx; - /* client context: loops must end */ + client_ctx = conn->ctx; conn->ctx->stop_flag = 1; } + else client_ctx = NULL; + #ifndef NO_SSL - if (conn->client_ssl_ctx != NULL) SSL_CTX_free((SSL_CTX *)conn->client_ssl_ctx); + if ( conn->client_ssl_ctx != NULL ) { + + SSL_CTX_free( (SSL_CTX *)conn->client_ssl_ctx ); + conn->client_ssl_ctx = NULL; + } #endif - XX_httplib_close_connection(conn); - if (client_ctx != NULL) { - /* join worker thread and free context */ - for (i = 0; i < client_ctx->cfg_worker_threads; i++) { - if (client_ctx->workerthreadids[i] != 0) XX_httplib_join_thread(client_ctx->workerthreadids[i]); + XX_httplib_close_connection( conn ); + + if ( client_ctx != NULL ) { + + /* + * join worker thread and free context + */ + + for (i=0; icfg_worker_threads; i++) { + + if ( client_ctx->workerthreadids[i] != 0 ) XX_httplib_join_thread( client_ctx->workerthreadids[i] ); } httplib_free( client_ctx->workerthreadids ); httplib_free( client_ctx ); + httplib_pthread_mutex_destroy( & conn->mutex ); + httplib_free( conn ); } diff --git a/src/httplib_config_options.c b/src/httplib_config_options.c index 20e1f6f8..83b44353 100644 --- a/src/httplib_config_options.c +++ b/src/httplib_config_options.c @@ -22,12 +22,15 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" -/* Config option name, config types, default value */ +/* + * Config option name, config types, default value + */ + struct httplib_option XX_httplib_config_options[] = { { "cgi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$" }, { "cgi_environment", CONFIG_TYPE_STRING, NULL }, @@ -84,4 +87,5 @@ struct httplib_option XX_httplib_config_options[] = { * Check if the XX_httplib_config_options and the corresponding enum have * compatible sizes */ + 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"); diff --git a/src/httplib_connect_client.c b/src/httplib_connect_client.c index e7eb5407..4afaa27f 100644 --- a/src/httplib_connect_client.c +++ b/src/httplib_connect_client.c @@ -33,8 +33,6 @@ static struct httplib_connection * httplib_connect_client_impl( 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 ); * @@ -49,8 +47,6 @@ LIBHTTP_API struct httplib_connection *httplib_connect_client_secure( const stru } /* 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 ); * @@ -82,32 +78,38 @@ struct httplib_connection * httplib_connect_client( const char *host, int port, 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_context fake_ctx; - struct httplib_connection *conn = NULL; + struct httplib_connection *conn; SOCKET sock; union usa sa; + socklen_t len; + struct sockaddr *psa; - if (!XX_httplib_connect_socket(&fake_ctx, client_options->host, client_options->port, use_ssl, ebuf, ebuf_len, &sock, &sa)) { - ; - } else if ((conn = httplib_calloc( 1, sizeof(*conn) + MAX_REQUEST_SIZE )) == NULL ) { - XX_httplib_snprintf(NULL, NULL, ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO)); - closesocket(sock); + if ( ! XX_httplib_connect_socket( &fake_ctx, 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 ) { + + XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO) ); + closesocket( sock ); + } #ifndef NO_SSL - } else if (use_ssl && (conn->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) { + + 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"); - closesocket(sock); + XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "SSL_CTX_new error" ); + closesocket( sock ); httplib_free( conn ); conn = NULL; + } #endif /* NO_SSL */ - } else { + else { #ifdef USE_IPV6 - socklen_t len = (sa.sa.sa_family == AF_INET) ? sizeof(conn->client.rsa.sin) : sizeof(conn->client.rsa.sin6); - struct sockaddr *psa = (sa.sa.sa_family == AF_INET) ? (struct sockaddr *)&(conn->client.rsa.sin) : (struct sockaddr *)&(conn->client.rsa.sin6); + len = (sa.sa.sa_family == AF_INET) ? sizeof(conn->client.rsa.sin) : sizeof(conn->client.rsa.sin6); + psa = (sa.sa.sa_family == AF_INET) ? (struct sockaddr *)&(conn->client.rsa.sin) : (struct sockaddr *)&(conn->client.rsa.sin6); #else - socklen_t len = sizeof(conn->client.rsa.sin); - struct sockaddr *psa = (struct sockaddr *)&(conn->client.rsa.sin); + len = sizeof(conn->client.rsa.sin); + psa = (struct sockaddr *)&(conn->client.rsa.sin); #endif conn->buf_size = MAX_REQUEST_SIZE; @@ -116,44 +118,51 @@ static struct httplib_connection *httplib_connect_client_impl( const struct http conn->client.sock = sock; conn->client.lsa = sa; - if (getsockname(sock, psa, &len) != 0) httplib_cry(conn, "%s: getsockname() failed: %s", __func__, strerror(ERRNO)); + if ( getsockname( sock, psa, &len ) != 0 ) httplib_cry(conn, "%s: getsockname() failed: %s", __func__, strerror(ERRNO) ); - conn->client.is_ssl = use_ssl ? 1 : 0; - pthread_mutex_init(&conn->mutex, &XX_httplib_pthread_mutex_attr); + conn->client.is_ssl = (use_ssl) ? 1 : 0; + pthread_mutex_init( &conn->mutex, &XX_httplib_pthread_mutex_attr ); #ifndef NO_SSL - if (use_ssl) { + if ( use_ssl ) { fake_ctx.ssl_ctx = conn->client_ssl_ctx; - /* TODO: Check ssl_verify_peer and ssl_ca_path here. + /* + * TODO: Check ssl_verify_peer and ssl_ca_path here. * SSL_CTX_set_verify call is needed to switch off server * certificate checking, which is off by default in OpenSSL and - * on in yaSSL. */ - /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx, - * SSL_VERIFY_PEER, verify_ssl_server); */ + * on in yaSSL. + * + * TODO: SSL_CTX_set_verify(conn->client_ssl_ctx, + * SSL_VERIFY_PEER, verify_ssl_server); + */ - if (client_options->client_cert) { - if (!XX_httplib_ssl_use_pem_file(&fake_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); - closesocket(sock); + if ( client_options->client_cert ) { + + if ( ! XX_httplib_ssl_use_pem_file( &fake_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 ); + closesocket( sock ); httplib_free( conn ); conn = NULL; } } - if (client_options->server_cert) { - SSL_CTX_load_verify_locations(conn->client_ssl_ctx, client_options->server_cert, NULL); - SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_PEER, NULL); - } else { - SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_NONE, NULL); - } + if ( client_options->server_cert ) { - if (!XX_httplib_sslize(conn, conn->client_ssl_ctx, SSL_connect)) { - XX_httplib_snprintf(NULL, NULL, ebuf, ebuf_len, "SSL connection error"); - SSL_CTX_free(conn->client_ssl_ctx); - closesocket(sock); + SSL_CTX_load_verify_locations( conn->client_ssl_ctx, client_options->server_cert, NULL ); + SSL_CTX_set_verify( conn->client_ssl_ctx, SSL_VERIFY_PEER, NULL ); + } + + else SSL_CTX_set_verify( conn->client_ssl_ctx, SSL_VERIFY_NONE, NULL ); + + if ( ! XX_httplib_sslize( conn, conn->client_ssl_ctx, SSL_connect ) ) { + + XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "SSL connection error" ); + SSL_CTX_free( conn->client_ssl_ctx ); + closesocket( sock ); httplib_free( conn ); conn = NULL; } diff --git a/src/httplib_connect_socket.c b/src/httplib_connect_socket.c index 5656686d..d7eb81c1 100644 --- a/src/httplib_connect_socket.c +++ b/src/httplib_connect_socket.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -41,88 +41,106 @@ int XX_httplib_connect_socket( struct httplib_context *ctx, const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, SOCKET *sock, union usa *sa ) { - int ip_ver = 0; + int ip_ver; - *sock = INVALID_SOCKET; - memset(sa, 0, sizeof(*sa)); + ip_ver = 0; + *sock = INVALID_SOCKET; + memset( sa, 0, sizeof(*sa) ); - if (ebuf_len > 0) *ebuf = 0; + if ( ebuf_len > 0 ) *ebuf = 0; - if (host == NULL) { - XX_httplib_snprintf(NULL, NULL, ebuf, ebuf_len, "%s", "NULL host"); + if ( host == NULL ) { + + XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "%s", "NULL host" ); return 0; } - if (port < 0 || !XX_httplib_is_valid_port((unsigned)port)) { - XX_httplib_snprintf(NULL, NULL, ebuf, ebuf_len, "%s", "invalid port"); + if ( port < 0 || ! XX_httplib_is_valid_port( (unsigned)port) ) { + + XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "%s", "invalid port" ); return 0; } #if !defined(NO_SSL) - if (use_ssl && (SSLv23_client_method == NULL)) { - XX_httplib_snprintf(NULL, NULL, ebuf, ebuf_len, "%s", "SSL is not initialized"); + + if ( use_ssl && SSLv23_client_method == NULL ) { + + XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "%s", "SSL is not initialized" ); return 0; } #else - (void)use_ssl; + UNUSED_PARAMETER(use_ssl); #endif if (XX_httplib_inet_pton(AF_INET, host, &sa->sin, sizeof(sa->sin))) { + sa->sin.sin_port = htons((uint16_t)port); ip_ver = 4; + } #ifdef USE_IPV6 - } else if (XX_httplib_inet_pton(AF_INET6, host, &sa->sin6, sizeof(sa->sin6))) { - sa->sin6.sin6_port = htons((uint16_t)port); + + else if ( XX_httplib_inet_pton( AF_INET6, host, &sa->sin6, sizeof(sa->sin6) ) ) { + + sa->sin6.sin6_port = htons( (uint16_t)port ); ip_ver = 6; - } else if (host[0] == '[') { - /* While getaddrinfo on Windows will work with [::1], - * getaddrinfo on Linux only works with ::1 (without []). */ - size_t l = strlen(host + 1); - char *h = (l > 1) ? XX_httplib_strdup(host + 1) : NULL; - if (h) { - h[l - 1] = 0; - if (XX_httplib_inet_pton(AF_INET6, h, &sa->sin6, sizeof(sa->sin6))) { - sa->sin6.sin6_port = htons((uint16_t)port); + } + + else if ( host[0] == '[' ) { + + /* + * While getaddrinfo on Windows will work with [::1], + * getaddrinfo on Linux only works with ::1 (without []). + */ + + size_t l = strlen(host+1); + char *h = (l > 1) ? XX_httplib_strdup(host+1) : NULL; + + if ( h != NULL ) { + + h[l-1] = 0; + + if ( XX_httplib_inet_pton( AF_INET6, h, &sa->sin6, sizeof(sa->sin6) ) ) { + + sa->sin6.sin6_port = htons( (uint16_t)port ); ip_ver = 6; } httplib_free( h ); } -#endif } +#endif + if ( ip_ver == 0 ) { - if (ip_ver == 0) { - XX_httplib_snprintf(NULL, NULL, ebuf, ebuf_len, "%s", "host not found"); + XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "%s", "host not found" ); return 0; } - if (ip_ver == 4) { *sock = socket(PF_INET, SOCK_STREAM, 0); } + if ( ip_ver == 4 ) *sock = socket( PF_INET, SOCK_STREAM, 0 ); #ifdef USE_IPV6 - else if (ip_ver == 6) { *sock = socket(PF_INET6, SOCK_STREAM, 0); } + else if ( ip_ver == 6 ) *sock = socket( PF_INET6, SOCK_STREAM, 0 ); #endif - if (*sock == INVALID_SOCKET) { - XX_httplib_snprintf(NULL, NULL, ebuf, ebuf_len, "socket(): %s", strerror(ERRNO)); + if ( *sock == INVALID_SOCKET ) { + + XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "socket(): %s", strerror(ERRNO) ); return 0; } - XX_httplib_set_close_on_exec(*sock, XX_httplib_fc(ctx)); + XX_httplib_set_close_on_exec( *sock, XX_httplib_fc(ctx) ); - if ((ip_ver == 4) && (connect(*sock, (struct sockaddr *)&sa->sin, sizeof(sa->sin)) == 0)) { - /* connected with IPv4 */ - return 1; - } + if ( ip_ver == 4 && connect( *sock, (struct sockaddr *)&sa->sin, sizeof(sa->sin) ) == 0 ) return 1; #ifdef USE_IPV6 - if ((ip_ver == 6) && (connect(*sock, (struct sockaddr *)&sa->sin6, sizeof(sa->sin6)) == 0)) { - /* connected with IPv6 */ - return 1; - } + if ( ip_ver == 6 && connect( *sock, (struct sockaddr *)&sa->sin6, sizeof(sa->sin6) ) == 0 ) return 1; #endif - /* Not connected */ - XX_httplib_snprintf(NULL, NULL, ebuf, ebuf_len, "connect(%s:%d): %s", host, port, strerror(ERRNO)); - closesocket(*sock); + /* + * Not connected + */ + + XX_httplib_snprintf( NULL, NULL, ebuf, ebuf_len, "connect(%s:%d): %s", host, port, strerror(ERRNO) ); + closesocket( *sock ); *sock = INVALID_SOCKET; + return 0; } /* XX_httplib_connect_socket */ diff --git a/src/httplib_construct_etag.c b/src/httplib_construct_etag.c index 715b6af9..b6382e78 100644 --- a/src/httplib_construct_etag.c +++ b/src/httplib_construct_etag.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -37,8 +37,9 @@ void XX_httplib_construct_etag( char *buf, size_t buf_len, const struct file *filep ) { - if (filep != NULL && buf != NULL) { - XX_httplib_snprintf(NULL, NULL, buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long)filep->last_modified, filep->size); + if ( filep != NULL && buf != NULL && buf_len > 0 ) { + + XX_httplib_snprintf( NULL, NULL, buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long)filep->last_modified, filep->size ); } } /* XX_httplib_construct_etag */ diff --git a/src/httplib_consume_socket.c b/src/httplib_consume_socket.c index 1df313cd..d128a5a7 100644 --- a/src/httplib_consume_socket.c +++ b/src/httplib_consume_socket.c @@ -22,12 +22,14 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" #include "httplib_pthread.h" +#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue))) + /* * int XX_httplib_consume_socket( struct httplib_context *ctx, struct socket *sp, int thread_index ); * @@ -40,10 +42,10 @@ int XX_httplib_consume_socket( struct httplib_context *ctx, struct socket *sp, int thread_index ) { ctx->client_socks[thread_index].in_use = 0; - event_wait(ctx->client_wait_events[thread_index]); + event_wait( ctx->client_wait_events[thread_index] ); *sp = ctx->client_socks[thread_index]; - return !ctx->stop_flag; + return ! ctx->stop_flag; } /* XX_httplib_consume_socket */ @@ -52,26 +54,34 @@ int XX_httplib_consume_socket( struct httplib_context *ctx, struct socket *sp, i /* Worker threads take accepted socket from the queue */ int XX_httplib_consume_socket( struct httplib_context *ctx, struct socket *sp, int thread_index ) { -#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue))) - UNUSED_PARAMETER(thread_index); httplib_pthread_mutex_lock( & ctx->thread_mutex ); - /* If the queue is empty, wait. We're idle at this point. */ - while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) { + /* + * If the queue is empty, wait. We're idle at this point. + */ - httplib_pthread_cond_wait( & ctx->sq_full, & ctx->thread_mutex ); - } + while ( ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0 ) httplib_pthread_cond_wait( & ctx->sq_full, & ctx->thread_mutex ); + + /* + * If we're stopping, sq_head may be equal to sq_tail. + */ + + if ( ctx->sq_head > ctx->sq_tail ) { + + /* + * Copy socket from the queue and increment tail + */ - /* If we're stopping, sq_head may be equal to sq_tail. */ - if (ctx->sq_head > ctx->sq_tail) { - /* Copy socket from the queue and increment tail */ *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)]; ctx->sq_tail++; - /* Wrap pointers if needed */ - while (ctx->sq_tail > QUEUE_SIZE(ctx)) { + /* + * Wrap pointers if needed + */ + + while ( ctx->sq_tail > QUEUE_SIZE(ctx) ) { ctx->sq_tail -= QUEUE_SIZE(ctx); ctx->sq_head -= QUEUE_SIZE(ctx); @@ -81,8 +91,7 @@ int XX_httplib_consume_socket( struct httplib_context *ctx, struct socket *sp, i httplib_pthread_cond_signal( & ctx->sq_empty ); httplib_pthread_mutex_unlock( & ctx->thread_mutex ); - return !ctx->stop_flag; -#undef QUEUE_SIZE + return ! ctx->stop_flag; } /* XX_httplib_consume_socket */ diff --git a/src/httplib_cry.c b/src/httplib_cry.c index f5e92510..d7beade9 100644 --- a/src/httplib_cry.c +++ b/src/httplib_cry.c @@ -22,14 +22,20 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" #include "httplib_ssl.h" -/* Print error message to the opened error log stream. */ -void httplib_cry(const struct httplib_connection *conn, const char *fmt, ...) { +/* + * void httplib_cry( const struct httplib_connection *conn, const char *fmt, ... ); + * + * The function httplib_cry() prints a formatted error message to the opened + * error log stream. + */ + +void httplib_cry( const struct httplib_connection *conn, const char *fmt, ... ) { char buf[MG_BUF_LEN]; char src_addr[IP_ADDR_STR_LEN]; @@ -37,51 +43,46 @@ void httplib_cry(const struct httplib_connection *conn, const char *fmt, ...) { struct file fi; time_t timestamp; - va_start(ap, fmt); - IGNORE_UNUSED_RESULT(vsnprintf_impl(buf, sizeof(buf), fmt, ap)); - va_end(ap); - buf[sizeof(buf) - 1] = 0; + va_start( ap, fmt ); + vsnprintf_impl( buf, sizeof(buf), fmt, ap ); + va_end( ap ); + buf[sizeof(buf)-1] = 0; - if (!conn) { - puts(buf); - return; - } + if ( conn == NULL || conn->ctx == NULL ) return; - /* Do not lock when getting the callback value, here and below. + /* + * Do not lock when getting the callback value, here and below. * I suppose this is fine, since function cannot disappear in the - * same way string option can. */ - if ((conn->ctx->callbacks.log_message == NULL) - || (conn->ctx->callbacks.log_message(conn, buf) == 0)) { + * same way string option can. + */ - if (conn->ctx->config[ERROR_LOG_FILE] != NULL) { - if (XX_httplib_fopen(conn, conn->ctx->config[ERROR_LOG_FILE], "a+", &fi) - == 0) { - fi.fp = NULL; - } - } else fi.fp = NULL; + if ( conn->ctx->callbacks.log_message == NULL || conn->ctx->callbacks.log_message( conn, buf ) == 0 ) { - if (fi.fp != NULL) { - flockfile(fi.fp); - timestamp = time(NULL); + if ( conn->ctx->config[ERROR_LOG_FILE] != NULL ) { - XX_httplib_sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa); - fprintf(fi.fp, - "[%010lu] [error] [client %s] ", - (unsigned long)timestamp, - src_addr); + if ( XX_httplib_fopen( conn, conn->ctx->config[ERROR_LOG_FILE], "a+", &fi ) == 0 ) fi.fp = NULL; + } + + else fi.fp = NULL; - if (conn->request_info.request_method != NULL) { - fprintf(fi.fp, - "%s %s: ", - conn->request_info.request_method, - conn->request_info.request_uri); + if ( fi.fp != NULL ) { + + flockfile( fi.fp ); + timestamp = time( NULL ); + + XX_httplib_sockaddr_to_string( src_addr, sizeof(src_addr), &conn->client.rsa ); + fprintf( fi.fp, "[%010lu] [error] [client %s] ", (unsigned long)timestamp, src_addr ); + + if ( conn->request_info.request_method != NULL ) { + + fprintf( fi.fp, "%s %s: ", conn->request_info.request_method, conn->request_info.request_uri ); } - fprintf(fi.fp, "%s", buf); - fputc('\n', fi.fp); - fflush(fi.fp); - funlockfile(fi.fp); - XX_httplib_fclose(&fi); + fprintf( fi.fp, "%s", buf ); + fputc( '\n', fi.fp ); + fflush( fi.fp ); + funlockfile( fi.fp ); + XX_httplib_fclose( &fi ); } } diff --git a/src/httplib_delete_file.c b/src/httplib_delete_file.c index 3673a5be..68ac2440 100644 --- a/src/httplib_delete_file.c +++ b/src/httplib_delete_file.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -40,46 +40,70 @@ void XX_httplib_delete_file( struct httplib_connection *conn, const char *path ) struct de de; - memset(&de.file, 0, sizeof(de.file)); - if (!XX_httplib_stat(conn, path, &de.file)) { - /* XX_httplib_stat returns 0 if the file does not exist */ - XX_httplib_send_http_error(conn, 404, "Error: Cannot delete file\nFile %s not found", path); + memset( &de.file, 0, sizeof(de.file) ); + + if ( ! XX_httplib_stat( conn, path, &de.file ) ) { + + /* + * XX_httplib_stat returns 0 if the file does not exist + */ + + XX_httplib_send_http_error( conn, 404, "Error: Cannot delete file\nFile %s not found", path ); return; } - if (de.file.membuf != NULL) { - /* the file is cached in memory */ - XX_httplib_send_http_error( conn, 405, "Error: Delete not possible\nDeleting %s is not supported", path); + if ( de.file.membuf != NULL ) { + + /* + * the file is cached in memory + */ + + XX_httplib_send_http_error( conn, 405, "Error: Delete not possible\nDeleting %s is not supported", path ); return; } - if (de.file.is_directory) { - if (XX_httplib_remove_directory(conn, path)) { - /* Delete is successful: Return 204 without content. */ - XX_httplib_send_http_error(conn, 204, "%s", ""); - } else { - /* Delete is not successful: Return 500 (Server error). */ - XX_httplib_send_http_error(conn, 500, "Error: Could not delete %s", path); + if ( de.file.is_directory ) { + + if ( XX_httplib_remove_directory( conn, path ) ) { + + /* + * Delete is successful: Return 204 without content. + */ + + XX_httplib_send_http_error( conn, 204, "%s", "" ); + } + + else { + /* + * Delete is not successful: Return 500 (Server error). + */ + + XX_httplib_send_http_error( conn, 500, "Error: Could not delete %s", path ); } return; } - /* This is an existing file (not a directory). - * Check if write permission is granted. */ - if (access(path, W_OK) != 0) { - /* File is read only */ - XX_httplib_send_http_error( conn, 403, "Error: Delete not possible\nDeleting %s is not allowed", path); + /* + * This is an existing file (not a directory). + * Check if write permission is granted. + */ + + if ( access( path, W_OK ) != 0 ) { + + /* + * File is read only + */ + + XX_httplib_send_http_error( conn, 403, "Error: Delete not possible\nDeleting %s is not allowed", path ); return; } - /* Try to delete it. */ - if (httplib_remove( path ) == 0) { - /* Delete was successful: Return 204 without content. */ - XX_httplib_send_http_error(conn, 204, "%s", ""); - } else { - /* Delete not successful (file locked). */ - XX_httplib_send_http_error(conn, 423, "Error: Cannot delete file\nremove(%s): %s", path, strerror(ERRNO)); - } + /* + * Try to delete it + */ + + if ( httplib_remove( path ) == 0 ) XX_httplib_send_http_error( conn, 204, "%s", "" ); + else XX_httplib_send_http_error( conn, 423, "Error: Cannot delete file\nremove(%s): %s", path, strerror(ERRNO) ); } /* XX_httplib_delete_file */ diff --git a/src/httplib_difftimespec.c b/src/httplib_difftimespec.c index 855b86d7..22334e88 100644 --- a/src/httplib_difftimespec.c +++ b/src/httplib_difftimespec.c @@ -22,16 +22,22 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" #include "httplib_utils.h" -/* difftime for struct timespec. Return value is in seconds. */ -double XX_httplib_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before) { +/* + * double XX_httplib_difftimespec( const struct timespec_ts_now, const struct timespec *ts_before ); + * + * The function XX_httplib_difftimespec() returns the time difference in + * seconds between two times specified with a timespec structure. + */ - return (double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9 - + (double)(ts_now->tv_sec - ts_before->tv_sec); +double XX_httplib_difftimespec( const struct timespec *ts_now, const struct timespec *ts_before ) { + + return ((double)(ts_now->tv_nsec - ts_before->tv_nsec)) * 1.0E-9 + + ((double)(ts_now->tv_sec - ts_before->tv_sec )); } /* XX_httplib_difftimespec */ diff --git a/src/httplib_discard_unread_request_data.c b/src/httplib_discard_unread_request_data.c index 51c906ac..d975bed1 100644 --- a/src/httplib_discard_unread_request_data.c +++ b/src/httplib_discard_unread_request_data.c @@ -22,40 +22,57 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" +/* + * void XX_httplib_discard_unread_request_data( struct httplib_connection *conn ); + * + * The function XX_httplib_discard_unread_request_data() discards any request + * data on a connection which is not further needed but has alread been + * received. + */ + void XX_httplib_discard_unread_request_data( struct httplib_connection *conn ) { char buf[MG_BUF_LEN]; size_t to_read; int nread; - if (conn == NULL) { - return; - } + if ( conn == NULL ) return; to_read = sizeof(buf); - if (conn->is_chunked) { - /* Chunked encoding: 1=chunk not read completely, 2=chunk read - * completely */ - while (conn->is_chunked == 1) { - nread = httplib_read(conn, buf, to_read); - if (nread <= 0) break; + if ( conn->is_chunked ) { + + /* + * Chunked encoding: 1=chunk not read completely, 2=chunk read + * completely + */ + + while ( conn->is_chunked == 1 ) { + + nread = httplib_read( conn, buf, to_read ); + if ( nread <= 0 ) break; } - } else { - /* Not chunked: content length is known */ - while (conn->consumed_content < conn->content_len) { - if (to_read - > (size_t)(conn->content_len - conn->consumed_content)) { + } + + else { + /* + * Not chunked: content length is known + */ + + while ( conn->consumed_content < conn->content_len ) { + + if ( to_read > (size_t)(conn->content_len - conn->consumed_content) ) { + to_read = (size_t)(conn->content_len - conn->consumed_content); } - nread = httplib_read(conn, buf, to_read); + nread = httplib_read( conn, buf, to_read ); if (nread <= 0) break; } } diff --git a/src/httplib_download.c b/src/httplib_download.c index 4e089086..34106281 100644 --- a/src/httplib_download.c +++ b/src/httplib_download.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -42,32 +42,41 @@ struct httplib_connection * httplib_download( const char *host, int port, int us int i; int reqerr; - va_start(ap, fmt); + va_start( ap, fmt ); ebuf[0] = '\0'; - /* open a connection */ - conn = httplib_connect_client(host, port, use_ssl, ebuf, ebuf_len); + conn = httplib_connect_client( host, port, use_ssl, ebuf, ebuf_len ); - 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"); - } else { + 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" ); + + else { XX_httplib_getreq(conn, ebuf, ebuf_len, &reqerr); - /* TODO: 1) uri is deprecated; - * 2) here, ri.uri is the http response code */ + /* + * TODO: 1) uri is deprecated; + * 2) here, ri.uri is the http response code + */ + conn->request_info.uri = conn->request_info.request_uri; } } - /* if an error occured, close the connection */ - if (ebuf[0] != '\0' && conn != NULL) { - httplib_close_connection(conn); + /* + * if an error occured, close the connection + */ + + if ( ebuf[0] != '\0' && conn != NULL ) { + + httplib_close_connection( conn ); conn = NULL; } - va_end(ap); + va_end( ap ); + return conn; } /* httplib_download */ diff --git a/src/httplib_event_queue.c b/src/httplib_event_queue.c index ad639c33..7142da17 100644 --- a/src/httplib_event_queue.c +++ b/src/httplib_event_queue.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -37,42 +37,49 @@ #if defined(ALTERNATIVE_QUEUE) -void * event_create(void) { +void *event_create( void ) { - int ret = eventfd(0, EFD_CLOEXEC); - if (ret == -1) { - /* Linux uses -1 on error, Windows NULL. */ - /* However, Linux does not return 0 on success either. */ - return 0; + int ret; + + ret = eventfd( 0, EFD_CLOEXEC ); + + if ( ret == -1 ) { + + /* + * Linux uses -1 on error, Windows NULL. + * However, Linux does not return 0 on success either. + */ + + return NULL; } return (void *)ret; } /* event_create */ -int event_wait(void *eventhdl) { +int event_wait( void *eventhdl ) { uint64_t u; - int s = (int)read((int)eventhdl, &u, sizeof(u)); - if (s != sizeof(uint64_t)) { - /* error */ - return 0; - } - (void)u; /* the value is not required */ + int s; + + s = (int)read( (int)eventhdl, &u, sizeof(u) ); + if ( s != sizeof(uint64_t) ) return 0; + return 1; } /* event_wait */ -int event_signal(void *eventhdl) { +int event_signal( void *eventhdl ) { - uint64_t u = 1; - int s = (int)write((int)eventhdl, &u, sizeof(u)); + uint64_t u; + int s; + + u = 1; + s = (int)write( (int)eventhdl, &u, sizeof(u) ); + + if ( s != sizeof(uint64_t) ) return 0; - if (s != sizeof(uint64_t)) { - /* error */ - return 0; - } return 1; } /* event_signal */ @@ -80,7 +87,7 @@ int event_signal(void *eventhdl) { void event_destroy( void *eventhdl ) { - close((int)eventhdl); + close( (int)eventhdl ); } /* event_destroy */ @@ -92,6 +99,7 @@ void event_destroy( void *eventhdl ) { #if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE) struct posix_event { + pthread_mutex_t mutex; pthread_cond_t cond; }; @@ -99,20 +107,31 @@ struct posix_event { void *event_create(void) { - struct posix_event *ret = XX_httplib_malloc(sizeof(struct posix_event)); + struct posix_event *ret; + + ret = XX_httplib_malloc( sizeof(struct posix_event) ); if ( ret == NULL ) return NULL; - if (0 != httplib_pthread_mutex_init( & ret->mutex, NULL ) ) { - /* pthread mutex not available */ - XX_httplib_free(ret); + if ( httplib_pthread_mutex_init( & ret->mutex, NULL ) != 0 ) { + + /* + * pthread mutex not available + */ + + XX_httplib_free( ret ); return NULL; } - if (0 != httplib_pthread_cond_init( & ret->cond, NULL)) { - /* pthread cond not available */ + if ( httplib_pthread_cond_init( & ret->cond, NULL ) != 0 ) { + + /* + * pthread cond not available + */ + httplib_pthread_mutex_destroy( & ret->mutex ); - XX_httplib_free(ret); + XX_httplib_free( ret ); return NULL; } + return ret; } /* event_create */ @@ -167,16 +186,18 @@ void event_destroy( void *eventhdl ) { #if defined(_WIN32) && defined(ALTERNATIVE_QUEUE) -void *event_create(void) { +void *event_create( void ) { return (void *) CreateEvent( NULL, FALSE, FALSE, NULL ); } /* event_create */ -int event_wait(void *eventhdl) { +int event_wait( void *eventhdl ) { - int res = WaitForSingleObject( (HANDLE) eventhdl, INFINITE ); + int res; + + res = WaitForSingleObject( (HANDLE) eventhdl, INFINITE ); return ( res == WAIT_OBJECT_0 ); } /* event_wait */ diff --git a/src/httplib_fc.c b/src/httplib_fc.c index 2e21f9d6..d92f8395 100644 --- a/src/httplib_fc.c +++ b/src/httplib_fc.c @@ -22,18 +22,23 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" -/* Return fake connection structure. Used for logging, if connection - * is not applicable at the moment of logging. */ +/* + * struct httplib_connection *XX_httplib_fc( struct httplib_context *ctx ); + * + * TThe function XX_httplib_fc() returns a fake connection structure specific + * for logging if a connection is not applicable at the moment of logging. + */ + struct httplib_connection *XX_httplib_fc( struct httplib_context *ctx ) { static struct httplib_connection fake_connection; fake_connection.ctx = ctx; - return &fake_connection; + return & fake_connection; } /* XX_httplib_fc */ diff --git a/src/httplib_fclose_on_exec.c b/src/httplib_fclose_on_exec.c index e06201d1..7aaf4fc0 100644 --- a/src/httplib_fclose_on_exec.c +++ b/src/httplib_fclose_on_exec.c @@ -22,21 +22,22 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" void XX_httplib_fclose_on_exec( struct file *filep, struct httplib_connection *conn ) { - if (filep != NULL && filep->fp != NULL) { + if ( filep == NULL || filep->fp == NULL ) return; + #ifdef _WIN32 - (void)conn; /* Unused. */ + UNUSED_PARAMETER(conn); #else - if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) { - httplib_cry(conn, "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s", __func__, strerror(ERRNO)); - } -#endif + if ( fcntl( fileno( filep->fp ), F_SETFD, FD_CLOEXEC) != 0 ) { + + httplib_cry( conn, "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s", __func__, strerror(ERRNO) ); } +#endif } /* XX_httplib_fclose_on_exec */ diff --git a/src/httplib_fgets.c b/src/httplib_fgets.c index f8bf9edd..85832f20 100644 --- a/src/httplib_fgets.c +++ b/src/httplib_fgets.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -35,22 +35,29 @@ const char *XX_httplib_fgets( char *buf, size_t size, struct file *filep, char * if ( filep == NULL ) return NULL; - if (filep->membuf != NULL && *p != NULL) { + if ( filep->membuf != NULL && *p != NULL ) { + memend = (const char *)&filep->membuf[filep->size]; - /* Search for \n from p till the end of stream */ + + /* + * Search for \n from p till the end of stream + */ + eof = (char *)memchr(*p, '\n', (size_t)(memend - *p)); - if (eof != NULL) { - eof += 1; /* Include \n */ - } else { - eof = memend; /* Copy remaining data */ - } + + if ( eof != NULL ) eof += 1; /* Include \n */ + else eof = memend; /* Copy remaining data */ + len = ((size_t)(eof - *p) > (size - 1)) ? (size - 1) : (size_t)(eof - *p); - memcpy(buf, *p, len); + memcpy( buf, *p, len ); buf[len] = '\0'; - *p += len; - return len ? eof : NULL; - } else if (filep->fp != NULL) { - return fgets(buf, (int)size, filep->fp); - } else return NULL; + *p += len; + + return (len) ? eof : NULL; + } + + if ( filep->fp != NULL ) return fgets( buf, (int)size, filep->fp ); + + return NULL; } /* XX_httplib_fgets */ diff --git a/src/httplib_free_context.c b/src/httplib_free_context.c index 9056b8a2..bfac57fc 100644 --- a/src/httplib_free_context.c +++ b/src/httplib_free_context.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -47,30 +47,37 @@ void XX_httplib_free_context( struct httplib_context *ctx ) { if ( ctx->callbacks.exit_context ) ctx->callbacks.exit_context( ctx ); - /* All threads exited, no sync is needed. Destroy thread mutex and + /* + * All threads exited, no sync is needed. Destroy thread mutex and * condvars */ + httplib_pthread_mutex_destroy( & ctx->thread_mutex ); #if defined(ALTERNATIVE_QUEUE) - XX_httplib_free(ctx->client_socks); - for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) { - event_destroy(ctx->client_wait_events[i]); - } - XX_httplib_free(ctx->client_wait_events); + XX_httplib_free( ctx->client_socks ); + for (i=0; (unsigned)i < ctx->cfg_worker_threads; i++) event_destroy( ctx->client_wait_events[i] ); + XX_httplib_free( ctx->client_wait_events ); #else httplib_pthread_cond_destroy( & ctx->sq_empty ); httplib_pthread_cond_destroy( & ctx->sq_full ); #endif - /* Destroy other context global data structures mutex */ + /* + * Destroy other context global data structures mutex + */ + httplib_pthread_mutex_destroy( & ctx->nonce_mutex ); #if defined(USE_TIMERS) timers_exit( ctx ); #endif - /* Deallocate config parameters */ + /* + * Deallocate config parameters + */ + for (i = 0; i < NUM_OPTIONS; i++) { + if (ctx->config[i] != NULL) { #if defined(_MSC_VER) #pragma warning(suppress : 6001) @@ -79,38 +86,60 @@ void XX_httplib_free_context( struct httplib_context *ctx ) { } } - /* Deallocate request handlers */ - while (ctx->handlers) { - tmp_rh = ctx->handlers; + /* + * Deallocate request handlers + */ + + while ( ctx->handlers ) { + + tmp_rh = ctx->handlers; ctx->handlers = tmp_rh->next; + httplib_free( tmp_rh->uri ); httplib_free( tmp_rh ); } #ifndef NO_SSL - /* Deallocate SSL context */ - if (ctx->ssl_ctx != NULL) SSL_CTX_free(ctx->ssl_ctx); + + /* + * Deallocate SSL context + */ + + if ( ctx->ssl_ctx != NULL ) SSL_CTX_free( ctx->ssl_ctx ); + #endif /* !NO_SSL */ - /* Deallocate worker thread ID array */ - if (ctx->workerthreadids != NULL) httplib_free( ctx->workerthreadids ); + /* + * Deallocate worker thread ID array + */ - /* Deallocate the tls variable */ - if (httplib_atomic_dec(&XX_httplib_sTlsInit) == 0) { + if ( ctx->workerthreadids != NULL ) httplib_free( ctx->workerthreadids ); + + /* + * Deallocate the tls variable + */ + + if ( httplib_atomic_dec(&XX_httplib_sTlsInit) == 0 ) { #if defined(_WIN32) - DeleteCriticalSection(&global_log_file_lock); + DeleteCriticalSection( & global_log_file_lock ); #endif /* _WIN32 */ #if !defined(_WIN32) - pthread_mutexattr_destroy(&XX_httplib_pthread_mutex_attr); + pthread_mutexattr_destroy( & XX_httplib_pthread_mutex_attr ); #endif httplib_pthread_key_delete( XX_httplib_sTlsKey ); } - /* deallocate system name string */ + /* + * deallocate system name string + */ + httplib_free( ctx->systemName ); - /* Deallocate context itself */ + /* + * Deallocate context itself + */ + httplib_free( ctx ); } /* XX_httplib_free_context */ diff --git a/src/httplib_get_cookie.c b/src/httplib_get_cookie.c index 677d6a81..d0e8bb9e 100644 --- a/src/httplib_get_cookie.c +++ b/src/httplib_get_cookie.c @@ -22,42 +22,49 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 1.9 */ #include "httplib_main.h" #include "httplib_string.h" /* HCP24: some changes to compare hole var_name */ -int httplib_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size) { +int httplib_get_cookie( const char *cookie_header, const char *var_name, char *dst, size_t dst_size ) { const char *s; const char *p; const char *end; int name_len; - int len = -1; + int len; - if (dst == NULL || dst_size == 0) return -2; + if ( dst == NULL || dst_size < 1 ) return -2; + len = -1; dst[0] = '\0'; - if (var_name == NULL || (s = cookie_header) == NULL) return -1; + if ( var_name == NULL || cookie_header == NULL ) return -1; + + s = cookie_header; + + name_len = (int)strlen( var_name ); + end = s + strlen( s ); - name_len = (int)strlen(var_name); - end = s + strlen(s); for (; (s = httplib_strcasestr( s, var_name )) != NULL; s += name_len) { if (s[name_len] == '=') { - /* HCP24: now check is it a substring or a full cookie name */ + + /* + * HCP24: now check is it a substring or a full cookie name + */ + if ((s == cookie_header) || (s[-1] == ' ')) { s += name_len + 1; - if ((p = strchr(s, ' ')) == NULL) { - p = end; - } - if (p[-1] == ';') p--; - if (*s == '"' && p[-1] == '"' && p > s + 1) { + if ( (p = strchr(s, ' ')) == NULL ) p = end; + if ( p[-1] == ';' ) p--; + if ( *s == '"' && p[-1] == '"' && p > s + 1 ) { s++; p--; } if ((size_t)(p - s) < dst_size) { + len = (int)(p - s); httplib_strlcpy( dst, s, (size_t)len+1 ); } else len = -3; @@ -65,6 +72,7 @@ int httplib_get_cookie(const char *cookie_header, const char *var_name, char *ds } } } + return len; } /* httplib_get_cookie */ diff --git a/src/httplib_get_first_ssl_listener_index.c b/src/httplib_get_first_ssl_listener_index.c index 3b014eab..7b74cb74 100644 --- a/src/httplib_get_first_ssl_listener_index.c +++ b/src/httplib_get_first_ssl_listener_index.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -42,7 +42,7 @@ int XX_httplib_get_first_ssl_listener_index( const struct httplib_context *ctx ) idx = -1; - if ( ctx != NULL ) for (i = 0; idx == -1 && i < ctx->num_listening_sockets; i++) idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1; + if ( ctx != NULL ) for (i=0; idx == -1 && i < ctx->num_listening_sockets; i++) idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1; return idx; diff --git a/src/httplib_get_header.c b/src/httplib_get_header.c index 21c74fe5..5d19b474 100644 --- a/src/httplib_get_header.c +++ b/src/httplib_get_header.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -31,10 +31,12 @@ const char *XX_httplib_get_header( const struct httplib_request_info *ri, const char *name ) { int i; - if (ri) { - for (i = 0; i < ri->num_headers; i++) { - if (!httplib_strcasecmp(name, ri->http_headers[i].name)) return ri->http_headers[i].value; - } + + if ( ri == NULL || name == NULL ) return NULL; + + for (i=0; inum_headers; i++) { + + if ( ! httplib_strcasecmp( name, ri->http_headers[i].name ) ) return ri->http_headers[i].value; } return NULL; diff --git a/src/httplib_get_mime_type.c b/src/httplib_get_mime_type.c index 10f2bbb1..5b91695e 100644 --- a/src/httplib_get_mime_type.c +++ b/src/httplib_get_mime_type.c @@ -22,13 +22,14 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" /* Look at the "path" extension and figure what mime type it has. * Store mime type in the vector. */ + void XX_httplib_get_mime_type( struct httplib_context *ctx, const char *path, struct vec *vec ) { struct vec ext_vec; @@ -37,17 +38,27 @@ void XX_httplib_get_mime_type( struct httplib_context *ctx, const char *path, st const char *ext; size_t path_len; - path_len = strlen(path); + if ( ctx == NULL || path == NULL || vec == NULL ) return; - if (ctx == NULL || vec == NULL) return; + path_len = strlen( path ); + + /* + * Scan user-defined mime types first, in case user wants to + * override default mime types. + */ - /* Scan user-defined mime types first, in case user wants to - * override default mime types. */ list = ctx->config[EXTRA_MIME_TYPES]; - while ((list = XX_httplib_next_option(list, &ext_vec, &mime_vec)) != NULL) { - /* ext now points to the path suffix */ + + while ( (list = XX_httplib_next_option( list, &ext_vec, &mime_vec )) != NULL ) { + + /* + * ext now points to the path suffix + */ + ext = path + path_len - ext_vec.len; - if (httplib_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) { + + if ( httplib_strncasecmp( ext, ext_vec.ptr, ext_vec.len ) == 0 ) { + *vec = mime_vec; return; } diff --git a/src/httplib_get_option_index.c b/src/httplib_get_option_index.c index dcbb3812..19019a53 100644 --- a/src/httplib_get_option_index.c +++ b/src/httplib_get_option_index.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -31,9 +31,13 @@ int XX_httplib_get_option_index( const char *name ) { int i; - for (i = 0; XX_httplib_config_options[i].name != NULL; i++) { - if (strcmp(XX_httplib_config_options[i].name, name) == 0) return i; + if ( name == NULL ) return -1; + + for (i=0; XX_httplib_config_options[i].name != NULL; i++) { + + if ( strcmp( XX_httplib_config_options[i].name, name ) == 0 ) return i; } + return -1; } /* XX_httplib_get_option_index */ diff --git a/src/httplib_get_random.c b/src/httplib_get_random.c index 2923745b..3a8d9fa2 100644 --- a/src/httplib_get_random.c +++ b/src/httplib_get_random.c @@ -22,40 +22,55 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" #include "httplib_utils.h" -/* Get a random number (independent of C rand function) */ +/* + * uint64_t XX_httplib_get_random( void ); + * + * The function XX_httplib_get_random() is a pseudo random generator which + * combines two high resolution random generators and the nano second part + * of the time to generate 64 bit random numbers. + */ + uint64_t XX_httplib_get_random( void ) { - static uint64_t lfsr = 0; /* Linear feedback shift register */ - static uint64_t lcg = 0; /* Linear congruential generator */ + static uint64_t lfsr = 0; /* Linear feedback shift register */ + static uint64_t lcg = 0; /* Linear congruential generator */ struct timespec now; - memset(&now, 0, sizeof(now)); - clock_gettime(CLOCK_MONOTONIC, &now); + memset( & now, 0, sizeof(now) ); + clock_gettime( CLOCK_MONOTONIC, &now ); - if (lfsr == 0) { - /* lfsr will be only 0 if has not been initialized, - * so this code is called only once. */ - lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec) - ^ ((uint64_t)(ptrdiff_t)&now) ^ (((uint64_t)time(NULL)) << 33); - lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec - + (uint64_t)(ptrdiff_t)&now; - } else { - /* Get the next step of both random number generators. */ - lfsr = (lfsr >> 1) - | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1) - << 63); - lcg = lcg * 6364136223846793005 + 1442695040888963407; + if ( lfsr == 0 ) { + + /* + * lfsr will be only 0 if has not been initialized, + * so this code is called only once. + */ + + lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec) ^ ((uint64_t)(ptrdiff_t)&now) ^ (((uint64_t)time(NULL)) << 33); + lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec + (uint64_t)(ptrdiff_t)&now; + } + + else { + /* + * Get the next step of both random number generators. + */ + + lfsr = (lfsr >> 1) | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1) << 63); + lcg = lcg * 6364136223846793005 + 1442695040888963407; } - /* Combining two pseudo-random number generators and a high resolution part + /* + * Combining two pseudo-random number generators and a high resolution part * of the current server time will make it hard (impossible?) to guess the - * next number. */ + * next number. + */ + return (lfsr ^ lcg ^ (uint64_t)now.tv_nsec); } /* XX_httplib_get_random */ diff --git a/src/httplib_get_rel_url_at_current_server.c b/src/httplib_get_rel_url_at_current_server.c index 6067e9c9..7e6b9e48 100644 --- a/src/httplib_get_rel_url_at_current_server.c +++ b/src/httplib_get_rel_url_at_current_server.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -38,74 +38,86 @@ const char * XX_httplib_get_rel_url_at_current_server( const char *uri, const st const char *server_domain; size_t server_domain_len; - size_t request_domain_len = 0; - unsigned long port = 0; + size_t request_domain_len; + unsigned long port; int i; - const char *hostbegin = NULL; - const char *hostend = NULL; + const char *hostbegin; + const char *hostend; const char *portbegin; char *portend; - /* DNS is case insensitive, so use case insensitive string compare here - */ - server_domain = conn->ctx->config[AUTHENTICATION_DOMAIN]; - if (!server_domain) { - return 0; - } - server_domain_len = strlen(server_domain); - if (!server_domain_len) { - return 0; - } + request_domain_len = 0; + port = 0; + hostbegin = NULL; + hostend = NULL; - for (i = 0; XX_httplib_abs_uri_protocols[i].proto != NULL; i++) { - if (httplib_strncasecmp(uri, - XX_httplib_abs_uri_protocols[i].proto, - XX_httplib_abs_uri_protocols[i].proto_len) == 0) { + /* + * DNS is case insensitive, so use case insensitive string compare here + */ + + server_domain = conn->ctx->config[AUTHENTICATION_DOMAIN]; + if ( server_domain == NULL ) return 0; + + server_domain_len = strlen( server_domain ); + if ( server_domain_len == 0 ) return 0; + + for (i=0; XX_httplib_abs_uri_protocols[i].proto != NULL; i++) { + + if ( httplib_strncasecmp( uri, XX_httplib_abs_uri_protocols[i].proto, XX_httplib_abs_uri_protocols[i].proto_len ) == 0 ) { hostbegin = uri + XX_httplib_abs_uri_protocols[i].proto_len; - hostend = strchr(hostbegin, '/'); - if (!hostend) { - return 0; - } - portbegin = strchr(hostbegin, ':'); - if ((!portbegin) || (portbegin > hostend)) { + hostend = strchr( hostbegin, '/' ); + + if ( hostend == NULL ) return 0; + + portbegin = strchr( hostbegin, ':' ); + + if ( ! portbegin || portbegin > hostend ) { + port = XX_httplib_abs_uri_protocols[i].default_port; request_domain_len = (size_t)(hostend - hostbegin); - } else { - port = strtoul(portbegin + 1, &portend, 10); - if ((portend != hostend) || !port || !XX_httplib_is_valid_port(port)) { - return 0; - } + } + + else { + port = strtoul( portbegin + 1, &portend, 10 ); + if ( portend != hostend || ! port || ! XX_httplib_is_valid_port( port ) ) return 0; request_domain_len = (size_t)(portbegin - hostbegin); } - /* protocol found, port set */ + + /* + * protocol found, port set + */ + break; } } - if (!port) { - /* port remains 0 if the protocol is not found */ + if ( port == 0 ) { + /* + * port remains 0 if the protocol is not found + */ + return 0; } #if defined(USE_IPV6) - if (conn->client.lsa.sa.sa_family == AF_INET6) { - if (ntohs(conn->client.lsa.sin6.sin6_port) != port) { - /* Request is directed to a different port */ - return 0; - } - } else + if ( conn->client.lsa.sa.sa_family == AF_INET6 ) { + + if ( ntohs( conn->client.lsa.sin6.sin6_port ) != port ) return 0; + } + + else #endif { - if (ntohs(conn->client.lsa.sin.sin_port) != port) { - /* Request is directed to a different port */ - return 0; - } + if ( ntohs( conn->client.lsa.sin.sin_port ) != port ) return 0; } - if ((request_domain_len != server_domain_len) - || (0 != memcmp(server_domain, hostbegin, server_domain_len))) { - /* Request is directed to another server */ + if ( request_domain_len != server_domain_len || ( memcmp( server_domain, hostbegin, server_domain_len ) != 0 ) ) { + + /* + * Request is directed to another server + */ + return 0; } diff --git a/src/httplib_get_remote_ip.c b/src/httplib_get_remote_ip.c index d3f1cc17..86874cb9 100644 --- a/src/httplib_get_remote_ip.c +++ b/src/httplib_get_remote_ip.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -38,6 +38,6 @@ uint32_t XX_httplib_get_remote_ip( const struct httplib_connection *conn ) { if ( conn == NULL ) return 0; - return ntohl(*(const uint32_t *)&conn->client.rsa.sin.sin_addr); + return ntohl( *(const uint32_t *)&conn->client.rsa.sin.sin_addr ); } /* XX_httplib_get_remote_ip */ diff --git a/src/httplib_get_request_handler.c b/src/httplib_get_request_handler.c index ccd78679..80dc159e 100644 --- a/src/httplib_get_request_handler.c +++ b/src/httplib_get_request_handler.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -31,90 +31,114 @@ * int XX_httplib_get_request_handler(); * * The function XX_httplib_get_request_handler() retrieves the request handlers - * for a connection. + * for a connection. The function returns 1 if request handlers could be found + * and 0 otherwise. */ int XX_httplib_get_request_handler( struct httplib_connection *conn, int handler_type, httplib_request_handler *handler, httplib_websocket_connect_handler *connect_handler, httplib_websocket_ready_handler *ready_handler, httplib_websocket_data_handler *data_handler, httplib_websocket_close_handler *close_handler, httplib_authorization_handler *auth_handler, void **cbdata ) { - const struct httplib_request_info *request_info = httplib_get_request_info(conn); - if ( request_info == NULL ) return 0; - - const char *uri = request_info->local_uri; - size_t urilen = strlen(uri); + const struct httplib_request_info *request_info; + const char *uri; + size_t urilen; struct httplib_handler_info *tmp_rh; if ( conn == NULL || conn->ctx == NULL ) return 0; - httplib_lock_context(conn->ctx); + request_info = httplib_get_request_info( conn ); + if ( request_info == NULL ) return 0; - /* first try for an exact match */ - for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL; - tmp_rh = tmp_rh->next) { - if (tmp_rh->handler_type == handler_type) { - if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri, uri)) { - if (handler_type == WEBSOCKET_HANDLER) { - *connect_handler = tmp_rh->connect_handler; - *ready_handler = tmp_rh->ready_handler; - *data_handler = tmp_rh->data_handler; - *close_handler = tmp_rh->close_handler; - } else if (handler_type == REQUEST_HANDLER) { - *handler = tmp_rh->handler; - } else { /* AUTH_HANDLER */ - *auth_handler = tmp_rh->auth_handler; - } - *cbdata = tmp_rh->cbdata; - httplib_unlock_context(conn->ctx); - return 1; - } - } - } + uri = request_info->local_uri; + urilen = strlen( uri ); - /* next try for a partial match, we will accept uri/something */ - for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL; - tmp_rh = tmp_rh->next) { - if (tmp_rh->handler_type == handler_type) { - if (tmp_rh->uri_len < urilen && uri[tmp_rh->uri_len] == '/' - && memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) { - if (handler_type == WEBSOCKET_HANDLER) { - *connect_handler = tmp_rh->connect_handler; - *ready_handler = tmp_rh->ready_handler; - *data_handler = tmp_rh->data_handler; - *close_handler = tmp_rh->close_handler; - } else if (handler_type == REQUEST_HANDLER) { - *handler = tmp_rh->handler; - } else { /* AUTH_HANDLER */ - *auth_handler = tmp_rh->auth_handler; - } - *cbdata = tmp_rh->cbdata; - httplib_unlock_context(conn->ctx); - return 1; - } - } - } + httplib_lock_context( conn->ctx ); + + /* + * first try for an exact match + */ + + for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) { + + if ( tmp_rh->handler_type == handler_type ) { + + if ( urilen == tmp_rh->uri_len && ! strcmp( tmp_rh->uri, uri ) ) { + + if ( handler_type == WEBSOCKET_HANDLER ) { - /* finally try for pattern match */ - for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL; - tmp_rh = tmp_rh->next) { - if (tmp_rh->handler_type == handler_type) { - if (XX_httplib_match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) { - if (handler_type == WEBSOCKET_HANDLER) { *connect_handler = tmp_rh->connect_handler; *ready_handler = tmp_rh->ready_handler; *data_handler = tmp_rh->data_handler; *close_handler = tmp_rh->close_handler; - } else if (handler_type == REQUEST_HANDLER) { - *handler = tmp_rh->handler; - } else { /* AUTH_HANDLER */ - *auth_handler = tmp_rh->auth_handler; } + else if ( handler_type == REQUEST_HANDLER ) *handler = tmp_rh->handler; + else *auth_handler = tmp_rh->auth_handler; + *cbdata = tmp_rh->cbdata; - httplib_unlock_context(conn->ctx); + httplib_unlock_context( conn->ctx ); + return 1; } } } - httplib_unlock_context(conn->ctx); + /* + * next try for a partial match, we will accept uri/something + */ + + for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) { + + if ( tmp_rh->handler_type == handler_type ) { + + if ( tmp_rh->uri_len < urilen && uri[tmp_rh->uri_len] == '/' && memcmp( tmp_rh->uri, uri, tmp_rh->uri_len ) == 0 ) { + + if ( handler_type == WEBSOCKET_HANDLER ) { + + *connect_handler = tmp_rh->connect_handler; + *ready_handler = tmp_rh->ready_handler; + *data_handler = tmp_rh->data_handler; + *close_handler = tmp_rh->close_handler; + } + + else if ( handler_type == REQUEST_HANDLER ) *handler = tmp_rh->handler; + else *auth_handler = tmp_rh->auth_handler; + + *cbdata = tmp_rh->cbdata; + httplib_unlock_context( conn->ctx ); + + return 1; + } + } + } + + /* + * finally try for pattern match + */ + + for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) { + + if ( tmp_rh->handler_type == handler_type ) { + + if ( XX_httplib_match_prefix( tmp_rh->uri, tmp_rh->uri_len, uri ) > 0 ) { + + if ( handler_type == WEBSOCKET_HANDLER ) { + + *connect_handler = tmp_rh->connect_handler; + *ready_handler = tmp_rh->ready_handler; + *data_handler = tmp_rh->data_handler; + *close_handler = tmp_rh->close_handler; + } + + else if ( handler_type == REQUEST_HANDLER ) *handler = tmp_rh->handler; + else *auth_handler = tmp_rh->auth_handler; + + *cbdata = tmp_rh->cbdata; + httplib_unlock_context( conn->ctx ); + + return 1; + } + } + } + + httplib_unlock_context( conn->ctx ); return 0; /* none found */ diff --git a/src/httplib_get_request_info.c b/src/httplib_get_request_info.c index f0a6394e..e8665d85 100644 --- a/src/httplib_get_request_info.c +++ b/src/httplib_get_request_info.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" diff --git a/src/httplib_get_request_len.c b/src/httplib_get_request_len.c index c8d82700..4c6b5386 100644 --- a/src/httplib_get_request_len.c +++ b/src/httplib_get_request_len.c @@ -22,34 +22,41 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" -/* Check whether full request is buffered. Return: +/* + * Check whether full request is buffered. Return: * -1 if request is malformed * 0 if request is not yet fully buffered - * >0 actual request length, including last \r\n\r\n */ + * >0 actual request length, including last \r\n\r\n + */ + int XX_httplib_get_request_len( const char *buf, int buflen ) { const char *s; const char *e; - int len = 0; + int len; - for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++) - /* Control characters are not allowed but >=128 is. */ - if (!isprint(*(const unsigned char *)s) && *s != '\r' && *s != '\n' - && *(const unsigned char *)s < 128) { - len = -1; - break; /* [i_a] abort scan as soon as one malformed character is - * found; */ - /* don't let subsequent \r\n\r\n win us over anyhow */ - } else if (s[0] == '\n' && s[1] == '\n') { - len = (int)(s - buf) + 2; - } else if (s[0] == '\n' && &s[1] < e && s[1] == '\r' && s[2] == '\n') { - len = (int)(s - buf) + 3; - } + len = 0; + s = buf; + e = s+buflen-1; + + while ( len <= 0 && s < e ) { + + /* + * Control characters are not allowed but >=128 is. + */ + + if ( ! isprint( *(const unsigned char *)s) && *s != '\r' && *s != '\n' && *(const unsigned char *)s < 128 ) return -1; + + if ( s[0] == '\n' && s[1] == '\n') len = (int)(s - buf) + 2; + else if ( s[0] == '\n' && &s[1] < e && s[1] == '\r' && s[2] == '\n') len = (int)(s - buf) + 3; + + s++; + } return len; diff --git a/src/httplib_get_response.c b/src/httplib_get_response.c index 7c6783f9..1b67b394 100644 --- a/src/httplib_get_response.c +++ b/src/httplib_get_response.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -31,37 +31,48 @@ /* * int httplib_get_response( struct httplib_connection *conn, char *ebuf, size_t ebuf_len, int timeout ); * - * The function httplib_get_response tries to get a response from a remote peer. + * The function httplib_get_response() tries to get a response from a remote + * peer. */ int httplib_get_response( struct httplib_connection *conn, char *ebuf, size_t ebuf_len, int timeout ) { - if ( conn == NULL ) return -1; - - /* Implementation of API function for HTTP clients */ - int err, ret; - struct httplib_context *octx = conn->ctx; - struct httplib_context rctx = *(conn->ctx); + int err; + int ret; + struct httplib_context *octx; + struct httplib_context rctx; char txt[32]; /* will not overflow */ - if (timeout >= 0) { - XX_httplib_snprintf(conn, NULL, txt, sizeof(txt), "%i", timeout); + if ( conn == NULL ) return -1; + + octx = conn->ctx; + rctx = *(conn->ctx); + + if ( timeout >= 0 ) { + + XX_httplib_snprintf( conn, NULL, txt, sizeof(txt), "%i", timeout ); rctx.config[REQUEST_TIMEOUT] = txt; - XX_httplib_set_sock_timeout(conn->client.sock, timeout); - } else { - rctx.config[REQUEST_TIMEOUT] = NULL; + XX_httplib_set_sock_timeout( conn->client.sock, timeout ); } + + else rctx.config[REQUEST_TIMEOUT] = NULL; conn->ctx = &rctx; - ret = XX_httplib_getreq(conn, ebuf, ebuf_len, &err); + ret = XX_httplib_getreq( conn, ebuf, ebuf_len, &err ); conn->ctx = octx; - /* TODO: 1) uri is deprecated; - * 2) here, ri.uri is the http response code */ + /* + * TODO: 1) uri is deprecated; + * 2) here, ri.uri is the http response code + */ + conn->request_info.uri = conn->request_info.request_uri; - /* TODO (mid): Define proper return values - maybe return length? - * For the first test use <0 for error and >0 for OK */ + /* + * TODO (mid): Define proper return values - maybe return length? + * For the first test use <0 for error and >0 for OK + */ + return (ret == 0) ? -1 : +1; } /* httplib_get_response */ diff --git a/src/httplib_get_response_code_text.c b/src/httplib_get_response_code_text.c index 391465c6..829d106c 100644 --- a/src/httplib_get_response_code_text.c +++ b/src/httplib_get_response_code_text.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -36,7 +36,8 @@ const char *httplib_get_response_code_text( struct httplib_connection *conn, int response_code ) { - /* See IANA HTTP status code assignment: + /* + * See IANA HTTP status code assignment: * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml */ @@ -113,10 +114,16 @@ const char *httplib_get_response_code_text( struct httplib_connection *conn, int default: - /* This error code is unknown. This should not happen. */ - if ( conn != NULL) httplib_cry( conn, "Unknown HTTP response code: %u", response_code ); + /* + * This error code is unknown. This should not happen. + */ + + if ( conn != NULL ) httplib_cry( conn, "Unknown HTTP response code: %u", response_code ); + + /* + * Return at least a category according to RFC 2616 Section 10. + */ - /* Return at least a category according to RFC 2616 Section 10. */ if (response_code >= 100 && response_code < 200) return "Information"; if (response_code >= 200 && response_code < 300) return "Success"; if (response_code >= 300 && response_code < 400) return "Redirection"; diff --git a/src/httplib_get_server_ports.c b/src/httplib_get_server_ports.c index 606b8e70..14a2c9f8 100644 --- a/src/httplib_get_server_ports.c +++ b/src/httplib_get_server_ports.c @@ -22,20 +22,23 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" -int httplib_get_server_ports(const struct httplib_context *ctx, int size, struct httplib_server_ports *ports) { +int httplib_get_server_ports( const struct httplib_context *ctx, int size, struct httplib_server_ports *ports ) { int i; - int cnt = 0; + int cnt; - if (size <= 0) { return -1; } - memset(ports, 0, sizeof(*ports) * (size_t)size); - if (!ctx) { return -1; } - if (!ctx->listening_sockets) { return -1; } + if ( ctx == NULL || ports == NULL || size <= 0 ) return -1; + + memset( ports, 0, sizeof(*ports) * (size_t)size ); + + if ( ctx->listening_sockets == NULL ) return -1; + + cnt = 0; for (i = 0; (i < size) && (i < (int)ctx->num_listening_sockets); i++) { @@ -46,18 +49,12 @@ int httplib_get_server_ports(const struct httplib_context *ctx, int size, struct : #endif ntohs(ctx->listening_sockets[i].lsa.sin.sin_port); - ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl; + + ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl; ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir; - if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) { - /* IPv4 */ - ports[cnt].protocol = 1; - cnt++; - } else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) { - /* IPv6 */ - ports[cnt].protocol = 3; - cnt++; - } + if ( ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET ) ports[cnt++].protocol = 1; + else if ( ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6 ) ports[cnt++].protocol = 3; } return cnt; diff --git a/src/httplib_get_system_name.c b/src/httplib_get_system_name.c index 4a894eba..d9bb1770 100644 --- a/src/httplib_get_system_name.c +++ b/src/httplib_get_system_name.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 1.9 */ #include "httplib_main.h" @@ -40,9 +40,13 @@ void XX_httplib_get_system_name( char **sysName ) { #if defined(_WIN32) #if defined(_WIN32_WCE) + *sysName = XX_httplib_strdup( "WinCE" ); -#else + +#else /* _WIN32_WCE */ + char name[128]; + DWORD dwVersion = 0; DWORD dwMajorVersion = 0; DWORD dwMinorVersion = 0; @@ -52,25 +56,31 @@ void XX_httplib_get_system_name( char **sysName ) { #pragma warning(push) // GetVersion was declared deprecated #pragma warning(disable : 4996) -#endif +#endif /* _MSC_VER */ + dwVersion = GetVersion(); + #ifdef _MSC_VER #pragma warning(pop) -#endif +#endif /* _MSC_VER */ dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); - dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0); + dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0); (void)dwBuild; - sprintf(name, "Windows %u.%u", (unsigned)dwMajorVersion, (unsigned)dwMinorVersion); - *sysName = XX_httplib_strdup(name); -#endif -#else + sprintf( name, "Windows %u.%u", (unsigned)dwMajorVersion, (unsigned)dwMinorVersion ); + *sysName = XX_httplib_strdup( name ); + +#endif /* _WIN32_WCE */ +#else /* _WIN32 */ + struct utsname name; - memset(&name, 0, sizeof(name)); - uname(&name); - *sysName = XX_httplib_strdup(name.sysname); -#endif + + memset( & name, 0, sizeof(name) ); + uname( & name ); + *sysName = XX_httplib_strdup( name.sysname ); + +#endif /* _WIN32 */ } /* XX_httplib_get_system_name */ diff --git a/src/httplib_get_uri_type.c b/src/httplib_get_uri_type.c index 0ff64a42..1002d47a 100644 --- a/src/httplib_get_uri_type.c +++ b/src/httplib_get_uri_type.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -48,65 +48,74 @@ int XX_httplib_get_uri_type( const char *uri ) { char *portend; unsigned long port; - /* According to the HTTP standard + /* + * According to the HTTP standard * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2 * URI can be an asterisk (*) or should start with slash (relative uri), - * or it should start with the protocol (absolute uri). */ + * or it should start with the protocol (absolute uri). + */ + if (uri[0] == '*' && uri[1] == '\0') return 1; - /* Valid URIs according to RFC 3986 + /* + * Valid URIs according to RFC 3986 * (https://www.ietf.org/rfc/rfc3986.txt) * must only contain reserved characters :/?#[]@!$&'()*+,;= * and unreserved characters A-Z a-z 0-9 and -._~ * and % encoded symbols. */ + for (i = 0; uri[i] != 0; i++) { - if (uri[i] < 33) { - /* control characters and spaces are invalid */ - return 0; - } - if (uri[i] > 126) { - /* non-ascii characters must be % encoded */ - return 0; - } else { - switch (uri[i]) { - case '"': /* 34 */ - case '<': /* 60 */ - case '>': /* 62 */ - case '\\': /* 92 */ - case '^': /* 94 */ - case '`': /* 96 */ + if ( uri[i] < 33 ) return 0; /* control characters and spaces are invalid */ + if ( uri[i] > 126 ) return 0; /* non-ascii characters must be % encoded */ + + switch ( uri[i] ) { + case '"': /* 34 */ + case '<': /* 60 */ + case '>': /* 62 */ + case '\\': /* 92 */ + case '^': /* 94 */ + case '`': /* 96 */ case '{': /* 123 */ case '|': /* 124 */ case '}': /* 125 */ return 0; + default: - /* character is ok */ + /* + * character is ok + */ + break; - } } } - /* A relative uri starts with a / character */ - if (uri[0] == '/') { - /* relative uri */ - return 2; - } + /* + * A relative uri starts with a / character + */ - /* It could be an absolute uri: */ - /* This function only checks if the uri is valid, not if it is + if ( uri[0] == '/' ) return 2; /* relative uri */ + + /* + * It could be an absolute uri: + * This function only checks if the uri is valid, not if it is * addressing the current server. So LibHTTP can also be used - * as a proxy server. */ - for (i = 0; XX_httplib_abs_uri_protocols[i].proto != NULL; i++) { - if (httplib_strncasecmp(uri, XX_httplib_abs_uri_protocols[i].proto, XX_httplib_abs_uri_protocols[i].proto_len) == 0) { + * as a proxy server. + */ - hostend = strchr(uri + XX_httplib_abs_uri_protocols[i].proto_len, '/'); - if (!hostend) return 0; - portbegin = strchr(uri + XX_httplib_abs_uri_protocols[i].proto_len, ':'); - if (!portbegin) return 3; + for (i=0; XX_httplib_abs_uri_protocols[i].proto != NULL; i++) { - port = strtoul(portbegin + 1, &portend, 10); - if ((portend != hostend) || !port || !XX_httplib_is_valid_port(port)) return 0; + if ( httplib_strncasecmp( uri, XX_httplib_abs_uri_protocols[i].proto, XX_httplib_abs_uri_protocols[i].proto_len ) == 0 ) { + + hostend = strchr( uri + XX_httplib_abs_uri_protocols[i].proto_len, '/' ); + if ( hostend == NULL ) return 0; + + portbegin = strchr( uri + XX_httplib_abs_uri_protocols[i].proto_len, ':' ); + if ( portbegin == NULL ) return 3; + + port = strtoul( portbegin+1, &portend, 10 ); + + if ( portend != hostend || ! port || ! XX_httplib_is_valid_port( port ) ) return 0; return 4; } diff --git a/src/httplib_get_user_connection_data.c b/src/httplib_get_user_connection_data.c index ef131e1d..8b250df4 100644 --- a/src/httplib_get_user_connection_data.c +++ b/src/httplib_get_user_connection_data.c @@ -22,15 +22,15 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" -void * httplib_get_user_connection_data(const struct httplib_connection *conn) { +void * httplib_get_user_connection_data( const struct httplib_connection *conn ) { - if (conn != NULL) return conn->request_info.conn_data; + if ( conn == NULL ) return NULL; - return NULL; + return conn->request_info.conn_data; } /* httplib_get_user_connection_data */ diff --git a/src/httplib_get_valid_options.c b/src/httplib_get_valid_options.c index dfd01d83..aff41154 100644 --- a/src/httplib_get_valid_options.c +++ b/src/httplib_get_valid_options.c @@ -22,12 +22,12 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" -const struct httplib_option *httplib_get_valid_options(void) { +const struct httplib_option *httplib_get_valid_options( void ) { return XX_httplib_config_options; diff --git a/src/httplib_get_var.c b/src/httplib_get_var.c index d7c39483..d84c6ca2 100644 --- a/src/httplib_get_var.c +++ b/src/httplib_get_var.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -42,38 +42,59 @@ int httplib_get_var2( const char *data, size_t data_len, const char *name, char size_t name_len; int len; - if (dst == NULL || dst_len == 0) { - len = -2; - } else if (data == NULL || name == NULL || data_len == 0) { - len = -1; - dst[0] = '\0'; - } else { - name_len = strlen(name); - e = data + data_len; - len = -1; + if ( dst == NULL || dst_len < 1 ) return -2; + + if ( data == NULL || name == NULL || data_len == 0 ) { + dst[0] = '\0'; + return -1; + } + + name_len = strlen( name ); + e = data + data_len; + len = -1; + dst[0] = '\0'; - /* data is "var1=val1&var2=val2...". Find variable first */ - for (p = data; p + name_len < e; p++) { - if ((p == data || p[-1] == '&') && p[name_len] == '=' - && !httplib_strncasecmp(name, p, name_len) && 0 == occurrence--) { - /* Point p to variable value */ - p += name_len + 1; + /* + * data is "var1=val1&var2=val2...". Find variable first + */ - /* Point s to the end of the value */ - s = (const char *)memchr(p, '&', (size_t)(e - p)); - if (s == NULL) s = e; - /* assert(s >= p); */ - if (s < p) return -3; + for (p=data; p+name_len < e; p++) { - /* Decode variable into destination buffer */ - len = httplib_url_decode(p, (int)(s - p), dst, (int)dst_len, 1); + if ( (p == data || p[-1] == '&') && p[name_len] == '=' && ! httplib_strncasecmp( name, p, name_len ) && occurrence-- == 0 ) { - /* Redirect error code from -1 to -2 (destination buffer too - * small). */ - if (len == -1) len = -2; - break; - } + /* + * Point p to variable value + */ + + p += name_len + 1; + + /* + * Point s to the end of the value + */ + + s = (const char *)memchr( p, '&', (size_t)(e - p) ); + if (s == NULL) s = e; + + /* + * assert(s >= p); + */ + + if (s < p) return -3; + + /* + * Decode variable into destination buffer + */ + + len = httplib_url_decode( p, (int)(s - p), dst, (int)dst_len, 1 ); + + /* + * Redirect error code from -1 to -2 (destination buffer too + * small). + */ + + if (len == -1) len = -2; + break; } } diff --git a/src/httplib_getreq.c b/src/httplib_getreq.c index c7af7f70..3b2d6c3a 100644 --- a/src/httplib_getreq.c +++ b/src/httplib_getreq.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -38,78 +38,134 @@ int XX_httplib_getreq( struct httplib_connection *conn, char *ebuf, size_t ebuf_ const char *cl; - if (ebuf_len > 0) ebuf[0] = '\0'; - *err = 0; + if ( err == NULL ) return 0; + if ( ebuf == NULL || ebuf_len < 1 ) { *err = 500; return 0; } - XX_httplib_reset_per_request_attributes(conn); + ebuf[0] = '\0'; + *err = 0; - if (!conn) { - XX_httplib_snprintf(conn, NULL, ebuf, ebuf_len, "%s", "Internal error"); + XX_httplib_reset_per_request_attributes( conn ); + + if ( conn == NULL ) { + + XX_httplib_snprintf( conn, NULL, ebuf, ebuf_len, "%s", "Internal error" ); *err = 500; return 0; } - /* Set the time the request was received. This value should be used for - * timeouts. */ - clock_gettime(CLOCK_MONOTONIC, &(conn->req_time)); - conn->request_len = - XX_httplib_read_request(NULL, conn, conn->buf, conn->buf_size, &conn->data_len); - /* assert(conn->request_len < 0 || conn->data_len >= conn->request_len); + /* + * Set the time the request was received. This value should be used for + * timeouts. */ - if (conn->request_len >= 0 && conn->data_len < conn->request_len) { - XX_httplib_snprintf(conn, NULL, ebuf, ebuf_len, "%s", "Invalid request size"); + + clock_gettime( CLOCK_MONOTONIC, &conn->req_time ); + + conn->request_len = XX_httplib_read_request( NULL, conn, conn->buf, conn->buf_size, &conn->data_len ); + + /* + * assert(conn->request_len < 0 || conn->data_len >= conn->request_len); + */ + + if ( conn->request_len >= 0 && conn->data_len < conn->request_len ) { + + XX_httplib_snprintf( conn, NULL, ebuf, ebuf_len, "%s", "Invalid request size" ); *err = 500; return 0; } - if (conn->request_len == 0 && conn->data_len == conn->buf_size) { - XX_httplib_snprintf(conn, NULL, ebuf, ebuf_len, "%s", "Request Too Large"); + if ( conn->request_len == 0 && conn->data_len == conn->buf_size ) { + + XX_httplib_snprintf( conn, NULL, ebuf, ebuf_len, "%s", "Request Too Large" ); *err = 413; return 0; - } else if (conn->request_len <= 0) { - if (conn->data_len > 0) { - XX_httplib_snprintf(conn, NULL, ebuf, ebuf_len, "%s", "Client sent malformed request"); + } + + else if ( conn->request_len <= 0 ) { + + if ( conn->data_len > 0 ) { + + XX_httplib_snprintf( conn, NULL, ebuf, ebuf_len, "%s", "Client sent malformed request" ); *err = 400; - } else { - /* Server did not send anything -> just close the connection */ + } + + else { + /* + * Server did not send anything -> just close the connection + */ + conn->must_close = 1; - XX_httplib_snprintf(conn, NULL, ebuf, ebuf_len, "%s", "Client did not send a request"); + XX_httplib_snprintf( conn, NULL, ebuf, ebuf_len, "%s", "Client did not send a request" ); *err = 0; } return 0; - } else if (XX_httplib_parse_http_message(conn->buf, conn->buf_size, &conn->request_info) <= 0) { - XX_httplib_snprintf(conn, NULL, ebuf, ebuf_len, "%s", "Bad Request"); + } + + else if ( XX_httplib_parse_http_message( conn->buf, conn->buf_size, &conn->request_info ) <= 0 ) { + + XX_httplib_snprintf( conn, NULL, ebuf, ebuf_len, "%s", "Bad Request" ); *err = 400; return 0; - } else { - /* Message is a valid request or response */ - if ((cl = XX_httplib_get_header(&conn->request_info, "Content-Length")) != NULL) { - /* Request/response has content length set */ + } + + else { + /* + * Message is a valid request or response + */ + + if ( (cl = XX_httplib_get_header( &conn->request_info, "Content-Length")) != NULL ) { + + /* + * Request/response has content length set + */ + char *endptr = NULL; - conn->content_len = strtoll(cl, &endptr, 10); - if (endptr == cl) { - XX_httplib_snprintf(conn, NULL, ebuf, ebuf_len, "%s", "Bad Request"); + conn->content_len = strtoll( cl, &endptr, 10 ); + + if ( endptr == cl ) { + + XX_httplib_snprintf( conn, NULL, ebuf, ebuf_len, "%s", "Bad Request" ); *err = 411; return 0; } - /* Publish the content length back to the request info. */ + + /* + * Publish the content length back to the request info. + */ + conn->request_info.content_length = conn->content_len; - } else if ((cl = XX_httplib_get_header(&conn->request_info, "Transfer-Encoding")) - != NULL - && !httplib_strcasecmp(cl, "chunked")) { + } + + else if ( (cl = XX_httplib_get_header( &conn->request_info, "Transfer-Encoding" )) != NULL && ! httplib_strcasecmp( cl, "chunked" ) ) { + conn->is_chunked = 1; - } else if (!httplib_strcasecmp(conn->request_info.request_method, "POST") - || !httplib_strcasecmp(conn->request_info.request_method, "PUT")) { - /* POST or PUT request without content length set */ + } + + else if ( ! httplib_strcasecmp( conn->request_info.request_method, "POST" ) || ! httplib_strcasecmp( conn->request_info.request_method, "PUT" ) ) { + + /* + * POST or PUT request without content length set + */ + conn->content_len = -1; - } else if (!httplib_strncasecmp(conn->request_info.request_method, "HTTP/", 5)) { - /* Response without content length set */ + } + + else if ( ! httplib_strncasecmp( conn->request_info.request_method, "HTTP/", 5 ) ) { + + /* + * Response without content length set + */ + conn->content_len = -1; } else { - /* Other request */ + + /* + * Other request + */ + conn->content_len = 0; } } + return 1; } /* XX_httplib_getreq */ diff --git a/src/httplib_global_data.c b/src/httplib_global_data.c index a987f0a1..de94b7f1 100644 --- a/src/httplib_global_data.c +++ b/src/httplib_global_data.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" diff --git a/src/httplib_gmt_time_string.c b/src/httplib_gmt_time_string.c index 697fdfe5..c02681b6 100644 --- a/src/httplib_gmt_time_string.c +++ b/src/httplib_gmt_time_string.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 1.9 */ #include "httplib_main.h" @@ -35,10 +35,13 @@ void XX_httplib_gmt_time_string( char *buf, size_t buf_len, time_t *t ) { struct tm *tm; - tm = ((t != NULL) ? gmtime(t) : NULL); - if (tm != NULL) { - strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm); - } else { + if ( buf == NULL || buf_len < 1 ) return; + + tm = ( t != NULL ) ? gmtime(t) : NULL; + + if ( tm != NULL ) strftime( buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm ); + + else { httplib_strlcpy( buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len ); buf[buf_len - 1] = '\0'; } diff --git a/src/httplib_handle_cgi_request.c b/src/httplib_handle_cgi_request.c index 0e9a141d..0827e345 100644 --- a/src/httplib_handle_cgi_request.c +++ b/src/httplib_handle_cgi_request.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 1.9 */ #include "httplib_main.h" @@ -63,62 +63,78 @@ void XX_httplib_handle_cgi_request( struct httplib_connection *conn, const char struct file fout = STRUCT_FILE_INITIALIZER; pid_t pid = (pid_t)-1; - if (conn == NULL) return; + if ( conn == NULL ) return; - in = NULL; - out = NULL; - err = NULL; + in = NULL; + out = NULL; + err = NULL; buf = NULL; buflen = 16384; - XX_httplib_prepare_cgi_environment(conn, prog, &blk); - /* CGI must be executed in its own directory. 'dir' must point to the + XX_httplib_prepare_cgi_environment( conn, prog, &blk ); + + /* + * CGI must be executed in its own directory. 'dir' must point to the * directory containing executable program, 'p' must point to the - * executable program name relative to 'dir'. */ - XX_httplib_snprintf(conn, &truncated, dir, sizeof(dir), "%s", prog); + * executable program name relative to 'dir'. + */ + + XX_httplib_snprintf( conn, &truncated, dir, sizeof(dir), "%s", prog ); + + if ( truncated ) { + + httplib_cry( conn, "Error: CGI program \"%s\": Path too long", prog ); + XX_httplib_send_http_error( conn, 500, "Error: %s", "CGI path too long" ); - if (truncated) { - httplib_cry(conn, "Error: CGI program \"%s\": Path too long", prog); - XX_httplib_send_http_error(conn, 500, "Error: %s", "CGI path too long"); goto done; } - if ((p = strrchr(dir, '/')) != NULL) { - *p++ = '\0'; - } else { + if ( (p = strrchr(dir, '/')) != NULL ) *p++ = '\0'; + + else { dir[0] = '.', dir[1] = '\0'; p = (char *)prog; } - if (pipe(fdin) != 0 || pipe(fdout) != 0 || pipe(fderr) != 0) { - status = strerror(ERRNO); - httplib_cry(conn, "Error: CGI program \"%s\": Can not create CGI pipes: %s", prog, status); - XX_httplib_send_http_error(conn, 500, "Error: Cannot create CGI pipe: %s", status); + if ( pipe(fdin) != 0 || pipe(fdout) != 0 || pipe(fderr) != 0 ) { + + status = strerror( ERRNO ); + httplib_cry( conn, "Error: CGI program \"%s\": Can not create CGI pipes: %s", prog, status ); + XX_httplib_send_http_error( conn, 500, "Error: Cannot create CGI pipe: %s", status ); + goto done; } - pid = XX_httplib_spawn_process(conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir); + pid = XX_httplib_spawn_process( conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir ); + + if ( pid == (pid_t)-1 ) { - if (pid == (pid_t)-1) { status = strerror(ERRNO); - httplib_cry(conn, "Error: CGI program \"%s\": Can not spawn CGI process: %s", prog, status); - XX_httplib_send_http_error(conn, 500, "Error: Cannot spawn CGI process [%s]: %s", prog, status); + httplib_cry( conn, "Error: CGI program \"%s\": Can not spawn CGI process: %s", prog, status ); + XX_httplib_send_http_error( conn, 500, "Error: Cannot spawn CGI process [%s]: %s", prog, status ); + goto done; } - /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */ - XX_httplib_set_close_on_exec( (SOCKET)fdin[0], conn ); /* stdin read */ - XX_httplib_set_close_on_exec( (SOCKET)fdout[1], conn ); /* stdout write */ - XX_httplib_set_close_on_exec( (SOCKET)fderr[1], conn ); /* stderr write */ - XX_httplib_set_close_on_exec( (SOCKET)fdin[1], conn ); /* stdin write */ - XX_httplib_set_close_on_exec( (SOCKET)fdout[0], conn ); /* stdout read */ - XX_httplib_set_close_on_exec( (SOCKET)fderr[0], conn ); /* stderr read */ + /* + * Make sure child closes all pipe descriptors. It must dup them to 0,1 + */ - /* Parent closes only one side of the pipes. + XX_httplib_set_close_on_exec( (SOCKET)fdin[0], conn ); /* stdin read */ + XX_httplib_set_close_on_exec( (SOCKET)fdout[1], conn ); /* stdout write */ + XX_httplib_set_close_on_exec( (SOCKET)fderr[1], conn ); /* stderr write */ + XX_httplib_set_close_on_exec( (SOCKET)fdin[1], conn ); /* stdin write */ + XX_httplib_set_close_on_exec( (SOCKET)fdout[0], conn ); /* stdout read */ + XX_httplib_set_close_on_exec( (SOCKET)fderr[0], conn ); /* stderr read */ + + /* + * Parent closes only one side of the pipes. * If we don't mark them as closed, close() attempt before * return from this function throws an exception on Windows. - * Windows does not like when closed descriptor is closed again. */ + * Windows does not like when closed descriptor is closed again. + */ + close( fdin[0] ); close( fdout[1] ); close( fderr[1] ); @@ -127,87 +143,126 @@ void XX_httplib_handle_cgi_request( struct httplib_connection *conn, const char fdout[1] = -1; fderr[1] = -1; - if ((in = fdopen(fdin[1], "wb")) == NULL) { + if ( (in = fdopen( fdin[1], "wb" )) == NULL ) { + status = strerror(ERRNO); - httplib_cry(conn, "Error: CGI program \"%s\": Can not open stdin: %s", prog, status); - XX_httplib_send_http_error(conn, 500, "Error: CGI can not open fdin\nfopen: %s", status); + httplib_cry( conn, "Error: CGI program \"%s\": Can not open stdin: %s", prog, status ); + XX_httplib_send_http_error( conn, 500, "Error: CGI can not open fdin\nfopen: %s", status ); + goto done; } - if ((out = fdopen(fdout[0], "rb")) == NULL) { + if ( (out = fdopen( fdout[0], "rb" )) == NULL ) { + status = strerror(ERRNO); - httplib_cry(conn, "Error: CGI program \"%s\": Can not open stdout: %s", prog, status); - XX_httplib_send_http_error(conn, 500, "Error: CGI can not open fdout\nfopen: %s", status); + httplib_cry( conn, "Error: CGI program \"%s\": Can not open stdout: %s", prog, status ); + XX_httplib_send_http_error( conn, 500, "Error: CGI can not open fdout\nfopen: %s", status ); + goto done; } - if ((err = fdopen(fderr[0], "rb")) == NULL) { + if ( (err = fdopen( fderr[0], "rb" )) == NULL ) { + status = strerror(ERRNO); - httplib_cry(conn, "Error: CGI program \"%s\": Can not open stderr: %s", prog, status); - XX_httplib_send_http_error(conn, 500, "Error: CGI can not open fdout\nfopen: %s", status); + httplib_cry( conn, "Error: CGI program \"%s\": Can not open stderr: %s", prog, status ); + XX_httplib_send_http_error( conn, 500, "Error: CGI can not open fdout\nfopen: %s", status ); + goto done; } setbuf( in, NULL ); setbuf( out, NULL ); setbuf( err, NULL ); + fout.fp = out; - if ((conn->request_info.content_length > 0) || conn->is_chunked) { - /* This is a POST/PUT request, or another request with body data. */ - if (!XX_httplib_forward_body_data(conn, in, INVALID_SOCKET, NULL)) { - /* Error sending the body data */ - httplib_cry(conn, "Error: CGI program \"%s\": Forward body data failed", prog); + if ( conn->request_info.content_length > 0 || conn->is_chunked ) { + + /* + * This is a POST/PUT request, or another request with body data. + */ + + if ( ! XX_httplib_forward_body_data( conn, in, INVALID_SOCKET, NULL ) ) { + + /* + * Error sending the body data + */ + + httplib_cry( conn, "Error: CGI program \"%s\": Forward body data failed", prog ); + goto done; } } - /* Close so child gets an EOF. */ - fclose(in); - in = NULL; + /* + * Close so child gets an EOF. + */ + + fclose( in ); + + in = NULL; fdin[1] = -1; - /* Now read CGI reply into a buffer. We need to set correct + /* + * Now read CGI reply into a buffer. We need to set correct * status code, thus we need to see all HTTP headers first. * Do not send anything back to client, until we buffer in all - * HTTP headers. */ + * HTTP headers. + */ + data_len = 0; buf = httplib_malloc( buflen ); - if (buf == NULL) { - XX_httplib_send_http_error(conn, 500, "Error: Not enough memory for CGI buffer (%u bytes)", (unsigned int)buflen); - httplib_cry(conn, "Error: CGI program \"%s\": Not enough memory for buffer (%u " "bytes)", prog, (unsigned int)buflen); + if ( buf == NULL ) { + + XX_httplib_send_http_error( conn, 500, "Error: Not enough memory for CGI buffer (%u bytes)", (unsigned int)buflen ); + httplib_cry( conn, "Error: CGI program \"%s\": Not enough memory for buffer (%u " "bytes)", prog, (unsigned int)buflen ); + goto done; } - headers_len = XX_httplib_read_request(out, conn, buf, (int)buflen, &data_len); - if (headers_len <= 0) { - /* Could not parse the CGI response. Check if some error message on - * stderr. */ - i = XX_httplib_pull_all(err, conn, buf, (int)buflen); - if (i > 0) { - httplib_cry(conn, "Error: CGI program \"%s\" sent error " "message: [%.*s]", prog, i, buf); - XX_httplib_send_http_error(conn, 500, "Error: CGI program \"%s\" sent error " "message: [%.*s]", prog, i, buf); - } else { - httplib_cry(conn, "Error: CGI program sent malformed or too big " "(>%u bytes) HTTP headers: [%.*s]", (unsigned)buflen, data_len, buf); + headers_len = XX_httplib_read_request( out, conn, buf, (int)buflen, &data_len ); + if ( headers_len <= 0 ) { - XX_httplib_send_http_error(conn, + /* + * Could not parse the CGI response. Check if some error message on + * stderr. + */ + + i = XX_httplib_pull_all( err, conn, buf, (int)buflen ); + + if ( i > 0 ) { + + httplib_cry( conn, "Error: CGI program \"%s\" sent error " "message: [%.*s]", prog, i, buf ); + XX_httplib_send_http_error( conn, 500, "Error: CGI program \"%s\" sent error " "message: [%.*s]", prog, i, buf ); + } + + else { + httplib_cry( conn, "Error: CGI program sent malformed or too big " "(>%u bytes) HTTP headers: [%.*s]", (unsigned)buflen, data_len, buf ); + + XX_httplib_send_http_error( conn, 500, "Error: CGI program sent malformed or too big " "(>%u bytes) HTTP headers: [%.*s]", (unsigned)buflen, data_len, - buf); + buf ); } goto done; } - pbuf = buf; - buf[headers_len - 1] = '\0'; - XX_httplib_parse_http_headers(&pbuf, &ri); - /* Make up and send the status line */ + pbuf = buf; + buf[headers_len - 1] = '\0'; + + XX_httplib_parse_http_headers( &pbuf, &ri ); + + /* + * Make up and send the status line + */ + status_text = "OK"; + if ((status = XX_httplib_get_header(&ri, "Status")) != NULL) { conn->status_code = atoi(status); status_text = status; @@ -215,40 +270,46 @@ void XX_httplib_handle_cgi_request( struct httplib_connection *conn, const char || *status_text == ' ') { status_text++; } - } else if (XX_httplib_get_header(&ri, "Location") != NULL) { - conn->status_code = 302; - } else { - conn->status_code = 200; } - connection_state = XX_httplib_get_header(&ri, "Connection"); - if (!XX_httplib_header_has_option(connection_state, "keep-alive")) { - conn->must_close = 1; - } - httplib_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, status_text); + else if ( XX_httplib_get_header( &ri, "Location" ) != NULL ) conn->status_code = 302; + else conn->status_code = 200; - /* Send headers */ - for (i = 0; i < ri.num_headers; i++) { - httplib_printf(conn, "%s: %s\r\n", ri.http_headers[i].name, ri.http_headers[i].value); - } - httplib_write(conn, "\r\n", 2); + connection_state = XX_httplib_get_header( &ri, "Connection" ); + if ( ! XX_httplib_header_has_option( connection_state, "keep-alive" ) ) conn->must_close = 1; + + httplib_printf( conn, "HTTP/1.1 %d %s\r\n", conn->status_code, status_text ); + + /* + * Send headers + */ + + for (i=0; inum_bytes_sent += httplib_write(conn, buf + headers_len, (size_t)(data_len - headers_len)); - /* Read the rest of CGI output and send to the client */ - XX_httplib_send_file_data(conn, &fout, 0, INT64_MAX); + /* + * Read the rest of CGI output and send to the client + */ + + XX_httplib_send_file_data( conn, &fout, 0, INT64_MAX ); done: httplib_free( blk.var ); httplib_free( blk.buf ); - if (pid != (pid_t)-1) { + if ( pid != (pid_t)-1 ) { + httplib_kill( pid, SIGKILL ); #if !defined(_WIN32) { int st; - while (waitpid(pid, &st, 0) != -1) - ; /* clean zombies */ + while ( waitpid( pid, &st, 0 ) != -1 ) {} /* clean zombies */ } #endif } diff --git a/src/httplib_handle_form_request.c b/src/httplib_handle_form_request.c index 6eb01d91..e56f5556 100644 --- a/src/httplib_handle_form_request.c +++ b/src/httplib_handle_form_request.c @@ -58,17 +58,20 @@ static int url_encoded_field_found(const struct httplib_connection *conn, } else filename_dec[0] = 0; - ret = - fdh->field_found(key_dec, filename_dec, path, path_len, fdh->user_data); + ret = fdh->field_found(key_dec, filename_dec, path, path_len, fdh->user_data); if ((ret & 0xF) == FORM_FIELD_STORAGE_GET) { + if (fdh->field_get == NULL) { + httplib_cry(conn, "%s: Function \"Get\" not available", __func__); return FORM_FIELD_STORAGE_SKIP; } } if ((ret & 0xF) == FORM_FIELD_STORAGE_STORE) { + if (fdh->field_store == NULL) { + httplib_cry(conn, "%s: Function \"Store\" not available", __func__); return FORM_FIELD_STORAGE_SKIP; } @@ -88,10 +91,15 @@ static int url_encoded_field_get(const struct httplib_connection *conn, char key_dec[1024]; char *value_dec = httplib_malloc( value_len+1 ); - int value_dec_len, ret; + int value_dec_len; + int ret; + + if ( value_dec == NULL ) { + + /* + * Log error message and stop parsing the form data. + */ - if (!value_dec) { - /* Log error message and stop parsing the form data. */ httplib_cry(conn, "%s: Not enough memory (required: %lu)", __func__, (unsigned long)(value_len + 1)); return FORM_FIELD_STORAGE_ABORT; } @@ -166,7 +174,8 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ int has_body_data = (conn->request_info.content_length > 0) || (conn->is_chunked); - /* There are three ways to encode data from a HTML form: + /* + * There are three ways to encode data from a HTML form: * 1) method: GET (default) * The form data is in the HTTP query string. * 2) method: POST, enctype: "application/x-www-form-urlencoded" @@ -191,7 +200,7 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ * call httplib_read. We just need to split the query string into key-value * pairs. */ data = conn->request_info.query_string; - if (!data) { + if ( data == NULL ) { /* No query string. */ return -1; } @@ -207,7 +216,8 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ } keylen = val - data; - /* In every "field_found" callback we ask what to do with the + /* + * In every "field_found" callback we ask what to do with the * data ("field_storage"). This could be: * FORM_FIELD_STORAGE_SKIP (0) ... ignore the value of this field * FORM_FIELD_STORAGE_GET (1) ... read the data and call the get @@ -218,6 +228,7 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ * (currently not implemented) * FORM_FIELD_STORAGE_ABORT (flag) ... stop parsing */ + memset(path, 0, sizeof(path)); field_count++; field_storage = url_encoded_field_found(conn, data, (size_t)keylen, NULL, 0, path, sizeof(path) - 1, fdh); @@ -234,16 +245,14 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ if (field_storage == FORM_FIELD_STORAGE_GET) { /* Call callback */ - url_encoded_field_get( - conn, data, (size_t)keylen, val, (size_t)vallen, fdh); + url_encoded_field_get( conn, data, (size_t)keylen, val, (size_t)vallen, fdh); } if (field_storage == FORM_FIELD_STORAGE_STORE) { /* Store the content to a file */ if (XX_httplib_fopen(conn, path, "wb", &fstore) == 0) fstore.fp = NULL; file_size = 0; if (fstore.fp != NULL) { - size_t n = - (size_t)fwrite(val, 1, (size_t)vallen, fstore.fp); + size_t n = (size_t)fwrite(val, 1, (size_t)vallen, fstore.fp); if ((n != (size_t)vallen) || (ferror(fstore.fp))) { httplib_cry(conn, "%s: Cannot write file %s", __func__, path); fclose(fstore.fp); @@ -348,13 +357,13 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ field_count++; field_storage = url_encoded_field_found(conn, buf, (size_t)keylen, NULL, 0, path, sizeof(path) - 1, fdh); - if ((field_storage & FORM_FIELD_STORAGE_ABORT) - == FORM_FIELD_STORAGE_ABORT) { + if ((field_storage & FORM_FIELD_STORAGE_ABORT) == FORM_FIELD_STORAGE_ABORT) { /* Stop parsing the request */ break; } if (field_storage == FORM_FIELD_STORAGE_STORE) { + if (XX_httplib_fopen(conn, path, "wb", &fstore) == 0) fstore.fp = NULL; file_size = 0; if (!fstore.fp) httplib_cry(conn, "%s: Cannot create file %s", __func__, path); @@ -385,8 +394,7 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ /* Call callback */ url_encoded_field_get(conn, ((get_block > 0) ? NULL : buf), - ((get_block > 0) ? 0 - : (size_t)keylen), + ((get_block > 0) ? 0 : (size_t)keylen), val, (size_t)vallen, fdh); @@ -454,9 +462,12 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ } if (!httplib_strncasecmp(content_type, "MULTIPART/FORM-DATA;", 20)) { - /* The form data is in the request body data, encoded as multipart + /* + * The form data is in the request body data, encoded as multipart * content (see https://www.ietf.org/rfc/rfc1867.txt, - * https://www.ietf.org/rfc/rfc2388.txt). */ + * https://www.ietf.org/rfc/rfc2388.txt). + */ + const char *boundary; size_t bl; ptrdiff_t used; @@ -476,7 +487,10 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ bl = 20; while (content_type[bl] == ' ') bl++; - /* There has to be a BOUNDARY definition in the Content-Type header */ + /* + * There has to be a BOUNDARY definition in the Content-Type header + */ + if (httplib_strncasecmp(content_type + bl, "BOUNDARY=", 9)) { /* Malformed request */ return -1; @@ -618,9 +632,7 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ if (field_storage == FORM_FIELD_STORAGE_GET) { unencoded_field_get(conn, ((get_block > 0) ? NULL : nbeg), - ((get_block > 0) - ? 0 - : (size_t)(nend - nbeg)), + ((get_block > 0) ? 0 : (size_t)(nend - nbeg)), hend, towrite, fdh); @@ -669,8 +681,7 @@ int httplib_handle_form_request(struct httplib_connection *conn, struct httplib_ /* Call callback */ unencoded_field_get(conn, ((get_block > 0) ? NULL : nbeg), - ((get_block > 0) ? 0 - : (size_t)(nend - nbeg)), + ((get_block > 0) ? 0 : (size_t)(nend - nbeg)), hend, towrite, fdh); diff --git a/src/httplib_printf.c b/src/httplib_printf.c index b8d4a0ae..19117fb2 100644 --- a/src/httplib_printf.c +++ b/src/httplib_printf.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -33,9 +33,9 @@ int httplib_printf( struct httplib_connection *conn, const char *fmt, ... ) { va_list ap; int result; - va_start(ap, fmt); - result = XX_httplib_vprintf(conn, fmt, ap); - va_end(ap); + va_start( ap, fmt ); + result = XX_httplib_vprintf( conn, fmt, ap ); + va_end( ap ); return result; diff --git a/src/httplib_pull.c b/src/httplib_pull.c index 6eeb5e57..d0e53cfb 100644 --- a/src/httplib_pull.c +++ b/src/httplib_pull.c @@ -22,15 +22,18 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 1.9 */ #include "httplib_main.h" #include "httplib_ssl.h" #include "httplib_utils.h" -/* Read from IO channel - opened file descriptor, socket, or SSL descriptor. - * Return negative value on error, or number of bytes read on success. */ +/* + * Read from IO channel - opened file descriptor, socket, or SSL descriptor. + * Return negative value on error, or number of bytes read on success. + */ + int XX_httplib_pull( FILE *fp, struct httplib_connection *conn, char *buf, int len, double timeout ) { int nread; @@ -44,49 +47,61 @@ int XX_httplib_pull( FILE *fp, struct httplib_connection *conn, char *buf, int l typedef size_t len_t; #endif - if (timeout > 0) { - memset(&start, 0, sizeof(start)); - memset(&now, 0, sizeof(now)); - clock_gettime(CLOCK_MONOTONIC, &start); + if ( timeout > 0 ) { + + memset( &start, 0, sizeof(start) ); + memset( &now, 0, sizeof(now) ); + + clock_gettime( CLOCK_MONOTONIC, &start ); } do { - if (fp != NULL) { + if ( fp != NULL ) { #if !defined(_WIN32_WCE) - /* Use read() instead of fread(), because if we're reading from the + /* + * Use read() instead of fread(), because if we're reading from the * CGI pipe, fread() may block until IO buffer is filled up. We * cannot afford to block and must pass all read bytes immediately - * to the client. */ - nread = (int)read(fileno(fp), buf, (size_t)len); + * to the client. + */ + + nread = (int)read( fileno(fp), buf, (size_t)len ); #else - /* WinCE does not support CGI pipes */ + /* + * WinCE does not support CGI pipes + */ + nread = (int)fread(buf, 1, (size_t)len, fp); #endif err = (nread < 0) ? ERRNO : 0; #ifndef NO_SSL - } else if (conn->ssl != NULL) { - nread = SSL_read(conn->ssl, buf, len); + } + + else if ( conn->ssl != NULL ) { + + nread = SSL_read( conn->ssl, buf, len ); + if (nread <= 0) { + err = SSL_get_error(conn->ssl, nread); - if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) { - err = ERRNO; - } else if ((err == SSL_ERROR_WANT_READ) || (err == SSL_ERROR_WANT_WRITE)) { - nread = 0; - } else return -1; - } else err = 0; + if ( err == SSL_ERROR_SYSCALL && (nread == -1)) err = ERRNO; + else if ( err == SSL_ERROR_WANT_READ || (err == SSL_ERROR_WANT_WRITE)) nread = 0; + + else return -1; + } + else err = 0; #endif - } else { + } + + else { nread = (int)recv(conn->client.sock, buf, (len_t)len, 0); - err = (nread < 0) ? ERRNO : 0; - if (nread == 0) { - /* shutdown of the socket at client side */ - return -1; - } + err = (nread < 0) ? ERRNO : 0; + if (nread == 0) return -1; /* shutdown of the socket at client side */ } - if (conn->ctx->stop_flag) return -1; + if ( conn->ctx->stop_flag ) return -1; if ((nread > 0) || (nread == 0 && len == 0)) { /* some data has been read, or no data was requested */ @@ -125,7 +140,10 @@ int XX_httplib_pull( FILE *fp, struct httplib_connection *conn, char *buf, int l if (timeout > 0) clock_gettime(CLOCK_MONOTONIC, &now); } while ((timeout <= 0) || (XX_httplib_difftimespec(&now, &start) <= timeout)); - /* Timeout occured, but no data available. */ + /* + * Timeout occured, but no data available. + */ + return -1; } /* XX_httplib_pull */ diff --git a/src/httplib_put_file.c b/src/httplib_put_file.c index 4f26409a..0263f7bd 100644 --- a/src/httplib_put_file.c +++ b/src/httplib_put_file.c @@ -47,7 +47,7 @@ void XX_httplib_put_file( struct httplib_connection *conn, const char *path ) { char date[64]; time_t curtime; - if (conn == NULL) return; + if ( conn == NULL ) return; curtime = time( NULL ); diff --git a/src/httplib_set_acl_option.c b/src/httplib_set_acl_option.c index 41935b5d..8c8a6026 100644 --- a/src/httplib_set_acl_option.c +++ b/src/httplib_set_acl_option.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" diff --git a/src/httplib_set_auth_handler.c b/src/httplib_set_auth_handler.c index 75be19b6..176ef07d 100644 --- a/src/httplib_set_auth_handler.c +++ b/src/httplib_set_auth_handler.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" diff --git a/src/httplib_set_gpass_option.c b/src/httplib_set_gpass_option.c index 20d8ec02..383fc5c8 100644 --- a/src/httplib_set_gpass_option.c +++ b/src/httplib_set_gpass_option.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -31,19 +31,21 @@ * int XX_httplib_set_gpass_option( struct httplib_context *ctx ); * * The function XX_httplib_set_gpass_option() sets the global password file - * oprion for a context. + * option for a context. */ int XX_httplib_set_gpass_option( struct httplib_context *ctx ) { + struct file file = STRUCT_FILE_INITIALIZER; + const char *path; + if ( ctx == NULL ) return 0; - struct file file = STRUCT_FILE_INITIALIZER; - const char *path = ctx->config[GLOBAL_PASSWORDS_FILE]; + path = ctx->config[GLOBAL_PASSWORDS_FILE]; - if (path != NULL && !XX_httplib_stat( XX_httplib_fc(ctx), path, &file)) { + if ( path != NULL && ! XX_httplib_stat( XX_httplib_fc(ctx), path, &file ) ) { - httplib_cry( XX_httplib_fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO)); + httplib_cry( XX_httplib_fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO) ); return 0; } return 1; diff --git a/src/httplib_set_uid_option.c b/src/httplib_set_uid_option.c index 404a7d92..86dd6999 100644 --- a/src/httplib_set_uid_option.c +++ b/src/httplib_set_uid_option.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" @@ -39,23 +39,20 @@ int XX_httplib_set_uid_option( struct httplib_context *ctx ) { struct passwd *pw; + const char *uid; - if ( ctx != NULL ) { + if ( ctx == NULL ) return 0; - const char *uid = ctx->config[RUN_AS_USER]; - int success = 0; + uid = ctx->config[RUN_AS_USER]; - if (uid == NULL) success = 1; - else { - if ( (pw = getpwnam(uid)) == NULL ) httplib_cry( XX_httplib_fc(ctx), "%s: unknown user [%s]", __func__, uid ); - else if ( setgid(pw->pw_gid) == -1 ) httplib_cry( XX_httplib_fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno) ); - else if ( setgroups(0, NULL) ) httplib_cry( XX_httplib_fc(ctx), "%s: setgroups(): %s", __func__, strerror(errno) ); - else if ( setuid(pw->pw_uid) == -1 ) httplib_cry( XX_httplib_fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno) ); - else success = 1; - } + if ( uid == NULL ) return 1; + + if ( (pw = getpwnam(uid)) == NULL ) httplib_cry( XX_httplib_fc(ctx), "%s: unknown user [%s]", __func__, uid ); + else if ( setgid(pw->pw_gid) == -1 ) httplib_cry( XX_httplib_fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno) ); + else if ( setgroups(0, NULL) ) httplib_cry( XX_httplib_fc(ctx), "%s: setgroups(): %s", __func__, strerror(errno) ); + else if ( setuid(pw->pw_uid) == -1 ) httplib_cry( XX_httplib_fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno) ); + else return 1; - return success; - } return 0; } /* XX_httplib_set_uid_option */