From ad8be7d4743ee6a95112fb74855bd30c5a5fe952 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 25 Mar 2016 23:51:42 +0900 Subject: [PATCH] src: parse_link_header takes StringRef --- src/http2.cc | 8 +- src/http2.h | 10 +- src/http2_test.cc | 231 ++++++++++++++++++------------------ src/shrpx_http2_upstream.cc | 4 +- 4 files changed, 123 insertions(+), 130 deletions(-) diff --git a/src/http2.cc b/src/http2.cc index f0631e01..458ec8a7 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -1171,12 +1171,10 @@ almost_done: } } // namespace -std::vector parse_link_header(const char *src, size_t len) { - auto first = src; - auto last = src + len; +std::vector parse_link_header(const StringRef &src) { std::vector res; - for (; first != last;) { - auto rv = parse_next_link_header_once(first, last); + for (auto first = std::begin(src); first != std::end(src);) { + auto rv = parse_next_link_header_once(first, std::end(src)); first = rv.second; auto &link = rv.first; if (!link.uri.empty()) { diff --git a/src/http2.h b/src/http2.h index 4412999c..0100551f 100644 --- a/src/http2.h +++ b/src/http2.h @@ -322,11 +322,11 @@ struct LinkHeader { StringRef uri; }; -// Returns next URI-reference in Link header field value |src| of -// length |len|. If no URI-reference found after searching all input, -// returned uri field is empty. This imply that empty URI-reference -// is ignored during parsing. -std::vector parse_link_header(const char *src, size_t len); +// Returns next URI-reference in Link header field value |src|. If no +// URI-reference found after searching all input, returned uri field +// is empty. This imply that empty URI-reference is ignored during +// parsing. +std::vector parse_link_header(const StringRef &src); // Constructs path by combining base path |base_path| with another // path |rel_path|. The base path and another path can have optional diff --git a/src/http2_test.cc b/src/http2_test.cc index 39832714..87d1a1e2 100644 --- a/src/http2_test.cc +++ b/src/http2_test.cc @@ -282,388 +282,385 @@ void test_http2_lookup_token(void) { void test_http2_parse_link_header(void) { { // only URI appears; we don't extract URI unless it bears rel=preload - constexpr char s[] = ""; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header(StringRef::from_lit("")); CU_ASSERT(0 == res.size()); } { // URI url should be extracted - constexpr char s[] = "; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit("; rel=preload")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // With extra link-param. URI url should be extracted - constexpr char s[] = "; rel=preload; as=file"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; rel=preload; as=file")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // With extra link-param. URI url should be extracted - constexpr char s[] = "; as=file; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; as=file; rel=preload")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // With extra link-param and quote-string. URI url should be // extracted - constexpr char s[] = R"(; rel=preload; title="foo,bar")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel=preload; title="foo,bar")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // With extra link-param and quote-string. URI url should be // extracted - constexpr char s[] = R"(; title="foo,bar"; rel=preload)"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; title="foo,bar"; rel=preload)")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // ',' after quote-string - constexpr char s[] = R"(; title="foo,bar", ; rel=preload)"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; title="foo,bar", ; rel=preload)")); CU_ASSERT(1 == res.size()); CU_ASSERT("url2" == res[0].uri); - CU_ASSERT(&s[25] == &res[0].uri[0]); } { // Only first URI should be extracted. - constexpr char s[] = "; rel=preload, "; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; rel=preload, ")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // Both have rel=preload, so both urls should be extracted - constexpr char s[] = "; rel=preload, ; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; rel=preload, ; rel=preload")); CU_ASSERT(2 == res.size()); CU_ASSERT("url" == res[0].uri); CU_ASSERT("url2" == res[1].uri); } { // Second URI uri should be extracted. - constexpr char s[] = ", ;rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(", ;rel=preload")); CU_ASSERT(1 == res.size()); CU_ASSERT("url2" == res[0].uri); } { // Error if input ends with ';' - constexpr char s[] = ";rel=preload;"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit(";rel=preload;")); CU_ASSERT(0 == res.size()); } { // Error if link header ends with ';' - constexpr char s[] = ";rel=preload;, "; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(";rel=preload;, ")); CU_ASSERT(0 == res.size()); } { // OK if input ends with ',' - constexpr char s[] = ";rel=preload,"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit(";rel=preload,")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // Multiple repeated ','s between fields is OK - constexpr char s[] = ",,,;rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(",,,;rel=preload")); CU_ASSERT(1 == res.size()); CU_ASSERT("url2" == res[0].uri); } { // Error if url is not enclosed by <> - constexpr char s[] = "url>;rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit("url>;rel=preload")); CU_ASSERT(0 == res.size()); } { // Error if url is not enclosed by <> - constexpr char s[] = ";rel=preload; as=")); CU_ASSERT(0 == res.size()); } { // Empty parameter value is not allowed - constexpr char s[] = ";as=;rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit(";as=;rel=preload")); CU_ASSERT(0 == res.size()); } { // Empty parameter value is not allowed - constexpr char s[] = ";as=, ;rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(";as=, ;rel=preload")); CU_ASSERT(0 == res.size()); } { // Empty parameter name is not allowed - constexpr char s[] = "; =file; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; =file; rel=preload")); CU_ASSERT(0 == res.size()); } { // Without whitespaces - constexpr char s[] = ";as=file;rel=preload,;rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(";as=file;rel=preload,;rel=preload")); CU_ASSERT(2 == res.size()); CU_ASSERT("url" == res[0].uri); CU_ASSERT("url2" == res[1].uri); } { // link-extension may have no value - constexpr char s[] = "; as; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit("; as; rel=preload")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // ext-name-star - constexpr char s[] = "; foo*=bar; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; foo*=bar; rel=preload")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // '*' is not allowed expect for trailing one - constexpr char s[] = "; *=bar; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; *=bar; rel=preload")); CU_ASSERT(0 == res.size()); } { // '*' is not allowed expect for trailing one - constexpr char s[] = "; foo*bar=buzz; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; foo*bar=buzz; rel=preload")); CU_ASSERT(0 == res.size()); } { // ext-name-star must be followed by '=' - constexpr char s[] = "; foo*; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; foo*; rel=preload")); CU_ASSERT(0 == res.size()); } { // '>' is not followed by ';' - constexpr char s[] = " rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit(" rel=preload")); CU_ASSERT(0 == res.size()); } { // Starting with whitespace is no problem. - constexpr char s[] = " ; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit(" ; rel=preload")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // preload is a prefix of bogus rel parameter value - constexpr char s[] = "; rel=preloadx"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit("; rel=preloadx")); CU_ASSERT(0 == res.size()); } { // preload in relation-types list - constexpr char s[] = R"(; rel="preload")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="preload")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // preload in relation-types list followed by another parameter - constexpr char s[] = R"(; rel="preload foo")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="preload foo")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // preload in relation-types list following another parameter - constexpr char s[] = R"(; rel="foo preload")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="foo preload")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // preload in relation-types list between other parameters - constexpr char s[] = R"(; rel="foo preload bar")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="foo preload bar")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // preload in relation-types list between other parameters - constexpr char s[] = R"(; rel="foo preload bar")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="foo preload bar")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // no preload in relation-types list - constexpr char s[] = R"(; rel="foo")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = + http2::parse_link_header(StringRef::from_lit(R"(; rel="foo")")); CU_ASSERT(0 == res.size()); } { // no preload in relation-types list, multiple unrelated elements. - constexpr char s[] = R"(; rel="foo bar")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="foo bar")")); CU_ASSERT(0 == res.size()); } { // preload in relation-types list, followed by another link-value. - constexpr char s[] = R"(; rel="preload", )"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="preload", )")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // preload in relation-types list, following another link-value. - constexpr char s[] = R"(, ; rel="preload")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(, ; rel="preload")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url2" == res[0].uri); } { // preload in relation-types list, followed by another link-param. - constexpr char s[] = R"(; rel="preload"; as="font")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="preload"; as="font")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // preload in relation-types list, followed by character other // than ';' or ',' - constexpr char s[] = R"(; rel="preload".)"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="preload".)")); CU_ASSERT(0 == res.size()); } { // preload in relation-types list, followed by ';' but it // terminates input - constexpr char s[] = R"(; rel="preload";)"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="preload";)")); CU_ASSERT(0 == res.size()); } { // preload in relation-types list, followed by ',' but it // terminates input - constexpr char s[] = R"(; rel="preload",)"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="preload",)")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // preload in relation-types list but there is preceding white // space. - constexpr char s[] = R"(; rel=" preload")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel=" preload")")); CU_ASSERT(0 == res.size()); } { // preload in relation-types list but there is trailing white // space. - constexpr char s[] = R"(; rel="preload ")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel="preload ")")); CU_ASSERT(0 == res.size()); } { // backslash escaped characters in quoted-string - constexpr char s[] = R"(; rel=preload; title="foo\"baz\"bar")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel=preload; title="foo\"baz\"bar")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // anchor="" is acceptable - constexpr char s[] = R"(; rel=preload; anchor="")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel=preload; anchor="")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // With anchor="#foo", url should be ignored - constexpr char s[] = R"(; rel=preload; anchor="#foo")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel=preload; anchor="#foo")")); CU_ASSERT(0 == res.size()); } { // With anchor=f, url should be ignored - constexpr char s[] = "; rel=preload; anchor=f"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; rel=preload; anchor=f")); CU_ASSERT(0 == res.size()); } { // First url is ignored With anchor="#foo", but url should be // accepted. - constexpr char s[] = - R"(; rel=preload; anchor="#foo", ; rel=preload)"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header(StringRef::from_lit( + R"(; rel=preload; anchor="#foo", ; rel=preload)")); CU_ASSERT(1 == res.size()); CU_ASSERT("url2" == res[0].uri); } { // With loadpolicy="next", url should be ignored - constexpr char s[] = R"(; rel=preload; loadpolicy="next")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel=preload; loadpolicy="next")")); CU_ASSERT(0 == res.size()); } { // url should be picked up if empty loadpolicy is specified - constexpr char s[] = R"(; rel=preload; loadpolicy="")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel=preload; loadpolicy="")")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // case-insensitive match - constexpr char s[] = R"(; rel=preload; ANCHOR="#foo", ; )" - R"(REL=PRELOAD, ; REL="foo PRELOAD bar")"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit(R"(; rel=preload; ANCHOR="#foo", ; )" + R"(REL=PRELOAD, ; REL="foo PRELOAD bar")")); CU_ASSERT(2 == res.size()); CU_ASSERT("url2" == res[0].uri); CU_ASSERT("url3" == res[1].uri); } { // nopush at the end of input - constexpr char s[] = "; rel=preload; nopush"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; rel=preload; nopush")); CU_ASSERT(0 == res.size()); } { // nopush followed by ';' - constexpr char s[] = "; rel=preload; nopush; foo"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; rel=preload; nopush; foo")); CU_ASSERT(0 == res.size()); } { // nopush followed by ',' - constexpr char s[] = "; nopush; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; nopush; rel=preload")); CU_ASSERT(0 == res.size()); } { // string whose prefix is nopush - constexpr char s[] = "; nopushyes; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; nopushyes; rel=preload")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } { // rel=preload twice - constexpr char s[] = "; rel=preload; rel=preload"; - auto res = http2::parse_link_header(s, str_size(s)); + auto res = http2::parse_link_header( + StringRef::from_lit("; rel=preload; rel=preload")); CU_ASSERT(1 == res.size()); CU_ASSERT("url" == res[0].uri); } diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index dc258b94..dbec6c16 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -1782,9 +1782,7 @@ int Http2Upstream::prepare_push_promise(Downstream *downstream) { if (kv.token != http2::HD_LINK) { continue; } - for (auto &link : - http2::parse_link_header(kv.value.c_str(), kv.value.size())) { - + for (auto &link : http2::parse_link_header(kv.value)) { StringRef scheme, authority, path; rv = http2::construct_push_component(balloc, scheme, authority, path,