More work on httpconn, add proxy module.
[shim.git] / headers.c
blob4689b7ce2f14c828e7863bd25b19bf7182db3da7
1 #include <assert.h>
2 #include <string.h>
3 #include <event2/buffer.h>
5 #include "util.h"
6 #include "headers.h"
8 void
9 headers_add_key(struct header_list *headers, const char *key, size_t n)
11 struct header *h;
13 h = mem_calloc(1, sizeof(*h) + n + 1);
14 TAILQ_INIT(&h->val);
15 memcpy(h->key, key, n);
16 TAILQ_INSERT_TAIL(headers, h, next);
19 void
20 headers_add_val(struct header_list *headers, const char *val, size_t n)
22 struct header *h;
23 struct val_line *line;
25 h = TAILQ_LAST(headers, header_list);
26 assert(h != NULL);
28 line = mem_calloc(1, sizeof(*line) + n + 1);
29 memcpy(line->str, val, n);
30 line->len = n;
31 TAILQ_INSERT_TAIL(&h->val, line, next);
32 h->val_len += n;
35 void
36 headers_dump(struct header_list *headers, struct evbuffer *buf)
38 struct header *h;
39 struct val_line *line;
41 TAILQ_FOREACH(h, headers, next) {
42 evbuffer_add_printf(buf, "%s:", h->key);
43 TAILQ_FOREACH(line, &h->val, next)
44 evbuffer_add_printf(buf, "%s\r\n", line->str);
47 evbuffer_add(buf, "\r\n", 2);
50 /* return: -1 error, 0 need more data, 1 finished. */
51 int
52 headers_parse(struct header_list *headers, struct evbuffer *buf)
54 char *line, *p;
56 while ((line = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF))) {
57 if (*line == '\0') {
58 mem_free(line);
59 return 1;
62 p = line;
64 if (*line != ' ' && *line != '\t') {
65 p = strchr(line, ':');
66 if (!p) {
67 mem_free(line);
68 return -1;
70 headers_add_key(headers, line, p - line);
71 ++p;
74 if (!TAILQ_LAST(headers, header_list)) {
75 mem_free(line);
76 return -1;
79 headers_add_val(headers, p, strlen(p));
80 mem_free(line);
83 return 0;
86 /* caller must free result; returns NULL if key not found. */
87 char *
88 headers_find(struct header_list *headers, const char *key)
90 struct header *h;
91 struct val_line *line;
92 char *ret, *p;
93 size_t len;
95 TAILQ_FOREACH(h, headers, next) {
96 if (evutil_ascii_strcasecmp(h->key, key))
97 continue;
99 /* calculate total size */
100 TAILQ_FOREACH(line, &h->val, next)
101 len += line->len;
103 /* XXX Some of this space is wasted if we trim any leading WS
104 from value lines */
105 ret = mem_calloc(1, len + 1);
106 p = ret;
108 TAILQ_FOREACH(line, &h->val, next) {
109 len = strspn(line->str, " \t");
110 /* after the first line, translate leading WS to
111 a single SP */
112 if (p != ret)
113 *p++ = ' ';
114 memcpy(p, line->str + len, line->len - len);
115 p += line->len - len;
118 return ret;
121 return NULL;
124 void
125 headers_clear(struct header_list *headers)
127 struct header *h;
128 struct val_line *line;
130 while ((h = TAILQ_FIRST(headers))) {
131 TAILQ_REMOVE(headers, h, next);
132 while ((line = TAILQ_FIRST(&h->val))) {
133 TAILQ_REMOVE(&h->val, line, next);
134 mem_free(line);
136 mem_free(h);
140 #ifdef TEST_HEADERS
141 #include <stdio.h>
142 int main(int argc, char **argv)
144 struct evbuffer *buf, *buf2;
145 struct header_list headers;
146 char line[256];
148 buf = evbuffer_new();
149 buf2 = evbuffer_new();
150 TAILQ_INIT(&headers);
152 while (fgets(line, sizeof(line), stdin)) {
153 evbuffer_add(buf, line, strlen(line));
156 headers_parse(&headers, buf);
157 headers_dump(&headers, buf2);
159 printf("buf1..\n");
160 fwrite(evbuffer_pullup(buf, evbuffer_get_length(buf)), evbuffer_get_length(buf), 1, stdout);
161 printf("\nbuf2..\n");
162 fwrite(evbuffer_pullup(buf2, evbuffer_get_length(buf2)), evbuffer_get_length(buf2), 1, stdout);
164 if (argc > 1) {
165 int i;
166 printf("\nfinding stuffs...\n");
167 for (i = 1; i < argc; ++i) {
168 char *buf = headers_find(&headers, argv[i]);
169 printf("%s? %s\n", argv[i], buf? buf : "NOT FOUND");
170 if (buf) mem_free(buf);
174 evbuffer_free(buf);
175 evbuffer_free(buf2);
177 return 0;
179 #endif