Annotation of embedaddon/libpdel/http/http_head.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42: #include <sys/queue.h>
43:
44: #include <netinet/in.h>
45:
46: #include <stdio.h>
47: #include <stdlib.h>
48: #include <stdarg.h>
49: #include <string.h>
50: #include <limits.h>
51: #include <pthread.h>
52: #include <errno.h>
53: #include <ctype.h>
54:
55: #include <openssl/ssl.h>
56:
57: #include "structs/structs.h"
58: #include "structs/type/array.h"
59:
60: #include "util/typed_mem.h"
61: #include "http/http_defs.h"
62: #include "http/http_server.h"
63: #include "http/http_internal.h"
64:
65: #define CR '\r'
66: #define LF '\n'
67:
68: #define MAX_STRING (64 * 1024)
69:
70: #define MEM_TYPE_HEAD "http_head"
71: #define MEM_TYPE_HDRS "http_head.hdrs"
72: #define MEM_TYPE_NAME "http_head.name"
73: #define MEM_TYPE_VALUE "http_head.value"
74:
75: #define issep(ch) (strchr("()<>@,;:\\\"/[]?={} \t", ch) != NULL)
76:
77: struct http_header {
78: char *name;
79: char *value;
80: };
81:
82: struct http_head {
83: char *words[3]; /* first line stuff */
84: int num_hdrs; /* number of headers */
85: struct http_header *hdrs; /* headers, sorted */
86: };
87:
88: /*
89: * Internal variables
90: */
91: static const char *header_sort[] = {
92: HTTP_HEADER_DATE,
93: HTTP_HEADER_SERVER,
94: HTTP_HEADER_CONNECTION,
95: HTTP_HEADER_PROXY_CONNECTION,
96: HTTP_HEADER_CACHE_CONTROL,
97: HTTP_HEADER_PRAGMA,
98: HTTP_HEADER_LAST_MODIFIED,
99: HTTP_HEADER_WWW_AUTHENTICATE,
100: HTTP_HEADER_CONTENT_TYPE,
101: HTTP_HEADER_CONTENT_LENGTH,
102: HTTP_HEADER_CONTENT_ENCODING,
103: };
104: #define NUM_HEADER_SORT (sizeof(header_sort) / sizeof(*header_sort))
105:
106: /*
107: * Internal functions
108: */
109: static int http_head_special(const char *name);
110: static int http_header_cmp(const void *v1, const void *v2);
111: static char *read_hval(FILE *fp);
112: static char *read_line(FILE *fp, const char *mtype);
113: static char *read_token(FILE *fp, int liberal, const char *mtype);
114: static void read_whitespace(FILE *fp);
115: static int addch(char **sp, int *slen, int ch, const char *mtype);
116:
117: /*
118: * Create new header object.
119: */
120: struct http_head *
121: _http_head_new(void)
122: {
123: struct http_head *head;
124:
125: /* Create structure */
126: if ((head = MALLOC(MEM_TYPE_HEAD, sizeof(*head))) == NULL)
127: return (NULL);
128: memset(head, 0, sizeof(*head));
129: return (head);
130: }
131:
132: /*
133: * Free a header object.
134: */
135: void
136: _http_head_free(struct http_head **headp)
137: {
138: struct http_head *const head = *headp;
139: int i;
140:
141: if (head == NULL)
142: return;
143: for (i = 0; i < 3; i++)
144: FREE(MEM_TYPE_VALUE, head->words[i]);
145: for (i = 0; i < head->num_hdrs; i++) {
146: struct http_header *const hdr = &head->hdrs[i];
147:
148: FREE(MEM_TYPE_NAME, hdr->name);
149: FREE(MEM_TYPE_VALUE, hdr->value);
150: }
151: FREE(MEM_TYPE_HDRS, head->hdrs);
152: FREE(MEM_TYPE_HEAD, head);
153: *headp = NULL;
154: }
155:
156: /*
157: * Copy headers
158: */
159: struct http_head *
160: _http_head_copy(struct http_head *head0)
161: {
162: struct http_head *head;
163: int i;
164:
165: /* Get new header struct */
166: if ((head = _http_head_new()) == NULL)
167: goto fail;
168:
169: /* Copy first line words */
170: for (i = 0; i < 3; i++) {
171: if (head0->words[i] == NULL)
172: continue;
173: if ((head->words[i] = STRDUP(MEM_TYPE_VALUE,
174: head0->words[i])) == NULL)
175: goto fail;
176: }
177:
178: /* Copy other headers */
179: for (i = 0; i < head0->num_hdrs; i++) {
180: const char *name;
181: const char *value;
182:
183: if (_http_head_get_by_index(head0, i, &name, &value) == -1)
184: goto fail;
185: if (_http_head_set(head, 0, name, "%s", value) == -1)
186: goto fail;
187: }
188:
189: /* Done */
190: return (head);
191:
192: fail:
193: _http_head_free(&head);
194: return (NULL);
195: }
196:
197: /*
198: * Get a header field value.
199: *
200: * For headers listed multiple times, this only gets the first instance.
201: */
202: const char *
203: _http_head_get(struct http_head *head, const char *name)
204: {
205: struct http_header key;
206: struct http_header *hdr;
207: int i;
208:
209: /* First line stuff */
210: if ((i = http_head_special(name)) != -1)
211: return (head->words[i]);
212:
213: /* Normal headers */
214: key.name = (char *)name;
215: if ((hdr = bsearch(&key, head->hdrs, head->num_hdrs,
216: sizeof(*head->hdrs), http_header_cmp)) == NULL) {
217: errno = ENOENT;
218: return (NULL);
219: }
220: return (hdr->value);
221: }
222:
223: /*
224: * Get the number of headers
225: */
226: int
227: _http_head_num_headers(struct http_head *head)
228: {
229: return (head->num_hdrs);
230: }
231:
232: /*
233: * Get a header by index.
234: */
235: int
236: _http_head_get_by_index(struct http_head *head, u_int index,
237: const char **namep, const char **valuep)
238: {
239: if (index >= head->num_hdrs) {
240: errno = EINVAL;
241: return (-1);
242: }
243: if (namep != NULL)
244: *namep = head->hdrs[index].name;
245: if (valuep != NULL)
246: *valuep = head->hdrs[index].value;
247: return (0);
248: }
249:
250: /*
251: * Get the names of all headers.
252: */
253: int
254: _http_head_get_headers(struct http_head *head,
255: const char **names, size_t max_names)
256: {
257: int i;
258:
259: if (max_names > head->num_hdrs)
260: max_names = head->num_hdrs;
261: for (i = 0; i < max_names; i++)
262: names[i] = head->hdrs[i].name;
263: return (i);
264: }
265:
266: /*
267: * Set header value, in either append or replace mode.
268: */
269: int
270: _http_head_set(struct http_head *head, int append,
271: const char *name, const char *valfmt, ...)
272: {
273: va_list args;
274: int ret;
275:
276: va_start(args, valfmt);
277: ret = _http_head_vset(head, append, name, valfmt, args);
278: va_end(args);
279: return (ret);
280: }
281:
282: /*
283: * Set header value, in either append or replace mode.
284: */
285: int
286: _http_head_vset(struct http_head *head, int append,
287: const char *name, const char *valfmt, va_list args)
288: {
289: struct http_header key;
290: struct http_header *hdr;
291: char *value;
292: void *mem;
293: int i;
294:
295: /* Generate value */
296: VASPRINTF(MEM_TYPE_VALUE, &value, valfmt, args);
297: if (value == NULL)
298: return (-1);
299:
300: /* First line stuff */
301: if ((i = http_head_special(name)) != -1) {
302: FREE(MEM_TYPE_VALUE, head->words[i]);
303: head->words[i] = value;
304: return (0);
305: }
306:
307: /* If header doesn't already exist, add it (unless special) */
308: key.name = (char *)name;
309: if (strcasecmp(name, HTTP_HEADER_SET_COOKIE) == 0 /* XXX blech */
310: || (hdr = bsearch(&key, head->hdrs, head->num_hdrs,
311: sizeof(*head->hdrs), http_header_cmp)) == NULL) {
312:
313: /* Extend headers array */
314: if ((mem = REALLOC(MEM_TYPE_HDRS, head->hdrs,
315: (head->num_hdrs + 1) * sizeof(*head->hdrs))) == NULL) {
316: FREE(MEM_TYPE_VALUE, value);
317: return (-1);
318: }
319: head->hdrs = mem;
320: hdr = &head->hdrs[head->num_hdrs];
321:
322: /* Copy name */
323: if ((hdr->name = STRDUP(MEM_TYPE_NAME, name)) == NULL) {
324: FREE(MEM_TYPE_VALUE, value);
325: return (-1);
326: }
327:
328: /* Add new header */
329: hdr->value = value;
330: head->num_hdrs++;
331:
332: /* Keep array sorted */
333: (void)mergesort(head->hdrs, head->num_hdrs,
334: sizeof(*head->hdrs), http_header_cmp);
335: return (0);
336: }
337:
338: /* Append or replace */
339: if (append) {
340: const int plen = strlen(hdr->value);
341:
342: if ((mem = REALLOC(MEM_TYPE_VALUE,
343: hdr->value, plen + strlen(value) + 3)) == NULL) {
344: FREE(MEM_TYPE_VALUE, value);
345: return (-1);
346: }
347: hdr->value = mem;
348: sprintf(hdr->value + plen, ", %s", value);
349: FREE(MEM_TYPE_VALUE, value);
350: } else {
351: FREE(MEM_TYPE_VALUE, hdr->value);
352: hdr->value = value;
353: }
354: return (0);
355: }
356:
357: /*
358: * Remove a header.
359: */
360: int
361: _http_head_remove(struct http_head *head, const char *name)
362: {
363: struct http_header key;
364: struct http_header *hdr;
365: int i;
366:
367: /* First line stuff */
368: if ((i = http_head_special(name)) != -1) {
369: if (head->words[i] != NULL) {
370: FREE(MEM_TYPE_VALUE, head->words[i]);
371: head->words[i] = NULL;
372: return (1);
373: }
374: return (0);
375: }
376:
377: /* Does header exist? */
378: key.name = (char *)name;
379: if ((hdr = bsearch(&key, head->hdrs, head->num_hdrs,
380: sizeof(*head->hdrs), http_header_cmp)) == NULL)
381: return (0);
382:
383: /* Remove header */
384: i = hdr - head->hdrs;
385: FREE(MEM_TYPE_NAME, hdr->name);
386: FREE(MEM_TYPE_VALUE, hdr->value);
387: memmove(head->hdrs + i, head->hdrs + i + 1,
388: (--head->num_hdrs - i) * sizeof(*head->hdrs));
389: return (1);
390: }
391:
392: /*
393: * Return index for one of the 'special' headers representing
394: * one of the three parts of the first line of the HTTP request
395: * or response.
396: */
397: static int
398: http_head_special(const char *name)
399: {
400: if (name == HDR_REQUEST_METHOD) /* also HDR_REPLY_VERSION */
401: return (0);
402: if (name == HDR_REQUEST_URI) /* also HDR_REPLY_STATUS */
403: return (1);
404: if (name == HDR_REQUEST_VERSION) /* also HDR_REPLY_REASON */
405: return (2);
406: return (-1);
407: }
408:
409: /*
410: * Compare two headers by name.
411: *
412: * XXX this could be faster
413: */
414: static int
415: http_header_cmp(const void *v1, const void *v2)
416: {
417: const struct http_header *const hdrs[] = { v1, v2 };
418: int sortval[2];
419: int i, j;
420:
421: /* Check assigned ordering list */
422: for (i = 0; i < 2; i++) {
423: const char *hdr = hdrs[i]->name;
424:
425: sortval[i] = INT_MAX;
426: for (j = 0; j < NUM_HEADER_SORT; j++) {
427: if (strcasecmp(hdr, header_sort[j]) == 0) {
428: sortval[i] = j;
429: break;
430: }
431: }
432: }
433: if (sortval[0] == INT_MAX && sortval[1] == INT_MAX)
434: return (strcasecmp(hdrs[0]->name, hdrs[1]->name));
435: return (sortval[0] - sortval[1]);
436: }
437:
438: /*
439: * Read an entire HTTP request or response header.
440: */
441: int
442: _http_head_read(struct http_head *head, FILE *fp, int req)
443: {
444: int ch;
445:
446: /* Read any initial whitespace including CR, LF */
447: while ((ch = getc(fp)) != EOF) {
448: if (!isspace(ch)) {
449: ungetc(ch, fp);
450: break;
451: }
452: }
453:
454: /* Read first word */
455: FREE(MEM_TYPE_VALUE, head->words[0]);
456: if ((head->words[0] = read_token(fp, 1, MEM_TYPE_VALUE)) == NULL)
457: return (-1);
458:
459: /* Get whitespace */
460: read_whitespace(fp);
461:
462: /* Read second word */
463: FREE(MEM_TYPE_VALUE, head->words[1]);
464: if ((head->words[1] = read_token(fp, 1, MEM_TYPE_VALUE)) == NULL)
465: return (-1);
466:
467: /* Get whitespace */
468: read_whitespace(fp);
469:
470: /* Read third and remaining words on the line including CR-LF */
471: FREE(MEM_TYPE_VALUE, head->words[2]);
472: if ((head->words[2] = read_line(fp, MEM_TYPE_VALUE)) == NULL)
473: return (-1);
474:
475: /* Special format for HTTP 0.9 request (no protocol or headers) */
476: if (req && *head->words[2] == '\0') {
477: FREE(MEM_TYPE_VALUE, head->words[2]);
478: if ((head->words[2] = STRDUP(MEM_TYPE_VALUE,
479: HTTP_PROTO_0_9)) == NULL)
480: return (-1);
481: return (0);
482: }
483:
484: /* Read headers */
485: if (_http_head_read_headers(head, fp) == -1)
486: return (-1);
487:
488: /* Done */
489: return (0);
490: }
491:
492: /*
493: * Read HTTP headers
494: */
495: int
496: _http_head_read_headers(struct http_head *head, FILE *fp)
497: {
498: char *name;
499: char *value;
500: int ret;
501: int ch;
502:
503: while (1) {
504:
505: /* Check for CR-LF */
506: if ((ch = getc(fp)) == EOF) {
507: if (ferror(fp))
508: goto fail;
509: goto fail_invalid;
510: }
511: if (ch == CR) {
512: if ((ch = getc(fp)) != LF) {
513: if (ch == EOF && ferror(fp))
514: goto fail;
515: goto fail_invalid;
516: }
517: return (0);
518: }
519: ungetc(ch, fp);
520:
521: /* Get header name */
522: if ((name = read_token(fp, 0, MEM_TYPE_NAME)) == NULL)
523: goto fail;
524:
525: /* Get separator */
526: if ((ch = getc(fp)) != ':') {
527: FREE(MEM_TYPE_NAME, name);
528: goto fail_invalid;
529: }
530:
531: /* Get whitespace */
532: read_whitespace(fp);
533:
534: /* Get header value including final CR-LF */
535: if ((value = read_hval(fp)) == NULL) {
536: FREE(MEM_TYPE_NAME, name);
537: goto fail;
538: }
539:
540: /* Append to header value */
541: ret = _http_head_set(head, 1, name, "%s", value);
542: FREE(MEM_TYPE_NAME, name);
543: FREE(MEM_TYPE_VALUE, value);
544: if (ret == -1)
545: goto fail;
546: }
547:
548: fail_invalid:
549: errno = EINVAL;
550: fail:
551: return (-1);
552: }
553:
554: /*
555: * Write out an HTTP header.
556: */
557: int
558: _http_head_write(struct http_head *head, FILE *fp)
559: {
560: int i;
561:
562: for (i = 0; i < 3; i++) {
563: if (head->words[i] == NULL) {
564: errno = EINVAL;
565: return (-1);
566: }
567: }
568: fprintf(fp, "%s %s %s\r\n",
569: head->words[0], head->words[1], head->words[2]);
570: for (i = 0; i < head->num_hdrs; i++) {
571: struct http_header *const hdr = &head->hdrs[i];
572:
573: fprintf(fp, "%s: %s\r\n", hdr->name, hdr->value);
574: }
575: fprintf(fp, "\r\n");
576: #if 0
577: fflush(fp);
578: #endif
579: return (0);
580: }
581:
582: /*
583: * Figure out whether there is anything in the head or not.
584: */
585: int
586: _http_head_has_anything(struct http_head *head)
587: {
588: return (head->words[0] != NULL);
589: }
590:
591: /*
592: * Determine if keep alive is requested.
593: */
594: int
595: _http_head_want_keepalive(struct http_head *head)
596: {
597: const char *hval;
598:
599: return (((hval = _http_head_get(head, HTTP_HEADER_CONNECTION)) != NULL
600: || (hval = _http_head_get(head,
601: HTTP_HEADER_PROXY_CONNECTION)) != NULL)
602: && strcasecmp(hval, "Keep-Alive") == 0);
603: }
604:
605: /*
606: * Read an HTTP header value.
607: */
608: static char *
609: read_hval(FILE *fp)
610: {
611: char *s = NULL;
612: int inquote = 0;
613: int bslash = 0;
614: int slen = 0;
615: int ch;
616:
617: /* Read characters */
618: while (1) {
619: if ((ch = getc(fp)) == EOF) {
620: if (ferror(fp))
621: goto fail;
622: goto fail_invalid;
623: }
624: if (bslash) { /* implies inquote */
625: if (!addch(&s, &slen, ch, MEM_TYPE_VALUE))
626: goto fail;
627: bslash = 0;
628: continue;
629: }
630: switch (ch) {
631: case '"':
632: inquote = !inquote;
633: break;
634: case '\\':
635: if (inquote) {
636: bslash = 1;
637: continue;
638: }
639: case CR:
640: if ((ch = getc(fp)) != LF) { /* read linefeed */
641: if (ch == EOF && ferror(fp))
642: goto fail;
643: goto fail_invalid;
644: }
645: if ((ch = getc(fp)) == EOF) { /* get next char */
646: if (ferror(fp))
647: goto fail;
648: goto fail_invalid;
649: }
650: if (ch == ' ' || ch == '\t') { /* line continuation */
651: read_whitespace(fp);
652: ch = ' ';
653: break;
654: }
655: ungetc(ch, fp);
656: goto done;
657: default:
658: if (iscntrl(ch) && ch != ' ' && ch != '\t')
659: goto fail_invalid;
660: break;
661: }
662: if (!addch(&s, &slen, ch, MEM_TYPE_VALUE))
663: goto fail;
664: }
665:
666: done:
667: /* Terminate and return string */
668: if (!addch(&s, &slen, '\0', MEM_TYPE_VALUE))
669: goto fail;
670: return (s);
671:
672: fail_invalid:
673: errno = EINVAL;
674: fail:
675: FREE(MEM_TYPE_VALUE, s);
676: return (NULL);
677: }
678:
679: /*
680: * Read up through end of line and return value, not including CR-LF.
681: */
682: static char *
683: read_line(FILE *fp, const char *mtype)
684: {
685: char *s = NULL;
686: int slen = 0;
687: int ch;
688:
689: /* Read characters */
690: while (1) {
691: if ((ch = getc(fp)) == EOF) {
692: if (ferror(fp))
693: goto fail;
694: goto fail_invalid;
695: }
696: if (ch == CR) {
697: if ((ch = getc(fp)) != LF) {
698: if (ch == EOF && ferror(fp))
699: goto fail;
700: goto fail_invalid;
701: }
702: goto done;
703: }
704: if (ch == LF) /* handle broken clients */
705: break;
706: if (!addch(&s, &slen, ch, mtype))
707: goto fail;
708: }
709:
710: done:
711: /* Terminate and return string */
712: if (!addch(&s, &slen, '\0', mtype))
713: goto fail;
714: return (s);
715:
716: fail_invalid:
717: errno = EINVAL;
718: fail:
719: FREE(mtype, s);
720: return (NULL);
721: }
722:
723: /*
724: * Read an HTTP header token.
725: */
726: static char *
727: read_token(FILE *fp, int liberal, const char *mtype)
728: {
729: char *s = NULL;
730: int slen = 0;
731: int ch;
732:
733: /* Read characters */
734: while (1) {
735: if ((ch = getc(fp)) == EOF) {
736: if (ferror(fp))
737: goto fail;
738: goto fail_invalid;
739: }
740: if (!isprint(ch)
741: || (ch == ' ' || ch == '\t')
742: || (!liberal && issep(ch))) {
743: ungetc(ch, fp);
744: break;
745: }
746: if (!addch(&s, &slen, ch, mtype))
747: goto fail;
748: }
749:
750: /* Terminate and return string */
751: if (!addch(&s, &slen, '\0', mtype))
752: goto fail;
753: return (s);
754:
755: fail_invalid:
756: errno = EINVAL;
757: fail:
758: FREE(mtype, s);
759: return (NULL);
760: }
761:
762: /*
763: * Read any amount of whitespace.
764: */
765: static void
766: read_whitespace(FILE *fp)
767: {
768: int ch;
769:
770: while (1) {
771: if ((ch = getc(fp)) == EOF)
772: return;
773: if (ch != ' ' && ch != '\t') {
774: ungetc(ch, fp);
775: break;
776: }
777: }
778: }
779:
780: /*
781: * Add a character to a malloc'd string.
782: */
783: static int
784: addch(char **sp, int *slen, int ch, const char *mtype)
785: {
786: void *mem;
787:
788: if (*slen >= MAX_STRING) {
789: errno = E2BIG;
790: return (0);
791: }
792: if (*slen % 128 == 0) {
793: if ((mem = REALLOC(mtype, *sp, *slen + 128)) == NULL)
794: return (0);
795: *sp = mem;
796: }
797: (*sp)[(*slen)++] = ch;
798: return (1);
799: }
800:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>