diff --git a/src/http2.cc b/src/http2.cc index 7c5d7aff..b96bd339 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -706,6 +706,28 @@ InputIt skip_to_next_field(InputIt first, InputIt last) { } } // namespace +namespace { +// Skip to the right dquote ('"'), handling backslash escapes. +// Returns |last| if input is not terminated with '"'. +template +InputIt skip_to_right_dquote(InputIt first, InputIt last) { + for (; first != last;) { + switch (*first) { + case '"': + return first; + case '\\': + ++first; + if (first == last) { + return first; + } + break; + } + ++first; + } + return first; +} +} // namespace + namespace { std::pair parse_next_link_header_once(const char *first, const char *last) { @@ -862,7 +884,7 @@ parse_next_link_header_once(const char *first, const char *last) { } if (*first == '"') { // quoted-string - first = std::find(first + 1, last, '"'); + first = skip_to_right_dquote(first + 1, last); if (first == last) { return {{{0, 0}}, first}; } diff --git a/src/http2_test.cc b/src/http2_test.cc index 9e77c920..5ff1b925 100644 --- a/src/http2_test.cc +++ b/src/http2_test.cc @@ -593,6 +593,13 @@ void test_http2_parse_link_header(void) { auto res = http2::parse_link_header(s, sizeof(s) - 1); CU_ASSERT(0 == res.size()); } + { + // backslash escaped characters in quoted-string + const char s[] = R"(; rel=preload; title="foo\"baz\"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); + } } void test_http2_path_join(void) {