From d783e794c2fa6a9e6bffff9f41cdb7e8033bf3c3 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Fri, 27 Feb 2026 12:30:45 +0100 Subject: Add http_strncasecmp(3) POSIX.1-2008 does not any locale-specific version of strncasecmp(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_strncasecmp.3 | 52 +++++++++++++++++++++++++++++++++++++++++++++ http.c | 41 +++++++++++++++++++++++++++++++---- include/libweb/http.h | 1 + 4 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 doc/man3/http_strncasecmp.3 diff --git a/doc/man3/Makefile b/doc/man3/Makefile index cdfff3d..ffdbf16 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_strncasecmp.3 \ $(DESTDIR)$(man3dir)/http_update.3 all: diff --git a/doc/man3/http_strncasecmp.3 b/doc/man3/http_strncasecmp.3 new file mode 100644 index 0000000..0d5449f --- /dev/null +++ b/doc/man3/http_strncasecmp.3 @@ -0,0 +1,52 @@ +.TH HTTP_STRNCASECMP 3 2026-02-27 0.6.0 "libweb Library Reference" + +.SH NAME +http_strncasecmp \- compare two strings ignoring case as "POSIX" locale + +.SH SYNOPSIS +.LP +.nf +#include +.P +char *http_strncasecmp(const char *\fIs1\fP, const char *\fIs2\fP, size_t \fIn\fP); +.fi + +.SH DESCRIPTION +The +.IR http_strncasecmp () +function compares two strings as done by +.IR strncasecmp (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_strncasecmp () +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_strcasecmp (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 261dcc0..c3c36b2 100644 --- a/http.c +++ b/http.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -1592,13 +1593,18 @@ static int process_header(struct http_ctx *const h, const char *const line, const struct header *const hdr = &headers[i]; int ret; - if (!strncasecmp(line, hdr->header, n)) + if ((ret = http_strncasecmp(line, hdr->header, n))) { - if ((ret = hdr->f(h, value))) + if (ret < 0) + { + fprintf(stderr, "%s: http_strncasecmp failed\n", __func__); return ret; - - break; + } } + else if ((ret = hdr->f(h, value))) + return ret; + else + break; } return append_header(h, line, n, value); @@ -2968,3 +2974,30 @@ end: return ret; } + +int http_strncasecmp(const char *s1, const char *s2, const size_t n) +{ + 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; + } + + for (size_t i = 0; i < n; i++, s1++, s2++) + if (!*s1 || !*s2 || tolower_l(*s1, l) != tolower_l(*s2, l)) + { + ret = 1; + goto end; + } + + ret = 0; + +end: + if (l != (locale_t)0) + freelocale(l); + + return ret; +} diff --git a/include/libweb/http.h b/include/libweb/http.h index ad4ebcd..41e1dce 100644 --- a/include/libweb/http.h +++ b/include/libweb/http.h @@ -150,5 +150,6 @@ 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_strncasecmp(const char *s1, const char *s2, size_t n); #endif /* HTTP_H */ -- cgit v1.2.3