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