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}