Merge branch 'master' into timeheap
[ashd.git] / lib / req.c
1 /*
2     ashd - A Sane HTTP Daemon
3     Copyright (C) 2008  Fredrik Tolf <fredrik@dolda2000.com>
4
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/socket.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <fcntl.h>
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <utils.h>
32 #include <log.h>
33 #include <req.h>
34 #include <proc.h>
35 #include <bufio.h>
36
37 struct hthead *mkreq(char *method, char *url, char *ver)
38 {
39     struct hthead *req;
40     
41     omalloc(req);
42     req->method = sstrdup(method);
43     req->url = sstrdup(url);
44     req->ver = sstrdup(ver);
45     req->rest = sstrdup(url);
46     return(req);
47 }
48
49 struct hthead *mkresp(int code, char *msg, char *ver)
50 {
51     struct hthead *resp;
52     
53     omalloc(resp);
54     resp->code = code;
55     resp->msg = sstrdup(msg);
56     resp->ver = sstrdup(ver);
57     return(resp);
58 }
59
60 void freehthead(struct hthead *head)
61 {
62     int i;
63     
64     if(head->method != NULL)
65         free(head->method);
66     if(head->url != NULL)
67         free(head->url);
68     if(head->msg != NULL)
69         free(head->msg);
70     if(head->ver != NULL)
71         free(head->ver);
72     if(head->rest != NULL)
73         free(head->rest);
74     if(head->headers) {
75         for(i = 0; i < head->noheaders; i++) {
76             free(head->headers[i][0]);
77             free(head->headers[i][1]);
78             free(head->headers[i]);
79         }
80         free(head->headers);
81     }
82     free(head);
83 }
84
85 char *getheader(struct hthead *head, char *name)
86 {
87     int i;
88     
89     for(i = 0; i < head->noheaders; i++) {
90         if(!strcasecmp(head->headers[i][0], name))
91             return(head->headers[i][1]);
92     }
93     return(NULL);
94 }
95
96 static void trim(struct charbuf *buf)
97 {
98     char *p;
99     
100     for(p = buf->b; (p - buf->b < buf->d) && isspace(*p); p++);
101     memmove(buf->b, p, buf->d -= (p - buf->b));
102     if(buf->d > 0)
103         for(p = buf->b + buf->d - 1; (p > buf->b) && isspace(*p); p--, buf->d--);
104 }
105
106 int parseheaders(struct hthead *head, FILE *in)
107 {
108     int c, state;
109     struct charbuf name, val;
110     size_t tsz;
111     
112     bufinit(name);
113     bufinit(val);
114     state = 0;
115     tsz = 0;
116     while(1) {
117         c = fgetc(in);
118         if(++tsz >= 65536)
119             goto fail;
120     again:
121         if(state == 0) {
122             if(c == '\r') {
123             } else if(c == '\n') {
124                 break;
125             } else if(c == EOF) {
126                 goto fail;
127             } else {
128                 state = 1;
129                 goto again;
130             }
131         } else if(state == 1) {
132             if(c == ':') {
133                 trim(&name);
134                 bufadd(name, 0);
135                 state = 2;
136             } else if(c == '\r') {
137             } else if(c == '\n') {
138                 goto fail;
139             } else if(c == EOF) {
140                 goto fail;
141             } else {
142                 bufadd(name, c);
143             }
144         } else if(state == 2) {
145             if(c == '\r') {
146             } else if(c == '\n') {
147                 trim(&val);
148                 bufadd(val, 0);
149                 headappheader(head, name.b, val.b);
150                 buffree(name);
151                 buffree(val);
152                 state = 0;
153             } else if(c == EOF) {
154                 goto fail;
155             } else {
156                 bufadd(val, c);
157             }
158         }
159     }
160     return(0);
161     
162 fail:
163     buffree(name);
164     buffree(val);
165     return(-1);
166 }
167
168 int parseheadersb(struct hthead *head, struct bufio *in)
169 {
170     int c, state;
171     struct charbuf name, val;
172     size_t tsz;
173     
174     bufinit(name);
175     bufinit(val);
176     state = 0;
177     tsz = 0;
178     while(1) {
179         c = biogetc(in);
180         if(++tsz >= 65536)
181             goto fail;
182     again:
183         if(state == 0) {
184             if(c == '\r') {
185             } else if(c == '\n') {
186                 break;
187             } else if(c == EOF) {
188                 goto fail;
189             } else {
190                 state = 1;
191                 goto again;
192             }
193         } else if(state == 1) {
194             if(c == ':') {
195                 trim(&name);
196                 bufadd(name, 0);
197                 state = 2;
198             } else if(c == '\r') {
199             } else if(c == '\n') {
200                 goto fail;
201             } else if(c == EOF) {
202                 goto fail;
203             } else {
204                 bufadd(name, c);
205             }
206         } else if(state == 2) {
207             if(c == '\r') {
208             } else if(c == '\n') {
209                 trim(&val);
210                 bufadd(val, 0);
211                 headappheader(head, name.b, val.b);
212                 buffree(name);
213                 buffree(val);
214                 state = 0;
215             } else if(c == EOF) {
216                 goto fail;
217             } else {
218                 bufadd(val, c);
219             }
220         }
221     }
222     return(0);
223     
224 fail:
225     buffree(name);
226     buffree(val);
227     return(-1);
228 }
229
230 struct hthead *parseresponse(FILE *in)
231 {
232     struct hthead *req;
233     int code;
234     struct charbuf ver, msg;
235     int c;
236     
237     req = NULL;
238     bufinit(ver);
239     bufinit(msg);
240     code = 0;
241     while(1) {
242         c = getc(in);
243         if(c == ' ') {
244             break;
245         } else if((c == EOF) || (c < 32) || (c >= 128)) {
246             goto fail;
247         } else {
248             bufadd(ver, c);
249             if(ver.d >= 128)
250                 goto fail;
251         }
252     }
253     while(1) {
254         c = getc(in);
255         if(c == ' ') {
256             break;
257         } else if((c == EOF) || (c < '0') || (c > '9')) {
258             goto fail;
259         } else {
260             code = (code * 10) + (c - '0');
261             if(code >= 10000)
262                 goto fail;
263         }
264     }
265     while(1) {
266         c = getc(in);
267         if(c == 10) {
268             break;
269         } else if(c == 13) {
270         } else if((c == EOF) || (c < 32)) {
271             goto fail;
272         } else {
273             bufadd(msg, c);
274             if(msg.d >= 512)
275                 goto fail;
276         }
277     }
278     bufadd(msg, 0);
279     bufadd(ver, 0);
280     req = mkresp(code, msg.b, ver.b);
281     if(parseheaders(req, in))
282         goto fail;
283     goto out;
284     
285 fail:
286     if(req != NULL) {
287         freehthead(req);
288         req = NULL;
289     }
290 out:
291     buffree(msg);
292     buffree(ver);
293     return(req);
294 }
295
296 struct hthead *parseresponseb(struct bufio *in)
297 {
298     struct hthead *req;
299     int code;
300     struct charbuf ver, msg;
301     int c;
302     
303     req = NULL;
304     bufinit(ver);
305     bufinit(msg);
306     code = 0;
307     while(1) {
308         c = biogetc(in);
309         if(c == ' ') {
310             break;
311         } else if((c == EOF) || (c < 32) || (c >= 128)) {
312             goto fail;
313         } else {
314             bufadd(ver, c);
315             if(ver.d >= 128)
316                 goto fail;
317         }
318     }
319     while(1) {
320         c = biogetc(in);
321         if(c == ' ') {
322             break;
323         } else if((c == EOF) || (c < '0') || (c > '9')) {
324             goto fail;
325         } else {
326             code = (code * 10) + (c - '0');
327             if(code >= 10000)
328                 goto fail;
329         }
330     }
331     while(1) {
332         c = biogetc(in);
333         if(c == 10) {
334             break;
335         } else if(c == 13) {
336         } else if((c == EOF) || (c < 32)) {
337             goto fail;
338         } else {
339             bufadd(msg, c);
340             if(msg.d >= 512)
341                 goto fail;
342         }
343     }
344     bufadd(msg, 0);
345     bufadd(ver, 0);
346     req = mkresp(code, msg.b, ver.b);
347     if(parseheadersb(req, in))
348         goto fail;
349     goto out;
350     
351 fail:
352     if(req != NULL) {
353         freehthead(req);
354         req = NULL;
355     }
356 out:
357     buffree(msg);
358     buffree(ver);
359     return(req);
360 }
361
362 void replrest(struct hthead *head, char *rest)
363 {
364     char *tmp;
365     
366     /* Do not free the current rest string yet, so that the new one
367      * can be taken from a subpart of the old one. */
368     tmp = head->rest;
369     head->rest = sstrdup(rest);
370     free(tmp);
371 }
372
373 void headpreheader(struct hthead *head, const char *name, const char *val)
374 {
375     head->headers = srealloc(head->headers, sizeof(*head->headers) * (head->noheaders + 1));
376     memmove(head->headers + 1, head->headers, sizeof(*head->headers) * head->noheaders);
377     head->noheaders++;
378     head->headers[0] = smalloc(sizeof(*head->headers[0]) * 2);
379     head->headers[0][0] = sstrdup(name);
380     head->headers[0][1] = sstrdup(val);
381 }
382
383 void headappheader(struct hthead *head, const char *name, const char *val)
384 {
385     int i;
386
387     i = head->noheaders++;
388     head->headers = srealloc(head->headers, sizeof(*head->headers) * head->noheaders);
389     head->headers[i] = smalloc(sizeof(*head->headers[i]) * 2);
390     head->headers[i][0] = sstrdup(name);
391     head->headers[i][1] = sstrdup(val);
392 }
393
394 void headrmheader(struct hthead *head, const char *name)
395 {
396     int i;
397     
398     for(i = 0; i < head->noheaders; i++) {
399         if(!strcasecmp(head->headers[i][0], name)) {
400             free(head->headers[i][0]);
401             free(head->headers[i][1]);
402             free(head->headers[i]);
403             memmove(head->headers + i, head->headers + i + 1, sizeof(head->headers) * (--head->noheaders - i));
404             return;
405         }
406     }
407 }
408
409 int writeresp(FILE *out, struct hthead *resp)
410 {
411     int i;
412     
413     if(fprintf(out, "%s %i %s\r\n", resp->ver, resp->code, resp->msg) < 0)
414         return(-1);
415     for(i = 0; i < resp->noheaders; i++) {
416         if(fprintf(out, "%s: %s\r\n", resp->headers[i][0], resp->headers[i][1]) < 0)
417             return(-1);
418     }
419     return(0);
420 }
421
422 int writerespb(struct bufio *out, struct hthead *resp)
423 {
424     int i;
425     
426     if(bioprintf(out, "%s %i %s\r\n", resp->ver, resp->code, resp->msg) < 0)
427         return(-1);
428     for(i = 0; i < resp->noheaders; i++) {
429         if(bioprintf(out, "%s: %s\r\n", resp->headers[i][0], resp->headers[i][1]) < 0)
430             return(-1);
431     }
432     return(0);
433 }
434
435 int sendreq2(int sock, struct hthead *req, int fd, int flags)
436 {
437     int ret, i;
438     struct charbuf buf;
439     
440     bufinit(buf);
441     bufcatstr2(buf, req->method);
442     bufcatstr2(buf, req->url);
443     bufcatstr2(buf, req->ver);
444     bufcatstr2(buf, req->rest);
445     for(i = 0; i < req->noheaders; i++) {
446         bufcatstr2(buf, req->headers[i][0]);
447         bufcatstr2(buf, req->headers[i][1]);
448     }
449     bufcatstr2(buf, "");
450     ret = sendfd2(sock, fd, buf.b, buf.d, flags);
451     buffree(buf);
452     if(ret < 0)
453         return(-1);
454     else
455         return(0);
456 }
457
458 int sendreq(int sock, struct hthead *req, int fd)
459 {
460     return(sendreq2(sock, req, fd, MSG_NOSIGNAL));
461 }
462
463 int recvreq(int sock, struct hthead **reqp)
464 {
465     int fd;
466     struct charbuf buf;
467     char *p;
468     size_t l;
469     char *name, *val;
470     struct hthead *req;
471     
472     if((fd = recvfd(sock, &buf.b, &buf.d)) < 0) {
473         return(-1);
474     }
475     fcntl(fd, F_SETFD, FD_CLOEXEC);
476     buf.s = buf.d;
477     p = buf.b;
478     l = buf.d;
479     
480     *reqp = omalloc(req);
481     if((req->method = sstrdup(decstr(&p, &l))) == NULL)
482         goto fail;
483     if((req->url = sstrdup(decstr(&p, &l))) == NULL)
484         goto fail;
485     if((req->ver = sstrdup(decstr(&p, &l))) == NULL)
486         goto fail;
487     if((req->rest = sstrdup(decstr(&p, &l))) == NULL)
488         goto fail;
489     
490     while(1) {
491         if(!*(name = decstr(&p, &l)))
492             break;
493         val = decstr(&p, &l);
494         headappheader(req, name, val);
495     }
496     
497     buffree(buf);
498     return(fd);
499     
500 fail:
501     close(fd);
502     freehthead(req);
503     errno = EPROTO;
504     return(-1);
505 }
506
507 char *unquoteurl(char *in)
508 {
509     struct charbuf buf;
510     char *p;
511     int c;
512     
513     bufinit(buf);
514     p = in;
515     while(*p) {
516         if(*p == '%') {
517             if(!p[1] || !p[2])
518                 goto fail;
519             c = 0;
520             if((p[1] >= '0') && (p[1] <= '9'))          c |= (p[1] - '0') << 4;
521             else if((p[1] >= 'a') && (p[1] <= 'f'))     c |= (p[1] - 'a' + 10) << 4;
522             else if((p[1] >= 'A') && (p[1] <= 'F'))     c |= (p[1] - 'A' + 10) << 4;
523             else                                        goto fail;
524             if((p[2] >= '0') && (p[2] <= '9'))          c |= (p[2] - '0');
525             else if((p[2] >= 'a') && (p[2] <= 'f'))     c |= (p[2] - 'a' + 10);
526             else if((p[2] >= 'A') && (p[2] <= 'F'))     c |= (p[2] - 'A' + 10);
527             else                                        goto fail;
528             bufadd(buf, c);
529             p += 3;
530         } else {
531             bufadd(buf, *(p++));
532         }
533     }
534     bufadd(buf, 0);
535     return(buf.b);
536 fail:
537     buffree(buf);
538     return(NULL);
539 }