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:
@@ -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_md5( buf, ... );`](api/httplib_md5.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_strlcpy( dst, src, len );`](api/httplib_strlcpy.md)
|
||||
* [`httplib_strncasecmp( s1, s2, len );`](api/httplib_strncasecmp.md)
|
||||
|
@@ -21,6 +21,7 @@ The function `httplib_strcasecmp()` is a helper function to compare two strings.
|
||||
|
||||
### See Also
|
||||
|
||||
* [`httplib_strcasestr();`](httplib_strcasestr.md)
|
||||
* [`httplib_strdup();`](httplib_strdup.md)
|
||||
* [`httplib_strncasecmp();`](httplib_strncasecmp.md)
|
||||
* [`httplib_strndup();`](httplib_strndup.md)
|
||||
|
27
doc/api/httplib_strcasestr.md
Normal file
27
doc/api/httplib_strcasestr.md
Normal 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)
|
@@ -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_strcasecmp();`](httplib_strcasecmp.md)
|
||||
* [`httplib_strcasestr();`](httplib_strcasestr.md)
|
||||
* [`httplib_strncasecmp();`](httplib_strncasecmp.md)
|
||||
* [`httplib_strndup();`](httplib_strndup.md)
|
||||
|
@@ -23,5 +23,6 @@ If the source string is longer than will fit in the receiving buffer, the remain
|
||||
### See Also
|
||||
|
||||
* [`httplib_strcasecmp();`](httplib_strcasecmp.md)
|
||||
* [`httplib_strcasestr();`](httplib_strcasestr.md)
|
||||
* [`httplib_strncasecmp();`](httplib_strncasecmp.md)
|
||||
* [`httplib_strndup();`](httplib_strndup.md)
|
||||
|
@@ -23,5 +23,6 @@ The function `httplib_strncasecmp()` is a helper function to compare two strings
|
||||
### See Also
|
||||
|
||||
* [`httplib_strcasecmp();`](httplib_strcasecmp.md)
|
||||
* [`httplib_strcasestr();`](httplib_strcasestr.md)
|
||||
* [`httplib_strdup();`](httplib_strdup.md)
|
||||
* [`httplib_strndup();`](httplib_strndup.md)
|
||||
|
@@ -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_strcasecmp();`](httplib_strcasecmp.md)
|
||||
* [`httplib_strcasestr();`](httplib_strcasestr.md)
|
||||
* [`httplib_strdup();`](httplib_strdup.md)
|
||||
* [`httplib_strncasecmp();`](httplib_strncasecmp.md)
|
||||
|
@@ -869,8 +869,6 @@ LIBHTTP_API void httplib_cry(const struct httplib_connection *conn, PRINTF_FORMA
|
||||
|
||||
|
||||
/* 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
|
||||
@@ -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 int httplib_remove( const char *path );
|
||||
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 int httplib_strncasecmp( const char *s1, const char *s2, size_t len );
|
||||
LIBHTTP_API char * httplib_strndup( const char *str, size_t len );
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -44,7 +44,7 @@ int httplib_get_cookie(const char *cookie_header, const char *var_name, char *ds
|
||||
|
||||
name_len = (int)strlen(var_name);
|
||||
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] == '=') {
|
||||
/* HCP24: now check is it a substring or a full cookie name */
|
||||
if ((s == cookie_header) || (s[-1] == ' ')) {
|
||||
|
@@ -50,12 +50,12 @@ bool XX_httplib_is_websocket_protocol( const struct httplib_connection *conn ) {
|
||||
upgrade = httplib_get_header(conn, "Upgrade");
|
||||
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");
|
||||
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
|
||||
* "Sec-WebSocket-Version" are also required.
|
||||
|
@@ -22,22 +22,21 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
#include "httplib_memory.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 );
|
||||
*
|
||||
* 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 ) {
|
||||
@@ -46,191 +45,216 @@ int XX_httplib_set_ports_option( struct httplib_context *ctx ) {
|
||||
int on = 1;
|
||||
#if defined(USE_IPV6)
|
||||
int off = 0;
|
||||
#endif
|
||||
#endif /* USE_IPV6 */
|
||||
struct vec vec;
|
||||
struct socket so, *ptr;
|
||||
|
||||
struct socket so;
|
||||
struct socket *ptr;
|
||||
struct pollfd *pfd;
|
||||
union usa usa;
|
||||
socklen_t len;
|
||||
int ip_version;
|
||||
|
||||
int portsTotal = 0;
|
||||
int portsOk = 0;
|
||||
int ports_total;
|
||||
int ports_ok;
|
||||
|
||||
if ( ctx == NULL ) return 0;
|
||||
|
||||
memset(&so, 0, sizeof(so));
|
||||
memset(&usa, 0, sizeof(usa));
|
||||
len = sizeof(usa);
|
||||
ports_total = 0;
|
||||
ports_ok = 0;
|
||||
|
||||
memset( & so, 0, sizeof(so) );
|
||||
memset( & usa, 0, sizeof(usa) );
|
||||
|
||||
len = sizeof(usa);
|
||||
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),
|
||||
"%.*s: invalid port spec (entry %i). Expecting list of: %s",
|
||||
(int)vec.len,
|
||||
vec.ptr,
|
||||
portsTotal,
|
||||
"[IP_ADDRESS:]PORT[s|r]");
|
||||
ports_total,
|
||||
"[IP_ADDRESS:]PORT[s|r]" );
|
||||
continue;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
#endif
|
||||
#endif /* ! NO_SLL */
|
||||
|
||||
if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
|
||||
== INVALID_SOCKET) {
|
||||
if ( ( so.sock = socket( so.lsa.sa.sa_family, SOCK_STREAM, 6 ) ) == 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;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Windows SO_REUSEADDR lets many procs binds to a
|
||||
#if defined(_WIN32)
|
||||
|
||||
/*
|
||||
* Windows SO_REUSEADDR lets many procs binds to a
|
||||
* socket, SO_EXCLUSIVEADDRUSE makes the bind fail
|
||||
* if someone already has the socket -- DTL */
|
||||
/* NOTE: If SO_EXCLUSIVEADDRUSE is used,
|
||||
* if someone already has the socket -- DTL
|
||||
*
|
||||
* NOTE: If SO_EXCLUSIVEADDRUSE is used,
|
||||
* Windows might need a few seconds before
|
||||
* the same port can be used again in the
|
||||
* same process, so a short Sleep may be
|
||||
* 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. */
|
||||
httplib_cry( XX_httplib_fc(ctx), "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)", portsTotal);
|
||||
if ( setsockopt( so.sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (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_EXCLUSIVEADDRUSE (entry %i)", ports_total );
|
||||
}
|
||||
#else
|
||||
if (setsockopt(so.sock, SOL_SOCKET, SO_REUSEADDR, (SOCK_OPT_TYPE)&on, sizeof(on)) != 0) {
|
||||
#else /* _WIN32 */
|
||||
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 (ip_version == 6) {
|
||||
if (so.lsa.sa.sa_family == AF_INET6
|
||||
&& setsockopt(so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&off, sizeof(off)) != 0) {
|
||||
if ( ip_version == 6 ) {
|
||||
|
||||
/* Set IPv6 only option, but don't abort on errors. */
|
||||
httplib_cry( XX_httplib_fc(ctx), "cannot set socket option IPV6_V6ONLY (entry %i)", portsTotal);
|
||||
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.
|
||||
*/
|
||||
|
||||
httplib_cry( XX_httplib_fc(ctx), "cannot set socket option IPV6_V6ONLY (entry %i)", ports_total );
|
||||
}
|
||||
}
|
||||
#else
|
||||
httplib_cry( XX_httplib_fc(ctx), "IPv6 not available");
|
||||
closesocket(so.sock);
|
||||
#else /* USE_IPV6 */
|
||||
httplib_cry( XX_httplib_fc(ctx), "IPv6 not available" );
|
||||
closesocket( so.sock );
|
||||
so.sock = INVALID_SOCKET;
|
||||
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);
|
||||
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));
|
||||
closesocket(so.sock);
|
||||
|
||||
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) );
|
||||
closesocket( so.sock );
|
||||
so.sock = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#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);
|
||||
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));
|
||||
closesocket(so.sock);
|
||||
|
||||
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) );
|
||||
closesocket( so.sock );
|
||||
so.sock = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* USE_IPV6 */
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
closesocket(so.sock);
|
||||
httplib_cry( XX_httplib_fc(ctx), "cannot listen to %.*s: %d (%s)", (int)vec.len, vec.ptr, (int)ERRNO, strerror(errno) );
|
||||
closesocket( so.sock );
|
||||
so.sock = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getsockname(so.sock, &(usa.sa), &len) != 0
|
||||
|| usa.sa.sa_family != so.lsa.sa.sa_family) {
|
||||
if ( getsockname( so.sock, &(usa.sa), &len ) != 0 || usa.sa.sa_family != so.lsa.sa.sa_family ) {
|
||||
|
||||
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));
|
||||
closesocket(so.sock);
|
||||
httplib_cry( XX_httplib_fc(ctx), "call to getsockname failed %.*s: %d (%s)", (int)vec.len, vec.ptr, err, strerror(errno) );
|
||||
closesocket( so.sock );
|
||||
so.sock = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Update lsa port in case of random free ports */
|
||||
/*
|
||||
* Update lsa port in case of random free ports
|
||||
*/
|
||||
|
||||
#if defined(USE_IPV6)
|
||||
if (so.lsa.sa.sa_family == AF_INET6) {
|
||||
so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
|
||||
} else
|
||||
#endif
|
||||
if ( so.lsa.sa.sa_family == AF_INET6 ) so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
|
||||
|
||||
else
|
||||
#endif /* USE_IPV6 */
|
||||
{
|
||||
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");
|
||||
closesocket(so.sock);
|
||||
if ( ptr != NULL ) ctx->listening_sockets = ptr;
|
||||
else {
|
||||
httplib_cry( XX_httplib_fc(ctx), "%s", "Out of memory" );
|
||||
closesocket( so.sock );
|
||||
so.sock = INVALID_SOCKET;
|
||||
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");
|
||||
closesocket(so.sock);
|
||||
pfd = httplib_realloc( ctx->listening_socket_fds, (ctx->num_listening_sockets+1) * sizeof(ctx->listening_socket_fds[0]) );
|
||||
|
||||
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;
|
||||
httplib_free( ptr );
|
||||
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_socket_fds = pfd;
|
||||
ctx->num_listening_sockets++;
|
||||
portsOk++;
|
||||
|
||||
ports_ok++;
|
||||
}
|
||||
|
||||
if (portsOk != portsTotal) {
|
||||
XX_httplib_close_all_listening_sockets(ctx);
|
||||
portsOk = 0;
|
||||
if ( ports_ok != ports_total ) {
|
||||
|
||||
XX_httplib_close_all_listening_sockets( ctx );
|
||||
ports_ok = 0;
|
||||
}
|
||||
|
||||
return portsOk;
|
||||
return ports_ok;
|
||||
|
||||
} /* 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]
|
||||
* 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
|
||||
* at all - it must be tested what options work best in the
|
||||
* 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 b;
|
||||
@@ -258,78 +284,122 @@ static int parse_port_string( const struct vec *vec, struct socket *so, int *ip_
|
||||
int len;
|
||||
#if defined(USE_IPV6)
|
||||
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
|
||||
* 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;
|
||||
* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if defined(USE_IPV6)
|
||||
} 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))) {
|
||||
/* IPv6 address, examples: see above */
|
||||
/* so->lsa.sin6.sin6_family = AF_INET6; already set by httplib_inet_pton
|
||||
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) ) ) {
|
||||
|
||||
/*
|
||||
* 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;
|
||||
#endif
|
||||
}
|
||||
#endif /* USE_IPV6 */
|
||||
|
||||
} else if ((vec->ptr[0] == '+')
|
||||
&& (sscanf(vec->ptr + 1, "%u%n", &port, &len) == 1)) {
|
||||
else if ( vec->ptr[0] == '+' && 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++;
|
||||
|
||||
#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_port = htons((uint16_t)port);
|
||||
so->lsa.sin6.sin6_port = htons(( uint16_t)port );
|
||||
|
||||
*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) {
|
||||
/* If only port is specified, bind to IPv4, INADDR_ANY */
|
||||
so->lsa.sin.sin_port = htons((uint16_t)port);
|
||||
#else /* USE_IPV6 */
|
||||
|
||||
/*
|
||||
* Bind to IPv4 only, since IPv6 is not built in.
|
||||
*/
|
||||
|
||||
so->lsa.sin.sin_port = htons( (uint16_t)port );
|
||||
*ip_version = 4;
|
||||
|
||||
} else {
|
||||
/* Parsing failure. Make port invalid. */
|
||||
#endif /* USE_IPV6 */
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
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 ',' */
|
||||
if (XX_httplib_is_valid_port(port) && (ch == '\0' || ch == 's' || ch == 'r' || ch == ',')) return 1;
|
||||
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 ','
|
||||
*/
|
||||
|
||||
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;
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
} /* parse_port_string */
|
||||
|
||||
|
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
|
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -31,14 +31,14 @@
|
||||
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
|
||||
* way.
|
||||
* way. The function returns false if an error occured, otherwise true.
|
||||
*/
|
||||
|
||||
#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;
|
||||
int callback_ret;
|
||||
@@ -47,7 +47,7 @@ int XX_httplib_set_ssl_option( struct httplib_context *ctx ) {
|
||||
const char *ca_file;
|
||||
int use_default_verify_paths;
|
||||
int verify_depth;
|
||||
time_t now_rt = time(NULL);
|
||||
time_t now_rt;
|
||||
struct timespec now_mt;
|
||||
md5_byte_t ssl_context_id[16];
|
||||
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
|
||||
* 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 (!ssllib_dll_handle) {
|
||||
ssllib_dll_handle = XX_httplib_load_dll(ctx, SSL_LIB, XX_httplib_ssl_sw);
|
||||
if (!ssllib_dll_handle) return 0;
|
||||
|
||||
if ( ssllib_dll_handle == NULL ) {
|
||||
|
||||
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 */
|
||||
|
||||
/* Initialize SSL library */
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
|
||||
if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
|
||||
httplib_cry( XX_httplib_fc(ctx), "SSL_CTX_new (server) error: %s", XX_httplib_ssl_error());
|
||||
return 0;
|
||||
ctx->ssl_ctx = SSL_CTX_new( SSLv23_server_method() );
|
||||
if ( ctx->ssl_ctx == NULL ) {
|
||||
|
||||
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);
|
||||
protocol_ver = atoi(ctx->config[SSL_PROTOCOL_VERSION]);
|
||||
SSL_CTX_set_options(ctx->ssl_ctx, XX_httplib_ssl_get_protocol(protocol_ver));
|
||||
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);
|
||||
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 ) );
|
||||
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. */
|
||||
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, initializing ssl fails. */
|
||||
if (callback_ret < 0) {
|
||||
httplib_cry( XX_httplib_fc(ctx), "SSL callback returned error: %i", callback_ret);
|
||||
return 0;
|
||||
* 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 false;
|
||||
}
|
||||
if (callback_ret > 0) {
|
||||
if (pem != NULL) {
|
||||
SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
|
||||
}
|
||||
return 1;
|
||||
|
||||
if ( callback_ret > 0 ) {
|
||||
|
||||
if ( pem != NULL ) SSL_CTX_use_certificate_chain_file( ctx->ssl_ctx, pem );
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Use some UID as session context ID. */
|
||||
md5_init(&md5state);
|
||||
md5_append(&md5state, (const md5_byte_t *)&now_rt, sizeof(now_rt));
|
||||
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 *)ctx->config[LISTENING_PORTS],
|
||||
strlen(ctx->config[LISTENING_PORTS]));
|
||||
md5_append(&md5state, (const md5_byte_t *)ctx, sizeof(*ctx));
|
||||
md5_finish(&md5state, ssl_context_id);
|
||||
md5_init( & md5state );
|
||||
md5_append( & md5state, (const md5_byte_t *)&now_rt, sizeof(now_rt) );
|
||||
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 *)ctx->config[ LISTENING_PORTS ], strlen( ctx->config[LISTENING_PORTS ] ) );
|
||||
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 (!XX_httplib_ssl_use_pem_file(ctx, pem)) return 0;
|
||||
}
|
||||
if ( pem != NULL && ! XX_httplib_ssl_use_pem_file( ctx, pem ) ) return false;
|
||||
|
||||
should_verify_peer =
|
||||
(ctx->config[SSL_DO_VERIFY_PEER] != NULL)
|
||||
&& (httplib_strcasecmp(ctx->config[SSL_DO_VERIFY_PEER], "yes") == 0);
|
||||
should_verify_peer = ctx->config[SSL_DO_VERIFY_PEER] != NULL && ! httplib_strcasecmp( ctx->config[SSL_DO_VERIFY_PEER], "yes" );
|
||||
use_default_verify_paths = ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL && ! httplib_strcasecmp( ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes" );
|
||||
|
||||
use_default_verify_paths =
|
||||
(ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL)
|
||||
&& (httplib_strcasecmp(ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes") == 0);
|
||||
if ( should_verify_peer ) {
|
||||
|
||||
if (should_verify_peer) {
|
||||
ca_path = ctx->config[SSL_CA_PATH];
|
||||
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),
|
||||
"SSL_CTX_load_verify_locations error: %s "
|
||||
"ssl_verify_peer requires setting "
|
||||
"either ssl_ca_path or ssl_ca_file. Is any of them "
|
||||
"present in "
|
||||
"the .conf file?",
|
||||
XX_httplib_ssl_error());
|
||||
return 0;
|
||||
XX_httplib_ssl_error() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SSL_CTX_set_verify(ctx->ssl_ctx,
|
||||
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
NULL);
|
||||
SSL_CTX_set_verify( ctx->ssl_ctx, 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());
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctx->config[SSL_VERIFY_DEPTH]) {
|
||||
verify_depth = atoi(ctx->config[SSL_VERIFY_DEPTH]);
|
||||
SSL_CTX_set_verify_depth(ctx->ssl_ctx, 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 );
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->config[SSL_CIPHER_LIST] != NULL) {
|
||||
if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, ctx->config[SSL_CIPHER_LIST]) != 1) {
|
||||
if ( ctx->config[SSL_CIPHER_LIST] != NULL ) {
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
} /* XX_httplib_set_ssl_option */
|
||||
|
||||
|
@@ -22,23 +22,27 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
#include "httplib_string.h"
|
||||
|
||||
#if !defined(NO_THREAD_NAME)
|
||||
|
||||
#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
|
||||
*/
|
||||
|
||||
#pragma pack(push, 8)
|
||||
typedef struct tagTHREADNAME_INFO {
|
||||
DWORD dwType; /* Must be 0x1000. */
|
||||
LPCSTR szName; /* Pointer to name (in user addr space). */
|
||||
DWORD dwThreadID; /* Thread ID (-1=caller thread). */
|
||||
DWORD dwFlags; /* Reserved for future use, must be zero. */
|
||||
DWORD dwType; /* Must be 0x1000. */
|
||||
LPCSTR szName; /* Pointer to name (in user addr space). */
|
||||
DWORD dwThreadID; /* Thread ID (-1=caller thread). */
|
||||
DWORD dwFlags; /* Reserved for future use, must be zero. */
|
||||
} THREADNAME_INFO;
|
||||
#pragma pack(pop)
|
||||
|
||||
@@ -48,46 +52,80 @@ typedef struct tagTHREADNAME_INFO {
|
||||
#include <sys/sendfile.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, threadName, sizeof(threadName), "libhttp-%s", name);
|
||||
XX_httplib_snprintf( NULL, NULL, thread_name, sizeof(thread_name), "libhttp-%s", name );
|
||||
|
||||
#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);
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
/*
|
||||
* 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__)
|
||||
/* No option known to set thread name for MinGW */
|
||||
#endif
|
||||
#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(), threadName );
|
||||
|
||||
/*
|
||||
* No option known to set thread name for MinGW
|
||||
*/
|
||||
|
||||
#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__)
|
||||
/* 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
|
||||
|
||||
} /* XX_httplib_set_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 */
|
||||
|
||||
#endif /* !NO_THREAD_NAME */
|
||||
|
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.h"
|
||||
@@ -37,29 +37,42 @@
|
||||
|
||||
int XX_httplib_set_throttle( const char *spec, uint32_t remote_ip, const char *uri ) {
|
||||
|
||||
int throttle = 0;
|
||||
struct vec vec, val;
|
||||
uint32_t net, mask;
|
||||
int facchar;
|
||||
struct vec vec;
|
||||
struct vec val;
|
||||
uint32_t net;
|
||||
uint32_t mask;
|
||||
char mult;
|
||||
double v;
|
||||
|
||||
while ((spec = XX_httplib_next_option(spec, &vec, &val)) != NULL) {
|
||||
while ( (spec = XX_httplib_next_option( spec, & vec, & val )) != NULL ) {
|
||||
|
||||
mult = ',';
|
||||
if ((val.ptr == NULL) || (sscanf(val.ptr, "%lf%c", &v, &mult) < 1)
|
||||
|| (v < 0) || ((XX_httplib_lowercase(&mult) != 'k')
|
||||
&& (XX_httplib_lowercase(&mult) != 'm') && (mult != ','))) {
|
||||
continue;
|
||||
|
||||
if ( val.ptr == NULL ) continue;
|
||||
if ( sscanf( val.ptr, "%lf%c", &v, &mult ) < 1 ) 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] == '*') {
|
||||
throttle = (int)v;
|
||||
} else if (XX_httplib_parse_net(vec.ptr, &net, &mask) > 0) {
|
||||
if ((remote_ip & mask) == net) {
|
||||
throttle = (int)v;
|
||||
}
|
||||
} else if (XX_httplib_match_prefix(vec.ptr, vec.len, uri) > 0) throttle = (int)v;
|
||||
|
||||
if ( vec.len == 1 && vec.ptr[0] == '*' ) return (int)v;
|
||||
|
||||
if ( XX_httplib_parse_net( vec.ptr, &net, &mask ) > 0 ) {
|
||||
|
||||
if ( (remote_ip & mask) == net ) return (int)v;
|
||||
}
|
||||
|
||||
if ( XX_httplib_match_prefix( vec.ptr, vec.len, uri) > 0 ) return (int)v;
|
||||
}
|
||||
|
||||
return throttle;
|
||||
return 0;
|
||||
|
||||
} /* XX_httplib_set_throttle */
|
||||
|
@@ -22,13 +22,21 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#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 */
|
||||
|
@@ -134,7 +134,7 @@ struct ssl_func {
|
||||
|
||||
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_set_ssl_option( struct httplib_context *ctx );
|
||||
bool XX_httplib_set_ssl_option( struct httplib_context *ctx );
|
||||
const char * XX_httplib_ssl_error( void );
|
||||
void XX_httplib_ssl_get_client_cert_info( struct httplib_connection *conn );
|
||||
long XX_httplib_ssl_get_protocol( int version_id );
|
||||
|
@@ -22,19 +22,25 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.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;
|
||||
|
||||
do {
|
||||
diff = XX_httplib_lowercase(s1++) - XX_httplib_lowercase(s2++);
|
||||
} while (diff == 0 && s1[-1] != '\0');
|
||||
if ( s1 == NULL || s2 == NULL ) return 0;
|
||||
do { diff = XX_httplib_lowercase(s1++) - XX_httplib_lowercase(s2++); } while ( diff == 0 && s1[-1] != '\0' );
|
||||
|
||||
return diff;
|
||||
|
||||
|
@@ -28,18 +28,32 @@
|
||||
#include "httplib_main.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 big_len = strlen(big_str);
|
||||
size_t small_len = strlen(small_str);
|
||||
size_t big_len;
|
||||
size_t small_len;
|
||||
|
||||
if (big_len >= small_len) {
|
||||
for (i = 0; i <= (big_len - small_len); i++) {
|
||||
if (httplib_strncasecmp(big_str + i, small_str, small_len) == 0) return big_str + i;
|
||||
}
|
||||
if ( big_str == NULL || small_str == NULL ) return NULL;
|
||||
|
||||
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;
|
||||
|
||||
} /* XX_httplib_strcasestr */
|
||||
} /* httplib_strcasestr */
|
||||
|
@@ -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);
|
||||
const char * XX_httplib_strcasestr( const char *big_str, const char *small_str );
|
||||
char * XX_httplib_strdup( const char *str );
|
||||
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 );
|
||||
|
@@ -22,21 +22,26 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* ============
|
||||
* Release: 1.8
|
||||
* Release: 2.0
|
||||
*/
|
||||
|
||||
#include "httplib_main.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 diff = 0;
|
||||
int diff;
|
||||
|
||||
if (len > 0) {
|
||||
do {
|
||||
diff = XX_httplib_lowercase(s1++) - XX_httplib_lowercase(s2++);
|
||||
} while (diff == 0 && s1[-1] != '\0' && --len > 0);
|
||||
}
|
||||
if ( s1 == NULL || s2 == NULL || len == 0 ) return 0;
|
||||
|
||||
do { diff = XX_httplib_lowercase(s1++) - XX_httplib_lowercase(s2++); } while ( diff == 0 && s1[-1] != '\0' && --len > 0 );
|
||||
|
||||
return diff;
|
||||
|
||||
|
Reference in New Issue
Block a user