From 6353beb60ceafbc743bde96684d666582195192f Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Fri, 27 Feb 2026 15:28:17 +0100 Subject: Add http_strcasecmp(3) POSIX.1-2008 does not any locale-specific version of strcasecmp(3), so conversions to lowercase depend on the system locale. Since HTTP header fields must be checked without case sensitivity and not depend on the system locale, a specialised function that forces the "POSIX" locale is required. --- doc/man3/Makefile | 1 + doc/man3/http_strcasecmp.3 | 52 ++++++++++++++++++++++++++++++++++++++++++++++ http.c | 26 +++++++++++++++++++++++ include/libweb/http.h | 1 + 4 files changed, 80 insertions(+) create mode 100644 doc/man3/http_strcasecmp.3 diff --git a/doc/man3/Makefile b/doc/man3/Makefile index ffdbf16..160476f 100644 --- a/doc/man3/Makefile +++ b/doc/man3/Makefile @@ -28,6 +28,7 @@ OBJECTS = \ $(DESTDIR)$(man3dir)/http_encode_url.3 \ $(DESTDIR)$(man3dir)/http_free.3 \ $(DESTDIR)$(man3dir)/http_response_add_header.3 \ + $(DESTDIR)$(man3dir)/http_strcasecmp.3 \ $(DESTDIR)$(man3dir)/http_strncasecmp.3 \ $(DESTDIR)$(man3dir)/http_update.3 diff --git a/doc/man3/http_strcasecmp.3 b/doc/man3/http_strcasecmp.3 new file mode 100644 index 0000000..3542ba8 --- /dev/null +++ b/doc/man3/http_strcasecmp.3 @@ -0,0 +1,52 @@ +.TH HTTP_STRCASECMP 3 2026-02-27 0.6.0 "libweb Library Reference" + +.SH NAME +http_strcasecmp \- compare two strings ignoring case as "POSIX" locale + +.SH SYNOPSIS +.LP +.nf +#include +.P +char *http_strcasecmp(const char *\fIs1\fP, const char *\fIs2\fP, size_t \fIn\fP); +.fi + +.SH DESCRIPTION +The +.IR http_strcasecmp () +function compares two strings as done by +.IR strcasecmp (3), +but forces the use of the "POSIX" locale, so that characters are converted +to lowercase with +.IR tolower_l (3), +rather than relying on the locale configured by the system. + +This makes +.IR http_strcasecmp () +ideal to compare HTTP headers, which must be checked without case sensitivity +according to RFC 9110. + +.SH RETURN VALUE +If the comparison is successful, zero is returned. If the two strings +are not equal (case ignored) or any of their characters could not be converted +by +.IR tolower_l(3) , +a positive integer is returned. +Otherwise, a negative integer is returned. + +.SH ERRORS +No errors are defined. + +.SH SEE ALSO +.BR libweb_http (7), +.BR http_strncasecmp (3). + +.B https://www.rfc-editor.org/rfc/rfc9110#name-field-names + +.SH COPYRIGHT +Copyright (C) 2023-2026 libweb contributors +.P +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. diff --git a/http.c b/http.c index c3c36b2..451ec88 100644 --- a/http.c +++ b/http.c @@ -2975,6 +2975,32 @@ end: return ret; } +int http_strcasecmp(const char *s1, const char *s2) +{ + int ret = -1; + const locale_t l = newlocale(LC_CTYPE_MASK, "POSIX", (locale_t)0); + + if (l == (locale_t)0) + { + fprintf(stderr, "%s: newlocale(3): %s\n", __func__, strerror(errno)); + goto end; + } + + while (*s1 && *s2) + if (tolower_l(*s1++, l) != tolower_l(*s2++, l)) + { + ret = 1; + goto end; + } + + ret = !!*s1 || !!*s2; +end: + if (l != (locale_t)0) + freelocale(l); + + return ret; +} + int http_strncasecmp(const char *s1, const char *s2, const size_t n) { int ret = -1; diff --git a/include/libweb/http.h b/include/libweb/http.h index 41e1dce..4548efc 100644 --- a/include/libweb/http.h +++ b/include/libweb/http.h @@ -150,6 +150,7 @@ char *http_cookie_create(const char *key, const char *value, const struct tm *exp); char *http_encode_url(const char *url); int http_decode_url(const char *url, bool spaces, char **out); +int http_strcasecmp(const char *s1, const char *s2); int http_strncasecmp(const char *s1, const char *s2, size_t n); #endif /* HTTP_H */ -- cgit v1.2.3