nghttpx: Parse te header field a bit more properly

This commit is contained in:
Tatsuhiro Tsujikawa 2016-11-07 22:47:48 +09:00
parent f5a4c9d971
commit 8471c9e92e
6 changed files with 48 additions and 1 deletions

View File

@ -1665,6 +1665,31 @@ StringRef copy_lower(BlockAllocator &balloc, const StringRef &src) {
return StringRef{iov.base, p}; return StringRef{iov.base, p};
} }
bool contains_trailers(const StringRef &s) {
constexpr auto trailers = StringRef::from_lit("trailers");
for (auto p = std::begin(s), end = std::end(s);; ++p) {
p = std::find_if(p, end, [](char c) { return c != ' ' && c != '\t'; });
if (p == end || end - p < trailers.size()) {
return false;
}
if (util::strieq(trailers, StringRef{p, p + trailers.size()})) {
// Make sure that there is no character other than white spaces
// before next "," or end of string.
p = std::find_if(p + trailers.size(), end,
[](char c) { return c != ' ' && c != '\t'; });
if (p == end || *p == ',') {
return true;
}
}
// Skip to next ",".
p = std::find_if(p, end, [](char c) { return c == ','; });
if (p == end) {
return false;
}
}
}
} // namespace http2 } // namespace http2
} // namespace nghttp2 } // namespace nghttp2

View File

@ -384,6 +384,9 @@ int construct_push_component(BlockAllocator &balloc, StringRef &scheme,
// Copies |src| and return its lower-cased version. // Copies |src| and return its lower-cased version.
StringRef copy_lower(BlockAllocator &balloc, const StringRef &src); StringRef copy_lower(BlockAllocator &balloc, const StringRef &src);
// Returns true if te header field value |s| contains "trailers".
bool contains_trailers(const StringRef &s);
} // namespace http2 } // namespace http2
} // namespace nghttp2 } // namespace nghttp2

View File

@ -962,4 +962,20 @@ void test_http2_construct_push_component(void) {
CU_ASSERT("/b/?q=a" == path); CU_ASSERT("/b/?q=a" == path);
} }
void test_http2_contains_trailers(void) {
CU_ASSERT(!http2::contains_trailers(StringRef::from_lit("")));
CU_ASSERT(http2::contains_trailers(StringRef::from_lit("trailers")));
// Match must be case-insensitive.
CU_ASSERT(http2::contains_trailers(StringRef::from_lit("TRAILERS")));
CU_ASSERT(!http2::contains_trailers(StringRef::from_lit("trailer")));
CU_ASSERT(!http2::contains_trailers(StringRef::from_lit("trailers 3")));
CU_ASSERT(http2::contains_trailers(StringRef::from_lit("trailers,")));
CU_ASSERT(http2::contains_trailers(StringRef::from_lit("trailers,foo")));
CU_ASSERT(http2::contains_trailers(StringRef::from_lit("foo,trailers")));
CU_ASSERT(http2::contains_trailers(StringRef::from_lit("foo,trailers,bar")));
CU_ASSERT(
http2::contains_trailers(StringRef::from_lit("foo, trailers ,bar")));
CU_ASSERT(http2::contains_trailers(StringRef::from_lit(",trailers")));
}
} // namespace shrpx } // namespace shrpx

View File

@ -46,6 +46,7 @@ void test_http2_normalize_path(void);
void test_http2_rewrite_clean_path(void); void test_http2_rewrite_clean_path(void);
void test_http2_get_pure_path_component(void); void test_http2_get_pure_path_component(void);
void test_http2_construct_push_component(void); void test_http2_construct_push_component(void);
void test_http2_contains_trailers(void);
} // namespace shrpx } // namespace shrpx

View File

@ -102,6 +102,8 @@ int main(int argc, char *argv[]) {
shrpx::test_http2_get_pure_path_component) || shrpx::test_http2_get_pure_path_component) ||
!CU_add_test(pSuite, "http2_construct_push_component", !CU_add_test(pSuite, "http2_construct_push_component",
shrpx::test_http2_construct_push_component) || shrpx::test_http2_construct_push_component) ||
!CU_add_test(pSuite, "http2_contains_trailers",
shrpx::test_http2_contains_trailers) ||
!CU_add_test(pSuite, "downstream_field_store_append_last_header", !CU_add_test(pSuite, "downstream_field_store_append_last_header",
shrpx::test_downstream_field_store_append_last_header) || shrpx::test_downstream_field_store_append_last_header) ||
!CU_add_test(pSuite, "downstream_field_store_header", !CU_add_test(pSuite, "downstream_field_store_header",

View File

@ -402,7 +402,7 @@ int Http2DownstreamConnection::push_request_headers() {
// HTTP/1 upstream request can contain keyword other than // HTTP/1 upstream request can contain keyword other than
// "trailers". We just forward "trailers". // "trailers". We just forward "trailers".
// TODO more strict handling required here. // TODO more strict handling required here.
if (te && util::strifind(te->value, StringRef::from_lit("trailers"))) { if (te && http2::contains_trailers(te->value)) {
nva.push_back(http2::make_nv_ll("te", "trailers")); nva.push_back(http2::make_nv_ll("te", "trailers"));
} }