aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2026-02-27 12:30:45 +0100
committerXavier Del Campo Romero <xavi92@disroot.org>2026-02-27 16:28:52 +0100
commitd783e794c2fa6a9e6bffff9f41cdb7e8033bf3c3 (patch)
treedd7d835b79db8d9ed1c5cdfdbc82f8f3d694ba95
parentfca0679e438e1cf8a3db9047f57d3b2363ab417e (diff)
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.
-rw-r--r--doc/man3/Makefile1
-rw-r--r--doc/man3/http_strncasecmp.352
-rw-r--r--http.c41
-rw-r--r--include/libweb/http.h1
4 files changed, 91 insertions, 4 deletions
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 <libweb/http.h>
+.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 <dynstr.h>
#include <sys/types.h>
#include <unistd.h>
+#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <locale.h>
@@ -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 */