diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-02-27 12:30:45 +0100 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-02-27 16:28:52 +0100 |
| commit | d783e794c2fa6a9e6bffff9f41cdb7e8033bf3c3 (patch) | |
| tree | dd7d835b79db8d9ed1c5cdfdbc82f8f3d694ba95 | |
| parent | fca0679e438e1cf8a3db9047f57d3b2363ab417e (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/Makefile | 1 | ||||
| -rw-r--r-- | doc/man3/http_strncasecmp.3 | 52 | ||||
| -rw-r--r-- | http.c | 41 | ||||
| -rw-r--r-- | include/libweb/http.h | 1 |
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. @@ -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 */ |
