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_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)

View File

@@ -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)

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_strcasecmp();`](httplib_strcasecmp.md)
* [`httplib_strcasestr();`](httplib_strcasestr.md)
* [`httplib_strncasecmp();`](httplib_strncasecmp.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
* [`httplib_strcasecmp();`](httplib_strcasecmp.md)
* [`httplib_strcasestr();`](httplib_strcasestr.md)
* [`httplib_strncasecmp();`](httplib_strncasecmp.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
* [`httplib_strcasecmp();`](httplib_strcasecmp.md)
* [`httplib_strcasestr();`](httplib_strcasestr.md)
* [`httplib_strdup();`](httplib_strdup.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_strcasecmp();`](httplib_strcasecmp.md)
* [`httplib_strcasestr();`](httplib_strcasestr.md)
* [`httplib_strdup();`](httplib_strdup.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. */
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

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);
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] == ' ')) {

View File

@@ -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.

View File

@@ -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 */

View File

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

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

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_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 );

View File

@@ -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;

View File

@@ -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 */

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);
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 );

View File

@@ -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;