diff --git a/src/http2.cc b/src/http2.cc index 0fbe2691..7777e5c3 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -756,6 +756,7 @@ parse_next_link_header_once(const char *first, const char *last) { } auto ok = false; + auto ign = false; for (;;) { first = skip_lws(first, last); if (first == last) { @@ -842,6 +843,23 @@ parse_next_link_header_once(const char *first, const char *last) { continue; } } + // we have to reject URI if we have nonempty anchor parameter. + static const char ANCHOR[] = "anchor="; + static const size_t ANCHORLEN = sizeof(ANCHOR) - 1; + if (!ign && first + ANCHORLEN <= last) { + if (std::equal(ANCHOR, ANCHOR + ANCHORLEN, first)) { + // we only accept URI if anchor="" here. + if (first + ANCHORLEN + 2 <= last) { + if (*(first + ANCHORLEN) != '"' || *(first + ANCHORLEN + 1) != '"') { + ign = true; + } + } else { + // here we got invalid production (anchor=") or anchor=? + ign = true; + } + } + } + auto param_first = first; for (; first != last;) { if (util::in_attr_char(*first)) { @@ -923,7 +941,7 @@ almost_done: if (*first == ',') { ++first; } - if (ok) { + if (ok && !ign) { return {{{url_first, url_last}}, first}; } return {{{0, 0}}, first}; diff --git a/src/http2_test.cc b/src/http2_test.cc index 5ff1b925..c7349c3e 100644 --- a/src/http2_test.cc +++ b/src/http2_test.cc @@ -600,6 +600,33 @@ void test_http2_parse_link_header(void) { CU_ASSERT(1 == res.size()); CU_ASSERT(std::make_pair(&s[1], &s[4]) == res[0].uri); } + { + // anchor="" is acceptable + const char s[] = R"(; rel=preload; anchor="")"; + 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); + } + { + // With anchor="#foo", url should be ignored + const char s[] = R"(; rel=preload; anchor="#foo")"; + auto res = http2::parse_link_header(s, sizeof(s) - 1); + CU_ASSERT(0 == res.size()); + } + { + // With anchor=f, url should be ignored + const char s[] = "; rel=preload; anchor=f"; + auto res = http2::parse_link_header(s, sizeof(s) - 1); + CU_ASSERT(0 == res.size()); + } + { + // First url is ignored With anchor="#foo", but url should be + // accepted. + const char s[] = R"(; rel=preload; anchor="#foo", ; rel=preload)"; + auto res = http2::parse_link_header(s, sizeof(s) - 1); + CU_ASSERT(1 == res.size()); + CU_ASSERT(std::make_pair(&s[36], &s[39]) == res[0].uri); + } } void test_http2_path_join(void) {