return hdr->unfolded;
}
+
+/* Specifically locale *un*aware tolower() - headers should be ascii
+ * only, and if they're not best to leave them as is */
+static char xtolower(char c)
+{
+ if ((c >= 'A') && (c <= 'Z'))
+ return 'a' + (c - 'A');
+ else
+ return c;
+}
+
+static bool hdr_name_eq(struct bytestring a, struct bytestring b)
+{
+ int i;
+
+ if (a.len != b.len)
+ return false;
+
+ for (i = 0; i < a.len; i++)
+ if (xtolower(a.ptr[i]) != xtolower(b.ptr[i]))
+ return false;
+
+ return true;
+}
+
+bool rfc822_header_is(struct rfc822_msg *msg, struct rfc822_header *hdr,
+ const char *name)
+{
+ struct bytestring hname = rfc822_header_raw_name(msg, hdr);
+
+ if (!hname.ptr || !name)
+ return false;
+
+ return hdr_name_eq(hname, bytestring_from_string(name));
+}
+
+struct rfc822_header *rfc822_next_header_of_name(struct rfc822_msg *msg,
+ struct rfc822_header *hdr,
+ const char *name)
+{
+ do {
+ hdr = rfc822_next_header(msg, hdr);
+ } while (hdr && !rfc822_header_is(msg, hdr, name));
+
+ return hdr;
+}
struct bytestring rfc822_header_unfolded_value(struct rfc822_msg *msg,
struct rfc822_header *hdr);
+/**
+ * rfc822_header_is - determine if a header is of a given name
+ * @msg: message
+ * @hdr: a header handle
+ * @name: header name
+ *
+ * This returns true if the header field @hdr has name @name (case
+ * insensitive), otherwise false.
+ */
+bool rfc822_header_is(struct rfc822_msg *msg, struct rfc822_header *hdr,
+ const char *name);
+
+struct rfc822_header *rfc822_next_header_of_name(struct rfc822_msg *msg,
+ struct rfc822_header *hdr,
+ const char *name);
+
+#define rfc822_first_header_of_name(_msg, _name) \
+ (rfc822_next_header_of_name((_msg), NULL, (_name)))
+
#endif /* CCAN_RFC822_H_ */
struct rfc822_header *hdr;
struct bytestring hfull;
- plan_tests(3);
+ plan_tests(6);
msg = rfc822_start(NULL, buf, len);
ok(hdr && (rfc822_header_errors(msg, hdr) == RFC822_HDR_NO_COLON),
"Second header invalid");
+ ok1(hdr && !rfc822_header_is(msg, hdr, NULL));
+ ok1(hdr && !rfc822_header_is(msg, hdr, ""));
+ ok1(hdr && !rfc822_header_is(msg, hdr, NO_COLON_STR));
+
hfull = rfc822_header_raw_content(msg, hdr);
allocation_failure_check();
--- /dev/null
+#include <ccan/foreach/foreach.h>
+#include <ccan/failtest/failtest_override.h>
+#include <ccan/failtest/failtest.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CCAN_RFC822_DEBUG
+
+#include <ccan/rfc822/rfc822.h>
+
+#include <ccan/rfc822/rfc822.c>
+
+#include "testdata.h"
+#include "helper.h"
+
+static void test_hdrbyname(const struct aexample *e, const char *buf, size_t len,
+ const char *exname, int crlf)
+{
+ struct rfc822_msg *msg;
+ struct rfc822_header *h, *hx;
+ int i, j;
+
+ msg = rfc822_start(NULL, buf, len);
+ allocation_failure_check();
+ ok(msg, "opened %s", exname);
+
+ for (i = 0; i < e->nhdrs; i++) {
+ struct testhdr *eh = &e->hdrs[i];
+
+ h = rfc822_first_header_of_name(msg, eh->name);
+ hx = rfc822_next_header_of_name(msg, NULL, eh->name);
+ ok1(h == hx);
+
+ for (j = 0; h && j < eh->index; j++)
+ h = rfc822_next_header_of_name(msg, h, eh->name);
+ ok(h, "header \"%s\" (#%d) exists", eh->name, eh->index);
+ if (!h)
+ break;
+ check_header(msg, h, eh->name, eh->val, eh->errors, crlf);
+
+ h = rfc822_next_header_of_name(msg, h, eh->name);
+ ok1((eh->index != eh->last) ^ !h);
+ }
+
+ h = rfc822_first_header_of_name(msg, NULL);
+ ok(!h, "Never match NULL name");
+
+ rfc822_free(msg);
+ allocation_failure_check();
+}
+
+int main(int argc, char *argv[])
+{
+ struct aexample *e;
+
+ /* This is how many tests you plan to run */
+ plan_tests(6*num_aexamples() + 14*num_aexample_hdrs());
+
+ failtest_setup(argc, argv);
+
+ for_each_aexample(e) {
+ int crlf;
+
+ foreach_int(crlf, 0, 1) {
+ const char *buf;
+ size_t len;
+ char exname[256];
+
+ sprintf(exname, "%s[%s]", e->name, NLT(crlf));
+
+ buf = assemble_msg(e, &len, crlf);
+ ok((buf), "assembled %s", exname);
+ if (!buf)
+ continue;
+
+ test_hdrbyname(e, buf, len, exname, crlf);
+
+ talloc_free(buf);
+ }
+ }
+
+ /* This exits depending on whether all tests passed */
+ failtest_exit(exit_status());
+}
struct testhdr {
const char *name, *val;
+ int index, last;
enum rfc822_header_errors errors;
};
#define bad_hdrs_body test_msg_1_body
AEXAMPLE(bad_hdrs)
+struct testhdr repeated_hdrs_1_hdrs[] = {
+ {"X-Repeated-Header", "#1", 0, 4},
+ {"x-repeated-header", "#2", 1, 4},
+ {"X-REPEATED-HEADER", "#3", 2, 4},
+ {"x-rEpEaTeD-hEaDeR", "#4", 3, 4},
+ {"X-Repeated-Header", "#5", 4, 4},
+};
+#define repeated_hdrs_1_body test_msg_1_body
+AEXAMPLE(repeated_hdrs_1);
+
+struct testhdr prefix_hdr_hdrs[] = {
+ {"X-Prefix", "Prefix", 0},
+ {"X-Prefix-and-Suffix", "Suffix", 0},
+};
+#define prefix_hdr_body test_msg_1_body
+AEXAMPLE(prefix_hdr);
+
#define for_each_aexample(_e) \
foreach_ptr((_e), &test_msg_1, &test_msg_empty_body, \
&test_msg_nlnl_lf, &test_msg_nlnl_crlf, \
&test_msg_nlnl_mixed, \
&test_msg_space_body, \
- &bad_hdrs)
+ &bad_hdrs, \
+ &repeated_hdrs_1, \
+ &prefix_hdr)
#define for_each_aexample_buf(_e, _buf, _len) \
for_each_aexample((_e)) \