1
0
mirror of https://github.com/lammertb/libhttp.git synced 2025-08-06 05:02:40 +03:00

Layout fixed and one send_file function

This commit is contained in:
Lammert Bies
2016-12-20 15:00:53 +01:00
parent afd229624d
commit 06ab21048b
22 changed files with 412 additions and 297 deletions

View File

@@ -5,6 +5,7 @@ Release Notes v2.0 (work in progress)
Changes Changes
------- -------
- Combined three send file functions into `httplib_send_file()`.
- Memory allocation debugging can be switched on and off dynamically - Memory allocation debugging can be switched on and off dynamically
- Memory allocation functions are available for the main application - Memory allocation functions are available for the main application
- Full API documentation now available at [`www.libhttp.org/api-reference/`](http://www.libhttp.org/api-reference/) - Full API documentation now available at [`www.libhttp.org/api-reference/`](http://www.libhttp.org/api-reference/)

View File

@@ -52,9 +52,7 @@ LibHTTP is often used as HTTP and HTTPS library inside a larger application. A
* [`httplib_handle_form_request( conn, fdh );`](api/httplib_handle_form_request.md) * [`httplib_handle_form_request( conn, fdh );`](api/httplib_handle_form_request.md)
* [`httplib_printf( conn, fmt, ... );`](api/httplib_printf.md) * [`httplib_printf( conn, fmt, ... );`](api/httplib_printf.md)
* [`httplib_read( conn, buf, len );`](api/httplib_read.md) * [`httplib_read( conn, buf, len );`](api/httplib_read.md)
* [`httplib_send_file( conn, path );`](api/httplib_send_file.md) * [`httplib_send_file( conn, path, mime_type, additional_headers );`](api/httplib_send_mime_file2.md)
* [`httplib_send_mime_file( conn, path, mime_type );`](api/httplib_send_mime_file.md)
* [`httplib_send_mime_file2( conn, path, mime_type, additional_headers );`](api/httplib_send_mime_file2.md)
* [`httplib_set_request_handler( ctx, uri, handler, cbdata );`](api/httplib_set_request_handler.md) * [`httplib_set_request_handler( ctx, uri, handler, cbdata );`](api/httplib_set_request_handler.md)
* [`httplib_set_user_connection_data( conn, data );`](api/httplib_set_user_connection_data.md) * [`httplib_set_user_connection_data( conn, data );`](api/httplib_set_user_connection_data.md)
* [`httplib_store_body( conn, path );`](api/httplib_store_body.md) * [`httplib_store_body( conn, path );`](api/httplib_store_body.md)

View File

@@ -24,5 +24,4 @@ The function uses an efficient binary search algorithm, but this has implication
### See Also ### See Also
* [`httplib_send_mime_file();`](httplib_send_mime_file.md) * [`httplib_send_file();`](httplib_send_file.md)
* [`httplib_send_mime_file2();`](httplib_send_mime_file2.md)

View File

@@ -1,6 +1,6 @@
# LibHTTP API Reference # LibHTTP API Reference
### `httplib_send_mime_file2( conn, path, mime_type, additional_headers );` ### `httplib_send_file( conn, path, mime_type, additional_headers );`
### Parameters ### Parameters
@@ -17,7 +17,7 @@
### Description ### Description
The function `httplib_send_mime_file2()` can be used to send a file over a connection. The function is similar to [`httplib_send_mime_file()`](httplib_send_mime_file.md) with the additional functionality that user specified headers can be sent. The MIME type of the file can be specified in the function call, or will be automatically determined based on the extension of the filename if the `mime_type` parameter has the value NULL. The function `httplib_send_file()` can be used to send a file over a connection. The MIME type of the file can be specified in the function call, or will be automatically determined based on the extension of the filename if the `mime_type` parameter has the value NULL.
Additional custom header fields can be added as a parameter. Please make sure that these header names begin with `X-` to prevent name clashes with other headers. If the `additional_headers` parameter is NULL, no custom headers will be added. Additional custom header fields can be added as a parameter. Please make sure that these header names begin with `X-` to prevent name clashes with other headers. If the `additional_headers` parameter is NULL, no custom headers will be added.
@@ -25,6 +25,4 @@ Additional custom header fields can be added as a parameter. Please make sure th
* [`httplib_get_builtin_mime_type();`](httplib_get_builtin_mime_type.md) * [`httplib_get_builtin_mime_type();`](httplib_get_builtin_mime_type.md)
* [`httplib_printf();`](httplib_printf.md) * [`httplib_printf();`](httplib_printf.md)
* [`httplib_send_file();`](httplib_send_file.md)
* [`httplib_send_mime_file();`](httplib_send_mime_file.md)
* [`httplib_write();`](httplib_write.md) * [`httplib_write();`](httplib_write.md)

View File

@@ -589,30 +589,6 @@ enum {
LIBHTTP_API int httplib_printf(struct httplib_connection *, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); LIBHTTP_API int httplib_printf(struct httplib_connection *, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
/* Send contents of the entire file together with HTTP headers. */
LIBHTTP_API void httplib_send_file(struct httplib_connection *conn, const char *path);
/* Send contents of the entire file together with HTTP headers.
Parameters:
conn: Current connection information.
path: Full path to the file to send.
mime_type: Content-Type for file. NULL will cause the type to be
looked up by the file extension.
*/
LIBHTTP_API void httplib_send_mime_file(struct httplib_connection *conn, const char *path, const char *mime_type);
/* Send contents of the entire file together with HTTP headers.
Parameters:
conn: Current connection information.
path: Full path to the file to send.
mime_type: Content-Type for file. NULL will cause the type to be
looked up by the file extension.
additional_headers: Additional custom header fields appended to the header.
Each header must start with an X- to ensure it is not
included twice.
NULL does not append anything.
*/
LIBHTTP_API void httplib_send_mime_file2(struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers);
/* Store body data into a file. */ /* Store body data into a file. */
LIBHTTP_API int64_t httplib_store_body(struct httplib_connection *conn, const char *path); LIBHTTP_API int64_t httplib_store_body(struct httplib_connection *conn, const char *path);
@@ -964,6 +940,18 @@ LIBHTTP_API int httplib_get_response(struct httplib_connection *conn, char *ebuf
*/ */
LIBHTTP_API unsigned httplib_check_feature(unsigned feature); LIBHTTP_API unsigned httplib_check_feature(unsigned feature);
#ifndef LIBHTTP_THREAD
#if defined(_WIN32)
#define LIBHTTP_THREAD unsigned __stcall
#define LIBHTTP_THREAD_RETNULL 0
#else /* _WIN32 */
#define LIBHTTP_THREAD void *
#define LIBHTTP_THREAD_RETNULL NULL
#endif /* _WIN32 */
#endif /* LIBHTTP_THREAD */
typedef void (*httplib_alloc_callback_func)( const char *file, unsigned line, const char *action, int64_t current_bytes, int64_t total_blocks, int64_t total_bytes ); typedef void (*httplib_alloc_callback_func)( const char *file, unsigned line, const char *action, int64_t current_bytes, int64_t total_blocks, int64_t total_bytes );
#define httplib_calloc(a, b) XX_httplib_calloc_ex(a, b, __FILE__, __LINE__) #define httplib_calloc(a, b) XX_httplib_calloc_ex(a, b, __FILE__, __LINE__)
@@ -1001,6 +989,7 @@ LIBHTTP_API pthread_t httplib_pthread_self( void );
LIBHTTP_API int httplib_pthread_setspecific( pthread_key_t key, const void *value ); LIBHTTP_API int httplib_pthread_setspecific( pthread_key_t key, const void *value );
LIBHTTP_API struct dirent * httplib_readdir( DIR *dir ); LIBHTTP_API struct dirent * httplib_readdir( DIR *dir );
LIBHTTP_API int httplib_remove( const char *path ); LIBHTTP_API int httplib_remove( const char *path );
LIBHTTP_API void httplib_send_file( struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers );
LIBHTTP_API void httplib_set_alloc_callback_func( httplib_alloc_callback_func log_func ); LIBHTTP_API void httplib_set_alloc_callback_func( httplib_alloc_callback_func log_func );
LIBHTTP_API int httplib_strcasecmp( const char *s1, const char *s2 ); LIBHTTP_API int httplib_strcasecmp( const char *s1, const char *s2 );
LIBHTTP_API const char * httplib_strcasestr( const char *big_str, const char *small_str ); LIBHTTP_API const char * httplib_strcasestr( const char *big_str, const char *small_str );

View File

@@ -904,6 +904,7 @@ pid_t XX_httplib_spawn_process( struct httplib_connection *conn, const char *p
int XX_httplib_stat( struct httplib_connection *conn, const char *path, struct file *filep ); int XX_httplib_stat( struct httplib_connection *conn, const char *path, struct file *filep );
int XX_httplib_substitute_index_file( struct httplib_connection *conn, char *path, size_t path_len, struct file *filep ); int XX_httplib_substitute_index_file( struct httplib_connection *conn, char *path, size_t path_len, struct file *filep );
const char * XX_httplib_suggest_connection_header( const struct httplib_connection *conn ); const char * XX_httplib_suggest_connection_header( const struct httplib_connection *conn );
LIBHTTP_THREAD XX_httplib_websocket_client_thread( void *data );
int XX_httplib_websocket_write_exec( struct httplib_connection *conn, int opcode, const char *data, size_t dataLen, uint32_t masking_key ); int XX_httplib_websocket_write_exec( struct httplib_connection *conn, int opcode, const char *data, size_t dataLen, uint32_t masking_key );
@@ -926,14 +927,12 @@ void md5_finish( md5_state_t *pms, md5_byte_t digest[16] );
#ifdef _WIN32 #ifdef _WIN32
unsigned __stdcall XX_httplib_master_thread( void *thread_func_param ); unsigned __stdcall XX_httplib_master_thread( void *thread_func_param );
int XX_httplib_start_thread_with_id( unsigned(__stdcall *f)(void *), void *p, pthread_t *threadidptr ); int XX_httplib_start_thread_with_id( unsigned(__stdcall *f)(void *), void *p, pthread_t *threadidptr );
unsigned __stdcall XX_httplib_websocket_client_thread( void *data );
unsigned __stdcall XX_httplib_worker_thread( void *thread_func_param ); unsigned __stdcall XX_httplib_worker_thread( void *thread_func_param );
extern struct pthread_mutex_undefined_struct * XX_httplib_pthread_mutex_attr; extern struct pthread_mutex_undefined_struct * XX_httplib_pthread_mutex_attr;
#else /* _WIN32 */ #else /* _WIN32 */
void * XX_httplib_master_thread( void *thread_func_param ); void * XX_httplib_master_thread( void *thread_func_param );
int XX_httplib_start_thread_with_id( httplib_thread_func_t func, void *param, pthread_t *threadidptr ); int XX_httplib_start_thread_with_id( httplib_thread_func_t func, void *param, pthread_t *threadidptr );
void * XX_httplib_websocket_client_thread( void *data );
void * XX_httplib_worker_thread( void *thread_func_param ); void * XX_httplib_worker_thread( void *thread_func_param );
extern pthread_mutexattr_t XX_httplib_pthread_mutex_attr; extern pthread_mutexattr_t XX_httplib_pthread_mutex_attr;

View File

@@ -22,13 +22,16 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 1.9
*/ */
#include "httplib_main.h" #include "httplib_main.h"
#include "httplib_ssl.h" #include "httplib_ssl.h"
#include "httplib_utils.h" #include "httplib_utils.h"
static volatile int reload_lock = 0;
static long int data_check = 0;
/* /*
* int XX_httplib_refresh_trust( struct httplib_connection *conn ); * int XX_httplib_refresh_trust( struct httplib_connection *conn );
* *
@@ -40,35 +43,32 @@
int XX_httplib_refresh_trust( struct httplib_connection *conn ) { int XX_httplib_refresh_trust( struct httplib_connection *conn ) {
static int reload_lock = 0; volatile int *p_reload_lock;
static long int data_check = 0;
volatile int *p_reload_lock = (volatile int *)&reload_lock;
struct stat cert_buf; struct stat cert_buf;
long int t; long int t;
char *pem; char *pem;
int should_verify_peer; int should_verify_peer;
if ((pem = conn->ctx->config[SSL_CERTIFICATE]) == NULL p_reload_lock = & reload_lock;
&& conn->ctx->callbacks.init_ssl == NULL) {
return 0;
}
t = data_check; pem = conn->ctx->config[SSL_CERTIFICATE];
if (stat(pem, &cert_buf) != -1) t = (long int)cert_buf.st_mtime; if ( pem == NULL && conn->ctx->callbacks.init_ssl == NULL ) return 0;
if ( stat( pem, &cert_buf ) != -1 ) t = (long int)cert_buf.st_mtime;
else t = data_check;
if ( data_check != t ) {
if (data_check != t) {
data_check = t; data_check = t;
should_verify_peer = should_verify_peer = conn->ctx->config[SSL_DO_VERIFY_PEER] != NULL && ! httplib_strcasecmp( conn->ctx->config[SSL_DO_VERIFY_PEER], "yes" );
(conn->ctx->config[SSL_DO_VERIFY_PEER] != NULL)
&& (httplib_strcasecmp(conn->ctx->config[SSL_DO_VERIFY_PEER], "yes") if ( should_verify_peer ) {
== 0);
if (should_verify_peer) {
char *ca_path = conn->ctx->config[SSL_CA_PATH]; char *ca_path = conn->ctx->config[SSL_CA_PATH];
char *ca_file = conn->ctx->config[SSL_CA_FILE]; char *ca_file = conn->ctx->config[SSL_CA_FILE];
if (SSL_CTX_load_verify_locations(conn->ctx->ssl_ctx, ca_file, ca_path) != 1) {
if ( SSL_CTX_load_verify_locations( conn->ctx->ssl_ctx, ca_file, ca_path ) != 1 ) {
httplib_cry( XX_httplib_fc(conn->ctx), httplib_cry( XX_httplib_fc(conn->ctx),
"SSL_CTX_load_verify_locations error: %s " "SSL_CTX_load_verify_locations error: %s "
@@ -76,18 +76,24 @@ int XX_httplib_refresh_trust( struct httplib_connection *conn ) {
"either ssl_ca_path or ssl_ca_file. Is any of them " "either ssl_ca_path or ssl_ca_file. Is any of them "
"present in " "present in "
"the .conf file?", "the .conf file?",
XX_httplib_ssl_error()); XX_httplib_ssl_error() );
return 0; return 0;
} }
} }
if (1 == httplib_atomic_inc(p_reload_lock)) { if ( httplib_atomic_inc( p_reload_lock ) == 1 ) {
if (XX_httplib_ssl_use_pem_file(conn->ctx, pem) == 0) return 0;
if ( XX_httplib_ssl_use_pem_file( conn->ctx, pem ) == 0 ) return 0;
*p_reload_lock = 0; *p_reload_lock = 0;
} }
} }
/* lock while cert is reloading */
while (*p_reload_lock) sleep(1); /*
* lock while cert is reloading
*/
while ( *p_reload_lock ) sleep( 1 );
return 1; return 1;

View File

@@ -22,12 +22,19 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
#include "httplib_string.h" #include "httplib_string.h"
/*
* int XX_httplib_remove_directory( struct httplib_connection *conn, const char *dir );
*
* The function XX_httplib_remove_directory() removes recirsively a directory
* tree.
*/
int XX_httplib_remove_directory( struct httplib_connection *conn, const char *dir ) { int XX_httplib_remove_directory( struct httplib_connection *conn, const char *dir ) {
char path[PATH_MAX]; char path[PATH_MAX];
@@ -35,53 +42,76 @@ int XX_httplib_remove_directory( struct httplib_connection *conn, const char *di
DIR *dirp; DIR *dirp;
struct de de; struct de de;
int truncated; int truncated;
int ok = 1; int ok;
ok = 1;
dirp = httplib_opendir( dir );
if ( dirp == NULL ) return 0;
if ((dirp = httplib_opendir( dir )) == NULL) {
return 0;
} else {
de.conn = conn; de.conn = conn;
while ((dp = httplib_readdir(dirp)) != NULL) { while ( (dp = httplib_readdir( dirp )) != NULL ) {
/* Do not show current dir (but show hidden files as they will
* also be removed) */
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
XX_httplib_snprintf( conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name); /*
* Do not show current dir (but show hidden files as they will
* also be removed)
*/
/* If we don't memset stat structure to zero, mtime will have if ( ! strcmp( dp->d_name, "." ) || ! strcmp( dp->d_name, ".." ) ) continue;
XX_httplib_snprintf( conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name );
/*
* If we don't memset stat structure to zero, mtime will have
* garbage and strftime() will segfault later on in * garbage and strftime() will segfault later on in
* XX_httplib_print_dir_entry(). memset is required only if XX_httplib_stat() * XX_httplib_print_dir_entry(). memset is required only if XX_httplib_stat()
* fails. For more details, see * fails. For more details, see
* http://code.google.com/p/mongoose/issues/detail?id=79 */ * http://code.google.com/p/mongoose/issues/detail?id=79
memset(&de.file, 0, sizeof(de.file)); */
memset( & de.file, 0, sizeof(de.file) );
if ( truncated ) {
/*
* Do not delete anything shorter
*/
if (truncated) {
/* Do not delete anything shorter */
ok = 0; ok = 0;
continue; continue;
} }
if (!XX_httplib_stat(conn, path, &de.file)) { if ( ! XX_httplib_stat( conn, path, & de.file ) ) {
httplib_cry(conn, "%s: XX_httplib_stat(%s) failed: %s", __func__, path, strerror(ERRNO));
ok = 0;
}
if (de.file.membuf == NULL) {
/* file is not in memory */
if (de.file.is_directory) {
if (XX_httplib_remove_directory(conn, path) == 0) ok = 0;
} else {
if (httplib_remove( path ) == 0) ok = 0;
}
} else {
/* file is in memory. It can not be deleted. */
ok = 0;
}
}
httplib_closedir(dirp);
IGNORE_UNUSED_RESULT(rmdir(dir)); httplib_cry( conn, "%s: XX_httplib_stat(%s) failed: %s", __func__, path, strerror(ERRNO) );
ok = 0;
} }
if ( de.file.membuf == NULL ) {
/*
* file is not in memory
*/
if ( de.file.is_directory ) {
if ( XX_httplib_remove_directory( conn, path ) == 0 ) ok = 0;
}
else if ( httplib_remove( path ) == 0 ) ok = 0;
}
else {
/*
* file is in memory. It can not be deleted.
*/
ok = 0;
}
}
httplib_closedir( dirp );
rmdir( dir );
return ok; return ok;

View File

@@ -22,32 +22,46 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
/* Protect against directory disclosure attack by removing '..', /*
* excessive '/' and '\' characters */ * void XX_httplib_remove_double_dots_and_double_slashes( char *s );
*
* The function XX_httplib_remove_double_dots_and_double_slashes() removes
* '..' instances and excessive '/' and `\` characters to protext against
* directory disclosure attacks.
*/
void XX_httplib_remove_double_dots_and_double_slashes( char *s ) { void XX_httplib_remove_double_dots_and_double_slashes( char *s ) {
char *p = s; char *p;
while ((s[0] == '.') && (s[1] == '.')) s++; p = s;
while ( s[0] == '.' && s[1] == '.' ) s++;
while ( *s != '\0' ) {
while (*s != '\0') {
*p++ = *s++; *p++ = *s++;
if (s[-1] == '/' || s[-1] == '\\') {
/* Skip all following slashes, backslashes and double-dots */ if ( s[-1] == '/' || s[-1] == '\\' ) {
while (s[0] != '\0') {
if (s[0] == '/' || s[0] == '\\') { /*
s++; * Skip all following slashes, backslashes and double-dots
} else if (s[0] == '.' && s[1] == '.') { */
s += 2;
} else break; while ( s[0] != '\0' ) {
if ( s[0] == '/' || s[0] == '\\' ) s++;
else if ( s[0] == '.' && s[1] == '.' ) s += 2;
else break;
} }
} }
} }
*p = '\0'; *p = '\0';
} /* XX_httplib_remove_double_dots_and_double_slashes */ } /* XX_httplib_remove_double_dots_and_double_slashes */

View File

@@ -22,7 +22,7 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"

View File

@@ -22,40 +22,36 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
void httplib_send_file( struct httplib_connection *conn, const char *path ) { /*
* void httplib_send_file( struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers );
*
* The function httplib_send_file() sends a file to the other peer. Optionally
* the MIME type and additional headers can be specified.
*/
httplib_send_mime_file( conn, path, NULL ); void httplib_send_file( struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers ) {
} /* httplib_send_file */
void httplib_send_mime_file( struct httplib_connection *conn, const char *path, const char *mime_type ) {
httplib_send_mime_file2( conn, path, mime_type, NULL );
} /* httplib_send_mime_file */
void httplib_send_mime_file2( struct httplib_connection *conn, const char *path, const char *mime_type, const char *additional_headers ) {
struct file file = STRUCT_FILE_INITIALIZER; struct file file = STRUCT_FILE_INITIALIZER;
if (XX_httplib_stat(conn, path, &file)) { if ( XX_httplib_stat( conn, path, &file ) ) {
if (file.is_directory) {
if ( conn == NULL ) return;
if (!httplib_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
XX_httplib_handle_directory_request(conn, path);
} else {
XX_httplib_send_http_error(conn, 403, "%s", "Error: Directory listing denied");
}
} else {
XX_httplib_handle_static_file_request( conn, path, &file, mime_type, additional_headers);
}
} else XX_httplib_send_http_error(conn, 404, "%s", "Error: File not found");
} /* httplib_send_mime_file2 */ if ( file.is_directory ) {
if ( conn == NULL ) return;
if ( ! httplib_strcasecmp( conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes" ) ) XX_httplib_handle_directory_request( conn, path );
else XX_httplib_send_http_error( conn, 403, "%s", "Error: Directory listing denied" );
}
else XX_httplib_handle_static_file_request( conn, path, &file, mime_type, additional_headers );
}
else XX_httplib_send_http_error( conn, 404, "%s", "Error: File not found" );
} /* httplib_send_file */

View File

@@ -22,31 +22,37 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
/*
* int XX_httplib_set_non_block_mode( SOCKET sock );
*
* The function XX_httplib_set_non_blocking_mode() is an internal function to
* set a socket in non blocking mode, independent of the platform where the
* program is running on.
*/
int XX_httplib_set_non_blocking_mode( SOCKET sock ) {
#if defined(_WIN32) #if defined(_WIN32)
int XX_httplib_set_non_blocking_mode( SOCKET sock ) { unsigned long on;
unsigned long on = 1; on = 1;
return ioctlsocket( sock, (long)FIONBIO, &on ); return ioctlsocket( sock, (long)FIONBIO, & on );
} /* XX_httplib_set_non_blocking_mode */ #else /* _WIN32 */
#else
int XX_httplib_set_non_blocking_mode( SOCKET sock ) {
int flags; int flags;
flags = fcntl(sock, F_GETFL, 0); flags = fcntl( sock, F_GETFL, 0 );
fcntl( sock, F_SETFL, flags | O_NONBLOCK ); fcntl( sock, F_SETFL, flags | O_NONBLOCK );
return 0; return 0;
} /* XX_httplib_set_non_blocking_mode */
#endif /* _WIN32 */ #endif /* _WIN32 */
} /* XX_httplib_set_non_blocking_mode */

View File

@@ -22,13 +22,19 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
/* Simplified version of XX_httplib_skip_quoted without quote char /*
* and whitespace == delimiters */ * char *XX_httplib_skip( char **buf, const char *delimiters );
*
* The function XX_httplib_skip is a simplified version of the function
* XX_httplib_skip_quoted() without a quote char and where delimiters are only
* whitespace.
*/
char *XX_httplib_skip( char **buf, const char *delimiters ) { char *XX_httplib_skip( char **buf, const char *delimiters ) {
return XX_httplib_skip_quoted( buf, delimiters, delimiters, 0 ); return XX_httplib_skip_quoted( buf, delimiters, delimiters, 0 );

View File

@@ -22,18 +22,26 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
#include "httplib_string.h" #include "httplib_string.h"
/*
* void XX_httplib_snprintf( const struct httplib_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, ... );
*
* The function XX_httplib_snprintf() is an internal function to send a string
* to a connection. The string can be formated with a format string and
* parameters in the same way as the snprintf function works.
*/
void XX_httplib_snprintf( const struct httplib_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, ... ) { void XX_httplib_snprintf( const struct httplib_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, ... ) {
va_list ap; va_list ap;
va_start(ap, fmt); va_start( ap, fmt );
XX_httplib_vsnprintf(conn, truncated, buf, buflen, fmt, ap); XX_httplib_vsnprintf( conn, truncated, buf, buflen, fmt, ap );
va_end(ap); va_end( ap );
} /* XX_httplib_snprintf */ } /* XX_httplib_snprintf */

View File

@@ -22,7 +22,7 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
@@ -45,7 +45,7 @@ void XX_httplib_ssl_locking_callback( int mode, int mutex_num, const char *file,
UNUSED_PARAMETER(line); UNUSED_PARAMETER(line);
UNUSED_PARAMETER(file); UNUSED_PARAMETER(file);
if ( mode & 1 ) httplib_pthread_mutex_lock( & XX_httplib_ssl_mutexes[mutex_num] ); if ( mode & 0x0001 ) httplib_pthread_mutex_lock( & XX_httplib_ssl_mutexes[mutex_num] );
else httplib_pthread_mutex_unlock( & XX_httplib_ssl_mutexes[mutex_num] ); else httplib_pthread_mutex_unlock( & XX_httplib_ssl_mutexes[mutex_num] );
} /* XX_httplib_ssl_locking_callback */ } /* XX_httplib_ssl_locking_callback */

View File

@@ -22,46 +22,49 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
#if ! defined(USE_STACK_SIZE) || (USE_STACK_SIZE <= 0)
#undef USE_STACK_SIZE
#define USE_STACK_SIZE 0
#endif /* USE_STACK_SIZE */
/*
* int httplib_start_thread( httplib_thread_func_t func, void *param );
*
* The functiom httplib_start_thread() is a convenience function to help to
* start a detached thread. The function returns 0 if successful, or a non-zero
* value if an error occurs. An optional pointer parameter can be passed to the
* newly created thread.
*/
int httplib_start_thread( httplib_thread_func_t func, void *param ) {
#if defined(_WIN32) #if defined(_WIN32)
int httplib_start_thread(httplib_thread_func_t f, void *p) { return ( (_beginthread( (void(__cdecl *)(void *))func, USE_STACK_SIZE, param ) == ((uintptr_t)(-1L))) ? -1 : 0 );
#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) #else /* _WIN32 */
/* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
*/
return ((_beginthread((void(__cdecl *)(void *))f, USE_STACK_SIZE, p) == ((uintptr_t)(-1L))) ? -1 : 0);
#else
return ( (_beginthread((void(__cdecl *)(void *))f, 0, p) == ((uintptr_t)(-1L))) ? -1 : 0);
#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
} /* httplib_start_thread */
#else
int httplib_start_thread(httplib_thread_func_t func, void *param) {
pthread_t thread_id; pthread_t thread_id;
pthread_attr_t attr; pthread_attr_t attr;
int result; int result;
pthread_attr_init(&attr); pthread_attr_init( & attr );
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate( & attr, PTHREAD_CREATE_DETACHED );
#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) #if (USE_STACK_SIZE > 1)
/* Compile-time option to control stack size, pthread_attr_setstacksize( & attr, USE_STACK_SIZE );
* e.g. -DUSE_STACK_SIZE=16384 */ #endif /* USE_STACK_SIZE > 1 */
pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
result = pthread_create(&thread_id, &attr, func, param); result = pthread_create( & thread_id, &attr, func, param );
pthread_attr_destroy(&attr); pthread_attr_destroy( & attr );
return result; return result;
} /* httplib_start_thread */
#endif /* _WIN32 */ #endif /* _WIN32 */
} /* httplib_start_thread */

View File

@@ -22,7 +22,7 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"

View File

@@ -22,48 +22,47 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
#include "httplib_memory.h" #include "httplib_memory.h"
/* /*
* ... XX_httplib_websocket_client_thread( void *data ); * LIBHTTP_THREAD XX_httplib_websocket_client_thread( void *data );
* *
* The function XX_httplib_websocket_client_thread() is the worker thread which * The function XX_httplib_websocket_client_thread() is the worker thread which
* connects as a client to a remote websocket server. * connects as a client to a remote websocket server.
*/ */
#if defined(USE_WEBSOCKET) #if defined(USE_WEBSOCKET)
#ifdef _WIN32
unsigned __stdcall XX_httplib_websocket_client_thread( void *data ) {
#else /* _WIN32 */
void * XX_httplib_websocket_client_thread(void *data) {
#endif /* _WIN32 */
struct websocket_client_thread_data *cdata = (struct websocket_client_thread_data *)data;
XX_httplib_set_thread_name("ws-client"); LIBHTTP_THREAD XX_httplib_websocket_client_thread( void *data ) {
if (cdata->conn->ctx) { struct websocket_client_thread_data *cdata;
if (cdata->conn->ctx->callbacks.init_thread) {
/* 3 indicates a websocket client thread */ cdata = data;
/* TODO: check if conn->ctx can be set */
cdata->conn->ctx->callbacks.init_thread(cdata->conn->ctx, 3); XX_httplib_set_thread_name( "ws-client" );
}
if ( cdata->conn->ctx != NULL ) {
/*
* 3 indicates a websocket client thread
* TODO: check if conn->ctx can be set
*/
if ( cdata->conn->ctx->callbacks.init_thread != NULL ) cdata->conn->ctx->callbacks.init_thread( cdata->conn->ctx, 3 );
} }
XX_httplib_read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data); XX_httplib_read_websocket( cdata->conn, cdata->data_handler, cdata->callback_data );
if (cdata->close_handler != NULL) cdata->close_handler(cdata->conn, cdata->callback_data); if ( cdata->close_handler != NULL ) cdata->close_handler( cdata->conn, cdata->callback_data );
httplib_free( cdata ); httplib_free( cdata );
return LIBHTTP_THREAD_RETNULL;
#ifdef _WIN32
return 0;
#else /* _WIN32 */
return NULL;
#endif /* _WIN32 */
} /* XX_httplib_websocket_client_thread */ } /* XX_httplib_websocket_client_thread */
#endif
#endif /* USE_WEBSOCKET */

View File

@@ -22,7 +22,7 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
@@ -36,23 +36,28 @@ static void mask_data( const char *in, size_t in_len, uint32_t masking_key, char
/* /*
* int httplib_websocket_client_write( struct httplib_connection *conn, int opcode, const char *data, size_t dataLen ); * int httplib_websocket_client_write( struct httplib_connection *conn, int opcode, const char *data, size_t dataLen );
* *
* The function httplib_websocket_client_write() is used to write as a client to a * The function httplib_websocket_client_write() is used to write as a client
* websocket server. * to a websocket server. The function returns -1 if an error occures,
* otherwise the amount of bytes written.
*/ */
int httplib_websocket_client_write( struct httplib_connection *conn, int opcode, const char *data, size_t dataLen ) { int httplib_websocket_client_write( struct httplib_connection *conn, int opcode, const char *data, size_t dataLen ) {
int retval = -1; int retval;
char *masked_data = httplib_malloc( ((dataLen + 7) / 4) * 4 ); char *masked_data;
uint32_t masking_key = (uint32_t)XX_httplib_get_random(); uint32_t masking_key;
if (masked_data == NULL) { retval = -1;
/* Return -1 in an error case */ masked_data = httplib_malloc( ((dataLen + 7) / 4) * 4 );
httplib_cry(conn, "Cannot allocate buffer for masked websocket response: Out of memory"); masking_key = (uint32_t) XX_httplib_get_random();
if ( masked_data == NULL ) {
httplib_cry( conn, "Cannot allocate buffer for masked websocket response: Out of memory" );
return -1; return -1;
} }
mask_data(data, dataLen, masking_key, masked_data); mask_data( data, dataLen, masking_key, masked_data );
retval = XX_httplib_websocket_write_exec( conn, opcode, masked_data, dataLen, masking_key ); retval = XX_httplib_websocket_write_exec( conn, opcode, masked_data, dataLen, masking_key );
httplib_free( masked_data ); httplib_free( masked_data );
@@ -61,8 +66,6 @@ int httplib_websocket_client_write( struct httplib_connection *conn, int opcode,
} /* httplib_websocket_client_write */ } /* httplib_websocket_client_write */
/* /*
* static void mask_data( const char *in, size_t in_len, uint32_t masking_key, char *out ); * static void mask_data( const char *in, size_t in_len, uint32_t masking_key, char *out );
* *
@@ -72,19 +75,30 @@ int httplib_websocket_client_write( struct httplib_connection *conn, int opcode,
static void mask_data( const char *in, size_t in_len, uint32_t masking_key, char *out ) { static void mask_data( const char *in, size_t in_len, uint32_t masking_key, char *out ) {
size_t i = 0; size_t i;
i = 0; i = 0;
if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
/* Convert in 32 bit words, if data is 4 byte aligned */ if ( in_len > 3 && ((ptrdiff_t)in % 4) == 0 ) {
while (i < (in_len - 3)) {
/*
* Convert in 32 bit words, if data is 4 byte aligned
*/
while ( i+3 < in_len ) {
*(uint32_t *)(void *)(out + i) = *(uint32_t *)(void *)(in + i) ^ masking_key; *(uint32_t *)(void *)(out + i) = *(uint32_t *)(void *)(in + i) ^ masking_key;
i += 4; i += 4;
} }
} }
if (i != in_len) { if ( i != in_len ) {
/* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
while (i < in_len) { /*
* convert 1-3 remaining bytes if ((dataLen % 4) != 0)
*/
while ( i < in_len ) {
*(uint8_t *)(void *)(out + i) = *(uint8_t *)(void *)(in + i) ^ *(((uint8_t *)&masking_key) + (i % 4)); *(uint8_t *)(void *)(out + i) = *(uint8_t *)(void *)(in + i) ^ *(((uint8_t *)&masking_key) + (i % 4));
i++; i++;
} }
@@ -92,5 +106,4 @@ static void mask_data( const char *in, size_t in_len, uint32_t masking_key, char
} /* mask_data */ } /* mask_data */
#endif /* !USE_WEBSOCKET */ #endif /* !USE_WEBSOCKET */

View File

@@ -22,7 +22,7 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"

View File

@@ -22,13 +22,13 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
/* /*
* int XX_httplib_websocket_write_exec( struct httplib_connection *conn, int opcode, const char *data, size_t dataLen, uint32_t masking_key ); * int XX_httplib_websocket_write_exec( struct httplib_connection *conn, int opcode, const char *data, size_t data_len, uint32_t masking_key );
* *
* The function XX_httplib_websocket_write_exec() does the heavy lifting in * The function XX_httplib_websocket_write_exec() does the heavy lifting in
* writing data over a websocket connectin to a remote peer. * writing data over a websocket connectin to a remote peer.
@@ -36,53 +36,84 @@
#if defined(USE_WEBSOCKET) #if defined(USE_WEBSOCKET)
int XX_httplib_websocket_write_exec( struct httplib_connection *conn, int opcode, const char *data, size_t dataLen, uint32_t masking_key ) { int XX_httplib_websocket_write_exec( struct httplib_connection *conn, int opcode, const char *data, size_t data_len, uint32_t masking_key ) {
unsigned char header[14]; unsigned char header[14];
size_t headerLen = 1; size_t header_len;
int retval;
int retval = -1; uint16_t len;
uint32_t len1;
uint32_t len2;
retval = -1;
header_len = 1;
header[0] = 0x80 + (opcode & 0xF); header[0] = 0x80 + (opcode & 0xF);
/* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */ /*
if (dataLen < 126) { * Frame format: http://tools.ietf.org/html/rfc6455#section-5.2
/* inline 7-bit length field */ */
header[1] = (unsigned char)dataLen;
headerLen = 2; if ( data_len < 126 ) {
} else if (dataLen <= 0xFFFF) {
/* 16-bit length field */ /*
uint16_t len = htons((uint16_t)dataLen); * inline 7-bit length field
*/
header[1] = (unsigned char)data_len;
header_len = 2;
}
else if ( data_len <= 65535 ) {
/*
* 16-bit length field
*/
len = htons( (uint16_t)data_len );
header[1] = 126; header[1] = 126;
memcpy(header + 2, &len, 2); header_len = 4;
headerLen = 4; memcpy( header+2, & len, 2 );
} else { }
/* 64-bit length field */
uint32_t len1 = htonl((uint64_t)dataLen >> 32); else {
uint32_t len2 = htonl(dataLen & 0xFFFFFFFF); /*
* 64-bit length field
*/
len1 = htonl( (uint64_t)data_len >> 32 );
len2 = htonl( data_len & 0xFFFFFFFF );
header[1] = 127; header[1] = 127;
memcpy(header + 2, &len1, 4); header_len = 10;
memcpy(header + 6, &len2, 4); memcpy( header + 2, & len1, 4 );
headerLen = 10; memcpy( header + 6, & len2, 4 );
} }
if (masking_key) { if ( masking_key ) {
/* add mask */
/*
* add mask
*/
header[1] |= 0x80; header[1] |= 0x80;
memcpy(header + headerLen, &masking_key, 4); memcpy( header + header_len, & masking_key, 4 );
headerLen += 4; header_len += 4;
} }
/* Note that POSIX/Winsock's send() is threadsafe /*
* Note that POSIX/Winsock's send() is threadsafe
* http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
* but mongoose's httplib_printf/httplib_write is not (because of the loop in * but LibHTTP's httplib_printf/httplib_write is not (because of the loop in
* push(), although that is only a problem if the packet is large or * push(), although that is only a problem if the packet is large or
* outgoing buffer is full). */ * outgoing buffer is full).
httplib_lock_connection(conn); */
retval = httplib_write(conn, header, headerLen);
if (dataLen > 0) retval = httplib_write(conn, data, dataLen); httplib_lock_connection( conn );
httplib_unlock_connection(conn);
retval = httplib_write( conn, header, header_len );
if ( data_len > 0 ) retval = httplib_write( conn, data, data_len );
httplib_unlock_connection( conn );
return retval; return retval;

View File

@@ -22,57 +22,76 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
int httplib_write( struct httplib_connection *conn, const void *buf, size_t len ) { /*
* The function httplib_write() writes a number of characters 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.
*/
int httplib_write( struct httplib_connection *conn, const void *buffie, size_t lennie ) {
time_t now; time_t now;
int64_t n; int64_t n;
int64_t len;
int64_t total; int64_t total;
int64_t allowed; int64_t allowed;
const char *buf;
if (conn == NULL) return 0; if ( conn == NULL || buffie == NULL || lennie == 0 ) return 0;
buf = buffie;
len = (int64_t)lennie;
if ( conn->throttle > 0 ) {
now = time( NULL );
if ( now != conn->last_throttle_time ) {
if (conn->throttle > 0) {
if ((now = time(NULL)) != conn->last_throttle_time) {
conn->last_throttle_time = now; conn->last_throttle_time = now;
conn->last_throttle_bytes = 0; conn->last_throttle_bytes = 0;
} }
allowed = conn->throttle - conn->last_throttle_bytes; allowed = conn->throttle - conn->last_throttle_bytes;
if (allowed > (int64_t)len) allowed = (int64_t)len; if ( allowed > len ) allowed = len;
if ((total = XX_httplib_push_all(conn->ctx,
NULL, total = XX_httplib_push_all( conn->ctx, NULL, conn->client.sock, conn->ssl, buf, allowed );
conn->client.sock,
conn->ssl, if ( total == allowed ) {
(const char *)buf,
(int64_t)allowed)) == allowed) { buf = buf + total;
buf = (const char *)buf + total;
conn->last_throttle_bytes += total; conn->last_throttle_bytes += total;
while (total < (int64_t)len && conn->ctx->stop_flag == 0) {
allowed = (conn->throttle > ((int64_t)len - total)) while ( total < len && conn->ctx->stop_flag == 0 ) {
? (int64_t)len - total
: conn->throttle; if ( conn->throttle > len-total ) allowed = len-total;
if ((n = XX_httplib_push_all(conn->ctx, else allowed = conn->throttle;
NULL,
conn->client.sock, n = XX_httplib_push_all( conn->ctx, NULL, conn->client.sock, conn->ssl, buf, allowed );
conn->ssl, if ( n != allowed ) {
(const char *)buf,
(int64_t)allowed)) != allowed) { if ( n > 0 ) total += n;
break; break;
} }
sleep(1);
sleep( 1 );
conn->last_throttle_bytes = allowed; conn->last_throttle_bytes = allowed;
conn->last_throttle_time = time(NULL); conn->last_throttle_time = time( NULL );
buf = (const char *)buf + n; buf = buf + n;
total += n; total += n;
} }
} }
} }
else total = XX_httplib_push_all(conn->ctx, NULL, conn->client.sock, conn->ssl, (const char *)buf, (int64_t)len); else total = XX_httplib_push_all( conn->ctx, NULL, conn->client.sock, conn->ssl, buf, len );
return (int)total; return (int)total;