1 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
7 #include <ccan/str/str.h>
8 #include <ccan/talloc/talloc.h>
9 #include <ccan/list/list.h>
11 #include <ccan/rfc822/rfc822.h>
14 void *memmem(const void *haystack, size_t haystacklen,
15 const void *needle, size_t needlelen)
20 last = p + haystacklen - needlelen;
23 if (memcmp(p, needle, needlelen) == 0)
25 } while (p++ <= last);
31 static void (*allocation_failure_hook)(const char *);
33 static void NORETURN default_allocation_failure(const char *s)
35 fprintf(stderr, "ccan/rfc822: Allocation failure: %s", s);
39 static void allocation_failure(const char *s)
41 if (allocation_failure_hook)
42 (*allocation_failure_hook)(s);
44 default_allocation_failure(s);
47 void rfc822_set_allocation_failure_handler(void (*h)(const char *))
49 allocation_failure_hook = h;
52 #define ALLOC_CHECK(p, r) \
55 allocation_failure(__FILE__ ":" stringify(__LINE__)); \
61 const char *data, *end;
62 const char *remainder;
63 struct list_head headers;
67 struct rfc822_header {
68 struct bytestring all, rawname, rawvalue;
69 struct bytestring unfolded;
70 struct list_node list;
73 struct rfc822_msg *rfc822_check(const struct rfc822_msg *msg,
77 if (!list_check(&msg->headers, abortstr))
79 return (struct rfc822_msg *)msg;
82 #ifdef CCAN_RFC822_DEBUG
83 #define CHECK(msg, str) do { rfc822_check((msg), (str)); } while (0)
85 #define CHECK(msg, str) do { } while (0)
88 struct rfc822_msg *rfc822_start(const void *ctx, const char *p, size_t len)
90 struct rfc822_msg *msg;
92 msg = talloc(ctx, struct rfc822_msg);
93 ALLOC_CHECK(msg, NULL);
98 msg->remainder = msg->data;
101 list_head_init(&msg->headers);
103 CHECK(msg, "<rfc22_start");
108 void rfc822_free(struct rfc822_msg *msg)
110 CHECK(msg, ">rfc822_free");
114 static struct rfc822_header *next_header_cached(struct rfc822_msg *msg,
115 struct rfc822_header *hdr)
117 struct list_node *h = &msg->headers.n;
118 const struct list_node *n = h;
120 CHECK(msg, ">next_header_cached");
128 CHECK(msg, "<next_header_cached");
130 return list_entry(n->next, struct rfc822_header, list);
133 static const char *next_line(const char *start, const char *end)
135 const char *p = memchr(start, '\n', end - start);
137 return p ? (p + 1) : end;
140 static struct rfc822_header *next_header_parse(struct rfc822_msg *msg)
142 const char *h, *eh, *ev, *colon;
143 struct rfc822_header *hi;
145 CHECK(msg, ">next_header_parse");
150 if (msg->body && (msg->remainder >= msg->body))
154 eh = next_line(h, msg->end);
157 if ((ev > h) && (ev[-1] == '\n'))
159 if ((ev > h) && (ev[-1] == '\r'))
162 /* Found the end of the headers */
164 assert(!msg->body || (msg->body == eh));
171 while ((eh < msg->end) && rfc822_iswsp(*eh))
172 eh = next_line(eh, msg->end);
175 msg->remainder = NULL;
180 hi = talloc_zero(msg, struct rfc822_header);
181 ALLOC_CHECK(hi, NULL);
183 hi->all = bytestring(h, eh - h);
184 list_add_tail(&msg->headers, &hi->list);
186 colon = memchr(h, ':', hi->all.len);
188 hi->rawname = bytestring(h, colon - h);
189 hi->rawvalue = bytestring(colon + 1, eh - colon - 1);
191 hi->rawname = bytestring_NULL;
192 hi->rawvalue = bytestring_NULL;
195 CHECK(msg, "<next_header_parse");
200 struct rfc822_header *rfc822_next_header(struct rfc822_msg *msg,
201 struct rfc822_header *hdr)
203 struct rfc822_header *h;
205 CHECK(msg, ">rfc822_next_header");
207 h = next_header_cached(msg, hdr);
211 return next_header_parse(msg);
214 struct bytestring rfc822_body(struct rfc822_msg *msg)
216 CHECK(msg, ">rfc822_body");
218 if (!msg->body && msg->remainder) {
221 p = memmem(msg->remainder, msg->end - msg->remainder,
223 q = memmem(msg->remainder, msg->end - msg->remainder,
226 if (p && (!q || (p < q)))
228 else if (q && (!p || (q < p)))
231 if (msg->body >= msg->end) {
232 assert(msg->body == msg->end);
237 CHECK(msg, "<rfc822_body");
240 return bytestring(msg->body, msg->end - msg->body);
242 return bytestring_NULL;
245 enum rfc822_header_errors rfc822_header_errors(struct rfc822_msg *msg,
246 struct rfc822_header *hdr)
248 enum rfc822_header_errors err = 0;
251 if (!hdr->rawname.ptr) {
252 err |= RFC822_HDR_NO_COLON;
254 for (i = 0; i < hdr->rawname.len; i++) {
255 char c = hdr->rawname.ptr[i];
259 if ((c < 33) || (c > 126)) {
260 err |= RFC822_HDR_BAD_NAME;
268 struct bytestring rfc822_header_raw_content(struct rfc822_msg *msg,
269 struct rfc822_header *hdr)
274 struct bytestring rfc822_header_raw_name(struct rfc822_msg *msg,
275 struct rfc822_header *hdr)
280 struct bytestring rfc822_header_raw_value(struct rfc822_msg *msg,
281 struct rfc822_header *hdr)
283 return hdr->rawvalue;
286 static void get_line(struct bytestring in, struct bytestring *first,
287 struct bytestring *rest)
289 size_t rawlen, trimlen;
290 const char *inp = in.ptr;
293 nl = memchr(inp, '\n', in.len);
297 rawlen = nl - inp + 1;
300 if ((trimlen > 0) && (inp[trimlen-1] == '\n')) {
302 if ((trimlen > 0) && (inp[trimlen-1] == '\r'))
306 *first = bytestring(in.ptr, trimlen);
309 *rest = bytestring(in.ptr + rawlen, in.len - rawlen);
311 *rest = bytestring_NULL;
315 struct bytestring rfc822_header_unfolded_value(struct rfc822_msg *msg,
316 struct rfc822_header *hdr)
318 struct bytestring raw = rfc822_header_raw_value(msg, hdr);
319 struct bytestring next, rest;
323 if (!hdr->unfolded.ptr) {
326 get_line(rest, &next, &rest);
332 hdr->unfolded = bytestring(raw.ptr, len);
334 char *unfold = talloc_array(msg, char, len);
337 ALLOC_CHECK(unfold, bytestring_NULL);
341 get_line(rest, &next, &rest);
342 memcpy(p, next.ptr, next.len);
346 assert(p == (unfold + len));
347 hdr->unfolded = bytestring(unfold, len);
351 return hdr->unfolded;