master uint/parados / server / utils.c
  1#include <ctype.h>
  2#include <errno.h>
  3#include <stdbool.h>
  4#include <stdio.h>
  5#include <string.h>
  6#include <unistd.h>
  7
  8#include "utils.h"
  9
 10static bool ci_key_match(const char* a, const char* b, size_t n);
 11
 12/* Compare two header keys case-insensitively
 13   Returns true=Match, false=No match */
 14static bool ci_key_match(const char* a, const char* b, size_t n)
 15{
 16	for (size_t i = 0; i < n; i++) {
 17		unsigned char ca = (unsigned char)a[i];
 18		unsigned char cb = (unsigned char)b[i];
 19		if (tolower(ca) != tolower(cb))
 20			return false;
 21	}
 22	return true;
 23}
 24
 25const char* cistrstr(const char* hay, const char* nee)
 26{
 27	size_t nl = strlen(nee);
 28	if (nl == 0)
 29		return hay;
 30
 31	for (; *hay; hay++) {
 32		size_t i = 0;
 33
 34		for (;;) {
 35			if (i == nl)
 36				return hay;
 37
 38			unsigned char a = (unsigned char)hay[i];
 39			unsigned char b = (unsigned char)nee[i];
 40
 41			if (a == '\0')
 42				break;
 43
 44			if (tolower(a) != tolower(b))
 45				break;
 46
 47			i++;
 48		}
 49	}
 50
 51	return NULL;
 52}
 53
 54int hdr_get_value(char out[512], const char* hdr, const char* key)
 55{
 56	size_t klen = strlen(key);
 57	if (!hdr || !key || klen == 0)
 58		return -1;
 59
 60	const char* p = hdr;
 61
 62	/* skip request line */
 63	const char* eol = strstr(p, "\r\n");
 64	if (!eol)
 65		return -1;
 66	p = eol + 2;
 67
 68	for (;;) {
 69		if (p[0] == '\r' && p[1] == '\n')
 70			break; /* end of headers */
 71
 72		const char* line_end = strstr(p, "\r\n");
 73		if (!line_end)
 74			break;
 75
 76		const char* colon = memchr(p, ':', (size_t)(line_end - p));
 77		if (colon) {
 78			size_t n = (size_t)(colon - p);
 79
 80			if (n == klen && ci_key_match(p, key, klen)) {
 81				const char* v = colon + 1;
 82				while (*v == ' ' || *v == '\t')
 83					v++;
 84
 85				size_t outn = 0;
 86				while (v < line_end) {
 87					if (outn + 1 >= 512)
 88						return -1;
 89					out[outn++] = *v++;
 90				}
 91				out[outn] = '\0';
 92
 93				if (outn == 0)
 94					return -1;
 95
 96				return 0;
 97			}
 98		}
 99
100		p = line_end + 2;
101	}
102
103	return -1;
104}
105
106int join_path(char* out, size_t outsz, const char* a, const char* b)
107{
108	if (!out || outsz == 0 || !a || !b)
109		return -1;
110
111	if (a[0] == '\0') {
112		int n = snprintf(out, outsz, "%s", b);
113		if (n < 0 || (size_t)n >= outsz)
114			return -1;
115		return 0;
116	}
117
118	if (b[0] == '\0') {
119		int n = snprintf(out, outsz, "%s", a);
120		if (n < 0 || (size_t)n >= outsz)
121			return -1;
122		return 0;
123	}
124
125	size_t al = strlen(a);
126
127	/* avoid double slashes */
128	if (a[al - 1] == '/')
129		return snprintf(out, outsz, "%s%s", a, b) < (int)outsz ? 0 : -1;
130
131	return snprintf(out, outsz, "%s/%s", a, b) < (int)outsz ? 0 : -1;
132}
133
134void secure_bzero(void* p, size_t n)
135{
136	if (!p || n == 0)
137		return;
138
139#if defined(__OpenBSD__)
140	explicit_bzero(p, n);
141#else
142	volatile unsigned char* vp = (volatile unsigned char*)p;
143	while (n--)
144		*vp++ = 0;
145#endif
146}
147
148int write_all(int fd, const void* buf, size_t n)
149{
150	const char* p = buf;
151
152	while (n > 0) {
153		ssize_t w = write(fd, p, n);
154		if (w < 0) {
155			if (errno == EINTR)
156				continue;
157			return -1;
158		}
159
160		p += (size_t)w;
161		n -= (size_t)w;
162	}
163
164	return 0;
165}