Blame


1 04e4e993 2023-08-14 op /*
2 c2117f4b 2023-08-31 op * This is free and unencumbered software released into the public domain.
3 04e4e993 2023-08-14 op *
4 c2117f4b 2023-08-31 op * Anyone is free to copy, modify, publish, use, compile, sell, or
5 c2117f4b 2023-08-31 op * distribute this software, either in source code form or as a compiled
6 c2117f4b 2023-08-31 op * binary, for any purpose, commercial or non-commercial, and by any
7 c2117f4b 2023-08-31 op * means.
8 04e4e993 2023-08-14 op *
9 c2117f4b 2023-08-31 op * In jurisdictions that recognize copyright laws, the author or authors
10 c2117f4b 2023-08-31 op * of this software dedicate any and all copyright interest in the
11 c2117f4b 2023-08-31 op * software to the public domain. We make this dedication for the benefit
12 c2117f4b 2023-08-31 op * of the public at large and to the detriment of our heirs and
13 c2117f4b 2023-08-31 op * successors. We intend this dedication to be an overt act of
14 c2117f4b 2023-08-31 op * relinquishment in perpetuity of all present and future rights to this
15 c2117f4b 2023-08-31 op * software under copyright law.
16 c2117f4b 2023-08-31 op *
17 c2117f4b 2023-08-31 op * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 c2117f4b 2023-08-31 op * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 c2117f4b 2023-08-31 op * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 c2117f4b 2023-08-31 op * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 c2117f4b 2023-08-31 op * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 c2117f4b 2023-08-31 op * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 c2117f4b 2023-08-31 op * OTHER DEALINGS IN THE SOFTWARE.
24 04e4e993 2023-08-14 op */
25 04e4e993 2023-08-14 op
26 04e4e993 2023-08-14 op #include "config.h"
27 04e4e993 2023-08-14 op
28 04e4e993 2023-08-14 op #include <sys/uio.h>
29 04e4e993 2023-08-14 op
30 04e4e993 2023-08-14 op #include <ctype.h>
31 04e4e993 2023-08-14 op #include <errno.h>
32 04e4e993 2023-08-14 op #include <limits.h>
33 04e4e993 2023-08-14 op #include <stdarg.h>
34 04e4e993 2023-08-14 op #include <stdio.h>
35 04e4e993 2023-08-14 op #include <stdlib.h>
36 04e4e993 2023-08-14 op #include <string.h>
37 04e4e993 2023-08-14 op #include <unistd.h>
38 04e4e993 2023-08-14 op
39 3634fa70 2023-08-31 op #include "bufio.h"
40 04e4e993 2023-08-14 op #include "http.h"
41 04e4e993 2023-08-14 op #include "log.h"
42 b42d807f 2023-09-02 op #include "ws.h"
43 04e4e993 2023-08-14 op #include "xmalloc.h"
44 04e4e993 2023-08-14 op
45 04e4e993 2023-08-14 op #ifndef nitems
46 04e4e993 2023-08-14 op #define nitems(x) (sizeof(x)/sizeof(x[0]))
47 04e4e993 2023-08-14 op #endif
48 04e4e993 2023-08-14 op
49 2216d3fb 2023-09-07 op #define HTTP_MAX_UPLOAD 4096
50 2216d3fb 2023-09-07 op
51 3634fa70 2023-08-31 op int
52 3634fa70 2023-08-31 op http_init(struct client *clt, int fd)
53 04e4e993 2023-08-14 op {
54 3634fa70 2023-08-31 op memset(clt, 0, sizeof(*clt));
55 3634fa70 2023-08-31 op if (bufio_init(&clt->bio) == -1)
56 3634fa70 2023-08-31 op return -1;
57 3634fa70 2023-08-31 op bufio_set_fd(&clt->bio, fd);
58 04e4e993 2023-08-14 op return 0;
59 04e4e993 2023-08-14 op }
60 04e4e993 2023-08-14 op
61 04e4e993 2023-08-14 op int
62 3634fa70 2023-08-31 op http_parse(struct client *clt)
63 04e4e993 2023-08-14 op {
64 3634fa70 2023-08-31 op struct buffer *rbuf = &clt->bio.rbuf;
65 3634fa70 2023-08-31 op struct request *req = &clt->req;
66 3634fa70 2023-08-31 op size_t len;
67 3634fa70 2023-08-31 op uint8_t *endln;
68 5e3e9499 2023-08-31 op char *frag, *query, *http, *line;
69 04e4e993 2023-08-14 op const char *errstr, *m;
70 04e4e993 2023-08-14 op
71 3634fa70 2023-08-31 op while (!clt->reqdone) {
72 3634fa70 2023-08-31 op endln = memmem(rbuf->buf, rbuf->len, "\r\n", 2);
73 3634fa70 2023-08-31 op if (endln == NULL) {
74 3634fa70 2023-08-31 op errno = EAGAIN;
75 04e4e993 2023-08-14 op return -1;
76 04e4e993 2023-08-14 op }
77 04e4e993 2023-08-14 op
78 3634fa70 2023-08-31 op line = rbuf->buf;
79 3634fa70 2023-08-31 op if (endln == rbuf->buf)
80 3634fa70 2023-08-31 op clt->reqdone = 1;
81 04e4e993 2023-08-14 op
82 3634fa70 2023-08-31 op len = endln - rbuf->buf + 2;
83 3634fa70 2023-08-31 op while (len > 0 && (line[len - 1] == '\r' ||
84 3634fa70 2023-08-31 op line[len - 1] == '\n' || line[len - 1] == ' ' ||
85 3634fa70 2023-08-31 op line[len - 1] == '\t'))
86 3634fa70 2023-08-31 op line[--len] = '\0';
87 04e4e993 2023-08-14 op
88 3634fa70 2023-08-31 op /* first line */
89 3634fa70 2023-08-31 op if (clt->req.method == METHOD_UNKNOWN) {
90 3634fa70 2023-08-31 op if (!strncmp("GET ", line, 4)) {
91 3634fa70 2023-08-31 op req->method = METHOD_GET;
92 7add2c3c 2023-08-31 op line += 4;
93 3634fa70 2023-08-31 op } else if (!strncmp("POST ", line, 5)) {
94 3634fa70 2023-08-31 op req->method = METHOD_POST;
95 7add2c3c 2023-08-31 op line += 5;
96 3634fa70 2023-08-31 op } else {
97 3634fa70 2023-08-31 op errno = EINVAL;
98 3634fa70 2023-08-31 op return -1;
99 04e4e993 2023-08-14 op }
100 04e4e993 2023-08-14 op
101 5e3e9499 2023-08-31 op if ((http = strchr(line, ' ')) == NULL)
102 5e3e9499 2023-08-31 op http = line;
103 5e3e9499 2023-08-31 op if (*http != '\0')
104 5e3e9499 2023-08-31 op *http++ = '\0';
105 a2298955 2023-08-31 op
106 a2298955 2023-08-31 op if ((query = strchr(line, '?')))
107 a2298955 2023-08-31 op *query = '\0';
108 a2298955 2023-08-31 op if ((frag = strchr(line, '#')))
109 a2298955 2023-08-31 op *frag = '\0';
110 a2298955 2023-08-31 op
111 7add2c3c 2023-08-31 op clt->req.path = xstrdup(line);
112 a2298955 2023-08-31 op
113 5e3e9499 2023-08-31 op if (!strcmp(http, "HTTP/1.0"))
114 3634fa70 2023-08-31 op clt->req.version = HTTP_1_0;
115 5e3e9499 2023-08-31 op else if (!strcmp(http, "HTTP/1.1")) {
116 3634fa70 2023-08-31 op clt->req.version = HTTP_1_1;
117 3634fa70 2023-08-31 op clt->chunked = 1;
118 3634fa70 2023-08-31 op } else {
119 5e3e9499 2023-08-31 op log_warnx("unknown http version %s", http);
120 3634fa70 2023-08-31 op errno = EINVAL;
121 3634fa70 2023-08-31 op return -1;
122 04e4e993 2023-08-14 op }
123 7add2c3c 2023-08-31 op
124 5e3e9499 2023-08-31 op line = http; /* so that no header below matches */
125 3634fa70 2023-08-31 op }
126 04e4e993 2023-08-14 op
127 3634fa70 2023-08-31 op if (!strncasecmp(line, "Content-Length:", 15)) {
128 3634fa70 2023-08-31 op line += 15;
129 3634fa70 2023-08-31 op line += strspn(line, " \t");
130 2216d3fb 2023-09-07 op clt->req.clen = strtonum(line, 0, HTTP_MAX_UPLOAD,
131 3634fa70 2023-08-31 op &errstr);
132 3634fa70 2023-08-31 op if (errstr) {
133 3634fa70 2023-08-31 op log_warnx("content-length is %s: %s",
134 3634fa70 2023-08-31 op errstr, line);
135 3634fa70 2023-08-31 op errno = EINVAL;
136 3634fa70 2023-08-31 op return -1;
137 3634fa70 2023-08-31 op }
138 04e4e993 2023-08-14 op }
139 3634fa70 2023-08-31 op
140 b42d807f 2023-09-02 op if (!strncasecmp(line, "Connection:", 11)) {
141 b42d807f 2023-09-02 op line += 11;
142 b42d807f 2023-09-02 op line += strspn(line, " \t");
143 b42d807f 2023-09-02 op if (!strcasecmp(line, "upgrade"))
144 b42d807f 2023-09-02 op req->flags |= R_CONNUPGR;
145 b42d807f 2023-09-02 op }
146 b42d807f 2023-09-02 op
147 b42d807f 2023-09-02 op if (!strncasecmp(line, "Upgrade:", 8)) {
148 b42d807f 2023-09-02 op line += 8;
149 b42d807f 2023-09-02 op line += strspn(line, " \t");
150 b42d807f 2023-09-02 op if (!strcasecmp(line, "websocket"))
151 b42d807f 2023-09-02 op req->flags |= R_UPGRADEWS;
152 b42d807f 2023-09-02 op }
153 b42d807f 2023-09-02 op
154 b42d807f 2023-09-02 op if (!strncasecmp(line, "Sec-WebSocket-Version:", 22)) {
155 b42d807f 2023-09-02 op line += 22;
156 b42d807f 2023-09-02 op line += strspn(line, " \t");
157 b42d807f 2023-09-02 op if (strcmp(line, "13") != 0) {
158 b42d807f 2023-09-02 op log_warnx("unsupported websocket version %s",
159 b42d807f 2023-09-02 op line);
160 b42d807f 2023-09-02 op errno = EINVAL;
161 b42d807f 2023-09-02 op return -1;
162 b42d807f 2023-09-02 op }
163 b42d807f 2023-09-02 op req->flags |= R_WSVERSION;
164 b42d807f 2023-09-02 op }
165 b42d807f 2023-09-02 op
166 b42d807f 2023-09-02 op if (!strncasecmp(line, "Sec-WebSocket-Key:", 18)) {
167 b42d807f 2023-09-02 op line += 18;
168 b42d807f 2023-09-02 op line += strspn(line, " \t");
169 b42d807f 2023-09-02 op req->secret = xstrdup(line);
170 b42d807f 2023-09-02 op }
171 b42d807f 2023-09-02 op
172 3634fa70 2023-08-31 op buf_drain(rbuf, endln - rbuf->buf + 2);
173 04e4e993 2023-08-14 op }
174 04e4e993 2023-08-14 op
175 04e4e993 2023-08-14 op if (req->method == METHOD_GET)
176 04e4e993 2023-08-14 op m = "GET";
177 04e4e993 2023-08-14 op else if (req->method == METHOD_POST)
178 04e4e993 2023-08-14 op m = "POST";
179 04e4e993 2023-08-14 op else
180 04e4e993 2023-08-14 op m = "unknown";
181 9daa6569 2023-08-31 op log_debug("< %s %s HTTP/%s", m, req->path,
182 9daa6569 2023-08-31 op req->version == HTTP_1_1 ? "1.1" : "1.0");
183 04e4e993 2023-08-14 op
184 04e4e993 2023-08-14 op return 0;
185 04e4e993 2023-08-14 op }
186 04e4e993 2023-08-14 op
187 04e4e993 2023-08-14 op int
188 3634fa70 2023-08-31 op http_read(struct client *clt)
189 04e4e993 2023-08-14 op {
190 2216d3fb 2023-09-07 op struct request *req = &clt->req;
191 2216d3fb 2023-09-07 op struct buffer *rbuf = &clt->bio.rbuf;
192 2216d3fb 2023-09-07 op size_t left;
193 3b486b32 2023-08-14 op
194 87eb9c1e 2023-08-15 op /* clients may have sent more data than advertised */
195 2216d3fb 2023-09-07 op if (req->clen < rbuf->len)
196 87eb9c1e 2023-08-15 op left = 0;
197 87eb9c1e 2023-08-15 op else
198 2216d3fb 2023-09-07 op left = req->clen - rbuf->len;
199 87eb9c1e 2023-08-15 op
200 3634fa70 2023-08-31 op if (left > 0) {
201 2216d3fb 2023-09-07 op errno = EAGAIN;
202 2216d3fb 2023-09-07 op return -1;
203 04e4e993 2023-08-14 op }
204 04e4e993 2023-08-14 op
205 2216d3fb 2023-09-07 op buf_write(rbuf, "", 1); /* append a NUL byte */
206 2216d3fb 2023-09-07 op while (rbuf->len > 0 && (rbuf->buf[rbuf->len - 1] == '\r' ||
207 2216d3fb 2023-09-07 op (rbuf->buf[rbuf->len - 1] == '\n')))
208 2216d3fb 2023-09-07 op rbuf->buf[--rbuf->len] = '\0';
209 3634fa70 2023-08-31 op
210 04e4e993 2023-08-14 op return 0;
211 04e4e993 2023-08-14 op }
212 04e4e993 2023-08-14 op
213 2216d3fb 2023-09-07 op void
214 2216d3fb 2023-09-07 op http_postdata(struct client *clt, char **data, size_t *len)
215 2216d3fb 2023-09-07 op {
216 2216d3fb 2023-09-07 op if (data)
217 2216d3fb 2023-09-07 op *data = clt->bio.rbuf.buf;
218 2216d3fb 2023-09-07 op if (len)
219 2216d3fb 2023-09-07 op *len = clt->bio.rbuf.len;
220 2216d3fb 2023-09-07 op }
221 2216d3fb 2023-09-07 op
222 04e4e993 2023-08-14 op int
223 99861c4a 2023-09-07 op http_reply(struct client *clt, int code, const char *reason,
224 99861c4a 2023-09-07 op const char *ctype)
225 04e4e993 2023-08-14 op {
226 2c962d05 2023-08-31 op const char *version, *location = NULL;
227 b42d807f 2023-09-02 op char b32[32] = "";
228 04e4e993 2023-08-14 op
229 04e4e993 2023-08-14 op log_debug("> %d %s", code, reason);
230 b42d807f 2023-09-02 op
231 b42d807f 2023-09-02 op if (code == 101) {
232 b42d807f 2023-09-02 op if (ws_accept_hdr(clt->req.secret, b32, sizeof(b32)) == -1) {
233 b42d807f 2023-09-02 op clt->err = 1;
234 b42d807f 2023-09-02 op return -1;
235 b42d807f 2023-09-02 op }
236 8701aaaa 2023-09-07 op free(clt->req.secret);
237 8701aaaa 2023-09-07 op clt->req.secret = NULL;
238 8701aaaa 2023-09-07 op
239 b42d807f 2023-09-02 op clt->chunked = 0;
240 b42d807f 2023-09-02 op }
241 04e4e993 2023-08-14 op
242 04e4e993 2023-08-14 op if (code >= 300 && code < 400) {
243 04e4e993 2023-08-14 op location = ctype;
244 c83e450a 2023-08-14 op ctype = "text/html;charset=UTF-8";
245 04e4e993 2023-08-14 op }
246 04e4e993 2023-08-14 op
247 2c962d05 2023-08-31 op version = "HTTP/1.1";
248 2c962d05 2023-08-31 op if (clt->req.version == HTTP_1_0)
249 2c962d05 2023-08-31 op version = "HTTP/1.0";
250 2c962d05 2023-08-31 op
251 f39ef3e4 2023-09-07 op if (http_fmt(clt, "%s %d %s\r\n"
252 04e4e993 2023-08-14 op "Connection: close\r\n"
253 5ce4c55c 2023-09-02 op "Cache-Control: no-store\r\n",
254 5ce4c55c 2023-09-02 op version, code, reason) == -1)
255 5ce4c55c 2023-09-02 op goto err;
256 5ce4c55c 2023-09-02 op if (ctype != NULL &&
257 f39ef3e4 2023-09-07 op http_fmt(clt, "Content-Type: %s\r\n", ctype) == -1)
258 5ce4c55c 2023-09-02 op goto err;
259 5ce4c55c 2023-09-02 op if (location != NULL &&
260 f39ef3e4 2023-09-07 op http_fmt(clt, "Location: %s\r\n", location) == -1)
261 5ce4c55c 2023-09-02 op goto err;
262 f39ef3e4 2023-09-07 op if (clt->chunked &&
263 f39ef3e4 2023-09-07 op http_writes(clt, "Transfer-Encoding: chunked\r\n") == -1)
264 5ce4c55c 2023-09-02 op goto err;
265 b42d807f 2023-09-02 op if (code == 101) {
266 f39ef3e4 2023-09-07 op if (http_fmt(clt, "Upgrade: websocket\r\n"
267 b42d807f 2023-09-02 op "Connection: Upgrade\r\n"
268 b42d807f 2023-09-02 op "Sec-WebSocket-Accept: %s\r\n", b32) == -1)
269 b42d807f 2023-09-02 op goto err;
270 b42d807f 2023-09-02 op }
271 f39ef3e4 2023-09-07 op if (http_write(clt, "\r\n", 2) == -1)
272 5ce4c55c 2023-09-02 op goto err;
273 04e4e993 2023-08-14 op
274 6d85a326 2023-08-31 op bufio_set_chunked(&clt->bio, clt->chunked);
275 6d85a326 2023-08-31 op
276 c83e450a 2023-08-14 op if (location) {
277 3634fa70 2023-08-31 op if (http_writes(clt, "<a href='") == -1 ||
278 3634fa70 2023-08-31 op http_htmlescape(clt, location) == -1 ||
279 3634fa70 2023-08-31 op http_writes(clt, "'>") == -1 ||
280 3634fa70 2023-08-31 op http_htmlescape(clt, reason) == -1 ||
281 3634fa70 2023-08-31 op http_writes(clt, "</a>") == -1)
282 c83e450a 2023-08-14 op return -1;
283 c83e450a 2023-08-14 op }
284 c83e450a 2023-08-14 op
285 c83e450a 2023-08-14 op return 0;
286 5ce4c55c 2023-09-02 op
287 5ce4c55c 2023-09-02 op err:
288 5ce4c55c 2023-09-02 op clt->err = 1;
289 5ce4c55c 2023-09-02 op return -1;
290 04e4e993 2023-08-14 op }
291 04e4e993 2023-08-14 op
292 04e4e993 2023-08-14 op int
293 3634fa70 2023-08-31 op http_flush(struct client *clt)
294 04e4e993 2023-08-14 op {
295 3634fa70 2023-08-31 op if (clt->err)
296 04e4e993 2023-08-14 op return -1;
297 04e4e993 2023-08-14 op
298 3634fa70 2023-08-31 op if (clt->len == 0)
299 04e4e993 2023-08-14 op return 0;
300 04e4e993 2023-08-14 op
301 3634fa70 2023-08-31 op if (bufio_compose(&clt->bio, clt->buf, clt->len) == -1) {
302 3634fa70 2023-08-31 op clt->err = 1;
303 04e4e993 2023-08-14 op return -1;
304 04e4e993 2023-08-14 op }
305 04e4e993 2023-08-14 op
306 3634fa70 2023-08-31 op clt->len = 0;
307 04e4e993 2023-08-14 op
308 04e4e993 2023-08-14 op return 0;
309 04e4e993 2023-08-14 op }
310 04e4e993 2023-08-14 op
311 04e4e993 2023-08-14 op int
312 3634fa70 2023-08-31 op http_write(struct client *clt, const char *d, size_t len)
313 04e4e993 2023-08-14 op {
314 04e4e993 2023-08-14 op size_t avail;
315 04e4e993 2023-08-14 op
316 3634fa70 2023-08-31 op if (clt->err)
317 04e4e993 2023-08-14 op return -1;
318 35cca6c5 2023-09-07 op
319 35cca6c5 2023-09-07 op if (!clt->bio.chunked) {
320 35cca6c5 2023-09-07 op if (bufio_compose(&clt->bio, d, len) == -1) {
321 35cca6c5 2023-09-07 op clt->err = 1;
322 35cca6c5 2023-09-07 op return -1;
323 35cca6c5 2023-09-07 op }
324 35cca6c5 2023-09-07 op return 0;
325 35cca6c5 2023-09-07 op }
326 04e4e993 2023-08-14 op
327 35cca6c5 2023-09-07 op if (clt->buf == NULL) {
328 35cca6c5 2023-09-07 op clt->cap = 1024;
329 35cca6c5 2023-09-07 op if ((clt->buf = malloc(clt->cap)) == NULL) {
330 35cca6c5 2023-09-07 op clt->err = 1;
331 35cca6c5 2023-09-07 op return -1;
332 35cca6c5 2023-09-07 op }
333 35cca6c5 2023-09-07 op }
334 35cca6c5 2023-09-07 op
335 04e4e993 2023-08-14 op while (len > 0) {
336 35cca6c5 2023-09-07 op avail = clt->cap - clt->len;
337 04e4e993 2023-08-14 op if (avail > len)
338 04e4e993 2023-08-14 op avail = len;
339 04e4e993 2023-08-14 op
340 3634fa70 2023-08-31 op memcpy(clt->buf + clt->len, d, avail);
341 3634fa70 2023-08-31 op clt->len += avail;
342 04e4e993 2023-08-14 op len -= avail;
343 04e4e993 2023-08-14 op d += avail;
344 35cca6c5 2023-09-07 op if (clt->len == clt->cap) {
345 3634fa70 2023-08-31 op if (http_flush(clt) == -1)
346 04e4e993 2023-08-14 op return -1;
347 04e4e993 2023-08-14 op }
348 04e4e993 2023-08-14 op }
349 04e4e993 2023-08-14 op
350 04e4e993 2023-08-14 op return 0;
351 04e4e993 2023-08-14 op }
352 04e4e993 2023-08-14 op
353 04e4e993 2023-08-14 op int
354 3634fa70 2023-08-31 op http_writes(struct client *clt, const char *str)
355 04e4e993 2023-08-14 op {
356 3634fa70 2023-08-31 op return http_write(clt, str, strlen(str));
357 04e4e993 2023-08-14 op }
358 04e4e993 2023-08-14 op
359 04e4e993 2023-08-14 op int
360 3634fa70 2023-08-31 op http_fmt(struct client *clt, const char *fmt, ...)
361 04e4e993 2023-08-14 op {
362 04e4e993 2023-08-14 op va_list ap;
363 04e4e993 2023-08-14 op char *str;
364 04e4e993 2023-08-14 op int r;
365 04e4e993 2023-08-14 op
366 04e4e993 2023-08-14 op va_start(ap, fmt);
367 04e4e993 2023-08-14 op r = vasprintf(&str, fmt, ap);
368 04e4e993 2023-08-14 op va_end(ap);
369 04e4e993 2023-08-14 op
370 04e4e993 2023-08-14 op if (r == -1) {
371 04e4e993 2023-08-14 op log_warn("vasprintf");
372 3634fa70 2023-08-31 op clt->err = 1;
373 04e4e993 2023-08-14 op return -1;
374 04e4e993 2023-08-14 op }
375 04e4e993 2023-08-14 op
376 3634fa70 2023-08-31 op r = http_write(clt, str, r);
377 04e4e993 2023-08-14 op free(str);
378 04e4e993 2023-08-14 op return r;
379 04e4e993 2023-08-14 op }
380 04e4e993 2023-08-14 op
381 04e4e993 2023-08-14 op int
382 3634fa70 2023-08-31 op http_urlescape(struct client *clt, const char *str)
383 04e4e993 2023-08-14 op {
384 04e4e993 2023-08-14 op int r;
385 04e4e993 2023-08-14 op char tmp[4];
386 04e4e993 2023-08-14 op
387 04e4e993 2023-08-14 op for (; *str; ++str) {
388 04e4e993 2023-08-14 op if (iscntrl((unsigned char)*str) ||
389 04e4e993 2023-08-14 op isspace((unsigned char)*str) ||
390 04e4e993 2023-08-14 op *str == '\'' || *str == '"' || *str == '\\') {
391 04e4e993 2023-08-14 op r = snprintf(tmp, sizeof(tmp), "%%%2X",
392 04e4e993 2023-08-14 op (unsigned char)*str);
393 04e4e993 2023-08-14 op if (r < 0 || (size_t)r >= sizeof(tmp)) {
394 04e4e993 2023-08-14 op log_warn("snprintf failed");
395 3634fa70 2023-08-31 op clt->err = 1;
396 04e4e993 2023-08-14 op return -1;
397 04e4e993 2023-08-14 op }
398 3634fa70 2023-08-31 op if (http_write(clt, tmp, r) == -1)
399 04e4e993 2023-08-14 op return -1;
400 3634fa70 2023-08-31 op } else if (http_write(clt, str, 1) == -1)
401 04e4e993 2023-08-14 op return -1;
402 04e4e993 2023-08-14 op }
403 04e4e993 2023-08-14 op
404 04e4e993 2023-08-14 op return 0;
405 04e4e993 2023-08-14 op }
406 04e4e993 2023-08-14 op
407 04e4e993 2023-08-14 op int
408 3634fa70 2023-08-31 op http_htmlescape(struct client *clt, const char *str)
409 04e4e993 2023-08-14 op {
410 04e4e993 2023-08-14 op int r;
411 04e4e993 2023-08-14 op
412 04e4e993 2023-08-14 op for (; *str; ++str) {
413 04e4e993 2023-08-14 op switch (*str) {
414 04e4e993 2023-08-14 op case '<':
415 3634fa70 2023-08-31 op r = http_writes(clt, "&lt;");
416 04e4e993 2023-08-14 op break;
417 04e4e993 2023-08-14 op case '>':
418 3634fa70 2023-08-31 op r = http_writes(clt, "&gt;");
419 04e4e993 2023-08-14 op break;
420 04e4e993 2023-08-14 op case '&':
421 3634fa70 2023-08-31 op r = http_writes(clt, "&gt;");
422 04e4e993 2023-08-14 op break;
423 04e4e993 2023-08-14 op case '"':
424 3634fa70 2023-08-31 op r = http_writes(clt, "&quot;");
425 04e4e993 2023-08-14 op break;
426 04e4e993 2023-08-14 op case '\'':
427 3634fa70 2023-08-31 op r = http_writes(clt, "&apos;");
428 04e4e993 2023-08-14 op break;
429 04e4e993 2023-08-14 op default:
430 3634fa70 2023-08-31 op r = http_write(clt, str, 1);
431 04e4e993 2023-08-14 op break;
432 04e4e993 2023-08-14 op }
433 04e4e993 2023-08-14 op
434 04e4e993 2023-08-14 op if (r == -1)
435 04e4e993 2023-08-14 op return -1;
436 04e4e993 2023-08-14 op }
437 04e4e993 2023-08-14 op
438 04e4e993 2023-08-14 op return 0;
439 04e4e993 2023-08-14 op }
440 04e4e993 2023-08-14 op
441 04e4e993 2023-08-14 op int
442 3634fa70 2023-08-31 op http_close(struct client *clt)
443 04e4e993 2023-08-14 op {
444 3634fa70 2023-08-31 op if (clt->err)
445 3634fa70 2023-08-31 op return -1;
446 3634fa70 2023-08-31 op if (clt->len != 0 && http_flush(clt) == -1)
447 3634fa70 2023-08-31 op return -1;
448 3634fa70 2023-08-31 op if (bufio_compose(&clt->bio, NULL, 0) == -1)
449 3634fa70 2023-08-31 op clt->err = 1;
450 3634fa70 2023-08-31 op return (clt->err ? -1 : 0);
451 04e4e993 2023-08-14 op }
452 04e4e993 2023-08-14 op
453 04e4e993 2023-08-14 op void
454 3634fa70 2023-08-31 op http_free(struct client *clt)
455 04e4e993 2023-08-14 op {
456 35cca6c5 2023-09-07 op free(clt->buf);
457 3634fa70 2023-08-31 op free(clt->req.path);
458 b42d807f 2023-09-02 op free(clt->req.secret);
459 3634fa70 2023-08-31 op free(clt->req.ctype);
460 3634fa70 2023-08-31 op free(clt->req.body);
461 3634fa70 2023-08-31 op bufio_free(&clt->bio);
462 04e4e993 2023-08-14 op }