diff --git a/Makefile b/Makefile index 7056c514..820cbdd6 100644 --- a/Makefile +++ b/Makefile @@ -1281,12 +1281,10 @@ ${OBJDIR}httplib_strcasestr${OBJEXT} : ${SRCDIR}httplib_strcasestr.c \ ${INCDIR}libhttp.h ${OBJDIR}httplib_strdup${OBJEXT} : ${SRCDIR}httplib_strdup.c \ - ${SRCDIR}httplib_string.h \ ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h ${OBJDIR}httplib_strlcpy${OBJEXT} : ${SRCDIR}httplib_strlcpy.c \ - ${SRCDIR}httplib_string.h \ ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h @@ -1297,7 +1295,6 @@ ${OBJDIR}httplib_strncasecmp${OBJEXT} : ${SRCDIR}httplib_strncasecmp.c \ ${OBJDIR}httplib_strndup${OBJEXT} : ${SRCDIR}httplib_strndup.c \ ${SRCDIR}httplib_memory.h \ - ${SRCDIR}httplib_string.h \ ${SRCDIR}httplib_main.h \ ${INCDIR}libhttp.h diff --git a/include/libhttp.h b/include/libhttp.h index 17b9f776..960f09a8 100644 --- a/include/libhttp.h +++ b/include/libhttp.h @@ -839,8 +839,6 @@ LIBHTTP_API const char * httplib_get_builtin_mime_type( const char *file_name ); LIBHTTP_API const char *httplib_get_response_code_text(struct httplib_connection *conn, int response_code); -/* Return LibHTTP version. */ -LIBHTTP_API const char *httplib_version(void); /* URL-decode input buffer into destination buffer. @@ -1019,6 +1017,7 @@ LIBHTTP_API char * httplib_strdup( const char *str ); LIBHTTP_API void httplib_strlcpy( char *dst, const char *src, size_t len ); LIBHTTP_API int httplib_strncasecmp( const char *s1, const char *s2, size_t len ); LIBHTTP_API char * httplib_strndup( const char *str, size_t len ); +LIBHTTP_API const char * httplib_version( void ); #ifdef __cplusplus } diff --git a/src/httplib_fclose.c b/src/httplib_fclose.c index c5125a2a..ad003244 100644 --- a/src/httplib_fclose.c +++ b/src/httplib_fclose.c @@ -20,27 +20,31 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. - * - * ============ - * Release: 2.0 */ #include "httplib_main.h" /* - * void XX_httplib_fclose( struct file *filep ); + * int XX_httplib_fclose( struct file *filep ); * * The function XX_httplib_fclose() closed a file associated with a filep - * structure. The function doesn't return a success or error code, but the - * value of the fp parameter in the filep structure is reset to NULL which - * prevents the old file pointer to be reused. + * structure. If the function succeeds, the value 0 is returned. Otherwise + * the return value is EOF and errno is set. */ -void XX_httplib_fclose( struct file *filep ) { +int XX_httplib_fclose( struct file *filep ) { - if ( filep == NULL || filep->fp == NULL ) return; + int retval; - fclose( filep->fp ); + if ( filep == NULL || filep->fp == NULL ) { + + errno = EINVAL; + return EOF; + } + + retval = fclose( filep->fp ); filep->fp = NULL; + return retval; + } /* XX_httplib_fclose */ diff --git a/src/httplib_main.h b/src/httplib_main.h index f5737846..1d5bf996 100644 --- a/src/httplib_main.h +++ b/src/httplib_main.h @@ -613,37 +613,36 @@ struct httplib_context { * struct httplib_connection; */ -struct httplib_connection { - struct httplib_request_info request_info; - struct httplib_context *ctx; - SSL *ssl; /* SSL descriptor */ - SSL_CTX *client_ssl_ctx; /* SSL context for client connections */ - struct socket client; /* Connected client */ - time_t conn_birth_time; /* Time (wall clock) when connection was established */ - struct timespec req_time; /* Time (since system start) when the request was received */ - int64_t num_bytes_sent; /* Total bytes sent to client */ - int64_t content_len; /* Content-Length header value */ - int64_t consumed_content; /* How many bytes of content have been read */ - int is_chunked; /* Transfer-Encoding is chunked: 0=no, 1=yes: data available, 2: all data read */ - size_t chunk_remainder; /* Unread data from the last chunk */ - char *buf; /* Buffer for received data */ - char *path_info; /* PATH_INFO part of the URL */ - - int must_close; /* 1 if connection must be closed */ - int in_error_handler; /* 1 if in handler for user defined error pages */ - int internal_error; /* 1 if an error occured while processing the request */ - - int buf_size; /* Buffer size */ - int request_len; /* Size of the request + headers in a buffer */ - int data_len; /* Total size of data in a buffer */ - int status_code; /* HTTP reply status code, e.g. 200 */ - int throttle; /* Throttling, bytes/sec. <= 0 means no throttle */ - time_t last_throttle_time; /* Last time throttled data was sent */ - int64_t last_throttle_bytes; /* Bytes sent this second */ - pthread_mutex_t mutex; /* Used by httplib_(un)lock_connection to ensure atomic transmissions for websockets */ - - int thread_index; /* Thread index within ctx */ -}; + /****************************************************************************************/ +struct httplib_connection { /* */ + struct httplib_request_info request_info; /* The request info of the connection */ + struct httplib_context *ctx; /* The LibHTTP context of the connection */ + SSL * ssl; /* SSL descriptor */ + SSL_CTX * client_ssl_ctx; /* SSL context for client connections */ + struct socket client; /* Connected client */ + time_t conn_birth_time; /* Time (wall clock) when connection was established */ + struct timespec req_time; /* Time (since system start) when the request was received */ + int64_t num_bytes_sent; /* Total bytes sent to client */ + int64_t content_len; /* Content-Length header value */ + int64_t consumed_content; /* How many bytes of content have been read */ + int is_chunked; /* Transfer-Encoding is chunked: 0=no, 1=yes: data available, 2: all data read */ + size_t chunk_remainder; /* Unread data from the last chunk */ + char * buf; /* Buffer for received data */ + char * path_info; /* PATH_INFO part of the URL */ + int must_close; /* 1 if connection must be closed */ + int in_error_handler; /* 1 if in handler for user defined error pages */ + int internal_error; /* 1 if an error occured while processing the request */ + int buf_size; /* Buffer size */ + int request_len; /* Size of the request + headers in a buffer */ + int data_len; /* Total size of data in a buffer */ + int status_code; /* HTTP reply status code, e.g. 200 */ + time_t last_throttle_time; /* Last time throttled data was sent */ + int64_t throttle; /* Throttling, bytes/sec. <= 0 means no throttle */ + int64_t last_throttle_bytes; /* Bytes sent this second */ + pthread_mutex_t mutex; /* Used by httplib_(un)lock_connection to ensure atomic transmissions for websockets */ + int thread_index; /* Thread index within ctx */ +}; /* */ + /****************************************************************************************/ struct worker_thread_args { struct httplib_context *ctx; @@ -673,7 +672,7 @@ struct file { int gzipped; /* set to 1 if the content is gzipped in which case we need a content-encoding: gzip header */ }; -#define STRUCT_FILE_INITIALIZER { (uint64_t)0, (time_t)0, (FILE *)NULL, (const char *)NULL, 0, 0 } +#define STRUCT_FILE_INITIALIZER { (uint64_t)0, (time_t)0, NULL, NULL, 0, 0 } /* Describes a string (chunk of memory). */ struct vec { @@ -805,7 +804,7 @@ void XX_httplib_delete_file( struct httplib_connection *conn, const char *path void XX_httplib_dir_scan_callback( struct de *de, void *data ); void XX_httplib_discard_unread_request_data( struct httplib_connection *conn ); struct httplib_connection * XX_httplib_fc( struct httplib_context *ctx ); -void XX_httplib_fclose( struct file *filep ); +int XX_httplib_fclose( struct file *filep ); void XX_httplib_fclose_on_exec( struct file *filep, struct httplib_connection *conn ); const char * XX_httplib_fgets( char *buf, size_t size, struct file *filep, char **p ); bool XX_httplib_fopen( const struct httplib_connection *conn, const char *path, const char *mode, struct file *filep ); diff --git a/src/httplib_mkcol.c b/src/httplib_mkcol.c index 078a41d7..e1bde5fa 100644 --- a/src/httplib_mkcol.c +++ b/src/httplib_mkcol.c @@ -32,7 +32,8 @@ * void XX_httplib_mkcol( struct httplib_connection *conn, const char *path ); * * The function XX_httplib_mkcol() handles a MKCOL command from a remote - * client. + * client. The MKCOL method is used to create a new collection resource at the + * location specificied by the request URI. */ #if !defined(NO_FILES) diff --git a/src/httplib_push_all.c b/src/httplib_push_all.c index 0f8ea884..4e102d2a 100644 --- a/src/httplib_push_all.c +++ b/src/httplib_push_all.c @@ -29,39 +29,43 @@ #include "httplib_ssl.h" #include "httplib_utils.h" -/* - * static int push( struct httplib_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int len, double timeout ); - * - * The function push() writes data to the I/O chanel, opened file descriptor, - * socket or SSL descriptor. The function returns the number of bytes which - * were actually written. - */ - -static int push( struct httplib_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int len, double timeout ) { - - struct timespec start; - struct timespec now; - int n; - int err; - #ifdef _WIN32 typedef int len_t; #else typedef size_t len_t; #endif +/* + * static int64_t push( struct httplib_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len, double timeout ); + * + * The function push() writes data to the I/O channel, opened file descriptor, + * socket or SSL descriptor. The function returns the number of bytes which + * were actually written. A negative value is returned if an error is + * encountered. + * + * Although we specify the number of bytes in a 64 bit integer, the OS functins + * may not be able to handle that. We therefore cap the amount of bytes to + * write to the maximum integer and size_t value, whatever is the smallest. The + * function push() will be called automatically again if not all bytes have + * been written. + */ + +static int64_t push( struct httplib_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len, double timeout ) { + + struct timespec start; + struct timespec now; + int n; + int err; + if ( ctx == NULL ) return -1; #ifdef NO_SSL if ( ssl != NULL ) return -1; -#endif +#endif /* NO_SSL */ - if ( timeout > 0 ) { + if ( len > (int64_t)SIZE_T_MAX ) len = SIZE_T_MAX; + if ( len > (int64_t)INT_MAX ) len = INT_MAX; - memset( & start, 0, sizeof(start) ); - memset( & now, 0, sizeof(now) ); - - clock_gettime( CLOCK_MONOTONIC, &start ); - } + if ( timeout > 0.0 ) clock_gettime( CLOCK_MONOTONIC, &start ); do { @@ -84,7 +88,7 @@ static int push( struct httplib_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, c } else -#endif +#endif /* NO_SSL */ if ( fp != NULL ) { n = (int)fwrite( buf, 1, (size_t)len, fp ); @@ -113,14 +117,7 @@ static int push( struct httplib_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, c if ( ctx->stop_flag ) return -1; - if ( n > 0 || (n == 0 && len == 0) ) { - - /* - * some data has been read, or no data was requested - */ - - return n; - } + if ( n > 0 || (n == 0 && len == 0) ) return n; if ( n < 0 ) { @@ -139,9 +136,9 @@ static int push( struct httplib_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, c * ==> Fix the TODOs above first. */ - if ( timeout > 0 ) clock_gettime( CLOCK_MONOTONIC, &now ); + if ( timeout > 0.0 ) clock_gettime( CLOCK_MONOTONIC, &now ); - } while ( timeout <= 0 || XX_httplib_difftimespec( &now, &start ) <= timeout ); + } while ( timeout <= 0.0 || XX_httplib_difftimespec( &now, &start ) <= timeout ); return -1; @@ -171,31 +168,18 @@ int64_t XX_httplib_push_all( struct httplib_context *ctx, FILE *fp, SOCKET sock, while ( len > 0 && ctx->stop_flag == 0 ) { - n = push( ctx, fp, sock, ssl, buf + nwritten, (int)len, timeout ); + n = push( ctx, fp, sock, ssl, buf + nwritten, len, timeout ); if ( n < 0 ) { - /* - * Propagate the error - */ - - if ( nwritten == 0 ) nwritten = n; - break; + if ( nwritten == 0 ) return n; + else return nwritten; } - else if ( n == 0 ) { - - /* - * No more data to write - */ - - break; - } + if ( n == 0 ) return nwritten; - else { - nwritten += n; - len -= n; - } + nwritten += n; + len -= n; } return nwritten; diff --git a/src/httplib_stat.c b/src/httplib_stat.c index 4e2e8e13..f1b547ed 100644 --- a/src/httplib_stat.c +++ b/src/httplib_stat.c @@ -58,7 +58,7 @@ int XX_httplib_stat( struct httplib_connection *conn, const char *path, struct f memset( filep, 0, sizeof(*filep) ); - if ( conn && XX_httplib_is_file_in_memory( conn, path, filep ) ) { + if ( conn != NULL && XX_httplib_is_file_in_memory( conn, path, filep ) ) { /* * filep->is_directory = 0; filep->gzipped = 0; .. already done by diff --git a/src/httplib_store_body.c b/src/httplib_store_body.c index 2a63e874..de58d8d9 100644 --- a/src/httplib_store_body.c +++ b/src/httplib_store_body.c @@ -30,7 +30,9 @@ /* * int64_t httplib_store_body( struct httplib_connection *conn, const char *path ); * - * The function httplib_store_body() stores in incoming body for future processing. + * The function httplib_store_body() stores in incoming body for future + * processing. The function returns the number of bytes actually read, or a + * negative number to indicate a failure. */ int64_t httplib_store_body( struct httplib_connection *conn, const char *path ) { @@ -59,6 +61,7 @@ int64_t httplib_store_body( struct httplib_connection *conn, const char *path ) return ret; } + if ( ret != 1 ) { /* @@ -84,12 +87,7 @@ int64_t httplib_store_body( struct httplib_connection *conn, const char *path ) ret = httplib_read( conn, buf, sizeof(buf) ); } - /* - * TODO: XX_httplib_fclose should return an error, - * and every caller should check and handle it. - */ - - if ( fclose(fi.fp) != 0 ) { + if ( XX_httplib_fclose( & fi ) != 0 ) { XX_httplib_remove_bad_file( conn, path ); return -14; diff --git a/src/httplib_strdup.c b/src/httplib_strdup.c index 2722709e..6ce89308 100644 --- a/src/httplib_strdup.c +++ b/src/httplib_strdup.c @@ -20,13 +20,9 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. - * - * ============ - * Release: 2.0 */ #include "httplib_main.h" -#include "httplib_string.h" /* * char *httplib_strdup( const char *str ); @@ -41,10 +37,10 @@ * the returned value is NULL. */ -char *httplib_strdup( const char *str ) { +LIBHTTP_API char *httplib_strdup( const char *str ) { if ( str == NULL ) return NULL; - return httplib_strndup(str, strlen( str ) ); + return httplib_strndup( str, strlen( str ) ); } /* httplib_strdup */ diff --git a/src/httplib_strlcpy.c b/src/httplib_strlcpy.c index 4ad08b37..992c92fe 100644 --- a/src/httplib_strlcpy.c +++ b/src/httplib_strlcpy.c @@ -20,13 +20,9 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. - * - * ============ - * Release: 2.0 */ #include "httplib_main.h" -#include "httplib_string.h" /* * void httplib_strlcpy( char *dst, const char *src, size_t len ); @@ -45,15 +41,15 @@ LIBHTTP_API void httplib_strlcpy( char *dst, const char *src, size_t len ) { - if ( dst == NULL || len == 0 ) return; - if ( src == NULL ) { *dst = 0; return; } - - while ( len > 1 && *src ) { + if ( dst == NULL || len == 0 ) return; + if ( src == NULL ) { *dst = '\0'; return; } + while ( len > 1 && *src != '\0' ) { + *dst++ = *src++; len--; } - *dst = 0; + *dst = '\0'; } /* httplib_strlcpy */ diff --git a/src/httplib_strndup.c b/src/httplib_strndup.c index a1bec281..3c22d07a 100644 --- a/src/httplib_strndup.c +++ b/src/httplib_strndup.c @@ -20,17 +20,13 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. - * - * ============ - * Release: 2.0 */ #include "httplib_main.h" #include "httplib_memory.h" -#include "httplib_string.h" /* - * char *httplib_strndup( const char *ptr, size_t len ); + * char *httplib_strndup( const char *str, size_t len ); * * The function strndup() duplicates a string with a maximum given length to a * new string in a newly allocated block of memory. The function is equivalent @@ -46,11 +42,16 @@ * the duplicate. */ -LIBHTTP_API char *httplib_strndup( const char *ptr, size_t len ) { +LIBHTTP_API char *httplib_strndup( const char *str, size_t len ) { char *p; - if ( (p = httplib_malloc( len+1 )) != NULL ) httplib_strlcpy( p, ptr, len+1 ); + if ( str == NULL ) return NULL; + + p = httplib_malloc( len+1 ); + if ( p == NULL ) return NULL; + + httplib_strlcpy( p, str, len+1 ); return p; diff --git a/src/httplib_version.c b/src/httplib_version.c index 15bd04fe..38182808 100644 --- a/src/httplib_version.c +++ b/src/httplib_version.c @@ -20,9 +20,6 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. - * - * ============ - * Release: 2.0 */ #include "httplib_main.h" @@ -34,7 +31,7 @@ * NULL terminated string. */ -const char *httplib_version( void ) { +LIBHTTP_API const char *httplib_version( void ) { return LIBHTTP_VERSION; diff --git a/src/httplib_websocket_write.c b/src/httplib_websocket_write.c index 5c4bc52d..f891da91 100644 --- a/src/httplib_websocket_write.c +++ b/src/httplib_websocket_write.c @@ -30,7 +30,8 @@ /* * int httplib_websocket_write( struct httplib_connection *conn, int opcode, const char *data, size_t dataLen ); * - * The function httplib_websocket_write() writes data over a websocket connection. + * The function httplib_websocket_write() writes data over a websocket + * connection. */ #if defined(USE_WEBSOCKET) diff --git a/src/httplib_write.c b/src/httplib_write.c index 6f3ea1a5..70575e67 100644 --- a/src/httplib_write.c +++ b/src/httplib_write.c @@ -20,19 +20,21 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. - * - * ============ - * Release: 2.0 */ #include "httplib_main.h" /* - * The function httplib_write() writes a number of characters over a - * connection. The amount of characters written is returned. If an error occurs + * The function httplib_write() writes a number of bytes over a connection. + * The amount of characters written is returned. If an error occurs * the value 0 is returned. * - * The function uses throtteling when necessary for a connection. + * The function uses throtteling when necessary for a connection. Throtteling + * uses the wall clock. Although this can be dangerous in some situations where + * the value of the wall clock is changed externally, it isn't in this case + * because the throttle function only looks when the time calue changes, but + * doesn't take the actual value of the clock in the calculation. In the latter + * case a monotonic clock with guaranteed increase would be a better choice. */ int httplib_write( struct httplib_connection *conn, const void *buffie, size_t lennie ) { @@ -47,7 +49,7 @@ int httplib_write( struct httplib_connection *conn, const void *buffie, size_t l if ( conn == NULL || buffie == NULL || lennie == 0 ) return 0; buf = buffie; - len = (int64_t)lennie; + len = lennie; if ( conn->throttle > 0 ) {