src: Support rel with quoted value in Link header parser

This commit is contained in:
Tatsuhiro Tsujikawa 2015-02-09 00:37:01 +09:00
parent 6b28e033de
commit 1b00bc1929
2 changed files with 152 additions and 0 deletions

View File

@ -741,6 +741,54 @@ parse_next_link_header_once(const char *first, const char *last) {
}
// we expect link-param
// rel can take several relations using quoted form.
static const char PLP[] = "rel=\"";
static const size_t PLPLEN = sizeof(PLP) - 1;
static const char PLT[] = "preload";
static const size_t PLTLEN = sizeof(PLT) - 1;
if (first + PLPLEN < last && *(first + PLPLEN - 1) == '"' &&
std::equal(PLP, PLP + PLPLEN, first)) {
// we have to search preload in whitespace separated list:
// rel="preload something http://example.org/foo"
first += PLPLEN;
auto start = first;
for (; first != last;) {
if (*first != ' ' && *first != '"') {
++first;
continue;
}
if (start == first) {
return {{{0, 0}}, last};
}
if (!ok && start + PLTLEN == first && *(start + PLTLEN - 1) == 'd' &&
std::equal(PLT, PLT + PLTLEN, start)) {
ok = true;
}
if (*first == '"') {
break;
}
first = skip_lws(first, last);
start = first;
}
if (first == last) {
return {{{0, 0}}, first};
}
assert(*first == '"');
++first;
if (first == last || *first == ',') {
goto almost_done;
}
if (*first == ';') {
++first;
// parse next link-param
continue;
}
return {{{0, 0}}, last};
}
// we are only interested in rel=preload parameter. Others are
// simply skipped.
static const char PL[] = "rel=preload";

View File

@ -489,6 +489,110 @@ void test_http2_parse_link_header(void) {
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
{
// preload in relation-types list
const char s[] = R"(<url>; rel="preload")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(1 == res.size());
CU_ASSERT(std::make_pair(&s[1], &s[4]) == res[0].uri);
}
{
// preload in relation-types list followed by another parameter
const char s[] = R"(<url>; rel="preload foo")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(1 == res.size());
CU_ASSERT(std::make_pair(&s[1], &s[4]) == res[0].uri);
}
{
// preload in relation-types list following another parameter
const char s[] = R"(<url>; rel="foo preload")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(1 == res.size());
CU_ASSERT(std::make_pair(&s[1], &s[4]) == res[0].uri);
}
{
// preload in relation-types list between other parameters
const char s[] = R"(<url>; rel="foo preload bar")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(1 == res.size());
CU_ASSERT(std::make_pair(&s[1], &s[4]) == res[0].uri);
}
{
// preload in relation-types list between other parameters
const char s[] = R"(<url>; rel="foo preload bar")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(1 == res.size());
CU_ASSERT(std::make_pair(&s[1], &s[4]) == res[0].uri);
}
{
// no preload in relation-types list
const char s[] = R"(<url>; rel="foo")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
{
// no preload in relation-types list, multiple unrelated elements.
const char s[] = R"(<url>; rel="foo bar")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
{
// preload in relation-types list, followed by another link-value.
const char s[] = R"(<url>; rel="preload", <url>)";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(1 == res.size());
CU_ASSERT(std::make_pair(&s[1], &s[4]) == res[0].uri);
}
{
// preload in relation-types list, following another link-value.
const char s[] = R"(<url>, <url>; rel="preload")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(1 == res.size());
CU_ASSERT(std::make_pair(&s[8], &s[11]) == res[0].uri);
}
{
// preload in relation-types list, followed by another link-param.
const char s[] = R"(<url>; rel="preload"; as="font")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(1 == res.size());
CU_ASSERT(std::make_pair(&s[1], &s[4]) == res[0].uri);
}
{
// preload in relation-types list, followed by character other
// than ';' or ','
const char s[] = R"(<url>; rel="preload".)";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
{
// preload in relation-types list, followed by ';' but it
// terminates input
const char s[] = R"(<url>; rel="preload";)";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
{
// preload in relation-types list, followed by ',' but it
// terminates input
const char s[] = R"(<url>; rel="preload",)";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(1 == res.size());
CU_ASSERT(std::make_pair(&s[1], &s[4]) == res[0].uri);
}
{
// preload in relation-types list but there is preceding white
// space.
const char s[] = R"(<url>; rel=" preload")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
{
// preload in relation-types list but there is trailing white
// space.
const char s[] = R"(<url>; rel="preload ")";
auto res = http2::parse_link_header(s, sizeof(s) - 1);
CU_ASSERT(0 == res.size());
}
}
void test_http2_path_join(void) {