Commit f71d6c64 authored by David Gibson's avatar David Gibson

rfc822: Retrieve header fields by name

This patch adds functions to the rfc822 module to retrieve header fields
of a given name.
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent 89f4cfdd
......@@ -350,3 +350,49 @@ struct bytestring rfc822_header_unfolded_value(struct rfc822_msg *msg,
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;
}
......@@ -168,4 +168,23 @@ struct bytestring rfc822_header_raw_value(struct rfc822_msg *msg,
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_ */
......@@ -29,7 +29,7 @@ static void test_no_colon(const char *buf, size_t len)
struct rfc822_header *hdr;
struct bytestring hfull;
plan_tests(3);
plan_tests(6);
msg = rfc822_start(NULL, buf, len);
......@@ -47,6 +47,10 @@ static void test_no_colon(const char *buf, size_t 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();
......
#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());
}
......@@ -7,6 +7,7 @@
struct testhdr {
const char *name, *val;
int index, last;
enum rfc822_header_errors errors;
};
......@@ -69,12 +70,31 @@ struct testhdr bad_hdrs_hdrs[] = {
#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)) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment