Dont fail in url_tokenize if input contains just a path.
[shim.git] / headers.c
blob20b34738dc5c99b36e1b88d714bbf114e4503ce0
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_add_key_val(struct header_list *headers, const char *key,
37 const char *val)
39 headers_add_key(headers, key, strlen(key));
40 headers_add_val(headers, val, strlen(val));
43 void
44 headers_dump(struct header_list *headers, struct evbuffer *buf)
46 struct header *h;
47 struct val_line *line;
49 TAILQ_FOREACH(h, headers, next) {
50 evbuffer_add_printf(buf, "%s: ", h->key);
51 TAILQ_FOREACH(line, &h->val, next) {
52 evbuffer_add_printf(buf, "%s\r\n", line->str);
56 evbuffer_add(buf, "\r\n", 2);
59 /* return: -1 error, 0 need more data, 1 finished. */
60 int
61 headers_load(struct header_list *headers, struct evbuffer *buf)
63 char *line, *p;
65 while ((line = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF))) {
66 if (*line == '\0') {
67 mem_free(line);
68 return 1;
71 p = line;
73 if (*line != ' ' && *line != '\t') {
74 p = strchr(line, ':');
75 if (!p || line == p) {
76 mem_free(line);
77 return -1;
79 headers_add_key(headers, line, p - line);
80 ++p;
81 p += strspn(p, " \t");
84 if (!TAILQ_LAST(headers, header_list)) {
85 mem_free(line);
86 return -1;
89 headers_add_val(headers, p, strlen(p));
90 mem_free(line);
93 return 0;
96 int
97 headers_has_key(struct header_list *headers, const char *key)
99 struct header *h;
101 TAILQ_FOREACH(h, headers, next) {
102 if (!evutil_ascii_strcasecmp(h->key, key))
103 return 1;
106 return 0;
109 /* caller must free result; returns NULL if key not found. */
110 char *
111 headers_find(struct header_list *headers, const char *key)
113 struct header *h;
114 struct val_line *line;
115 char *ret, *p;
116 size_t len;
118 TAILQ_FOREACH(h, headers, next) {
119 if (evutil_ascii_strcasecmp(h->key, key))
120 continue;
122 len = h->val_len;
124 /* XXX Some of this space is wasted if we trim any leading WS
125 from value lines */
126 ret = mem_calloc(1, len + 1);
127 p = ret;
129 TAILQ_FOREACH(line, &h->val, next) {
130 len = strspn(line->str, " \t");
131 /* after the first line, translate leading WS to
132 a single SP */
133 if (p != ret)
134 *p++ = ' ';
135 memcpy(p, line->str + len, line->len - len);
136 p += line->len - len;
139 return ret;
142 return NULL;
145 static void
146 remove_one(struct header_list *headers, struct header *h)
148 struct val_line *line;
150 TAILQ_REMOVE(headers, h, next);
151 while ((line = TAILQ_FIRST(&h->val))) {
152 TAILQ_REMOVE(&h->val, line, next);
153 mem_free(line);
155 mem_free(h);
158 void
159 headers_clear(struct header_list *headers)
161 struct header *h;
163 while ((h = TAILQ_FIRST(headers)))
164 remove_one(headers, h);
168 headers_remove(struct header_list *headers, const char *key)
170 int count;
171 struct header *h, *next;
173 count = 0;
174 for (h = TAILQ_FIRST(headers); h != NULL; h = next) {
175 next = TAILQ_NEXT(h, next);
176 if (!evutil_ascii_strcasecmp(h->key, key)) {
177 count++;
178 remove_one(headers, h);
182 return count;
185 #ifdef TEST_HEADERS
186 #include <stdio.h>
187 int main(int argc, char **argv)
189 struct evbuffer *buf, *buf2;
190 struct header_list headers;
191 char line[256];
193 buf = evbuffer_new();
194 buf2 = evbuffer_new();
195 TAILQ_INIT(&headers);
197 while (fgets(line, sizeof(line), stdin)) {
198 evbuffer_add(buf, line, strlen(line));
201 headers_load(&headers, buf);
202 headers_dump(&headers, buf2);
204 printf("buf1..\n");
205 fwrite(evbuffer_pullup(buf, evbuffer_get_length(buf)), evbuffer_get_length(buf), 1, stdout);
206 printf("\nbuf2..\n");
207 fwrite(evbuffer_pullup(buf2, evbuffer_get_length(buf2)), evbuffer_get_length(buf2), 1, stdout);
209 if (argc > 1) {
210 int i;
211 printf("\nfinding stuffs...\n");
212 for (i = 1; i < argc; ++i) {
213 char *buf = headers_find(&headers, argv[i]);
214 printf("%s? %s\n", argv[i], buf? buf : "NOT FOUND");
215 if (buf) {
216 mem_free(buf);
217 headers_remove(&headers, argv[i]);
222 evbuffer_free(buf);
223 evbuffer_free(buf2);
225 return 0;
227 #endif