nghttpx: Implement cookie crumbling

This commit is contained in:
Tatsuhiro Tsujikawa 2013-11-16 21:15:55 +09:00
parent 0c669898a4
commit e14baf134c
9 changed files with 119 additions and 1 deletions

View File

@ -179,6 +179,7 @@ size_t IGN_HDLEN = sizeof(IGN_HD)/sizeof(IGN_HD[0]);
namespace {
const char *HTTP1_IGN_HD[] = {
"connection",
"cookie",
"expect",
"http2-settings",
"keep-alive",

View File

@ -106,7 +106,7 @@ void copy_norm_headers_to_nv
// Appends HTTP/1.1 style header lines to |hdrs| from headers in
// |headers|. Certain headers, which requires special handling
// (i.e. via), are not appended.
// (i.e. via and cookie), are not appended.
void build_http1_headers_from_norm_headers
(std::string& hdrs,
const std::vector<std::pair<std::string, std::string>>& headers);

View File

@ -92,6 +92,10 @@ int main(int argc, char* argv[])
shrpx::test_downstream_get_norm_request_header) ||
!CU_add_test(pSuite, "downstream_get_norm_response_header",
shrpx::test_downstream_get_norm_response_header) ||
!CU_add_test(pSuite, "downstream_crumble_request_cookie",
shrpx::test_downstream_crumble_request_cookie) ||
!CU_add_test(pSuite, "downstream_assemble_request_cookie",
shrpx::test_downstream_assemble_request_cookie) ||
!CU_add_test(pSuite, "util_streq", shrpx::test_util_streq) ||
!CU_add_test(pSuite, "util_inp_strlower",
shrpx::test_util_inp_strlower) ||

View File

@ -178,6 +178,69 @@ const Headers& Downstream::get_request_headers() const
return request_headers_;
}
void Downstream::assemble_request_cookie()
{
std::string& cookie = assembled_request_cookie_;
cookie = "";
for(auto& kv : request_headers_) {
if(util::strieq("cookie", kv.first.c_str())) {
auto end = kv.second.find_last_not_of(" ;");
if(end == std::string::npos) {
cookie += kv.second;
} else {
cookie.append(std::begin(kv.second), std::begin(kv.second) + end + 1);
}
cookie += "; ";
}
}
if(cookie.size() >= 2) {
cookie.erase(cookie.size() - 2);
}
}
void Downstream::crumble_request_cookie()
{
Headers cookie_hdrs;
for(auto& kv : request_headers_) {
if(util::strieq("cookie", kv.first.c_str())) {
size_t last = kv.second.size();
size_t num = 0;
std::string rep_cookie;
for(size_t j = 0; j < last;) {
j = kv.second.find_first_not_of("\t ;", j);
if(j == std::string::npos) {
break;
}
auto first = j;
j = kv.second.find(';', j);
if(j == std::string::npos) {
j = last;
}
if(num == 0) {
rep_cookie = kv.second.substr(first, j - first);
} else {
cookie_hdrs.push_back
(std::make_pair("cookie", kv.second.substr(first, j - first)));
}
++num;
}
if(num > 0) {
kv.second = std::move(rep_cookie);
}
}
}
request_headers_.insert(std::end(request_headers_),
std::begin(cookie_hdrs), std::end(cookie_hdrs));
}
const std::string& Downstream::get_assembled_request_cookie() const
{
return assembled_request_cookie_;
}
void Downstream::normalize_request_headers()
{
normalize_headers(request_headers_);

View File

@ -82,6 +82,9 @@ public:
bool http2_upgrade_request() const;
// downstream request API
const Headers& get_request_headers() const;
void crumble_request_cookie();
void assemble_request_cookie();
const std::string& get_assembled_request_cookie() const;
// Makes key lowercase and sort headers by name using <
void normalize_request_headers();
// Returns iterator pointing to the request header with the name
@ -197,6 +200,7 @@ private:
bool chunked_request_;
bool request_connection_close_;
bool request_expect_100_continue_;
std::string assembled_request_cookie_;
Headers request_headers_;
bool request_header_key_prev_;
// the length of request body

View File

@ -110,4 +110,40 @@ void test_downstream_get_norm_response_header(void)
CU_ASSERT(i == std::end(d.get_response_headers()));
}
void test_downstream_crumble_request_cookie(void)
{
Downstream d(nullptr, 0, 0);
d.add_request_header(":method", "get");
d.add_request_header(":path", "/");
d.add_request_header("cookie", "alpha; bravo; ; ;; charlie;;");
d.add_request_header("cookie", ";delta");
d.add_request_header("cookie", "echo");
d.crumble_request_cookie();
Headers ans = {
std::make_pair(":method", "get"),
std::make_pair(":path", "/"),
std::make_pair("cookie", "alpha"),
std::make_pair("cookie", "delta"),
std::make_pair("cookie", "echo"),
std::make_pair("cookie", "bravo"),
std::make_pair("cookie", "charlie")
};
CU_ASSERT(ans == d.get_request_headers());
}
void test_downstream_assemble_request_cookie(void)
{
Downstream d(nullptr, 0, 0);
d.add_request_header(":method", "get");
d.add_request_header(":path", "/");
d.add_request_header("cookie", "alpha");
d.add_request_header("cookie", "bravo;");
d.add_request_header("cookie", "charlie; ");
d.add_request_header("cookie", "delta;;");
d.assemble_request_cookie();
CU_ASSERT("alpha; bravo; charlie; delta" ==
d.get_assembled_request_cookie());
}
} // namespace shrpx

View File

@ -31,6 +31,8 @@ void test_downstream_normalize_request_headers(void);
void test_downstream_normalize_response_headers(void);
void test_downstream_get_norm_request_header(void);
void test_downstream_get_norm_response_header(void);
void test_downstream_crumble_request_cookie(void);
void test_downstream_assemble_request_cookie(void);
} // namespace shrpx

View File

@ -228,6 +228,7 @@ int Http2DownstreamConnection::push_request_headers()
return 0;
}
size_t nheader = downstream_->get_request_headers().size();
downstream_->crumble_request_cookie();
downstream_->normalize_request_headers();
auto end_headers = std::end(downstream_->get_request_headers());
// 12 means:

View File

@ -116,6 +116,7 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream)
int HttpDownstreamConnection::push_request_headers()
{
downstream_->assemble_request_cookie();
downstream_->normalize_request_headers();
auto end_headers = std::end(downstream_->get_request_headers());
// Assume that method and request path do not contain \r\n.
@ -152,6 +153,12 @@ int HttpDownstreamConnection::push_request_headers()
http2::build_http1_headers_from_norm_headers
(hdrs, downstream_->get_request_headers());
if(!downstream_->get_assembled_request_cookie().empty()) {
hdrs += "Cookie: ";
hdrs += downstream_->get_assembled_request_cookie();
hdrs += "\r\n";
}
if(downstream_->get_request_connection_close()) {
hdrs += "Connection: close\r\n";
}