diff --git a/doc/APIReference.md b/doc/APIReference.md index 8737e1af..91785483 100644 --- a/doc/APIReference.md +++ b/doc/APIReference.md @@ -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) diff --git a/doc/api/httplib_strcasecmp.md b/doc/api/httplib_strcasecmp.md index 86eab6ed..8ce8127f 100644 --- a/doc/api/httplib_strcasecmp.md +++ b/doc/api/httplib_strcasecmp.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) diff --git a/doc/api/httplib_strcasestr.md b/doc/api/httplib_strcasestr.md new file mode 100644 index 00000000..b395efe7 --- /dev/null +++ b/doc/api/httplib_strcasestr.md @@ -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) diff --git a/doc/api/httplib_strdup.md b/doc/api/httplib_strdup.md index d48fa88e..6765d0ed 100644 --- a/doc/api/httplib_strdup.md +++ b/doc/api/httplib_strdup.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) diff --git a/doc/api/httplib_strlcpy.md b/doc/api/httplib_strlcpy.md index 0b8901e7..aad50ac3 100644 --- a/doc/api/httplib_strlcpy.md +++ b/doc/api/httplib_strlcpy.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) diff --git a/doc/api/httplib_strncasecmp.md b/doc/api/httplib_strncasecmp.md index b1793303..c6107d5a 100644 --- a/doc/api/httplib_strncasecmp.md +++ b/doc/api/httplib_strncasecmp.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) diff --git a/doc/api/httplib_strndup.md b/doc/api/httplib_strndup.md index c6fe9e97..c7c94d97 100644 --- a/doc/api/httplib_strndup.md +++ b/doc/api/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) diff --git a/include/libhttp.h b/include/libhttp.h index 423943fd..c4142eec 100644 --- a/include/libhttp.h +++ b/include/libhttp.h @@ -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 diff --git a/src/httplib_get_cookie.c b/src/httplib_get_cookie.c index 07a551dd..677d6a81 100644 --- a/src/httplib_get_cookie.c +++ b/src/httplib_get_cookie.c @@ -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] == ' ')) { diff --git a/src/httplib_is_websocket_protocol.c b/src/httplib_is_websocket_protocol.c index ff9dfef6..a5a4b911 100644 --- a/src/httplib_is_websocket_protocol.c +++ b/src/httplib_is_websocket_protocol.c @@ -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. diff --git a/src/httplib_set_ports_option.c b/src/httplib_set_ports_option.c index 1bb2d0dc..a7242245 100644 --- a/src/httplib_set_ports_option.c +++ b/src/httplib_set_ports_option.c @@ -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 */ - diff --git a/src/httplib_set_request_handler.c b/src/httplib_set_request_handler.c index 3ad032eb..c84ecd7c 100644 --- a/src/httplib_set_request_handler.c +++ b/src/httplib_set_request_handler.c @@ -22,7 +22,7 @@ * THE SOFTWARE. * * ============ - * Release: 1.8 + * Release: 2.0 */ #include "httplib_main.h" diff --git a/src/httplib_set_ssl_option.c b/src/httplib_set_ssl_option.c index cdf68b64..5c6417b6 100644 --- a/src/httplib_set_ssl_option.c +++ b/src/httplib_set_ssl_option.c @@ -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 */ diff --git a/src/httplib_set_thread_name.c b/src/httplib_set_thread_name.c index 7a014d13..f12626dd 100644 --- a/src/httplib_set_thread_name.c +++ b/src/httplib_set_thread_name.c @@ -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 #include -#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 */ diff --git a/src/httplib_set_throttle.c b/src/httplib_set_throttle.c index 59d3d24c..263de2d9 100644 --- a/src/httplib_set_throttle.c +++ b/src/httplib_set_throttle.c @@ -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 */ diff --git a/src/httplib_set_user_connection_data.c b/src/httplib_set_user_connection_data.c index 07bdb86c..c3365fd5 100644 --- a/src/httplib_set_user_connection_data.c +++ b/src/httplib_set_user_connection_data.c @@ -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 */ diff --git a/src/httplib_ssl.h b/src/httplib_ssl.h index f96e189f..7b77cc27 100644 --- a/src/httplib_ssl.h +++ b/src/httplib_ssl.h @@ -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 ); diff --git a/src/httplib_strcasecmp.c b/src/httplib_strcasecmp.c index 521e10a2..c73a6446 100644 --- a/src/httplib_strcasecmp.c +++ b/src/httplib_strcasecmp.c @@ -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; diff --git a/src/httplib_strcasestr.c b/src/httplib_strcasestr.c index d4c908a7..4684ae44 100644 --- a/src/httplib_strcasestr.c +++ b/src/httplib_strcasestr.c @@ -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 */ diff --git a/src/httplib_string.h b/src/httplib_string.h index 3f5cb151..d99ceb3f 100644 --- a/src/httplib_string.h +++ b/src/httplib_string.h @@ -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 ); diff --git a/src/httplib_strncasecmp.c b/src/httplib_strncasecmp.c index 38ef618f..da8e31ae 100644 --- a/src/httplib_strncasecmp.c +++ b/src/httplib_strncasecmp.c @@ -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;