1
0
mirror of https://github.com/lammertb/libhttp.git synced 2025-08-09 03:22:45 +03:00

Made httplib_strcasestr global

This commit is contained in:
Lammert Bies
2016-12-20 12:30:49 +01:00
parent 0ee926db97
commit b18d663d3d
21 changed files with 482 additions and 285 deletions

View File

@@ -79,6 +79,7 @@ LibHTTP is often used as HTTP and HTTPS library inside a larger application. A
* [`httplib_base64_encode( src, src_len, dst, dst_len );`](api/httplib_base64_encode.md) * [`httplib_base64_encode( src, src_len, dst, dst_len );`](api/httplib_base64_encode.md)
* [`httplib_md5( buf, ... );`](api/httplib_md5.md) * [`httplib_md5( buf, ... );`](api/httplib_md5.md)
* [`httplib_strcasecmp( s1, s2 );`](api/httplib_strcasecmp.md) * [`httplib_strcasecmp( s1, s2 );`](api/httplib_strcasecmp.md)
* [`httplib_strcasestr( big_str, small_str );`](api/httplib_strcasestr.md)
* [`httplib_strdup( str );`](api/httplib_strdup.md) * [`httplib_strdup( str );`](api/httplib_strdup.md)
* [`httplib_strlcpy( dst, src, len );`](api/httplib_strlcpy.md) * [`httplib_strlcpy( dst, src, len );`](api/httplib_strlcpy.md)
* [`httplib_strncasecmp( s1, s2, len );`](api/httplib_strncasecmp.md) * [`httplib_strncasecmp( s1, s2, len );`](api/httplib_strncasecmp.md)

View File

@@ -21,6 +21,7 @@ The function `httplib_strcasecmp()` is a helper function to compare two strings.
### See Also ### See Also
* [`httplib_strcasestr();`](httplib_strcasestr.md)
* [`httplib_strdup();`](httplib_strdup.md) * [`httplib_strdup();`](httplib_strdup.md)
* [`httplib_strncasecmp();`](httplib_strncasecmp.md) * [`httplib_strncasecmp();`](httplib_strncasecmp.md)
* [`httplib_strndup();`](httplib_strndup.md) * [`httplib_strndup();`](httplib_strndup.md)

View File

@@ -0,0 +1,27 @@
# LibHTTP API Reference
### `httplib_strcasestr( big_str, small_str );`
### Parameters
| Parameter | Type | Description |
| :--- | :--- | :--- |
|**`big_str`**|`const char *`|The string to search in|
|**`small_str`**|`const char *`|The string to search for|
### Return Value
| Type | Description |
| :--- | :--- |
|`int`|First occurence of the small string, or NULL if the string could not be found|
### Description
The function `httplib_strcasestr()` is a helper function to search a NUL terminated string in another NUL terminated string. The search is case insensitive. A pointer to the first occurence of the substring in the large string is returned, or `NULL` if the string could not be found.
### See Also
* [`httplib_strcasecmp();`](httplib_strcasecmp.md)
* [`httplib_strdup();`](httplib_strdup.md)
* [`httplib_strncasecmp();`](httplib_strncasecmp.md)
* [`httplib_strndup();`](httplib_strndup.md)

View File

@@ -26,5 +26,6 @@ If the function fails the value `NULL` is returned, otherwise a pointer to the d
* [`httplib_free();`](httplib_free.md) * [`httplib_free();`](httplib_free.md)
* [`httplib_strcasecmp();`](httplib_strcasecmp.md) * [`httplib_strcasecmp();`](httplib_strcasecmp.md)
* [`httplib_strcasestr();`](httplib_strcasestr.md)
* [`httplib_strncasecmp();`](httplib_strncasecmp.md) * [`httplib_strncasecmp();`](httplib_strncasecmp.md)
* [`httplib_strndup();`](httplib_strndup.md) * [`httplib_strndup();`](httplib_strndup.md)

View File

@@ -23,5 +23,6 @@ If the source string is longer than will fit in the receiving buffer, the remain
### See Also ### See Also
* [`httplib_strcasecmp();`](httplib_strcasecmp.md) * [`httplib_strcasecmp();`](httplib_strcasecmp.md)
* [`httplib_strcasestr();`](httplib_strcasestr.md)
* [`httplib_strncasecmp();`](httplib_strncasecmp.md) * [`httplib_strncasecmp();`](httplib_strncasecmp.md)
* [`httplib_strndup();`](httplib_strndup.md) * [`httplib_strndup();`](httplib_strndup.md)

View File

@@ -23,5 +23,6 @@ The function `httplib_strncasecmp()` is a helper function to compare two strings
### See Also ### See Also
* [`httplib_strcasecmp();`](httplib_strcasecmp.md) * [`httplib_strcasecmp();`](httplib_strcasecmp.md)
* [`httplib_strcasestr();`](httplib_strcasestr.md)
* [`httplib_strdup();`](httplib_strdup.md) * [`httplib_strdup();`](httplib_strdup.md)
* [`httplib_strndup();`](httplib_strndup.md) * [`httplib_strndup();`](httplib_strndup.md)

View File

@@ -27,5 +27,6 @@ If the function fails the value `NULL` is returned, otherwise a pointer to the d
* [`httplib_free();`](httplib_free.md) * [`httplib_free();`](httplib_free.md)
* [`httplib_strcasecmp();`](httplib_strcasecmp.md) * [`httplib_strcasecmp();`](httplib_strcasecmp.md)
* [`httplib_strcasestr();`](httplib_strcasestr.md)
* [`httplib_strdup();`](httplib_strdup.md) * [`httplib_strdup();`](httplib_strdup.md)
* [`httplib_strncasecmp();`](httplib_strncasecmp.md) * [`httplib_strncasecmp();`](httplib_strncasecmp.md)

View File

@@ -869,8 +869,6 @@ LIBHTTP_API void httplib_cry(const struct httplib_connection *conn, PRINTF_FORMA
/* utility methods to compare two buffers, case insensitive. */ /* utility methods to compare two buffers, case insensitive. */
LIBHTTP_API int httplib_strcasecmp(const char *s1, const char *s2);
LIBHTTP_API int httplib_strncasecmp(const char *s1, const char *s2, size_t len);
/* Connect to a websocket as a client /* Connect to a websocket as a client
@@ -1004,7 +1002,10 @@ LIBHTTP_API int httplib_pthread_setspecific( pthread_key_t key, const void *va
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_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 const char * httplib_strcasestr( const char *big_str, const char *small_str );
LIBHTTP_API void httplib_strlcpy( char *dst, const char *src, size_t len ); 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 char * httplib_strndup( const char *str, size_t len );
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -44,7 +44,7 @@ int httplib_get_cookie(const char *cookie_header, const char *var_name, char *ds
name_len = (int)strlen(var_name); name_len = (int)strlen(var_name);
end = s + strlen(s); end = s + strlen(s);
for (; (s = XX_httplib_strcasestr(s, var_name)) != NULL; s += name_len) { for (; (s = httplib_strcasestr( s, var_name )) != NULL; s += name_len) {
if (s[name_len] == '=') { if (s[name_len] == '=') {
/* HCP24: now check is it a substring or a full cookie name */ /* HCP24: now check is it a substring or a full cookie name */
if ((s == cookie_header) || (s[-1] == ' ')) { if ((s == cookie_header) || (s[-1] == ' ')) {

View File

@@ -50,12 +50,12 @@ bool XX_httplib_is_websocket_protocol( const struct httplib_connection *conn ) {
upgrade = httplib_get_header(conn, "Upgrade"); upgrade = httplib_get_header(conn, "Upgrade");
if (upgrade == NULL) return false; /* fail early, don't waste time checking other header * fields */ if (upgrade == NULL) return false; /* fail early, don't waste time checking other header * fields */
if (!XX_httplib_strcasestr(upgrade, "websocket")) return false; if ( httplib_strcasestr(upgrade, "websocket") == NULL ) return false;
connection = httplib_get_header(conn, "Connection"); connection = httplib_get_header(conn, "Connection");
if (connection == NULL) return false; if (connection == NULL) return false;
if (!XX_httplib_strcasestr(connection, "upgrade")) return false; if ( httplib_strcasestr(connection, "upgrade") == NULL ) return false;
/* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
* "Sec-WebSocket-Version" are also required. * "Sec-WebSocket-Version" are also required.

View File

@@ -22,22 +22,21 @@
* 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"
#include "httplib_utils.h" #include "httplib_utils.h"
static int parse_port_string( const struct vec *vec, struct socket *so, int *ip_version ); static bool parse_port_string( const struct vec *vec, struct socket *so, int *ip_version );
/* /*
* int XX_httplib_set_ports_option( struct httplib_context *ctx ); * int XX_httplib_set_ports_option( struct httplib_context *ctx );
* *
* The function XX_httplib_set_ports_option() set the port options for a * The function XX_httplib_set_ports_option() set the port options for a
* context. * context. The function returns the total number of ports opened, or 0 if no
* ports have been opened.
*/ */
int XX_httplib_set_ports_option( struct httplib_context *ctx ) { int XX_httplib_set_ports_option( struct httplib_context *ctx ) {
@@ -46,191 +45,216 @@ int XX_httplib_set_ports_option( struct httplib_context *ctx ) {
int on = 1; int on = 1;
#if defined(USE_IPV6) #if defined(USE_IPV6)
int off = 0; int off = 0;
#endif #endif /* USE_IPV6 */
struct vec vec; struct vec vec;
struct socket so, *ptr; struct socket so;
struct socket *ptr;
struct pollfd *pfd; struct pollfd *pfd;
union usa usa; union usa usa;
socklen_t len; socklen_t len;
int ip_version; int ip_version;
int ports_total;
int portsTotal = 0; int ports_ok;
int portsOk = 0;
if ( ctx == NULL ) return 0; if ( ctx == NULL ) return 0;
memset(&so, 0, sizeof(so)); ports_total = 0;
memset(&usa, 0, sizeof(usa)); ports_ok = 0;
len = sizeof(usa);
memset( & so, 0, sizeof(so) );
memset( & usa, 0, sizeof(usa) );
len = sizeof(usa);
list = ctx->config[LISTENING_PORTS]; list = ctx->config[LISTENING_PORTS];
while ((list = XX_httplib_next_option(list, &vec, NULL)) != NULL) { while ( (list = XX_httplib_next_option( list, &vec, NULL )) != NULL ) {
portsTotal++; ports_total++;
if ( ! parse_port_string( & vec, & so, & ip_version ) ) {
if (!parse_port_string(&vec, &so, &ip_version)) {
httplib_cry( XX_httplib_fc(ctx), httplib_cry( XX_httplib_fc(ctx),
"%.*s: invalid port spec (entry %i). Expecting list of: %s", "%.*s: invalid port spec (entry %i). Expecting list of: %s",
(int)vec.len, (int)vec.len,
vec.ptr, vec.ptr,
portsTotal, ports_total,
"[IP_ADDRESS:]PORT[s|r]"); "[IP_ADDRESS:]PORT[s|r]" );
continue; continue;
} }
#if !defined(NO_SSL) #if !defined(NO_SSL)
if (so.is_ssl && ctx->ssl_ctx == NULL) { if ( so.is_ssl && ctx->ssl_ctx == NULL ) {
httplib_cry( XX_httplib_fc(ctx), "Cannot add SSL socket (entry %i). Is -ssl_certificate option set?", portsTotal); httplib_cry( XX_httplib_fc(ctx), "Cannot add SSL socket (entry %i). Is -ssl_certificate option set?", ports_total );
continue; continue;
} }
#endif #endif /* ! NO_SLL */
if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6)) if ( ( so.sock = socket( so.lsa.sa.sa_family, SOCK_STREAM, 6 ) ) == INVALID_SOCKET ) {
== INVALID_SOCKET) {
httplib_cry( XX_httplib_fc(ctx), "cannot create socket (entry %i)", portsTotal); httplib_cry( XX_httplib_fc(ctx), "cannot create socket (entry %i)", ports_total );
continue; continue;
} }
#ifdef _WIN32 #if defined(_WIN32)
/* Windows SO_REUSEADDR lets many procs binds to a
/*
* Windows SO_REUSEADDR lets many procs binds to a
* socket, SO_EXCLUSIVEADDRUSE makes the bind fail * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
* if someone already has the socket -- DTL */ * if someone already has the socket -- DTL
/* NOTE: If SO_EXCLUSIVEADDRUSE is used, *
* NOTE: If SO_EXCLUSIVEADDRUSE is used,
* Windows might need a few seconds before * Windows might need a few seconds before
* the same port can be used again in the * the same port can be used again in the
* same process, so a short Sleep may be * same process, so a short Sleep may be
* required between httplib_stop and httplib_start. * required between httplib_stop and httplib_start.
*/ */
if (setsockopt(so.sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (SOCK_OPT_TYPE)&on, sizeof(on)) != 0) {
/* Set reuse option, but don't abort on errors. */ if ( setsockopt( so.sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (SOCK_OPT_TYPE)&on, sizeof(on) ) != 0 ) {
httplib_cry( XX_httplib_fc(ctx), "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)", portsTotal);
/*
* Set reuse option, but don't abort on errors.
*/
httplib_cry( XX_httplib_fc(ctx), "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)", ports_total );
} }
#else #else /* _WIN32 */
if (setsockopt(so.sock, SOL_SOCKET, SO_REUSEADDR, (SOCK_OPT_TYPE)&on, sizeof(on)) != 0) { if ( setsockopt( so.sock, SOL_SOCKET, SO_REUSEADDR, (SOCK_OPT_TYPE)&on, sizeof(on) ) != 0 ) {
/* Set reuse option, but don't abort on errors. */ /*
httplib_cry( XX_httplib_fc(ctx), "cannot set socket option SO_REUSEADDR (entry %i)", portsTotal); * Set reuse option, but don't abort on errors.
*/
httplib_cry( XX_httplib_fc(ctx), "cannot set socket option SO_REUSEADDR (entry %i)", ports_total );
} }
#endif #endif /* _WIN32 */
if (ip_version > 4) { if ( ip_version > 4 ) {
#if defined(USE_IPV6) #if defined(USE_IPV6)
if (ip_version == 6) { if ( ip_version == 6 ) {
if (so.lsa.sa.sa_family == AF_INET6
&& setsockopt(so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&off, sizeof(off)) != 0) {
/* Set IPv6 only option, but don't abort on errors. */ if ( so.lsa.sa.sa_family == AF_INET6 && setsockopt( so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&off, sizeof(off) ) != 0 ) {
httplib_cry( XX_httplib_fc(ctx), "cannot set socket option IPV6_V6ONLY (entry %i)", portsTotal);
/*
* Set IPv6 only option, but don't abort on errors.
*/
httplib_cry( XX_httplib_fc(ctx), "cannot set socket option IPV6_V6ONLY (entry %i)", ports_total );
} }
} }
#else #else /* USE_IPV6 */
httplib_cry( XX_httplib_fc(ctx), "IPv6 not available"); httplib_cry( XX_httplib_fc(ctx), "IPv6 not available" );
closesocket(so.sock); closesocket( so.sock );
so.sock = INVALID_SOCKET; so.sock = INVALID_SOCKET;
continue; continue;
#endif #endif /* USE_IPV6 */
} }
if (so.lsa.sa.sa_family == AF_INET) { if ( so.lsa.sa.sa_family == AF_INET ) {
len = sizeof(so.lsa.sin); len = sizeof(so.lsa.sin);
if (bind(so.sock, &so.lsa.sa, len) != 0) {
httplib_cry( XX_httplib_fc(ctx), "cannot bind to %.*s: %d (%s)", (int)vec.len, vec.ptr, (int)ERRNO, strerror(errno)); if ( bind( so.sock, &so.lsa.sa, len ) != 0 ) {
closesocket(so.sock);
httplib_cry( XX_httplib_fc(ctx), "cannot bind to %.*s: %d (%s)", (int)vec.len, vec.ptr, (int)ERRNO, strerror(errno) );
closesocket( so.sock );
so.sock = INVALID_SOCKET; so.sock = INVALID_SOCKET;
continue; continue;
} }
} }
#if defined(USE_IPV6) #if defined(USE_IPV6)
else if (so.lsa.sa.sa_family == AF_INET6) { else if ( so.lsa.sa.sa_family == AF_INET6 ) {
len = sizeof(so.lsa.sin6); len = sizeof(so.lsa.sin6);
if (bind(so.sock, &so.lsa.sa, len) != 0) {
httplib_cry( XX_httplib_fc(ctx), "cannot bind to IPv6 %.*s: %d (%s)", (int)vec.len, vec.ptr, (int)ERRNO, strerror(errno)); if ( bind( so.sock, &so.lsa.sa, len ) != 0 ) {
closesocket(so.sock);
httplib_cry( XX_httplib_fc(ctx), "cannot bind to IPv6 %.*s: %d (%s)", (int)vec.len, vec.ptr, (int)ERRNO, strerror(errno) );
closesocket( so.sock );
so.sock = INVALID_SOCKET; so.sock = INVALID_SOCKET;
continue; continue;
} }
} }
#endif #endif /* USE_IPV6 */
else { else {
httplib_cry( XX_httplib_fc(ctx), "cannot bind: address family not supported (entry %i)", portsTotal); httplib_cry( XX_httplib_fc(ctx), "cannot bind: address family not supported (entry %i)", ports_total );
continue; continue;
} }
if (listen(so.sock, SOMAXCONN) != 0) { if ( listen( so.sock, SOMAXCONN ) != 0 ) {
httplib_cry( XX_httplib_fc(ctx), "cannot listen to %.*s: %d (%s)", (int)vec.len, vec.ptr, (int)ERRNO, strerror(errno)); httplib_cry( XX_httplib_fc(ctx), "cannot listen to %.*s: %d (%s)", (int)vec.len, vec.ptr, (int)ERRNO, strerror(errno) );
closesocket(so.sock); closesocket( so.sock );
so.sock = INVALID_SOCKET; so.sock = INVALID_SOCKET;
continue; continue;
} }
if (getsockname(so.sock, &(usa.sa), &len) != 0 if ( getsockname( so.sock, &(usa.sa), &len ) != 0 || usa.sa.sa_family != so.lsa.sa.sa_family ) {
|| usa.sa.sa_family != so.lsa.sa.sa_family) {
int err = (int)ERRNO; int err = (int)ERRNO;
httplib_cry( XX_httplib_fc(ctx), "call to getsockname failed %.*s: %d (%s)", (int)vec.len, vec.ptr, err, strerror(errno)); httplib_cry( XX_httplib_fc(ctx), "call to getsockname failed %.*s: %d (%s)", (int)vec.len, vec.ptr, err, strerror(errno) );
closesocket(so.sock); closesocket( so.sock );
so.sock = INVALID_SOCKET; so.sock = INVALID_SOCKET;
continue; continue;
} }
/* Update lsa port in case of random free ports */ /*
* Update lsa port in case of random free ports
*/
#if defined(USE_IPV6) #if defined(USE_IPV6)
if (so.lsa.sa.sa_family == AF_INET6) { if ( so.lsa.sa.sa_family == AF_INET6 ) so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
} else else
#endif #endif /* USE_IPV6 */
{ {
so.lsa.sin.sin_port = usa.sin.sin_port; so.lsa.sin.sin_port = usa.sin.sin_port;
} }
if ((ptr = httplib_realloc( ctx->listening_sockets, (ctx->num_listening_sockets + 1) * sizeof(ctx->listening_sockets[0]) )) == NULL) { ptr = httplib_realloc( ctx->listening_sockets, (ctx->num_listening_sockets+1) * sizeof(ctx->listening_sockets[0]) );
httplib_cry( XX_httplib_fc(ctx), "%s", "Out of memory"); if ( ptr != NULL ) ctx->listening_sockets = ptr;
closesocket(so.sock); else {
httplib_cry( XX_httplib_fc(ctx), "%s", "Out of memory" );
closesocket( so.sock );
so.sock = INVALID_SOCKET; so.sock = INVALID_SOCKET;
continue; continue;
} }
if ((pfd = httplib_realloc(
ctx->listening_socket_fds,
(ctx->num_listening_sockets + 1)
* sizeof(ctx->listening_socket_fds[0]))) == NULL) {
httplib_cry( XX_httplib_fc(ctx), "%s", "Out of memory"); pfd = httplib_realloc( ctx->listening_socket_fds, (ctx->num_listening_sockets+1) * sizeof(ctx->listening_socket_fds[0]) );
closesocket(so.sock);
if ( pfd != NULL ) ctx->listening_socket_fds = pfd;
else {
httplib_cry( XX_httplib_fc(ctx), "%s", "Out of memory" );
closesocket( so.sock );
so.sock = INVALID_SOCKET; so.sock = INVALID_SOCKET;
httplib_free( ptr );
continue; continue;
} }
XX_httplib_set_close_on_exec(so.sock, XX_httplib_fc(ctx));
ctx->listening_sockets = ptr; XX_httplib_set_close_on_exec( so.sock, XX_httplib_fc(ctx) );
ctx->listening_sockets[ctx->num_listening_sockets] = so; ctx->listening_sockets[ctx->num_listening_sockets] = so;
ctx->listening_socket_fds = pfd;
ctx->num_listening_sockets++; ctx->num_listening_sockets++;
portsOk++;
ports_ok++;
} }
if (portsOk != portsTotal) { if ( ports_ok != ports_total ) {
XX_httplib_close_all_listening_sockets(ctx);
portsOk = 0; XX_httplib_close_all_listening_sockets( ctx );
ports_ok = 0;
} }
return portsOk; return ports_ok;
} /* XX_httplib_set_ports_option */ } /* XX_httplib_set_ports_option */
/* /*
* static int parse_port_string( const struct vec *vec, struct socket *so, int *ip_version ); * static bool parse_port_string( const struct vec *vec, struct socket *so, int *ip_version );
* *
* Valid listening port specification is: [ip_address:]port[s] * Valid listening port specification is: [ip_address:]port[s]
* Examples for IPv4: 80, 443s, 127.0.0.1:3128, 192.0.2.3:8080s * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 192.0.2.3:8080s
@@ -245,9 +269,11 @@ int XX_httplib_set_ports_option( struct httplib_context *ctx ) {
* environment, they might work differently, or might not work * environment, they might work differently, or might not work
* at all - it must be tested what options work best in the * at all - it must be tested what options work best in the
* relevant network environment. * relevant network environment.
*
* The function returns false if an error occurs and true otherwise.
*/ */
static int parse_port_string( const struct vec *vec, struct socket *so, int *ip_version ) { static bool parse_port_string( const struct vec *vec, struct socket *so, int *ip_version ) {
unsigned int a; unsigned int a;
unsigned int b; unsigned int b;
@@ -258,78 +284,122 @@ static int parse_port_string( const struct vec *vec, struct socket *so, int *ip_
int len; int len;
#if defined(USE_IPV6) #if defined(USE_IPV6)
char buf[100] = {0}; char buf[100] = {0};
#endif #endif /* USE_IPV6 */
/* MacOS needs that. If we do not zero it, subsequent bind() will fail. /*
* MacOS needs that. If we do not zero it, subsequent bind() will fail.
* Also, all-zeroes in the socket address means binding to all addresses * Also, all-zeroes in the socket address means binding to all addresses
* for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */ * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
memset(so, 0, sizeof(*so)); */
so->lsa.sin.sin_family = AF_INET;
*ip_version = 0; memset( so, 0, sizeof(*so) );
so->lsa.sin.sin_family = AF_INET;
*ip_version = 0;
if ( sscanf( vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len ) == 5 ) {
/*
* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080
*/
so->lsa.sin.sin_addr.s_addr = htonl( (a << 24) | (b << 16) | (c << 8) | d );
so->lsa.sin.sin_port = htons( (uint16_t)port );
if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
== 5) {
/* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
so->lsa.sin.sin_addr.s_addr =
htonl((a << 24) | (b << 16) | (c << 8) | d);
so->lsa.sin.sin_port = htons((uint16_t)port);
*ip_version = 4; *ip_version = 4;
}
#if defined(USE_IPV6) #if defined(USE_IPV6)
} else if (sscanf(vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len) == 2 else if ( sscanf( vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len ) == 2 && XX_httplib_inet_pton( AF_INET6, buf, &so->lsa.sin6, sizeof(so->lsa.sin6) ) ) {
&& XX_httplib_inet_pton( AF_INET6, buf, &so->lsa.sin6, sizeof(so->lsa.sin6))) {
/* IPv6 address, examples: see above */ /*
/* so->lsa.sin6.sin6_family = AF_INET6; already set by httplib_inet_pton * IPv6 address, examples: see above
* so->lsa.sin6.sin6_family = AF_INET6; already set by httplib_inet_pton
*/ */
so->lsa.sin6.sin6_port = htons((uint16_t)port);
so->lsa.sin6.sin6_port = htons( (uint16_t)port );
*ip_version = 6; *ip_version = 6;
#endif }
#endif /* USE_IPV6 */
} else if ((vec->ptr[0] == '+') else if ( vec->ptr[0] == '+' && sscanf( vec->ptr + 1, "%u%n", &port, &len ) == 1 ) {
&& (sscanf(vec->ptr + 1, "%u%n", &port, &len) == 1)) {
/*
* Port is specified with a +, bind to IPv6 and IPv4, INADDR_ANY
* Add 1 to len for the + character we skipped before
*/
/* Port is specified with a +, bind to IPv6 and IPv4, INADDR_ANY */
/* Add 1 to len for the + character we skipped before */
len++; len++;
#if defined(USE_IPV6) #if defined(USE_IPV6)
/* Set socket family to IPv6, do not use IPV6_V6ONLY */
/*
* Set socket family to IPv6, do not use IPV6_V6ONLY
*/
so->lsa.sin6.sin6_family = AF_INET6; so->lsa.sin6.sin6_family = AF_INET6;
so->lsa.sin6.sin6_port = htons((uint16_t)port); so->lsa.sin6.sin6_port = htons(( uint16_t)port );
*ip_version = 4 + 6; *ip_version = 4 + 6;
#else
/* Bind to IPv4 only, since IPv6 is not built in. */
so->lsa.sin.sin_port = htons((uint16_t)port);
*ip_version = 4;
#endif
} else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) { #else /* USE_IPV6 */
/* If only port is specified, bind to IPv4, INADDR_ANY */
so->lsa.sin.sin_port = htons((uint16_t)port); /*
* Bind to IPv4 only, since IPv6 is not built in.
*/
so->lsa.sin.sin_port = htons( (uint16_t)port );
*ip_version = 4; *ip_version = 4;
} else { #endif /* USE_IPV6 */
/* Parsing failure. Make port invalid. */
}
else if ( sscanf( vec->ptr, "%u%n", &port, &len ) == 1 ) {
/*
* If only port is specified, bind to IPv4, INADDR_ANY
*/
so->lsa.sin.sin_port = htons( (uint16_t)port );
*ip_version = 4;
}
else {
/*
* Parsing failure. Make port invalid.
*/
port = 0; port = 0;
len = 0; len = 0;
} }
/* sscanf and the option splitting code ensure the following condition /*
* sscanf and the option splitting code ensure the following condition
*/ */
if ((len < 0) && ((unsigned)len > (unsigned)vec->len)) {
if ( len < 0 && ((unsigned)len) > ((unsigned)vec->len) ) {
*ip_version = 0; *ip_version = 0;
return 0; return false;
} }
ch = vec->ptr[len]; /* Next character after the port number */
so->is_ssl = (ch == 's');
so->ssl_redir = (ch == 'r');
/* Make sure the port is valid and vector ends with 's', 'r' or ',' */ ch = vec->ptr[len]; /* Next character after the port number */
if (XX_httplib_is_valid_port(port) && (ch == '\0' || ch == 's' || ch == 'r' || ch == ',')) return 1; so->is_ssl = ( ch == 's' );
so->ssl_redir = ( ch == 'r' );
/*
* Make sure the port is valid and vector ends with 's', 'r' or ','
*/
if ( XX_httplib_is_valid_port( port ) && ( ch == '\0' || ch == 's' || ch == 'r' || ch == ',' ) ) return true;
/*
* Reset ip_version to 0 if there is an error
*/
/* Reset ip_version to 0 of there is an error */
*ip_version = 0; *ip_version = 0;
return 0; return false;
} /* parse_port_string */ } /* parse_port_string */

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,7 +22,7 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
@@ -31,14 +31,14 @@
static void *ssllib_dll_handle; /* Store the ssl library handle. */ static void *ssllib_dll_handle; /* Store the ssl library handle. */
/* /*
* int XX_httplib_set_ssl_option( struct httplib_context *ctx ); * bool XX_httplib_set_ssl_option( struct httplib_context *ctx );
* *
* The function XX_httplib_set_ssl_option() loads the SSL library in a dynamic * The function XX_httplib_set_ssl_option() loads the SSL library in a dynamic
* way. * way. The function returns false if an error occured, otherwise true.
*/ */
#if !defined(NO_SSL) #if !defined(NO_SSL)
int XX_httplib_set_ssl_option( struct httplib_context *ctx ) { bool XX_httplib_set_ssl_option( struct httplib_context *ctx ) {
const char *pem; const char *pem;
int callback_ret; int callback_ret;
@@ -47,7 +47,7 @@ int XX_httplib_set_ssl_option( struct httplib_context *ctx ) {
const char *ca_file; const char *ca_file;
int use_default_verify_paths; int use_default_verify_paths;
int verify_depth; int verify_depth;
time_t now_rt = time(NULL); time_t now_rt;
struct timespec now_mt; struct timespec now_mt;
md5_byte_t ssl_context_id[16]; md5_byte_t ssl_context_id[16];
md5_state_t md5state; md5_state_t md5state;
@@ -55,115 +55,125 @@ int XX_httplib_set_ssl_option( struct httplib_context *ctx ) {
/* If PEM file is not specified and the init_ssl callback /* If PEM file is not specified and the init_ssl callback
* is not specified, skip SSL initialization. */ * is not specified, skip SSL initialization. */
if ( ctx == NULL ) return 0; if ( ctx == NULL ) return false;
if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL && ctx->callbacks.init_ssl == NULL) return 1; now_rt = time( NULL );
pem = ctx->config[ SSL_CERTIFICATE ];
if (!XX_httplib_initialize_ssl(ctx)) return 0; if ( pem == NULL && ctx->callbacks.init_ssl == NULL ) return true;
if ( ! XX_httplib_initialize_ssl( ctx ) ) return false;
#if !defined(NO_SSL_DL) #if !defined(NO_SSL_DL)
if (!ssllib_dll_handle) {
ssllib_dll_handle = XX_httplib_load_dll(ctx, SSL_LIB, XX_httplib_ssl_sw); if ( ssllib_dll_handle == NULL ) {
if (!ssllib_dll_handle) return 0;
ssllib_dll_handle = XX_httplib_load_dll( ctx, SSL_LIB, XX_httplib_ssl_sw );
if ( ssllib_dll_handle == NULL ) return false;
} }
#endif /* NO_SSL_DL */ #endif /* NO_SSL_DL */
/* Initialize SSL library */
SSL_library_init(); SSL_library_init();
SSL_load_error_strings(); SSL_load_error_strings();
if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) { ctx->ssl_ctx = SSL_CTX_new( SSLv23_server_method() );
httplib_cry( XX_httplib_fc(ctx), "SSL_CTX_new (server) error: %s", XX_httplib_ssl_error()); if ( ctx->ssl_ctx == NULL ) {
return 0;
httplib_cry( XX_httplib_fc(ctx), "SSL_CTX_new (server) error: %s", XX_httplib_ssl_error() );
return false;
} }
SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); SSL_CTX_clear_options( ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 );
protocol_ver = atoi(ctx->config[SSL_PROTOCOL_VERSION]);
SSL_CTX_set_options(ctx->ssl_ctx, XX_httplib_ssl_get_protocol(protocol_ver)); protocol_ver = atoi( ctx->config[ SSL_PROTOCOL_VERSION ] );
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_SINGLE_DH_USE);
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); SSL_CTX_set_options( ctx->ssl_ctx, XX_httplib_ssl_get_protocol( protocol_ver ) );
SSL_CTX_set_ecdh_auto(ctx->ssl_ctx, 1); SSL_CTX_set_options( ctx->ssl_ctx, SSL_OP_SINGLE_DH_USE );
SSL_CTX_set_options( ctx->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE );
SSL_CTX_set_ecdh_auto( ctx->ssl_ctx, 1 );
/* If a callback has been specified, call it. */ /* If a callback has been specified, call it. */
callback_ret = (ctx->callbacks.init_ssl == NULL) ? 0 : (ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data));
/* If callback returns 0, LibHTTP sets up the SSL certificate. if ( ctx->callbacks.init_ssl == NULL ) callback_ret = 0;
else callback_ret = ctx->callbacks.init_ssl( ctx->ssl_ctx, ctx->user_data );
/*
* If callback returns 0, LibHTTP sets up the SSL certificate.
* If it returns 1, LibHTTP assumes the calback already did this. * If it returns 1, LibHTTP assumes the calback already did this.
* If it returns -1, initializing ssl fails. */ * If it returns -1, initializing ssl fails.
if (callback_ret < 0) { */
httplib_cry( XX_httplib_fc(ctx), "SSL callback returned error: %i", callback_ret);
return 0; if ( callback_ret < 0 ) {
httplib_cry( XX_httplib_fc(ctx), "SSL callback returned error: %i", callback_ret );
return false;
} }
if (callback_ret > 0) {
if (pem != NULL) { if ( callback_ret > 0 ) {
SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
} if ( pem != NULL ) SSL_CTX_use_certificate_chain_file( ctx->ssl_ctx, pem );
return 1; return true;
} }
/* Use some UID as session context ID. */ /* Use some UID as session context ID. */
md5_init(&md5state); md5_init( & md5state );
md5_append(&md5state, (const md5_byte_t *)&now_rt, sizeof(now_rt)); md5_append( & md5state, (const md5_byte_t *)&now_rt, sizeof(now_rt) );
clock_gettime(CLOCK_MONOTONIC, &now_mt); clock_gettime( CLOCK_MONOTONIC, &now_mt );
md5_append(&md5state, (const md5_byte_t *)&now_mt, sizeof(now_mt)); md5_append( & md5state, (const md5_byte_t *)&now_mt, sizeof(now_mt) );
md5_append(&md5state, md5_append( & md5state, (const md5_byte_t *)ctx->config[ LISTENING_PORTS ], strlen( ctx->config[LISTENING_PORTS ] ) );
(const md5_byte_t *)ctx->config[LISTENING_PORTS], md5_append( & md5state, (const md5_byte_t *)ctx, sizeof(*ctx) );
strlen(ctx->config[LISTENING_PORTS])); md5_finish( & md5state, ssl_context_id );
md5_append(&md5state, (const md5_byte_t *)ctx, sizeof(*ctx));
md5_finish(&md5state, ssl_context_id);
SSL_CTX_set_session_id_context(ctx->ssl_ctx, (const unsigned char *)&ssl_context_id, sizeof(ssl_context_id)); SSL_CTX_set_session_id_context( ctx->ssl_ctx, (const unsigned char *)&ssl_context_id, sizeof(ssl_context_id) );
if (pem != NULL) { if ( pem != NULL && ! XX_httplib_ssl_use_pem_file( ctx, pem ) ) return false;
if (!XX_httplib_ssl_use_pem_file(ctx, pem)) return 0;
}
should_verify_peer = should_verify_peer = ctx->config[SSL_DO_VERIFY_PEER] != NULL && ! httplib_strcasecmp( ctx->config[SSL_DO_VERIFY_PEER], "yes" );
(ctx->config[SSL_DO_VERIFY_PEER] != NULL) use_default_verify_paths = ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL && ! httplib_strcasecmp( ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes" );
&& (httplib_strcasecmp(ctx->config[SSL_DO_VERIFY_PEER], "yes") == 0);
use_default_verify_paths = if ( should_verify_peer ) {
(ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL)
&& (httplib_strcasecmp(ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes") == 0);
if (should_verify_peer) {
ca_path = ctx->config[SSL_CA_PATH]; ca_path = ctx->config[SSL_CA_PATH];
ca_file = ctx->config[SSL_CA_FILE]; ca_file = ctx->config[SSL_CA_FILE];
if (SSL_CTX_load_verify_locations(ctx->ssl_ctx, ca_file, ca_path)
!= 1) { if ( SSL_CTX_load_verify_locations( ctx->ssl_ctx, ca_file, ca_path ) != 1 ) {
httplib_cry( XX_httplib_fc(ctx), httplib_cry( XX_httplib_fc(ctx),
"SSL_CTX_load_verify_locations error: %s " "SSL_CTX_load_verify_locations error: %s "
"ssl_verify_peer requires setting " "ssl_verify_peer requires setting "
"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 false;
} }
SSL_CTX_set_verify(ctx->ssl_ctx, SSL_CTX_set_verify( ctx->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL );
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL); if ( use_default_verify_paths && SSL_CTX_set_default_verify_paths( ctx->ssl_ctx ) != 1 ) {
if (use_default_verify_paths
&& SSL_CTX_set_default_verify_paths(ctx->ssl_ctx) != 1) {
httplib_cry( XX_httplib_fc(ctx), "SSL_CTX_set_default_verify_paths error: %s", XX_httplib_ssl_error()); httplib_cry( XX_httplib_fc(ctx), "SSL_CTX_set_default_verify_paths error: %s", XX_httplib_ssl_error());
return 0; return false;
} }
if (ctx->config[SSL_VERIFY_DEPTH]) { if ( ctx->config[SSL_VERIFY_DEPTH] != NULL ) {
verify_depth = atoi(ctx->config[SSL_VERIFY_DEPTH]);
SSL_CTX_set_verify_depth(ctx->ssl_ctx, verify_depth); verify_depth = atoi( ctx->config[SSL_VERIFY_DEPTH] );
SSL_CTX_set_verify_depth( ctx->ssl_ctx, verify_depth );
} }
} }
if (ctx->config[SSL_CIPHER_LIST] != NULL) { if ( ctx->config[SSL_CIPHER_LIST] != NULL ) {
if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, ctx->config[SSL_CIPHER_LIST]) != 1) {
if ( SSL_CTX_set_cipher_list( ctx->ssl_ctx, ctx->config[SSL_CIPHER_LIST] ) != 1 ) {
httplib_cry( XX_httplib_fc(ctx), "SSL_CTX_set_cipher_list error: %s", XX_httplib_ssl_error()); httplib_cry( XX_httplib_fc(ctx), "SSL_CTX_set_cipher_list error: %s", XX_httplib_ssl_error());
} }
} }
return 1; return true;
} /* XX_httplib_set_ssl_option */ } /* XX_httplib_set_ssl_option */

View File

@@ -22,23 +22,27 @@
* 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"
#if !defined(NO_THREAD_NAME) #if !defined(NO_THREAD_NAME)
#if defined(_WIN32) && defined(_MSC_VER) #if defined(_WIN32) && defined(_MSC_VER)
/* Set the thread name for debugging purposes in Visual Studio
/*
* Set the thread name for debugging purposes in Visual Studio
* http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
*/ */
#pragma pack(push, 8) #pragma pack(push, 8)
typedef struct tagTHREADNAME_INFO { typedef struct tagTHREADNAME_INFO {
DWORD dwType; /* Must be 0x1000. */ DWORD dwType; /* Must be 0x1000. */
LPCSTR szName; /* Pointer to name (in user addr space). */ LPCSTR szName; /* Pointer to name (in user addr space). */
DWORD dwThreadID; /* Thread ID (-1=caller thread). */ DWORD dwThreadID; /* Thread ID (-1=caller thread). */
DWORD dwFlags; /* Reserved for future use, must be zero. */ DWORD dwFlags; /* Reserved for future use, must be zero. */
} THREADNAME_INFO; } THREADNAME_INFO;
#pragma pack(pop) #pragma pack(pop)
@@ -48,46 +52,80 @@ typedef struct tagTHREADNAME_INFO {
#include <sys/sendfile.h> #include <sys/sendfile.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
#endif #endif /* __linux__ */
void XX_httplib_set_thread_name( const char *name ) {
void XX_httplib_set_thread_name(const char *name) { char thread_name[16+1]; /* 16 = Max. thread length in Linux/OSX/.. */
char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */ XX_httplib_snprintf( NULL, NULL, thread_name, sizeof(thread_name), "libhttp-%s", name );
XX_httplib_snprintf( NULL, NULL, threadName, sizeof(threadName), "libhttp-%s", name);
#if defined(_WIN32) #if defined(_WIN32)
#if defined(_MSC_VER)
/* Windows and Visual Studio Compiler */
__try
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = ~0U;
info.dwFlags = 0;
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); #if defined(_MSC_VER)
}
__except(EXCEPTION_EXECUTE_HANDLER) /*
{ * Windows and Visual Studio Compiler
*/
__try {
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = thread_name;
info.dwThreadID = ~0U;
info.dwFlags = 0;
RaiseException( 0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info );
} }
__except(EXCEPTION_EXECUTE_HANDLER) {}
#elif defined(__MINGW32__) #elif defined(__MINGW32__)
/* No option known to set thread name for MinGW */
#endif /*
#elif defined(__GLIBC__) \ * No option known to set thread name for MinGW
&& ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12))) */
/* pthread_setname_np first appeared in glibc in version 2.12*/
pthread_setname_np( httplib_pthread_self(), threadName ); #else /* _MSC_VER or __MINGW32__ */
/*
* Any other Windows compiler like Watcom, Embarcadero etc
*/
#endif /* _MSC_VER or __MINGW32__ */
#elif defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
/*
* pthread_setname_np first appeared in glibc in version 2.12
*/
pthread_setname_np( httplib_pthread_self(), thread_name );
#elif defined(__linux__) #elif defined(__linux__)
/* on linux we can use the old prctl function */
prctl(PR_SET_NAME, threadName, 0, 0, 0); /*
* on linux we can use the old prctl function
*/
prctl( PR_SET_NAME, threadName, 0, 0, 0 );
#else
/*
* Other exotic systems or very old glibc versions
*/
#endif #endif
} /* XX_httplib_set_thread_name */ } /* XX_httplib_set_thread_name */
#else /* !defined(NO_THREAD_NAME) */ #else /* !defined(NO_THREAD_NAME) */
void XX_httplib_set_thread_name(const char *threadName) {
void XX_httplib_set_thread_name( const char *name ) {
UNUSED_PARAMETER(name);
} /* XX_httplib_set_thread_name */ } /* XX_httplib_set_thread_name */
#endif /* !NO_THREAD_NAME */ #endif /* !NO_THREAD_NAME */

View File

@@ -22,7 +22,7 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
@@ -37,29 +37,42 @@
int XX_httplib_set_throttle( const char *spec, uint32_t remote_ip, const char *uri ) { int XX_httplib_set_throttle( const char *spec, uint32_t remote_ip, const char *uri ) {
int throttle = 0; int facchar;
struct vec vec, val; struct vec vec;
uint32_t net, mask; struct vec val;
uint32_t net;
uint32_t mask;
char mult; char mult;
double v; double v;
while ((spec = XX_httplib_next_option(spec, &vec, &val)) != NULL) { while ( (spec = XX_httplib_next_option( spec, & vec, & val )) != NULL ) {
mult = ','; mult = ',';
if ((val.ptr == NULL) || (sscanf(val.ptr, "%lf%c", &v, &mult) < 1)
|| (v < 0) || ((XX_httplib_lowercase(&mult) != 'k') if ( val.ptr == NULL ) continue;
&& (XX_httplib_lowercase(&mult) != 'm') && (mult != ','))) { if ( sscanf( val.ptr, "%lf%c", &v, &mult ) < 1 ) continue;
continue; if ( v < 0 ) continue;
facchar = XX_httplib_lowercase( & mult );
if ( facchar != 'k' && facchar != 'm' && mult != ',' ) continue;
switch ( facchar ) {
case 'k' : v *= 1024.0; break;
case 'm' : v *= 1024.0*1024.0; break;
} }
v *= (XX_httplib_lowercase(&mult) == 'k') ? 1024 : ((XX_httplib_lowercase(&mult) == 'm') ? 1048576 : 1);
if (vec.len == 1 && vec.ptr[0] == '*') { if ( vec.len == 1 && vec.ptr[0] == '*' ) return (int)v;
throttle = (int)v;
} else if (XX_httplib_parse_net(vec.ptr, &net, &mask) > 0) { if ( XX_httplib_parse_net( vec.ptr, &net, &mask ) > 0 ) {
if ((remote_ip & mask) == net) {
throttle = (int)v; if ( (remote_ip & mask) == net ) return (int)v;
} }
} else if (XX_httplib_match_prefix(vec.ptr, vec.len, uri) > 0) throttle = (int)v;
if ( XX_httplib_match_prefix( vec.ptr, vec.len, uri) > 0 ) return (int)v;
} }
return throttle; return 0;
} /* XX_httplib_set_throttle */ } /* XX_httplib_set_throttle */

View File

@@ -22,13 +22,21 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
void httplib_set_user_connection_data(struct httplib_connection *conn, void *data) { /*
* void httplib_set_user_connection_data( struct httplib_connection *conn, void *data );
*
* The function void htptlib_set_user_connection_data() registers a block of
* data with a connection. If the function is called with NULL as parameter for
* the data, the link between the connection and data is removed.
*/
if (conn != NULL) conn->request_info.conn_data = data; void httplib_set_user_connection_data( struct httplib_connection *conn, void *data ) {
if ( conn != NULL ) conn->request_info.conn_data = data;
} /* mt_set_user_connection_data */ } /* mt_set_user_connection_data */

View File

@@ -134,7 +134,7 @@ struct ssl_func {
int XX_httplib_get_first_ssl_listener_index( const struct httplib_context *ctx ); int XX_httplib_get_first_ssl_listener_index( const struct httplib_context *ctx );
int XX_httplib_initialize_ssl( struct httplib_context *ctx ); int XX_httplib_initialize_ssl( struct httplib_context *ctx );
int XX_httplib_set_ssl_option( struct httplib_context *ctx ); bool XX_httplib_set_ssl_option( struct httplib_context *ctx );
const char * XX_httplib_ssl_error( void ); const char * XX_httplib_ssl_error( void );
void XX_httplib_ssl_get_client_cert_info( struct httplib_connection *conn ); void XX_httplib_ssl_get_client_cert_info( struct httplib_connection *conn );
long XX_httplib_ssl_get_protocol( int version_id ); long XX_httplib_ssl_get_protocol( int version_id );

View File

@@ -22,19 +22,25 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
#include "httplib_utils.h" #include "httplib_utils.h"
int httplib_strcasecmp(const char *s1, const char *s2) { /*
* int httplib_strcasecmp( const char *s1, const char *s2 );
*
* The function httplib_strcasecmp() provides a platform independent way to
* compare two strings in a case insensitive way.
*/
int httplib_strcasecmp( const char *s1, const char *s2 ) {
int diff; int diff;
do { if ( s1 == NULL || s2 == NULL ) return 0;
diff = XX_httplib_lowercase(s1++) - XX_httplib_lowercase(s2++); do { diff = XX_httplib_lowercase(s1++) - XX_httplib_lowercase(s2++); } while ( diff == 0 && s1[-1] != '\0' );
} while (diff == 0 && s1[-1] != '\0');
return diff; return diff;

View File

@@ -28,18 +28,32 @@
#include "httplib_main.h" #include "httplib_main.h"
#include "httplib_string.h" #include "httplib_string.h"
const char * XX_httplib_strcasestr( const char *big_str, const char *small_str ) { /*
* const char *httplib_strcasestr( const char *big_str, const char *small_str );
*
* The function httplib_strcasestr() searches case insensitive for a NUL
* terminated string in another string and returns a pointer to the first
* occurrence, or NULL if the substring could not be found.
*/
LIBHTTP_API const char *httplib_strcasestr( const char *big_str, const char *small_str ) {
size_t i; size_t i;
size_t big_len = strlen(big_str); size_t big_len;
size_t small_len = strlen(small_str); size_t small_len;
if (big_len >= small_len) { if ( big_str == NULL || small_str == NULL ) return NULL;
for (i = 0; i <= (big_len - small_len); i++) {
if (httplib_strncasecmp(big_str + i, small_str, small_len) == 0) return big_str + i; big_len = strlen( big_str );
} small_len = strlen( small_str );
if ( big_len < small_len ) return NULL;
for (i=0; i<=big_len-small_len; i++) {
if ( httplib_strncasecmp( big_str+i, small_str, small_len ) == 0 ) return big_str+i;
} }
return NULL; return NULL;
} /* XX_httplib_strcasestr */ } /* httplib_strcasestr */

View File

@@ -23,7 +23,6 @@
void XX_httplib_snprintf( const struct httplib_connection *conn, int *truncated, char *buf, size_t buflen, PRINTF_FORMAT_STRING(const char *fmt), ... ) PRINTF_ARGS(5, 6); void XX_httplib_snprintf( const struct httplib_connection *conn, int *truncated, char *buf, size_t buflen, PRINTF_FORMAT_STRING(const char *fmt), ... ) PRINTF_ARGS(5, 6);
const char * XX_httplib_strcasestr( const char *big_str, const char *small_str );
char * XX_httplib_strdup( const char *str ); char * XX_httplib_strdup( const char *str );
int XX_httplib_vprintf( struct httplib_connection *conn, const char *fmt, va_list ap ); int XX_httplib_vprintf( struct httplib_connection *conn, const char *fmt, va_list ap );
void XX_httplib_vsnprintf( const struct httplib_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, va_list ap ); void XX_httplib_vsnprintf( const struct httplib_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, va_list ap );

View File

@@ -22,21 +22,26 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
* ============ * ============
* Release: 1.8 * Release: 2.0
*/ */
#include "httplib_main.h" #include "httplib_main.h"
#include "httplib_utils.h" #include "httplib_utils.h"
/*
* int httplib_strncasecmp( const char *s1, const char *s2, size_t len );
*
* The function httplib_strncasecmp() provides a case insensitive way to
* compare two strings over a maximum number of characters.
*/
int httplib_strncasecmp( const char *s1, const char *s2, size_t len ) { int httplib_strncasecmp( const char *s1, const char *s2, size_t len ) {
int diff = 0; int diff;
if (len > 0) { if ( s1 == NULL || s2 == NULL || len == 0 ) return 0;
do {
diff = XX_httplib_lowercase(s1++) - XX_httplib_lowercase(s2++); do { diff = XX_httplib_lowercase(s1++) - XX_httplib_lowercase(s2++); } while ( diff == 0 && s1[-1] != '\0' && --len > 0 );
} while (diff == 0 && s1[-1] != '\0' && --len > 0);
}
return diff; return diff;