diff --git a/src/http2.cc b/src/http2.cc index 0fe82678..58b49977 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -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", diff --git a/src/http2.h b/src/http2.h index 8713d22d..eea19e1d 100644 --- a/src/http2.h +++ b/src/http2.h @@ -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>& headers); diff --git a/src/shrpx-unittest.cc b/src/shrpx-unittest.cc index 77108dc6..a3469888 100644 --- a/src/shrpx-unittest.cc +++ b/src/shrpx-unittest.cc @@ -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) || diff --git a/src/shrpx_downstream.cc b/src/shrpx_downstream.cc index 414e9caa..d1ffb988 100644 --- a/src/shrpx_downstream.cc +++ b/src/shrpx_downstream.cc @@ -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_); diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index 91290d7b..9b81d1ed 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -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 diff --git a/src/shrpx_downstream_test.cc b/src/shrpx_downstream_test.cc index ce3f2de3..2a0ab18b 100644 --- a/src/shrpx_downstream_test.cc +++ b/src/shrpx_downstream_test.cc @@ -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 diff --git a/src/shrpx_downstream_test.h b/src/shrpx_downstream_test.h index 50e0b9f5..ef645578 100644 --- a/src/shrpx_downstream_test.h +++ b/src/shrpx_downstream_test.h @@ -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 diff --git a/src/shrpx_http2_downstream_connection.cc b/src/shrpx_http2_downstream_connection.cc index 0ab95879..6c7d7cd6 100644 --- a/src/shrpx_http2_downstream_connection.cc +++ b/src/shrpx_http2_downstream_connection.cc @@ -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: diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index e3cc2e08..f2641f52 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -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"; }