src: Support rel with quoted value in Link header parser
This commit is contained in:
parent
6b28e033de
commit
1b00bc1929
48
src/http2.cc
48
src/http2.cc
|
@ -741,6 +741,54 @@ parse_next_link_header_once(const char *first, const char *last) {
|
||||||
}
|
}
|
||||||
// we expect link-param
|
// 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
|
// we are only interested in rel=preload parameter. Others are
|
||||||
// simply skipped.
|
// simply skipped.
|
||||||
static const char PL[] = "rel=preload";
|
static const char PL[] = "rel=preload";
|
||||||
|
|
|
@ -489,6 +489,110 @@ void test_http2_parse_link_header(void) {
|
||||||
auto res = http2::parse_link_header(s, sizeof(s) - 1);
|
auto res = http2::parse_link_header(s, sizeof(s) - 1);
|
||||||
CU_ASSERT(0 == res.size());
|
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) {
|
void test_http2_path_join(void) {
|
||||||
|
|
Loading…
Reference in New Issue