mirror of
https://github.com/lammertb/libhttp.git
synced 2026-01-27 08:02:47 +03:00
Code cleanup
This commit is contained in:
4
Makefile
4
Makefile
@@ -253,7 +253,7 @@ OBJLIST = \
|
||||
${OBJDIR}httplib_is_valid_http_method${OBJEXT} \
|
||||
${OBJDIR}httplib_is_valid_port${OBJEXT} \
|
||||
${OBJDIR}httplib_is_websocket_protocol${OBJEXT} \
|
||||
${OBJDIR}httplib_join_thread${OBJEXT} \
|
||||
${OBJDIR}httplib_pthread_join${OBJEXT} \
|
||||
${OBJDIR}httplib_kill${OBJEXT} \
|
||||
${OBJDIR}httplib_load_dll${OBJEXT} \
|
||||
${OBJDIR}httplib_lock_unlock_connection${OBJEXT} \
|
||||
@@ -817,7 +817,7 @@ ${OBJDIR}httplib_is_websocket_protocol${OBJEXT} : ${SRCDIR}httplib_is_websock
|
||||
${SRCDIR}httplib_main.h \
|
||||
${INCDIR}libhttp.h
|
||||
|
||||
${OBJDIR}httplib_join_thread${OBJEXT} : ${SRCDIR}httplib_join_thread.c \
|
||||
${OBJDIR}httplib_pthread_join${OBJEXT} : ${SRCDIR}httplib_pthread_join.c \
|
||||
${SRCDIR}httplib_main.h \
|
||||
${INCDIR}libhttp.h
|
||||
|
||||
|
||||
@@ -22,44 +22,51 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
/*
|
||||
* int httplib_pthread_join( pthread_t thread, void **value_ptr );
|
||||
*
|
||||
* The platform independent function httplib_pthread_join() suspends the
|
||||
* current thread and waits until another thread has terminated. Succes is
|
||||
* returned with 0, while an error code is returned otherwise. The function is
|
||||
* a wrapper around pthread_join() on systems which support it, or own code
|
||||
* which emulates the same functionality otherwise.
|
||||
*
|
||||
* On systems which do not support pthread_join() natively, the value_ptr
|
||||
* parameter is ignored.
|
||||
*/
|
||||
|
||||
/* Wait for a thread to finish. */
|
||||
int XX_httplib_join_thread( pthread_t threadid ) {
|
||||
int httplib_pthread_join( pthread_t thread, void **value_ptr ) {
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
int result;
|
||||
DWORD dwevent;
|
||||
|
||||
result = -1;
|
||||
dwevent = WaitForSingleObject(threadid, INFINITE);
|
||||
if (dwevent == WAIT_FAILED) {
|
||||
} else {
|
||||
if (dwevent == WAIT_OBJECT_0) {
|
||||
CloseHandle(threadid);
|
||||
result = 0;
|
||||
}
|
||||
UNUSED_PARAMETER(value_ptr);
|
||||
|
||||
result = -1;
|
||||
dwevent = WaitForSingleObject( threadid, INFINITE );
|
||||
|
||||
if ( dwevent == WAIT_FAILED ) {
|
||||
}
|
||||
|
||||
else if ( dwevent == WAIT_OBJECT_0 ) {
|
||||
|
||||
CloseHandle( threadid );
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} /* XX_httplib_join_thread */
|
||||
#else /* _WIN32 */
|
||||
|
||||
#else
|
||||
return pthread_join( thread, value_ptr );
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* Wait for a thread to finish. */
|
||||
int XX_httplib_join_thread( pthread_t threadid ) {
|
||||
|
||||
int result;
|
||||
|
||||
result = pthread_join(threadid, NULL);
|
||||
return result;
|
||||
|
||||
} /* XX_httplib_join_thread */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
} /* httplib_pthread_join */
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -36,38 +36,44 @@ int XX_httplib_scan_directory( struct httplib_connection *conn, const char *dir,
|
||||
struct de de;
|
||||
int truncated;
|
||||
|
||||
if ((dirp = httplib_opendir( dir)) == NULL) {
|
||||
return 0;
|
||||
} else {
|
||||
de.conn = conn;
|
||||
dirp = httplib_opendir( dir );
|
||||
if ( dirp == NULL ) return 0;
|
||||
|
||||
while ((dp = httplib_readdir(dirp)) != NULL) {
|
||||
/* Do not show current dir and hidden files */
|
||||
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") || XX_httplib_must_hide_file(conn, dp->d_name)) continue;
|
||||
de.conn = conn;
|
||||
|
||||
XX_httplib_snprintf( conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
|
||||
while ( (dp = httplib_readdir(dirp)) != NULL ) {
|
||||
|
||||
/* If we don't memset stat structure to zero, mtime will have
|
||||
* garbage and strftime() will segfault later on in
|
||||
* XX_httplib_print_dir_entry(). memset is required only if XX_httplib_stat()
|
||||
* fails. For more details, see
|
||||
* http://code.google.com/p/mongoose/issues/detail?id=79 */
|
||||
memset(&de.file, 0, sizeof(de.file));
|
||||
/*
|
||||
* Do not show current dir and hidden files
|
||||
*/
|
||||
|
||||
if (truncated) {
|
||||
/* If the path is not complete, skip processing. */
|
||||
continue;
|
||||
}
|
||||
if ( ! strcmp( dp->d_name, "." ) || ! strcmp(dp->d_name, "..") || XX_httplib_must_hide_file( conn, dp->d_name ) ) continue;
|
||||
|
||||
if (!XX_httplib_stat(conn, path, &de.file)) {
|
||||
httplib_cry(conn, "%s: XX_httplib_stat(%s) failed: %s", __func__, path, strerror(ERRNO));
|
||||
}
|
||||
de.file_name = dp->d_name;
|
||||
cb(&de, data);
|
||||
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
|
||||
* XX_httplib_print_dir_entry(). memset is required only if XX_httplib_stat()
|
||||
* fails. For more details, see
|
||||
* http://code.google.com/p/mongoose/issues/detail?id=79
|
||||
*/
|
||||
|
||||
memset( &de.file, 0, sizeof(de.file) );
|
||||
|
||||
if ( truncated ) continue; /* If the path is not complete, skip processing. */
|
||||
|
||||
if ( ! XX_httplib_stat( conn, path, &de.file ) ) {
|
||||
|
||||
httplib_cry( conn, "%s: XX_httplib_stat(%s) failed: %s", __func__, path, strerror(ERRNO) );
|
||||
}
|
||||
|
||||
httplib_closedir(dirp);
|
||||
de.file_name = dp->d_name;
|
||||
cb( &de, data );
|
||||
}
|
||||
|
||||
httplib_closedir( dirp );
|
||||
|
||||
return 1;
|
||||
|
||||
} /* XX_httplib_scan_directory */
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -38,18 +38,28 @@ void httplib_stop( struct httplib_context *ctx ) {
|
||||
|
||||
pthread_t mt;
|
||||
|
||||
if ( ctx == NULL ) return;
|
||||
/* We don't use a lock here. Calling httplib_stop with the same ctx from
|
||||
* two threads is not allowed. */
|
||||
if ( ctx == NULL ) return;
|
||||
|
||||
/*
|
||||
* We don't use a lock here. Calling httplib_stop with the same ctx from
|
||||
* two threads is not allowed.
|
||||
*/
|
||||
|
||||
mt = ctx->masterthreadid;
|
||||
if ( mt == 0 ) return;
|
||||
|
||||
ctx->masterthreadid = 0;
|
||||
|
||||
/* Set stop flag, so all threads know they have to exit. */
|
||||
/*
|
||||
* Set stop flag, so all threads know they have to exit.
|
||||
*/
|
||||
|
||||
ctx->stop_flag = 1;
|
||||
|
||||
/* Wait until everything has stopped. */
|
||||
/*
|
||||
* Wait until everything has stopped.
|
||||
*/
|
||||
|
||||
while ( ctx->stop_flag != 2 ) httplib_sleep( 10 );
|
||||
|
||||
XX_httplib_join_thread( mt );
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -52,12 +52,19 @@ int64_t httplib_store_body( struct httplib_connection *conn, const char *path )
|
||||
ret = XX_httplib_put_dir( conn, path );
|
||||
if ( ret < 0 ) {
|
||||
|
||||
/* -1 for path too long,
|
||||
* -2 for path can not be created. */
|
||||
/*
|
||||
* -1 for path too long,
|
||||
* -2 for path can not be created.
|
||||
*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
if ( ret != 1 ) {
|
||||
/* Return 0 means, path itself is a directory. */
|
||||
|
||||
/*
|
||||
* Return 0 means, path itself is a directory.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,59 +22,86 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
#include "httplib_string.h"
|
||||
|
||||
/*
|
||||
* int XX_httplib_substitute_index_file( struct httplib_connection *conn, char *path, size_t path_len, struct file *filep );
|
||||
* bool XX_httplib_substitute_index_file( struct httplib_connection *conn, char *path, size_t path_len, struct file *filep );
|
||||
*
|
||||
* The function XX_httplib_substiture_index_file() tries to find an index file
|
||||
* matching a given directory path. The function returns 1 of an index file has
|
||||
* been found and 0 if the file could not be found. If a file could be located,
|
||||
* it's stats are returnd in stp.
|
||||
* matching a given directory path. The function returns true of an index file
|
||||
* has been found and false if the file could not be found. If a file could be
|
||||
* located, it's stats are returnd in stp.
|
||||
*/
|
||||
|
||||
#if !defined(NO_FILES)
|
||||
|
||||
int XX_httplib_substitute_index_file( struct httplib_connection *conn, char *path, size_t path_len, struct file *filep ) {
|
||||
|
||||
if ( conn == NULL || conn->ctx == NULL ) return 0;
|
||||
|
||||
const char *list = conn->ctx->config[INDEX_FILES];
|
||||
const char *list;
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
struct vec filename_vec;
|
||||
size_t n = strlen(path);
|
||||
int found = 0;
|
||||
size_t n;
|
||||
bool found;
|
||||
|
||||
/* The 'path' given to us points to the directory. Remove all trailing
|
||||
if ( conn == NULL || conn->ctx == NULL || path == NULL ) return 0;
|
||||
|
||||
list = conn->ctx->config[INDEX_FILES];
|
||||
n = strlen( path );
|
||||
found = false;
|
||||
|
||||
/*
|
||||
* The 'path' given to us points to the directory. Remove all trailing
|
||||
* directory separator characters from the end of the path, and
|
||||
* then append single directory separator character. */
|
||||
while (n > 0 && path[n - 1] == '/') n--;
|
||||
* then append single directory separator character.
|
||||
*/
|
||||
|
||||
while ( n > 0 && path[n - 1] == '/' ) n--;
|
||||
path[n] = '/';
|
||||
|
||||
/* Traverse index files list. For each entry, append it to the given
|
||||
* path and see if the file exists. If it exists, break the loop */
|
||||
while ((list = XX_httplib_next_option(list, &filename_vec, NULL)) != NULL) {
|
||||
/* Ignore too long entries that may overflow path buffer */
|
||||
if (filename_vec.len > path_len - (n + 2)) continue;
|
||||
/*
|
||||
* Traverse index files list. For each entry, append it to the given
|
||||
* path and see if the file exists. If it exists, break the loop
|
||||
*/
|
||||
|
||||
/* Prepare full path to the index file */
|
||||
httplib_strlcpy( path + n + 1, filename_vec.ptr, filename_vec.len + 1 );
|
||||
while ( (list = XX_httplib_next_option( list, &filename_vec, NULL )) != NULL ) {
|
||||
|
||||
/*
|
||||
* Ignore too long entries that may overflow path buffer
|
||||
*/
|
||||
|
||||
if ( filename_vec.len > path_len - (n+2) ) continue;
|
||||
|
||||
/*
|
||||
* Prepare full path to the index file
|
||||
*/
|
||||
|
||||
httplib_strlcpy( path+n+1, filename_vec.ptr, filename_vec.len + 1 );
|
||||
|
||||
/*
|
||||
* Does it exist?
|
||||
*/
|
||||
|
||||
if ( XX_httplib_stat( conn, path, &file ) ) {
|
||||
|
||||
/*
|
||||
* Yes it does, break the loop
|
||||
*/
|
||||
|
||||
/* Does it exist? */
|
||||
if (XX_httplib_stat(conn, path, &file)) {
|
||||
/* Yes it does, break the loop */
|
||||
*filep = file;
|
||||
found = 1;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no index file exists, restore directory path */
|
||||
if (!found) path[n] = '\0';
|
||||
/*
|
||||
* If no index file exists, restore directory path
|
||||
*/
|
||||
|
||||
if ( ! found ) path[n] = '\0';
|
||||
|
||||
return found;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 1.9
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -43,27 +43,30 @@ struct ttimer {
|
||||
};
|
||||
|
||||
struct ttimers {
|
||||
pthread_t threadid; /* Timer thread ID */
|
||||
pthread_mutex_t mutex; /* Protects timer lists */
|
||||
struct ttimer timers[MAX_TIMERS]; /* List of timers */
|
||||
unsigned timer_count; /* Current size of timer list */
|
||||
pthread_t threadid; /* Timer thread ID */
|
||||
pthread_mutex_t mutex; /* Protects timer lists */
|
||||
struct ttimer timers[MAX_TIMERS]; /* List of timers */
|
||||
unsigned timer_count; /* Current size of timer list */
|
||||
};
|
||||
|
||||
static int timer_add( struct httplib_context *ctx, double next_time, double period, int is_relative, taction action, void *arg ) {
|
||||
|
||||
unsigned u;
|
||||
unsigned v;
|
||||
int error = 0;
|
||||
int error;
|
||||
struct timespec now;
|
||||
double dt; /* double time */
|
||||
|
||||
if (ctx->stop_flag) return 0;
|
||||
if ( ctx == NULL || ctx->stop_flag ) return 0;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
dt = (double)now.tv_sec;
|
||||
error = 0;
|
||||
|
||||
clock_gettime( CLOCK_MONOTONIC, &now );
|
||||
dt = (double)now.tv_sec;
|
||||
dt += now.tv_nsec * 1.0E-9;
|
||||
|
||||
/* HCP24: if is_relative = 0 and next_time < now
|
||||
/*
|
||||
* HCP24: if is_relative = 0 and next_time < now
|
||||
* action will be called so fast as possible
|
||||
* if additional period > 0
|
||||
* action will be called so fast as possible
|
||||
@@ -73,30 +76,37 @@ static int timer_add( struct httplib_context *ctx, double next_time, double peri
|
||||
* if next_time < now then we set next_time = now.
|
||||
* The first callback will be so fast as possible (now)
|
||||
* but the next callback on period
|
||||
*/
|
||||
*/
|
||||
|
||||
if ( is_relative ) next_time += dt;
|
||||
else if ( next_time < dt ) next_time = dt;
|
||||
|
||||
httplib_pthread_mutex_lock( & ctx->timers->mutex );
|
||||
if (ctx->timers->timer_count == MAX_TIMERS) {
|
||||
error = 1;
|
||||
} else {
|
||||
for (u = 0; u < ctx->timers->timer_count; u++) {
|
||||
if ( ctx->timers->timer_count == MAX_TIMERS ) error = 1;
|
||||
|
||||
else {
|
||||
for (u=0; u<ctx->timers->timer_count; u++) {
|
||||
|
||||
if (ctx->timers->timers[u].time > next_time) {
|
||||
/* HCP24: moving all timers > next_time */
|
||||
for (v = ctx->timers->timer_count; v > u; v--) {
|
||||
ctx->timers->timers[v] = ctx->timers->timers[v - 1];
|
||||
}
|
||||
|
||||
/*
|
||||
* HCP24: moving all timers > next_time
|
||||
*/
|
||||
|
||||
for (v=ctx->timers->timer_count; v>u; v--) ctx->timers->timers[v] = ctx->timers->timers[v - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->timers->timers[u].time = next_time;
|
||||
ctx->timers->timers[u].period = period;
|
||||
ctx->timers->timers[u].action = action;
|
||||
ctx->timers->timers[u].arg = arg;
|
||||
ctx->timers->timer_count++;
|
||||
}
|
||||
|
||||
httplib_pthread_mutex_unlock( & ctx->timers->mutex );
|
||||
|
||||
return error;
|
||||
|
||||
} /* timer_add */
|
||||
@@ -110,37 +120,32 @@ static void timer_thread_run( void *thread_func_param ) {
|
||||
int re_schedule;
|
||||
struct ttimer t;
|
||||
|
||||
httplib_set_thread_name("timer");
|
||||
httplib_set_thread_name( "timer" );
|
||||
|
||||
if (ctx->callbacks.init_thread) {
|
||||
/* Timer thread */
|
||||
ctx->callbacks.init_thread(ctx, 2);
|
||||
}
|
||||
if ( ctx->callbacks.init_thread ) ctx->callbacks.init_thread( ctx, 2 ); /* Timer thread */
|
||||
|
||||
#if defined(HAVE_CLOCK_NANOSLEEP) /* Linux with librt */
|
||||
/* TODO */
|
||||
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &request, &request)
|
||||
== EINTR) { /*nop*/
|
||||
;
|
||||
}
|
||||
while ( clock_nanosleep( CLOCK_MONOTONIC, TIMER_ABSTIME, &request, &request ) == EINTR ) { /*nop*/ ; }
|
||||
|
||||
#else /* HAVE_CLOCK_NANOSLEEP */
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
clock_gettime( CLOCK_MONOTONIC, &now );
|
||||
d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
|
||||
while (ctx->stop_flag == 0) {
|
||||
|
||||
while ( ctx->stop_flag == 0 ) {
|
||||
|
||||
httplib_pthread_mutex_lock( & ctx->timers->mutex );
|
||||
if (ctx->timers->timer_count > 0 && d >= ctx->timers->timers[0].time) {
|
||||
|
||||
if ( ctx->timers->timer_count > 0 && d >= ctx->timers->timers[0].time ) {
|
||||
|
||||
t = ctx->timers->timers[0];
|
||||
for (u = 1; u < ctx->timers->timer_count; u++) {
|
||||
ctx->timers->timers[u - 1] = ctx->timers->timers[u];
|
||||
}
|
||||
for (u=1; u<ctx->timers->timer_count; u++) ctx->timers->timers[u-1] = ctx->timers->timers[u];
|
||||
ctx->timers->timer_count--;
|
||||
httplib_pthread_mutex_unlock( & ctx->timers->mutex );
|
||||
re_schedule = t.action(t.arg);
|
||||
if (re_schedule && (t.period > 0)) {
|
||||
timer_add(ctx, t.time + t.period, t.period, 0, t.action, t.arg);
|
||||
}
|
||||
re_schedule = t.action( t.arg );
|
||||
if ( re_schedule && t.period > 0 ) timer_add( ctx, t.time + t.period, t.period, 0, t.action, t.arg );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -175,10 +180,13 @@ static void * timer_thread( void *thread_func_param ) {
|
||||
|
||||
static int timers_init( struct httplib_context *ctx ) {
|
||||
|
||||
ctx->timers = (struct ttimers *)httplib_calloc(sizeof(struct ttimers), 1);
|
||||
ctx->timers = httplib_calloc( sizeof(struct ttimers), 1 );
|
||||
httplib_pthread_mutex_init( & ctx->timers->mutex, NULL );
|
||||
|
||||
/* Start timer thread */
|
||||
/*
|
||||
* Start timer thread
|
||||
*/
|
||||
|
||||
httplib_start_thread_with_id(timer_thread, ctx, &ctx->timers->threadid);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -39,12 +39,14 @@
|
||||
|
||||
void XX_httplib_tls_dtor( void *key ) {
|
||||
|
||||
struct httplib_workerTLS *tls = (struct httplib_workerTLS *)key;
|
||||
struct httplib_workerTLS *tls;
|
||||
|
||||
tls = key;
|
||||
/* key == httplib_pthread_getspecific( XX_httplib_sTlsKey ); */
|
||||
|
||||
if ( tls != NULL ) {
|
||||
|
||||
if (tls->is_master == 2) {
|
||||
if ( tls->is_master == 2 ) {
|
||||
|
||||
tls->is_master = -3; /* Mark memory as dead */
|
||||
httplib_free( tls );
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -36,17 +36,24 @@ int httplib_url_decode( const char *src, int src_len, char *dst, int dst_len, in
|
||||
int a;
|
||||
int b;
|
||||
|
||||
for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
|
||||
if (i < src_len - 2 && src[i] == '%'
|
||||
&& isxdigit(*(const unsigned char *)(src + i + 1))
|
||||
&& isxdigit(*(const unsigned char *)(src + i + 2))) {
|
||||
a = tolower(*(const unsigned char *)(src + i + 1));
|
||||
b = tolower(*(const unsigned char *)(src + i + 2));
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
||||
while ( i < src_len && j < dst_len-1 ) {
|
||||
|
||||
if ( i < src_len - 2 && src[i] == '%' && isxdigit(*(const unsigned char *)(src + i + 1)) && isxdigit(*(const unsigned char *)(src + i + 2)) ) {
|
||||
|
||||
a = tolower(*(const unsigned char *)(src + i + 1));
|
||||
b = tolower(*(const unsigned char *)(src + i + 2));
|
||||
dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b));
|
||||
i += 2;
|
||||
} else if (is_form_url_encoded && src[i] == '+') {
|
||||
dst[j] = ' ';
|
||||
} else dst[j] = src[i];
|
||||
i += 2;
|
||||
}
|
||||
|
||||
else if (is_form_url_encoded && src[i] == '+') dst[j] = ' ';
|
||||
else dst[j] = src[i];
|
||||
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
|
||||
dst[j] = '\0'; /* Null-terminate the destination */
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -31,19 +31,31 @@ int httplib_url_encode( const char *src, char *dst, size_t dst_len ) {
|
||||
|
||||
static const char *dont_escape = "._-$,;~()";
|
||||
static const char *hex = "0123456789abcdef";
|
||||
char *pos = dst;
|
||||
const char *end = dst + dst_len - 1;
|
||||
char *pos;
|
||||
const char *end;
|
||||
|
||||
if ( dst == NULL || dst_len < 1 ) return 0;
|
||||
if ( src == NULL ) { dst[0] = '\0'; return 0; }
|
||||
|
||||
pos = dst;
|
||||
end = dst + dst_len - 1;
|
||||
|
||||
while ( *src != '\0' && pos < end ) {
|
||||
|
||||
if ( isalnum(*(const unsigned char *)src) || strchr( dont_escape, *(const unsigned char *)src ) != NULL ) *pos = *src;
|
||||
|
||||
else if ( pos + 2 < end ) {
|
||||
|
||||
for (; *src != '\0' && pos < end; src++, pos++) {
|
||||
if (isalnum(*(const unsigned char *)src)
|
||||
|| strchr(dont_escape, *(const unsigned char *)src) != NULL) {
|
||||
*pos = *src;
|
||||
} else if (pos + 2 < end) {
|
||||
pos[0] = '%';
|
||||
pos[1] = hex[(*(const unsigned char *)src) >> 4];
|
||||
pos[2] = hex[(*(const unsigned char *)src) & 0xf];
|
||||
pos += 2;
|
||||
} else break;
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
else break;
|
||||
|
||||
src++;
|
||||
pos++;
|
||||
}
|
||||
|
||||
*pos = '\0';
|
||||
|
||||
@@ -22,41 +22,52 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
#include "httplib_memory.h"
|
||||
#include "httplib_string.h"
|
||||
|
||||
/* Alternative alloc_vprintf() for non-compliant C runtimes */
|
||||
/*
|
||||
* Alternative alloc_vprintf() for non-compliant C runtimes
|
||||
*/
|
||||
|
||||
static int alloc_vprintf2( char **buf, const char *fmt, va_list ap ) {
|
||||
|
||||
va_list ap_copy;
|
||||
size_t size = MG_BUF_LEN / 4;
|
||||
int len = -1;
|
||||
size_t size;
|
||||
int len;
|
||||
|
||||
size = MG_BUF_LEN / 4;
|
||||
len = -1;
|
||||
*buf = NULL;
|
||||
while (len < 0) {
|
||||
if (*buf) httplib_free( *buf );
|
||||
|
||||
while ( len < 0 ) {
|
||||
|
||||
if ( *buf != NULL ) httplib_free( *buf );
|
||||
|
||||
size *= 4;
|
||||
*buf = httplib_malloc( size );
|
||||
if (!*buf) break;
|
||||
if ( *buf == NULL ) break;
|
||||
|
||||
va_copy(ap_copy, ap);
|
||||
len = vsnprintf_impl(*buf, size - 1, fmt, ap_copy);
|
||||
va_end(ap_copy);
|
||||
(*buf)[size - 1] = 0;
|
||||
va_copy( ap_copy, ap );
|
||||
len = vsnprintf_impl( *buf, size - 1, fmt, ap_copy );
|
||||
va_end( ap_copy );
|
||||
|
||||
(*buf)[size-1] = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* Print message to buffer. If buffer is large enough to hold the message,
|
||||
/*
|
||||
* Print message to buffer. If buffer is large enough to hold the message,
|
||||
* return buffer. If buffer is to small, allocate large enough buffer on heap,
|
||||
* and return allocated buffer. */
|
||||
* and return allocated buffer.
|
||||
*/
|
||||
|
||||
static int alloc_vprintf( char **out_buf, char *prealloc_buf, size_t prealloc_size, const char *fmt, va_list ap ) {
|
||||
|
||||
va_list ap_copy;
|
||||
@@ -71,37 +82,60 @@ static int alloc_vprintf( char **out_buf, char *prealloc_buf, size_t prealloc_si
|
||||
* On second pass, actually print the message.
|
||||
*/
|
||||
|
||||
va_copy(ap_copy, ap);
|
||||
len = vsnprintf_impl(NULL, 0, fmt, ap_copy);
|
||||
va_end(ap_copy);
|
||||
va_copy( ap_copy, ap );
|
||||
len = vsnprintf_impl( NULL, 0, fmt, ap_copy );
|
||||
va_end( ap_copy );
|
||||
|
||||
if (len < 0) {
|
||||
/* C runtime is not standard compliant, vsnprintf() returned -1.
|
||||
if ( len < 0 ) {
|
||||
|
||||
/*
|
||||
* C runtime is not standard compliant, vsnprintf() returned -1.
|
||||
* Switch to alternative code path that uses incremental allocations.
|
||||
*/
|
||||
va_copy(ap_copy, ap);
|
||||
len = alloc_vprintf2(out_buf, fmt, ap);
|
||||
va_end(ap_copy);
|
||||
|
||||
} else if ((size_t)(len) >= prealloc_size) {
|
||||
/* The pre-allocated buffer not large enough. */
|
||||
/* Allocate a new buffer. */
|
||||
va_copy( ap_copy, ap );
|
||||
len = alloc_vprintf2( out_buf, fmt, ap );
|
||||
va_end( ap_copy );
|
||||
|
||||
}
|
||||
|
||||
else if ( (size_t)(len) >= prealloc_size ) {
|
||||
|
||||
/*
|
||||
* The pre-allocated buffer not large enough.
|
||||
* Allocate a new buffer.
|
||||
*/
|
||||
|
||||
*out_buf = httplib_malloc( (size_t)(len) + 1 );
|
||||
if (!*out_buf) {
|
||||
/* Allocation failed. Return -1 as "out of memory" error. */
|
||||
if ( *out_buf == NULL ) {
|
||||
|
||||
/*
|
||||
* Allocation failed. Return -1 as "out of memory" error.
|
||||
*/
|
||||
|
||||
return -1;
|
||||
}
|
||||
/* Buffer allocation successful. Store the string there. */
|
||||
va_copy(ap_copy, ap);
|
||||
vsnprintf_impl(*out_buf, (size_t)(len) + 1, fmt, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
} else {
|
||||
/* The pre-allocated buffer is large enough.
|
||||
* Use it to store the string and return the address. */
|
||||
va_copy(ap_copy, ap);
|
||||
vsnprintf_impl(prealloc_buf, prealloc_size, fmt, ap_copy);
|
||||
va_end(ap_copy);
|
||||
/*
|
||||
* Buffer allocation successful. Store the string there.
|
||||
*/
|
||||
|
||||
va_copy( ap_copy, ap );
|
||||
vsnprintf_impl( *out_buf, (size_t)(len) + 1, fmt, ap_copy );
|
||||
va_end( ap_copy );
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
/*
|
||||
* The pre-allocated buffer is large enough.
|
||||
* Use it to store the string and return the address.
|
||||
*/
|
||||
|
||||
va_copy( ap_copy, ap );
|
||||
vsnprintf_impl( prealloc_buf, prealloc_size, fmt, ap_copy );
|
||||
va_end( ap_copy );
|
||||
|
||||
*out_buf = prealloc_buf;
|
||||
}
|
||||
|
||||
@@ -113,11 +147,13 @@ static int alloc_vprintf( char **out_buf, char *prealloc_buf, size_t prealloc_si
|
||||
int XX_httplib_vprintf( struct httplib_connection *conn, const char *fmt, va_list ap ) {
|
||||
|
||||
char mem[MG_BUF_LEN];
|
||||
char *buf = NULL;
|
||||
char *buf;
|
||||
int len;
|
||||
|
||||
if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) len = httplib_write(conn, buf, (size_t)len);
|
||||
if (buf != mem && buf != NULL) httplib_free( buf );
|
||||
buf = NULL;
|
||||
|
||||
if ( (len = alloc_vprintf( &buf, mem, sizeof(mem), fmt, ap )) > 0 ) len = httplib_write( conn, buf, (size_t)len );
|
||||
if ( buf != mem && buf != NULL ) httplib_free( buf );
|
||||
|
||||
return len;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -36,7 +36,7 @@
|
||||
void XX_httplib_vsnprintf( const struct httplib_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, va_list ap ) {
|
||||
|
||||
int n;
|
||||
int ok;
|
||||
bool ok;
|
||||
|
||||
if ( buf == NULL || buflen < 1 ) return;
|
||||
|
||||
@@ -47,20 +47,20 @@ void XX_httplib_vsnprintf( const struct httplib_connection *conn, int *truncated
|
||||
* indirectly by XX_httplib_snprintf */
|
||||
#endif
|
||||
|
||||
n = (int)vsnprintf_impl( buf, buflen, fmt, ap );
|
||||
ok = (n >= 0) && ((size_t)n < buflen);
|
||||
n = (int)vsnprintf_impl( buf, buflen, fmt, ap );
|
||||
ok = (n >= 0) && ((size_t)n < buflen);
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
if (ok) {
|
||||
if ( ok ) {
|
||||
if ( truncated != NULL ) *truncated = 0;
|
||||
}
|
||||
|
||||
else {
|
||||
if ( truncated != NULL ) *truncated = 1;
|
||||
httplib_cry(conn, "truncating vsnprintf buffer: [%.*s]", (int)((buflen > 200) ? 200 : (buflen - 1)), buf);
|
||||
httplib_cry( conn, "truncating vsnprintf buffer: [%.*s]", (int)((buflen > 200) ? 200 : (buflen - 1)), buf );
|
||||
n = (int)buflen - 1;
|
||||
}
|
||||
buf[n] = '\0';
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -41,17 +41,19 @@ static void * worker_thread_run( struct worker_thread_args *thread_args );
|
||||
* operating system.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned __stdcall XX_httplib_worker_thread( void *thread_func_param ) {
|
||||
#else
|
||||
void *XX_httplib_worker_thread( void *thread_func_param ) {
|
||||
#endif
|
||||
LIBHTTP_THREAD XX_httplib_worker_thread( void *thread_func_param ) {
|
||||
|
||||
struct worker_thread_args *pwta = (struct worker_thread_args *)thread_func_param;
|
||||
worker_thread_run( pwta );
|
||||
httplib_free( thread_func_param );
|
||||
struct worker_thread_args *pwta;
|
||||
|
||||
return 0;
|
||||
if ( thread_func_param != NULL ) {
|
||||
|
||||
pwta = thread_func_param;
|
||||
|
||||
worker_thread_run( pwta );
|
||||
httplib_free( thread_func_param );
|
||||
}
|
||||
|
||||
return LIBHTTP_THREAD_RETNULL;
|
||||
|
||||
} /* XX_httplib_worker_thread */
|
||||
|
||||
@@ -70,45 +72,56 @@ static void *worker_thread_run( struct worker_thread_args *thread_args ) {
|
||||
struct httplib_connection *conn;
|
||||
struct httplib_workerTLS tls;
|
||||
|
||||
if ( thread_args == NULL ) return NULL;
|
||||
|
||||
ctx = thread_args->ctx;
|
||||
|
||||
XX_httplib_set_thread_name( "worker" );
|
||||
|
||||
tls.is_master = 0;
|
||||
tls.thread_idx = (unsigned)httplib_atomic_inc(&XX_httplib_thread_idx_max);
|
||||
tls.thread_idx = (unsigned)httplib_atomic_inc( & XX_httplib_thread_idx_max );
|
||||
#if defined(_WIN32)
|
||||
tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
tls.pthread_cond_helper_mutex = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
#endif
|
||||
|
||||
if ( ctx->callbacks.init_thread != NULL ) ctx->callbacks.init_thread( ctx, 1 ); /* call init_thread for a worker thread (type 1) */
|
||||
|
||||
conn = httplib_calloc( 1, sizeof(*conn) + MAX_REQUEST_SIZE );
|
||||
if ( conn == NULL ) httplib_cry( XX_httplib_fc(ctx), "%s", "Cannot create new connection struct, OOM");
|
||||
if ( conn == NULL ) httplib_cry( XX_httplib_fc(ctx), "%s", "Cannot create new connection struct, OOM" );
|
||||
|
||||
else {
|
||||
httplib_pthread_setspecific( XX_httplib_sTlsKey, &tls );
|
||||
|
||||
conn->buf_size = MAX_REQUEST_SIZE;
|
||||
conn->buf = (char *)(conn + 1);
|
||||
conn->buf = (char *)(conn+1);
|
||||
conn->ctx = ctx;
|
||||
conn->thread_index = thread_args->index;
|
||||
conn->request_info.user_data = ctx->user_data;
|
||||
/* Allocate a mutex for this connection to allow communication both
|
||||
|
||||
/*
|
||||
* Allocate a mutex for this connection to allow communication both
|
||||
* within the request handler and from elsewhere in the application
|
||||
*/
|
||||
|
||||
pthread_mutex_init( & conn->mutex, &XX_httplib_pthread_mutex_attr );
|
||||
|
||||
/* Call XX_httplib_consume_socket() even when ctx->stop_flag > 0, to let it
|
||||
/*
|
||||
* Call XX_httplib_consume_socket() even when ctx->stop_flag > 0, to let it
|
||||
* signal sq_empty condvar to wake up the master waiting in
|
||||
* produce_socket() */
|
||||
while (XX_httplib_consume_socket(ctx, &conn->client, conn->thread_index)) {
|
||||
* produce_socket()
|
||||
*/
|
||||
|
||||
conn->conn_birth_time = time(NULL);
|
||||
while ( XX_httplib_consume_socket( ctx, &conn->client, conn->thread_index ) ) {
|
||||
|
||||
/* Fill in IP, port info early so even if SSL setup below fails,
|
||||
* error handler would have the corresponding info.
|
||||
* Thanks to Johannes Winkelmann for the patch.
|
||||
*/
|
||||
conn->conn_birth_time = time( NULL );
|
||||
|
||||
/*
|
||||
* Fill in IP, port info early so even if SSL setup below fails,
|
||||
* error handler would have the corresponding info.
|
||||
* Thanks to Johannes Winkelmann for the patch.
|
||||
*/
|
||||
#if defined(USE_IPV6)
|
||||
if ( conn->client.rsa.sa.sa_family == AF_INET6 ) conn->request_info.remote_port = ntohs(conn->client.rsa.sin6.sin6_port);
|
||||
if ( conn->client.rsa.sa.sa_family == AF_INET6 ) conn->request_info.remote_port = ntohs( conn->client.rsa.sin6.sin6_port );
|
||||
|
||||
else
|
||||
#endif
|
||||
@@ -116,22 +129,34 @@ static void *worker_thread_run( struct worker_thread_args *thread_args ) {
|
||||
conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);
|
||||
}
|
||||
|
||||
XX_httplib_sockaddr_to_string(conn->request_info.remote_addr, sizeof(conn->request_info.remote_addr), &conn->client.rsa);
|
||||
XX_httplib_sockaddr_to_string( conn->request_info.remote_addr, sizeof(conn->request_info.remote_addr), &conn->client.rsa );
|
||||
|
||||
conn->request_info.is_ssl = conn->client.is_ssl;
|
||||
|
||||
if (conn->client.is_ssl) {
|
||||
if ( conn->client.is_ssl ) {
|
||||
#ifndef NO_SSL
|
||||
/* HTTPS connection */
|
||||
/*
|
||||
* HTTPS connection
|
||||
*/
|
||||
|
||||
if ( XX_httplib_sslize( conn, conn->ctx->ssl_ctx, SSL_accept ) ) {
|
||||
|
||||
/* Get SSL client certificate information (if set) */
|
||||
/*
|
||||
* Get SSL client certificate information (if set)
|
||||
*/
|
||||
|
||||
XX_httplib_ssl_get_client_cert_info( conn );
|
||||
|
||||
/* process HTTPS connection */
|
||||
/*
|
||||
* process HTTPS connection
|
||||
*/
|
||||
|
||||
XX_httplib_process_new_connection( conn );
|
||||
|
||||
/* Free client certificate info */
|
||||
/*
|
||||
* Free client certificate info
|
||||
*/
|
||||
|
||||
if ( conn->request_info.client_cert != NULL ) {
|
||||
|
||||
httplib_free( (void *)conn->request_info.client_cert->subject );
|
||||
|
||||
Reference in New Issue
Block a user