Commit b1edb1f3 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

Don't index name/value pair bearing NO_INDEX flag when forwarding it

parent c53c1dc6
...@@ -1342,6 +1342,10 @@ typedef int (*nghttp2_on_begin_headers_callback) ...@@ -1342,6 +1342,10 @@ typedef int (*nghttp2_on_begin_headers_callback)
* The |value| of length |valuelen| is header value. The |flags| is * The |value| of length |valuelen| is header value. The |flags| is
* bitwise OR of one or more of :type:`nghttp2_nv_flag`. * bitwise OR of one or more of :type:`nghttp2_nv_flag`.
* *
* If :enum:`NGHTTP2_NV_FLAG_NO_INDEX` is set in |flags|, the receiver
* must not index this name/value pair when forwarding it to the next
* hop.
*
* When this callback is invoked, ``frame->hd.type`` is either * When this callback is invoked, ``frame->hd.type`` is either
* :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`. After all * :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`. After all
* header name/value pairs are processed with this callback, and no * header name/value pairs are processed with this callback, and no
......
...@@ -805,7 +805,7 @@ int Http2Handler::submit_response ...@@ -805,7 +805,7 @@ int Http2Handler::submit_response
http2::make_nv_ls("date", date_str) http2::make_nv_ls("date", date_str)
}; };
for(size_t i = 0; i < headers.size(); ++i) { for(size_t i = 0; i < headers.size(); ++i) {
nva.push_back(http2::make_nv(headers[i].first, headers[i].second)); nva.push_back(http2::make_nv(headers[i].first, headers[i].second, false));
} }
int r = nghttp2_submit_response(session_, stream_id, nva.data(), nva.size(), int r = nghttp2_submit_response(session_, stream_id, nva.data(), nva.size(),
data_prd); data_prd);
...@@ -830,21 +830,21 @@ int Http2Handler::submit_push_promise(Stream *stream, ...@@ -830,21 +830,21 @@ int Http2Handler::submit_push_promise(Stream *stream,
std::string authority; std::string authority;
auto itr = std::lower_bound(std::begin(stream->headers), auto itr = std::lower_bound(std::begin(stream->headers),
std::end(stream->headers), std::end(stream->headers),
std::make_pair(std::string(":authority"), Header(":authority", ""));
std::string("")));
if(itr == std::end(stream->headers) || (*itr).first != ":authority") { if(itr == std::end(stream->headers) || (*itr).name != ":authority") {
itr = std::lower_bound(std::begin(stream->headers), itr = std::lower_bound(std::begin(stream->headers),
std::end(stream->headers), std::end(stream->headers),
std::make_pair(std::string("host"), Header("host", ""));
std::string("")));
} }
auto nva = std::vector<nghttp2_nv>{ auto nva = std::vector<nghttp2_nv>{
http2::make_nv_ll(":method", "GET"), http2::make_nv_ll(":method", "GET"),
http2::make_nv_ls(":path", push_path), http2::make_nv_ls(":path", push_path),
get_config()->no_tls ? get_config()->no_tls ?
http2::make_nv_ll(":scheme", "http") : http2::make_nv_ll(":scheme", "http") :
http2::make_nv_ll(":scheme", "https"), http2::make_nv_ll(":scheme", "https"),
http2::make_nv_ls(":authority", (*itr).second) http2::make_nv_ls(":authority", (*itr).value)
}; };
return nghttp2_submit_push_promise(session_, NGHTTP2_FLAG_END_HEADERS, return nghttp2_submit_push_promise(session_, NGHTTP2_FLAG_END_HEADERS,
stream->stream_id, nva.data(), nva.size(), stream->stream_id, nva.data(), nva.size(),
...@@ -1008,18 +1008,17 @@ void prepare_response(Stream *stream, Http2Handler *hd, bool allow_push = true) ...@@ -1008,18 +1008,17 @@ void prepare_response(Stream *stream, Http2Handler *hd, bool allow_push = true)
int rv; int rv;
auto url = (*std::lower_bound(std::begin(stream->headers), auto url = (*std::lower_bound(std::begin(stream->headers),
std::end(stream->headers), std::end(stream->headers),
std::make_pair(std::string(":path"), Header(":path", ""))).value;
std::string()))).second;
auto ims = std::lower_bound(std::begin(stream->headers), auto ims = std::lower_bound(std::begin(stream->headers),
std::end(stream->headers), std::end(stream->headers),
std::make_pair(std::string("if-modified-since"), Header("if-modified-since", ""));
std::string()));
time_t last_mod = 0; time_t last_mod = 0;
bool last_mod_found = false; bool last_mod_found = false;
if(ims != std::end(stream->headers) && if(ims != std::end(stream->headers) &&
(*ims).first == "if-modified-since") { (*ims).name == "if-modified-since") {
last_mod_found = true; last_mod_found = true;
last_mod = util::parse_http_date((*ims).second); last_mod = util::parse_http_date((*ims).value);
} }
auto query_pos = url.find("?"); auto query_pos = url.find("?");
if(query_pos != std::string::npos) { if(query_pos != std::string::npos) {
...@@ -1078,7 +1077,8 @@ void append_nv(Stream *stream, const std::vector<nghttp2_nv>& nva) ...@@ -1078,7 +1077,8 @@ void append_nv(Stream *stream, const std::vector<nghttp2_nv>& nva)
{ {
for(auto& nv : nva) { for(auto& nv : nva) {
http2::split_add_header(stream->headers, http2::split_add_header(stream->headers,
nv.name, nv.namelen, nv.value, nv.valuelen); nv.name, nv.namelen, nv.value, nv.valuelen,
nv.flags & NGHTTP2_NV_FLAG_NO_INDEX);
} }
} }
} // namespace } // namespace
...@@ -1114,7 +1114,8 @@ int on_header_callback(nghttp2_session *session, ...@@ -1114,7 +1114,8 @@ int on_header_callback(nghttp2_session *session,
if(!http2::check_nv(name, namelen, value, valuelen)) { if(!http2::check_nv(name, namelen, value, valuelen)) {
return 0; return 0;
} }
http2::split_add_header(stream->headers, name, namelen, value, valuelen); http2::split_add_header(stream->headers, name, namelen, value, valuelen,
flags & NGHTTP2_NV_FLAG_NO_INDEX);
return 0; return 0;
} }
} // namespace } // namespace
......
...@@ -792,7 +792,7 @@ int main(int argc, char **argv) ...@@ -792,7 +792,7 @@ int main(int argc, char **argv)
nva.push_back(http2::make_nv_ls(":path", req)); nva.push_back(http2::make_nv_ls(":path", req));
for(auto& nv : shared_nva) { for(auto& nv : shared_nva) {
nva.push_back(http2::make_nv(nv.first, nv.second)); nva.push_back(http2::make_nv(nv.name, nv.value, false));
} }
config.nva.push_back(std::move(nva)); config.nva.push_back(std::move(nva));
...@@ -804,12 +804,12 @@ int main(int argc, char **argv) ...@@ -804,12 +804,12 @@ int main(int argc, char **argv)
cva.push_back(req.c_str()); cva.push_back(req.c_str());
for(auto& nv : shared_nva) { for(auto& nv : shared_nva) {
if(nv.first == ":authority") { if(nv.name == ":authority") {
cva.push_back(":host"); cva.push_back(":host");
} else { } else {
cva.push_back(nv.first.c_str()); cva.push_back(nv.name.c_str());
} }
cva.push_back(nv.second.c_str()); cva.push_back(nv.value.c_str());
} }
cva.push_back(":version"); cva.push_back(":version");
cva.push_back("HTTP/1.1"); cva.push_back("HTTP/1.1");
......
...@@ -206,14 +206,14 @@ auto nv_name_less = [](const nghttp2_nv& lhs, const nghttp2_nv& rhs) ...@@ -206,14 +206,14 @@ auto nv_name_less = [](const nghttp2_nv& lhs, const nghttp2_nv& rhs)
bool name_less(const Headers::value_type& lhs, bool name_less(const Headers::value_type& lhs,
const Headers::value_type& rhs) const Headers::value_type& rhs)
{ {
return lhs.first < rhs.first; return lhs.name < rhs.name;
} }
bool check_http2_headers(const Headers& nva) bool check_http2_headers(const Headers& nva)
{ {
for(size_t i = 0; i < DISALLOWED_HDLEN; ++i) { for(size_t i = 0; i < DISALLOWED_HDLEN; ++i) {
if(std::binary_search(std::begin(nva), std::end(nva), if(std::binary_search(std::begin(nva), std::end(nva),
std::make_pair(DISALLOWED_HD[i], ""), name_less)) { Header(DISALLOWED_HD[i], ""), name_less)) {
return false; return false;
} }
} }
...@@ -223,7 +223,7 @@ bool check_http2_headers(const Headers& nva) ...@@ -223,7 +223,7 @@ bool check_http2_headers(const Headers& nva)
void normalize_headers(Headers& nva) void normalize_headers(Headers& nva)
{ {
for(auto& kv : nva) { for(auto& kv : nva) {
util::inp_strlower(kv.first); util::inp_strlower(kv.name);
} }
std::stable_sort(std::begin(nva), std::end(nva), name_less); std::stable_sort(std::begin(nva), std::end(nva), name_less);
} }
...@@ -260,20 +260,23 @@ std::vector<nghttp2_nv> sort_nva(const nghttp2_nv *nva, size_t nvlen) ...@@ -260,20 +260,23 @@ std::vector<nghttp2_nv> sort_nva(const nghttp2_nv *nva, size_t nvlen)
} }
Headers::value_type to_header(const uint8_t *name, size_t namelen, Headers::value_type to_header(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen) const uint8_t *value, size_t valuelen,
bool no_index)
{ {
return std::make_pair(std::string(reinterpret_cast<const char*>(name), return Header(std::string(reinterpret_cast<const char*>(name),
namelen), namelen),
std::string(reinterpret_cast<const char*>(value), std::string(reinterpret_cast<const char*>(value),
valuelen)); valuelen),
no_index);
} }
void split_add_header(Headers& nva, void split_add_header(Headers& nva,
const uint8_t *name, size_t namelen, const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen) const uint8_t *value, size_t valuelen,
bool no_index)
{ {
if(valuelen == 0) { if(valuelen == 0) {
nva.push_back(to_header(name, namelen, value, valuelen)); nva.push_back(to_header(name, namelen, value, valuelen, no_index));
return; return;
} }
auto j = value; auto j = value;
...@@ -289,7 +292,7 @@ void split_add_header(Headers& nva, ...@@ -289,7 +292,7 @@ void split_add_header(Headers& nva,
break; break;
} }
auto l = std::find(j, end, '\0'); auto l = std::find(j, end, '\0');
nva.push_back(to_header(name, namelen, j, l-j)); nva.push_back(to_header(name, namelen, j, l-j, no_index));
j = l; j = l;
} }
} }
...@@ -299,9 +302,9 @@ const Headers::value_type* get_unique_header(const Headers& nva, ...@@ -299,9 +302,9 @@ const Headers::value_type* get_unique_header(const Headers& nva,
{ {
auto nv = Headers::value_type(name, ""); auto nv = Headers::value_type(name, "");
auto i = std::lower_bound(std::begin(nva), std::end(nva), nv, name_less); auto i = std::lower_bound(std::begin(nva), std::end(nva), nv, name_less);
if(i != std::end(nva) && (*i).first == nv.first) { if(i != std::end(nva) && (*i).name == nv.name) {
auto j = i + 1; auto j = i + 1;
if(j == std::end(nva) || (*j).first != nv.first) { if(j == std::end(nva) || (*j).name != nv.name) {
return &(*i); return &(*i);
} }
} }
...@@ -312,7 +315,7 @@ const Headers::value_type* get_header(const Headers& nva, const char *name) ...@@ -312,7 +315,7 @@ const Headers::value_type* get_header(const Headers& nva, const char *name)
{ {
auto nv = Headers::value_type(name, ""); auto nv = Headers::value_type(name, "");
auto i = std::lower_bound(std::begin(nva), std::end(nva), nv, name_less); auto i = std::lower_bound(std::begin(nva), std::end(nva), nv, name_less);
if(i != std::end(nva) && (*i).first == nv.first) { if(i != std::end(nva) && (*i).name == nv.name) {
return &(*i); return &(*i);
} }
return nullptr; return nullptr;
...@@ -321,14 +324,14 @@ const Headers::value_type* get_header(const Headers& nva, const char *name) ...@@ -321,14 +324,14 @@ const Headers::value_type* get_header(const Headers& nva, const char *name)
std::string value_to_str(const Headers::value_type *nv) std::string value_to_str(const Headers::value_type *nv)
{ {
if(nv) { if(nv) {
return nv->second; return nv->value;
} }
return ""; return "";
} }
bool value_lws(const Headers::value_type *nv) bool value_lws(const Headers::value_type *nv)
{ {
return (*nv).second.find_first_not_of("\t ") == std::string::npos; return (*nv).value.find_first_not_of("\t ") == std::string::npos;
} }
bool non_empty_value(const Headers::value_type *nv) bool non_empty_value(const Headers::value_type *nv)
...@@ -336,13 +339,18 @@ bool non_empty_value(const Headers::value_type *nv) ...@@ -336,13 +339,18 @@ bool non_empty_value(const Headers::value_type *nv)
return nv && !value_lws(nv); return nv && !value_lws(nv);
} }
nghttp2_nv make_nv(const std::string& name, const std::string& value) nghttp2_nv make_nv(const std::string& name, const std::string& value,
bool no_index)
{ {
uint8_t flags;
flags = no_index ? NGHTTP2_NV_FLAG_NO_INDEX : NGHTTP2_NV_FLAG_NONE;
return { return {
(uint8_t*)name.c_str(), (uint8_t*)name.c_str(),
(uint8_t*)value.c_str(), (uint8_t*)value.c_str(),
(uint16_t)name.size(), (uint16_t)value.size(), (uint16_t)name.size(), (uint16_t)value.size(),
NGHTTP2_NV_FLAG_NONE flags
}; };
} }
...@@ -351,12 +359,17 @@ Headers concat_norm_headers(Headers headers) ...@@ -351,12 +359,17 @@ Headers concat_norm_headers(Headers headers)
auto res = Headers(); auto res = Headers();
res.reserve(headers.size()); res.reserve(headers.size());
for(auto& kv : headers) { for(auto& kv : headers) {
if(!res.empty() && res.back().first == kv.first && if(!res.empty() && res.back().name == kv.name &&
kv.first != "cookie" && kv.first != "set-cookie") { kv.name != "cookie" && kv.name != "set-cookie") {
if(!kv.second.empty()) {
res.back().second.append(1, '\0'); auto& last = res.back();
res.back().second += kv.second;
if(!kv.value.empty()) {
last.value.append(1, '\0');
last.value += kv.value;
} }
// We do ORing nv flags. This is done even if value is empty.
last.no_index |= kv.no_index;
} else { } else {
res.push_back(std::move(kv)); res.push_back(std::move(kv));
} }
...@@ -369,10 +382,11 @@ void copy_norm_headers_to_nva ...@@ -369,10 +382,11 @@ void copy_norm_headers_to_nva
{ {
size_t i, j; size_t i, j;
for(i = 0, j = 0; i < headers.size() && j < IGN_HDLEN;) { for(i = 0, j = 0; i < headers.size() && j < IGN_HDLEN;) {
int rv = strcmp(headers[i].first.c_str(), IGN_HD[j]); auto& kv = headers[i];
int rv = strcmp(kv.name.c_str(), IGN_HD[j]);
if(rv < 0) { if(rv < 0) {
if(!headers[i].first.empty() && headers[i].first.c_str()[0] != ':') { if(!kv.name.empty() && kv.name.c_str()[0] != ':') {
nva.push_back(make_nv(headers[i].first, headers[i].second)); nva.push_back(make_nv(kv.name, kv.value, kv.no_index));
} }
++i; ++i;
} else if(rv > 0) { } else if(rv > 0) {
...@@ -382,8 +396,9 @@ void copy_norm_headers_to_nva ...@@ -382,8 +396,9 @@ void copy_norm_headers_to_nva
} }
} }
for(; i < headers.size(); ++i) { for(; i < headers.size(); ++i) {
if(!headers[i].first.empty() && headers[i].first.c_str()[0] != ':') { auto& kv = headers[i];
nva.push_back(make_nv(headers[i].first, headers[i].second)); if(!kv.name.empty() && kv.name.c_str()[0] != ':') {
nva.push_back(make_nv(kv.name, kv.value, kv.no_index));
} }
} }
} }
...@@ -393,14 +408,16 @@ void build_http1_headers_from_norm_headers ...@@ -393,14 +408,16 @@ void build_http1_headers_from_norm_headers
{ {
size_t i, j; size_t i, j;
for(i = 0, j = 0; i < headers.size() && j < HTTP1_IGN_HDLEN;) { for(i = 0, j = 0; i < headers.size() && j < HTTP1_IGN_HDLEN;) {
int rv = strcmp(headers[i].first.c_str(), HTTP1_IGN_HD[j]); auto& kv = headers[i];
auto rv = strcmp(kv.name.c_str(), HTTP1_IGN_HD[j]);
if(rv < 0) { if(rv < 0) {
if(!headers[i].first.empty() && headers[i].first.c_str()[0] != ':') { if(!kv.name.empty() && kv.name.c_str()[0] != ':') {
hdrs += headers[i].first; hdrs += kv.name;
capitalize(hdrs, hdrs.size()-headers[i].first.size()); capitalize(hdrs, hdrs.size() - kv.name.size());
hdrs += ": "; hdrs += ": ";
hdrs += headers[i].second; hdrs += kv.value;
sanitize_header_value(hdrs, hdrs.size() - headers[i].second.size()); sanitize_header_value(hdrs, hdrs.size() - kv.value.size());
hdrs += "\r\n"; hdrs += "\r\n";
} }
++i; ++i;
...@@ -411,12 +428,14 @@ void build_http1_headers_from_norm_headers ...@@ -411,12 +428,14 @@ void build_http1_headers_from_norm_headers
} }
} }
for(; i < headers.size(); ++i) { for(; i < headers.size(); ++i) {
if(!headers[i].first.empty() && headers[i].first.c_str()[0] != ':') { auto& kv = headers[i];
hdrs += headers[i].first;
capitalize(hdrs, hdrs.size()-headers[i].first.size()); if(!kv.name.empty() && kv.name.c_str()[0] != ':') {
hdrs += kv.name;
capitalize(hdrs, hdrs.size() - kv.name.size());
hdrs += ": "; hdrs += ": ";
hdrs += headers[i].second; hdrs += kv.value;
sanitize_header_value(hdrs, hdrs.size() - headers[i].second.size()); sanitize_header_value(hdrs, hdrs.size() - kv.value.size());
hdrs += "\r\n"; hdrs += "\r\n";
} }
} }
...@@ -472,9 +491,9 @@ void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen) ...@@ -472,9 +491,9 @@ void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen)
void dump_nv(FILE *out, const Headers& nva) void dump_nv(FILE *out, const Headers& nva)
{ {
for(auto& nv : nva) { for(auto& nv : nva) {
fwrite(nv.first.c_str(), nv.first.size(), 1, out); fwrite(nv.name.c_str(), nv.name.size(), 1, out);
fwrite(": ", 2, 1, out); fwrite(": ", 2, 1, out);
fwrite(nv.second.c_str(), nv.second.size(), 1, out); fwrite(nv.value.c_str(), nv.value.size(), 1, out);
fwrite("\n", 1, 1, out); fwrite("\n", 1, 1, out);
} }
fwrite("\n", 1, 1, out); fwrite("\n", 1, 1, out);
......
...@@ -38,7 +38,33 @@ ...@@ -38,7 +38,33 @@
namespace nghttp2 { namespace nghttp2 {
typedef std::vector<std::pair<std::string, std::string>> Headers; struct Header {
Header(std::string name, std::string value, bool no_index=false)
: name(std::move(name)),
value(std::move(value)),
no_index(no_index)
{}
Header()
: no_index(false)
{}
bool operator==(const Header& other) const
{
return name == other.name && value == other.value;
}
bool operator<(const Header& rhs) const
{
return name < rhs.name || (name == rhs.name && value < rhs.value);
}
std::string name;
std::string value;
bool no_index;
};
typedef std::vector<Header> Headers;
namespace http2 { namespace http2 {
...@@ -75,15 +101,18 @@ bool name_less(const Headers::value_type& lhs, const Headers::value_type& rhs); ...@@ -75,15 +101,18 @@ bool name_less(const Headers::value_type& lhs, const Headers::value_type& rhs);
void normalize_headers(Headers& nva); void normalize_headers(Headers& nva);
Headers::value_type to_header(const uint8_t *name, size_t namelen, Headers::value_type to_header(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen); const uint8_t *value, size_t valuelen,
bool no_index);
// Add name/value pairs to |nva|. The name is given in the |name| with // Add name/value pairs to |nva|. The name is given in the |name| with
// |namelen| bytes. This function inspects the |value| and split it // |namelen| bytes. This function inspects the |value| and split it
// using '\0' as delimiter. Each token is added to the |nva| with the // using '\0' as delimiter. Each token is added to the |nva| with the
// name |name|. // name |name|. If |no_index| is true, this name/value pair won't be
// indexed when it is forwarded to the next hop.
void split_add_header(Headers& nva, void split_add_header(Headers& nva,
const uint8_t *name, size_t namelen, const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen); const uint8_t *value, size_t valuelen,
bool no_index);
// Returns sorted |nva| with |nvlen| elements. The headers are sorted // Returns sorted |nva| with |nvlen| elements. The headers are sorted
// by name only and not necessarily stable. In addition to the // by name only and not necessarily stable. In addition to the
...@@ -122,8 +151,10 @@ Headers concat_norm_headers(Headers headers); ...@@ -122,8 +151,10 @@ Headers concat_norm_headers(Headers headers);
// Creates nghttp2_nv using |name| and |value| and returns it. The // Creates nghttp2_nv using |name| and |value| and returns it. The
// returned value only references the data pointer to name.c_str() and // returned value only references the data pointer to name.c_str() and
// value.c_str(). // value.c_str(). If |no_index| is true, nghttp2_nv flags member has
nghttp2_nv make_nv(const std::string& name, const std::string& value); // NGHTTP2_NV_FLAG_NO_INDEX flag set.
nghttp2_nv make_nv(const std::string& name, const std::string& value,
bool no_index);
// Create nghttp2_nv from string literal |name| and |value|. // Create nghttp2_nv from string literal |name| and |value|.
template<size_t N, size_t M> template<size_t N, size_t M>
......
...@@ -44,13 +44,12 @@ using namespace nghttp2; ...@@ -44,13 +44,12 @@ using namespace nghttp2;
namespace shrpx { namespace shrpx {
namespace { namespace {
void check_nv(const std::pair<std::string, std::string>& a, void check_nv(const Header& a, const nghttp2_nv *b)
const nghttp2_nv *b)
{ {
CU_ASSERT(a.first.size() == b->namelen); CU_ASSERT(a.name.size() == b->namelen);
CU_ASSERT(a.second.size() == b->valuelen); CU_ASSERT(a.value.size() == b->valuelen);
CU_ASSERT(memcmp(a.first.c_str(), b->name, b->namelen) == 0); CU_ASSERT(memcmp(a.name.c_str(), b->name, b->namelen) == 0);
CU_ASSERT(memcmp(a.second.c_str(), b->value, b->valuelen) == 0); CU_ASSERT(memcmp(a.value.c_str(), b->value, b->valuelen) == 0);
} }
} // namespace } // namespace
...@@ -78,7 +77,7 @@ void test_http2_split_add_header(void) ...@@ -78,7 +77,7 @@ void test_http2_split_add_header(void)
const uint8_t concatval[] = { '4', 0x00, 0x00, '6', 0x00, '5', '9', 0x00 }; const uint8_t concatval[] = { '4', 0x00, 0x00, '6', 0x00, '5', '9', 0x00 };
auto nva = Headers(); auto nva = Headers();
http2::split_add_header(nva, (const uint8_t*)"delta", 5, http2::split_add_header(nva, (const uint8_t*)"delta", 5,
concatval, sizeof(concatval)); concatval, sizeof(concatval), false);
CU_ASSERT(Headers::value_type("delta", "4") == nva[0]); CU_ASSERT(Headers::value_type("delta", "4") == nva[0]);
CU_ASSERT(Headers::value_type("delta", "6") == nva[1]); CU_ASSERT(Headers::value_type("delta", "6") == nva[1]);
CU_ASSERT(Headers::value_type("delta", "59") == nva[2]); CU_ASSERT(Headers::value_type("delta", "59") == nva[2]);
...@@ -86,14 +85,16 @@ void test_http2_split_add_header(void) ...@@ -86,14 +85,16 @@ void test_http2_split_add_header(void)
nva.clear(); nva.clear();
http2::split_add_header(nva, (const uint8_t*)"alpha", 5, http2::split_add_header(nva, (const uint8_t*)"alpha", 5,
(const uint8_t*)"123", 3); (const uint8_t*)"123", 3, false);
CU_ASSERT(Headers::value_type("alpha", "123") == nva[0]); CU_ASSERT(Headers::value_type("alpha", "123") == nva[0]);
CU_ASSERT(!nva[0].no_index);
nva.clear(); nva.clear();
http2::split_add_header(nva, (const uint8_t*)"alpha", 5, http2::split_add_header(nva, (const uint8_t*)"alpha", 5,
(const uint8_t*)"", 0); (const uint8_t*)"", 0, true);
CU_ASSERT(Headers::value_type("alpha", "") == nva[0]); CU_ASSERT(Headers::value_type("alpha", "") == nva[0]);
CU_ASSERT(nva[0].no_index);
} }
void test_http2_check_http2_headers(void) void test_http2_check_http2_headers(void)
...@@ -133,7 +134,7 @@ void test_http2_get_unique_header(void) ...@@ -133,7 +134,7 @@ void test_http2_get_unique_header(void)
const Headers::value_type *rv; const Headers::value_type *rv;
rv = http2::get_unique_header(nva, "delta"); rv = http2::get_unique_header(nva, "delta");
CU_ASSERT(rv != nullptr); CU_ASSERT(rv != nullptr);
CU_ASSERT("delta" == rv->first); CU_ASSERT("delta" == rv->name);
rv = http2::get_unique_header(nva, "bravo"); rv = http2::get_unique_header(nva, "bravo");
CU_ASSERT(rv == nullptr); CU_ASSERT(rv == nullptr);
...@@ -155,11 +156,11 @@ void test_http2_get_header(void) ...@@ -155,11 +156,11 @@ void test_http2_get_header(void)
const Headers::value_type *rv; const Headers::value_type *rv;
rv = http2::get_header(nva, "delta"); rv = http2::get_header(nva, "delta");
CU_ASSERT(rv != nullptr); CU_ASSERT(rv != nullptr);
CU_ASSERT("delta" == rv->first); CU_ASSERT("delta" == rv->name);
rv = http2::get_header(nva, "bravo"); rv = http2::get_header(nva, "bravo");
CU_ASSERT(rv != nullptr); CU_ASSERT(rv != nullptr);
CU_ASSERT("bravo" == rv->first); CU_ASSERT("bravo" == rv->name);
rv = http2::get_header(nva, "foxtrot"); rv = http2::get_header(nva, "foxtrot");
CU_ASSERT(rv == nullptr); CU_ASSERT(rv == nullptr);
...@@ -182,8 +183,8 @@ void test_http2_value_lws(void) ...@@ -182,8 +183,8 @@ void test_http2_value_lws(void)
} }
namespace { namespace {
auto headers = std::vector<std::pair<std::string, std::string>> auto headers = Headers
{{"alpha", "0"}, {{"alpha", "0", true},
{"bravo", "1"}, {"bravo", "1"},
{"connection", "2"}, {"connection", "2"},
{"connection", "3"}, {"connection", "3"},
...@@ -207,7 +208,7 @@ void test_http2_concat_norm_headers(void) ...@@ -207,7 +208,7 @@ void test_http2_concat_norm_headers(void)
hds.emplace_back("set-cookie", "buzz"); hds.emplace_back("set-cookie", "buzz");
auto res = http2::concat_norm_headers(hds); auto res = http2::concat_norm_headers(hds);
CU_ASSERT(14 == res.size()); CU_ASSERT(14 == res.size());
CU_ASSERT(std::string("2") + '\0' + std::string("3") == res[2].second); CU_ASSERT(std::string("2") + '\0' + std::string("3") == res[2].value);
} }
void test_http2_copy_norm_headers_to_nva(void) void test_http2_copy_norm_headers_to_nva(void)
...@@ -218,6 +219,12 @@ void test_http2_copy_norm_headers_to_nva(void) ...@@ -218,6 +219,12 @@ void test_http2_copy_norm_headers_to_nva(void)
auto ans = std::vector<int>{0, 1, 4, 6, 7, 12}; auto ans = std::vector<int>{0, 1, 4, 6, 7, 12};
for(size_t i = 0; i < ans.size(); ++i) { for(size_t i = 0; i < ans.size(); ++i) {
check_nv(headers[ans[i]], &nva[i]); check_nv(headers[ans[i]], &nva[i]);
if(ans[i] == 0) {
CU_ASSERT(nva[i].flags & NGHTTP2_NV_FLAG_NO_INDEX);
} else {
CU_ASSERT(NGHTTP2_NV_FLAG_NONE == nva[i].flags);
}
} }
} }
......
...@@ -921,7 +921,7 @@ int submit_request ...@@ -921,7 +921,7 @@ int submit_request
{ {
auto path = req->make_reqpath(); auto path = req->make_reqpath();
auto scheme = util::get_uri_field(req->uri.c_str(), req->u, UF_SCHEMA); auto scheme = util::get_uri_field(req->uri.c_str(), req->u, UF_SCHEMA);
auto build_headers = std::vector<std::pair<std::string, std::string>> auto build_headers = Headers
{{":method", req->data_prd ? "POST" : "GET"}, {{":method", req->data_prd ? "POST" : "GET"},
{":path", path}, {":path", path},
{":scheme", scheme}, {":scheme", scheme},
...@@ -942,27 +942,30 @@ int submit_request ...@@ -942,27 +942,30 @@ int submit_request
for(auto& kv : headers) { for(auto& kv : headers) {
size_t i; size_t i;
for(i = 0; i < num_initial_headers; ++i) { for(i = 0; i < num_initial_headers; ++i) {
if(util::strieq(kv.first, build_headers[i].first)) { if(util::strieq(kv.first, build_headers[i].name)) {
build_headers[i].second = kv.second; build_headers[i].value = kv.second;
break; break;
} }
} }
if(i < num_initial_headers) { if(i < num_initial_headers) {
continue; continue;
} }
build_headers.push_back(kv); build_headers.emplace_back(kv.first, kv.second);
} }
std::stable_sort(std::begin(build_headers), std::end(build_headers), std::stable_sort(std::begin(build_headers), std::end(build_headers),
[](const std::pair<std::string, std::string>& lhs, [](const Headers::value_type& lhs,
const std::pair<std::string, std::string>& rhs) const Headers::value_type& rhs)
{ {
return lhs.first < rhs.first; return lhs.name < rhs.name;
}); });
build_headers = http2::concat_norm_headers(std::move(build_headers)); build_headers = http2::concat_norm_headers(std::move(build_headers));
auto nva = std::vector<nghttp2_nv>(); auto nva = std::vector<nghttp2_nv>();
nva.reserve(build_headers.size()); nva.reserve(build_headers.size());
for(auto& kv : build_headers) { for(auto& kv : build_headers) {
nva.push_back(http2::make_nv(kv.first, kv.second)); nva.push_back(http2::make_nv(kv.name, kv.value, false));
} }
auto rv = nghttp2_submit_request(client->session, &req->pri_spec, auto rv = nghttp2_submit_request(client->session, &req->pri_spec,
...@@ -1157,13 +1160,13 @@ void check_response_header(nghttp2_session *session, Request* req) ...@@ -1157,13 +1160,13 @@ void check_response_header(nghttp2_session *session, Request* req)
{ {
bool gzip = false; bool gzip = false;
for(auto& nv : req->res_nva) { for(auto& nv : req->res_nva) {
if("content-encoding" == nv.first) { if("content-encoding" == nv.name) {
gzip = util::strieq("gzip", nv.second) || gzip = util::strieq("gzip", nv.value) ||
util::strieq("deflate", nv.second); util::strieq("deflate", nv.value);
continue; continue;
} }
if(":status" == nv.first) { if(":status" == nv.name) {
req->status.assign(nv.second); req->status.assign(nv.value);
} }
} }
if(gzip) { if(gzip) {
...@@ -1228,7 +1231,8 @@ int on_header_callback(nghttp2_session *session, ...@@ -1228,7 +1231,8 @@ int on_header_callback(nghttp2_session *session,
if(!req) { if(!req) {
break; break;
} }
http2::split_add_header(req->res_nva, name, namelen, value, valuelen); http2::split_add_header(req->res_nva, name, namelen, value, valuelen,
flags & NGHTTP2_NV_FLAG_NO_INDEX);
break; break;
} }
case NGHTTP2_PUSH_PROMISE: { case NGHTTP2_PUSH_PROMISE: {
...@@ -1237,7 +1241,8 @@ int on_header_callback(nghttp2_session *session, ...@@ -1237,7 +1241,8 @@ int on_header_callback(nghttp2_session *session,
if(!req) { if(!req) {
break; break;
} }
http2::split_add_header(req->push_req_nva, name, namelen, value, valuelen); http2::split_add_header(req->push_req_nva, name, namelen, value, valuelen,
flags & NGHTTP2_NV_FLAG_NO_INDEX);
break; break;
} }
} }
...@@ -1284,20 +1289,20 @@ int on_frame_recv_callback2 ...@@ -1284,20 +1289,20 @@ int on_frame_recv_callback2
} }
std::string scheme, authority, method, path; std::string scheme, authority, method, path;
for(auto& nv : req->push_req_nva) { for(auto& nv : req->push_req_nva) {
if(nv.first == ":scheme") { if(nv.name == ":scheme") {
scheme = nv.second; scheme = nv.value;
continue; continue;
} }
if(nv.first == ":authority" || nv.first == "host") { if(nv.name == ":authority" || nv.name == "host") {
authority = nv.second; authority = nv.value;
continue; continue;
} }
if(nv.first == ":method") { if(nv.name == ":method") {
method = nv.second; method = nv.value;
continue; continue;
} }
if(nv.first == ":path") { if(nv.name == ":path") {
path = nv.second; path = nv.value;
continue; continue;
} }
} }
......
...@@ -121,8 +121,8 @@ namespace { ...@@ -121,8 +121,8 @@ namespace {
void check_header_field(bool *result, const Headers::value_type &item, void check_header_field(bool *result, const Headers::value_type &item,
const char *name, const char *value) const char *name, const char *value)
{ {
if(util::strieq(item.first.c_str(), name)) { if(util::strieq(item.name.c_str(), name)) {
if(util::strifind(item.second.c_str(), value)) { if(util::strifind(item.value.c_str(), value)) {
*result = true; *result = true;
} }
} }
...@@ -150,8 +150,8 @@ Headers::const_iterator get_norm_header(const Headers& headers, ...@@ -150,8 +150,8 @@ Headers::const_iterator get_norm_header(const Headers& headers,
const std::string& name) const std::string& name)
{ {
auto i = std::lower_bound(std::begin(headers), std::end(headers), auto i = std::lower_bound(std::begin(headers), std::end(headers),
std::make_pair(name, ""), http2::name_less); Header(name, ""), http2::name_less);
if(i != std::end(headers) && (*i).first == name) { if(i != std::end(headers) && (*i).name == name) {
return i; return i;
} }
return std::end(headers); return std::end(headers);
...@@ -162,8 +162,8 @@ namespace { ...@@ -162,8 +162,8 @@ namespace {
Headers::iterator get_norm_header(Headers& headers, const std::string& name) Headers::iterator get_norm_header(Headers& headers, const std::string& name)
{ {
auto i = std::lower_bound(std::begin(headers), std::end(headers), auto i = std::lower_bound(std::begin(headers), std::end(headers),
std::make_pair(name, ""), http2::name_less); Header(name, ""), http2::name_less);
if(i != std::end(headers) && (*i).first == name) { if(i != std::end(headers) && (*i).name == name) {
return i; return i;
} }
return std::end(headers); return std::end(headers);
...@@ -180,12 +180,12 @@ void Downstream::assemble_request_cookie() ...@@ -180,12 +180,12 @@ void Downstream::assemble_request_cookie()
std::string& cookie = assembled_request_cookie_; std::string& cookie = assembled_request_cookie_;
cookie = ""; cookie = "";
for(auto& kv : request_headers_) { for(auto& kv : request_headers_) {
if(util::strieq("cookie", kv.first.c_str())) { if(util::strieq("cookie", kv.name.c_str())) {
auto end = kv.second.find_last_not_of(" ;"); auto end = kv.value.find_last_not_of(" ;");
if(end == std::string::npos) { if(end == std::string::npos) {
cookie += kv.second; cookie += kv.value;
} else { } else {
cookie.append(std::begin(kv.second), std::begin(kv.second) + end + 1); cookie.append(std::begin(kv.value), std::begin(kv.value) + end + 1);
} }
cookie += "; "; cookie += "; ";
} }
...@@ -199,19 +199,19 @@ void Downstream::crumble_request_cookie() ...@@ -199,19 +199,19 @@ void Downstream::crumble_request_cookie()
{ {
Headers cookie_hdrs; Headers cookie_hdrs;
for(auto& kv : request_headers_) { for(auto& kv : request_headers_) {
if(util::strieq("cookie", kv.first.c_str())) { if(util::strieq("cookie", kv.name.c_str())) {
size_t last = kv.second.size(); size_t last = kv.value.size();
size_t num = 0; size_t num = 0;
std::string rep_cookie; std::string rep_cookie;
for(size_t j = 0; j < last;) { for(size_t j = 0; j < last;) {
j = kv.second.find_first_not_of("\t ;", j); j = kv.value.find_first_not_of("\t ;", j);
if(j == std::string::npos) { if(j == std::string::npos) {
break; break;
} }
auto first = j; auto first = j;
j = kv.second.find(';', j); j = kv.value.find(';', j);
if(j == std::string::npos) { if(j == std::string::npos) {
j = last; j = last;
} }
...@@ -220,15 +220,16 @@ void Downstream::crumble_request_cookie() ...@@ -220,15 +220,16 @@ void Downstream::crumble_request_cookie()
if(first == 0 && j == last) { if(first == 0 && j == last) {
break; break;
} }
rep_cookie = kv.second.substr(first, j - first); rep_cookie = kv.value.substr(first, j - first);
} else { } else {
cookie_hdrs.push_back cookie_hdrs.push_back
(std::make_pair("cookie", kv.second.substr(first, j - first))); (Header("cookie", kv.value.substr(first, j - first),
kv.no_index));
} }
++num; ++num;
} }
if(num > 0) { if(num > 0) {
kv.second = std::move(rep_cookie); kv.value = std::move(rep_cookie);
} }
} }
} }
...@@ -269,17 +270,19 @@ void Downstream::set_last_request_header_value(std::string value) ...@@ -269,17 +270,19 @@ void Downstream::set_last_request_header_value(std::string value)
request_header_key_prev_ = false; request_header_key_prev_ = false;
request_headers_sum_ += value.size(); request_headers_sum_ += value.size();
Headers::value_type &item = request_headers_.back(); Headers::value_type &item = request_headers_.back();
item.second = std::move(value); item.value = std::move(value);
check_transfer_encoding_chunked(&chunked_request_, item); check_transfer_encoding_chunked(&chunked_request_, item);
check_expect_100_continue(&request_expect_100_continue_, item); check_expect_100_continue(&request_expect_100_continue_, item);
} }
void Downstream::split_add_request_header void Downstream::split_add_request_header
(const uint8_t *name, size_t namelen, (const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen) const uint8_t *value, size_t valuelen,
bool no_index)
{ {
request_headers_sum_ += namelen + valuelen; request_headers_sum_ += namelen + valuelen;
http2::split_add_header(request_headers_, name, namelen, value, valuelen); http2::split_add_header(request_headers_, name, namelen, value, valuelen,
no_index);
} }
bool Downstream::get_request_header_key_prev() const bool Downstream::get_request_header_key_prev() const
...@@ -292,7 +295,7 @@ void Downstream::append_last_request_header_key(const char *data, size_t len) ...@@ -292,7 +295,7 @@ void Downstream::append_last_request_header_key(const char *data, size_t len)
assert(request_header_key_prev_); assert(request_header_key_prev_);
request_headers_sum_ += len; request_headers_sum_ += len;
auto& item = request_headers_.back(); auto& item = request_headers_.back();
item.first.append(data, len); item.name.append(data, len);
} }
void Downstream::append_last_request_header_value(const char *data, size_t len) void Downstream::append_last_request_header_value(const char *data, size_t len)
...@@ -300,7 +303,7 @@ void Downstream::append_last_request_header_value(const char *data, size_t len) ...@@ -300,7 +303,7 @@ void Downstream::append_last_request_header_value(const char *data, size_t len)
assert(!request_header_key_prev_); assert(!request_header_key_prev_);
request_headers_sum_ += len; request_headers_sum_ += len;
auto& item = request_headers_.back(); auto& item = request_headers_.back();
item.second.append(data, len); item.value.append(data, len);
} }
size_t Downstream::get_request_headers_sum() const size_t Downstream::get_request_headers_sum() const
...@@ -498,14 +501,14 @@ void Downstream::rewrite_norm_location_response_header ...@@ -498,14 +501,14 @@ void Downstream::rewrite_norm_location_response_header
} }
http_parser_url u; http_parser_url u;
memset(&u, 0, sizeof(u)); memset(&u, 0, sizeof(u));
int rv = http_parser_parse_url((*hd).second.c_str(), (*hd).second.size(), int rv = http_parser_parse_url((*hd).value.c_str(), (*hd).value.size(),
0, &u); 0, &u);
if(rv != 0) { if(rv != 0) {
return; return;
} }
std::string new_uri; std::string new_uri;
if(!request_http2_authority_.empty()) { if(!request_http2_authority_.empty()) {
new_uri = http2::rewrite_location_uri((*hd).second, u, new_uri = http2::rewrite_location_uri((*hd).value, u,
request_http2_authority_, request_http2_authority_,
upstream_scheme, upstream_port); upstream_scheme, upstream_port);
} }
...@@ -514,11 +517,11 @@ void Downstream::rewrite_norm_location_response_header ...@@ -514,11 +517,11 @@ void Downstream::rewrite_norm_location_response_header
if(host == std::end(request_headers_)) { if(host == std::end(request_headers_)) {
return; return;
} }
new_uri = http2::rewrite_location_uri((*hd).second, u, (*host).second, new_uri = http2::rewrite_location_uri((*hd).value, u, (*host).value,
upstream_scheme, upstream_port); upstream_scheme, upstream_port);
} }
if(!new_uri.empty()) { if(!new_uri.empty()) {
(*hd).second = std::move(new_uri); (*hd).value = std::move(new_uri);
} }
} }
...@@ -536,16 +539,18 @@ void Downstream::set_last_response_header_value(std::string value) ...@@ -536,16 +539,18 @@ void Downstream::set_last_response_header_value(std::string value)
response_header_key_prev_ = false; response_header_key_prev_ = false;
response_headers_sum_ += value.size(); response_headers_sum_ += value.size();
auto& item = response_headers_.back(); auto& item = response_headers_.back();
item.second = std::move(value); item.value = std::move(value);
check_transfer_encoding_chunked(&chunked_response_, item); check_transfer_encoding_chunked(&chunked_response_, item);
} }
void Downstream::split_add_response_header void Downstream::split_add_response_header
(const uint8_t *name, size_t namelen, (const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen) const uint8_t *value, size_t valuelen,
bool no_index)
{ {
response_headers_sum_ += namelen + valuelen; response_headers_sum_ += namelen + valuelen;
http2::split_add_header(response_headers_, name, namelen, value, valuelen); http2::split_add_header(response_headers_, name, namelen, value, valuelen,
no_index);
} }
bool Downstream::get_response_header_key_prev() const bool Downstream::get_response_header_key_prev() const
...@@ -558,7 +563,7 @@ void Downstream::append_last_response_header_key(const char *data, size_t len) ...@@ -558,7 +563,7 @@ void Downstream::append_last_response_header_key(const char *data, size_t len)
assert(response_header_key_prev_); assert(response_header_key_prev_);
response_headers_sum_ += len; response_headers_sum_ += len;
auto& item = response_headers_.back(); auto& item = response_headers_.back();
item.first.append(data, len); item.name.append(data, len);
} }
void Downstream::append_last_response_header_value(const char *data, void Downstream::append_last_response_header_value(const char *data,
...@@ -567,7 +572,7 @@ void Downstream::append_last_response_header_value(const char *data, ...@@ -567,7 +572,7 @@ void Downstream::append_last_response_header_value(const char *data,
assert(!response_header_key_prev_); assert(!response_header_key_prev_);
response_headers_sum_ += len; response_headers_sum_ += len;
auto& item = response_headers_.back(); auto& item = response_headers_.back();
item.second.append(data, len); item.value.append(data, len);
} }
size_t Downstream::get_response_headers_sum() const size_t Downstream::get_response_headers_sum() const
...@@ -692,7 +697,7 @@ void Downstream::check_upgrade_fulfilled() ...@@ -692,7 +697,7 @@ void Downstream::check_upgrade_fulfilled()
// TODO Do more strict checking for upgrade headers // TODO Do more strict checking for upgrade headers
if(response_http_status_ == 101) { if(response_http_status_ == 101) {
for(auto& hd : request_headers_) { for(auto& hd : request_headers_) {
if(util::strieq("upgrade", hd.first.c_str())) { if(util::strieq("upgrade", hd.name.c_str())) {
upgraded_ = true; upgraded_ = true;
break; break;
} }
...@@ -713,7 +718,7 @@ void Downstream::check_upgrade_request() ...@@ -713,7 +718,7 @@ void Downstream::check_upgrade_request()
} else { } else {
// TODO Do more strict checking for upgrade headers // TODO Do more strict checking for upgrade headers
for(auto& hd : request_headers_) { for(auto& hd : request_headers_) {
if(util::strieq("upgrade", hd.first.c_str())) { if(util::strieq("upgrade", hd.name.c_str())) {
upgrade_request_ = true; upgrade_request_ = true;
break; break;
} }
...@@ -737,12 +742,12 @@ bool Downstream::http2_upgrade_request() const ...@@ -737,12 +742,12 @@ bool Downstream::http2_upgrade_request() const
// For now just check NGHTTP2_CLEARTEXT_PROTO_VERSION_ID in // For now just check NGHTTP2_CLEARTEXT_PROTO_VERSION_ID in
// Upgrade header field and existence of HTTP2-Settings header // Upgrade header field and existence of HTTP2-Settings header
// field. // field.
if(util::strieq(hd.first.c_str(), "upgrade")) { if(util::strieq(hd.name.c_str(), "upgrade")) {
if(util::strieq(hd.second.c_str(), if(util::strieq(hd.value.c_str(),
NGHTTP2_CLEARTEXT_PROTO_VERSION_ID)) { NGHTTP2_CLEARTEXT_PROTO_VERSION_ID)) {
upgrade_seen = true; upgrade_seen = true;
} }
} else if(util::strieq(hd.first.c_str(), "http2-settings")) { } else if(util::strieq(hd.name.c_str(), "http2-settings")) {
http2_settings_seen = true; http2_settings_seen = true;
} }
} }
......
...@@ -103,7 +103,8 @@ public: ...@@ -103,7 +103,8 @@ public:
void set_last_request_header_value(std::string value); void set_last_request_header_value(std::string value);
void split_add_request_header(const uint8_t *name, size_t namelen, void split_add_request_header(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen); const uint8_t *value, size_t valuelen,
bool no_index);
bool get_request_header_key_prev() const; bool get_request_header_key_prev() const;
void append_last_request_header_key(const char *data, size_t len); void append_last_request_header_key(const char *data, size_t len);
...@@ -171,7 +172,8 @@ public: ...@@ -171,7 +172,8 @@ public:
void set_last_response_header_value(std::string value); void set_last_response_header_value(std::string value);
void split_add_response_header(const uint8_t *name, size_t namelen, void split_add_response_header(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen); const uint8_t *value, size_t valuelen,
bool no_index);
bool get_response_header_key_prev() const; bool get_response_header_key_prev() const;
void append_last_response_header_key(const char *data, size_t len); void append_last_response_header_key(const char *data, size_t len);
......
...@@ -78,13 +78,13 @@ void test_downstream_get_norm_request_header(void) ...@@ -78,13 +78,13 @@ void test_downstream_get_norm_request_header(void)
d.add_request_header("delta", "4"); d.add_request_header("delta", "4");
d.add_request_header("echo", "5"); d.add_request_header("echo", "5");
auto i = d.get_norm_request_header("alpha"); auto i = d.get_norm_request_header("alpha");
CU_ASSERT(std::make_pair(std::string("alpha"), std::string("0")) == *i); CU_ASSERT(Header("alpha", "0") == *i);
i = d.get_norm_request_header("bravo"); i = d.get_norm_request_header("bravo");
CU_ASSERT(std::make_pair(std::string("bravo"), std::string("1")) == *i); CU_ASSERT(Header("bravo", "1") == *i);
i = d.get_norm_request_header("delta"); i = d.get_norm_request_header("delta");
CU_ASSERT(std::make_pair(std::string("delta"), std::string("4")) == *i); CU_ASSERT(Header("delta", "4") == *i);
i = d.get_norm_request_header("echo"); i = d.get_norm_request_header("echo");
CU_ASSERT(std::make_pair(std::string("echo"), std::string("5")) == *i); CU_ASSERT(Header("echo", "5") == *i);
i = d.get_norm_request_header("foxtrot"); i = d.get_norm_request_header("foxtrot");
CU_ASSERT(i == std::end(d.get_request_headers())); CU_ASSERT(i == std::end(d.get_request_headers()));
} }
...@@ -99,13 +99,13 @@ void test_downstream_get_norm_response_header(void) ...@@ -99,13 +99,13 @@ void test_downstream_get_norm_response_header(void)
d.add_response_header("delta", "4"); d.add_response_header("delta", "4");
d.add_response_header("echo", "5"); d.add_response_header("echo", "5");
auto i = d.get_norm_response_header("alpha"); auto i = d.get_norm_response_header("alpha");
CU_ASSERT(std::make_pair(std::string("alpha"), std::string("0")) == *i); CU_ASSERT(Header("alpha", "0") == *i);
i = d.get_norm_response_header("bravo"); i = d.get_norm_response_header("bravo");
CU_ASSERT(std::make_pair(std::string("bravo"), std::string("1")) == *i); CU_ASSERT(Header("bravo", "1") == *i);
i = d.get_norm_response_header("delta"); i = d.get_norm_response_header("delta");
CU_ASSERT(std::make_pair(std::string("delta"), std::string("4")) == *i); CU_ASSERT(Header("delta", "4") == *i);
i = d.get_norm_response_header("echo"); i = d.get_norm_response_header("echo");
CU_ASSERT(std::make_pair(std::string("echo"), std::string("5")) == *i); CU_ASSERT(Header("echo", "5") == *i);
i = d.get_norm_response_header("foxtrot"); i = d.get_norm_response_header("foxtrot");
CU_ASSERT(i == std::end(d.get_response_headers())); CU_ASSERT(i == std::end(d.get_response_headers()));
} }
...@@ -120,13 +120,13 @@ void test_downstream_crumble_request_cookie(void) ...@@ -120,13 +120,13 @@ void test_downstream_crumble_request_cookie(void)
d.add_request_header("cookie", "echo"); d.add_request_header("cookie", "echo");
d.crumble_request_cookie(); d.crumble_request_cookie();
Headers ans = { Headers ans = {
std::make_pair(":method", "get"), {":method", "get"},
std::make_pair(":path", "/"), {":path", "/"},
std::make_pair("cookie", "alpha"), {"cookie", "alpha"},
std::make_pair("cookie", "delta"), {"cookie", "delta"},
std::make_pair("cookie", "echo"), {"cookie", "echo"},
std::make_pair("cookie", "bravo"), {"cookie", "bravo"},
std::make_pair("cookie", "charlie") {"cookie", "charlie"}
}; };
CU_ASSERT(ans == d.get_request_headers()); CU_ASSERT(ans == d.get_request_headers());
} }
...@@ -154,7 +154,7 @@ void test_downstream_rewrite_norm_location_response_header(void) ...@@ -154,7 +154,7 @@ void test_downstream_rewrite_norm_location_response_header(void)
d.add_response_header("location", "http://localhost:3000/"); d.add_response_header("location", "http://localhost:3000/");
d.rewrite_norm_location_response_header("https", 443); d.rewrite_norm_location_response_header("https", 443);
auto location = d.get_norm_response_header("location"); auto location = d.get_norm_response_header("location");
CU_ASSERT("https://localhost/" == (*location).second); CU_ASSERT("https://localhost/" == (*location).value);
} }
{ {
Downstream d(nullptr, 0, 0); Downstream d(nullptr, 0, 0);
...@@ -162,7 +162,7 @@ void test_downstream_rewrite_norm_location_response_header(void) ...@@ -162,7 +162,7 @@ void test_downstream_rewrite_norm_location_response_header(void)
d.add_response_header("location", "http://localhost/"); d.add_response_header("location", "http://localhost/");
d.rewrite_norm_location_response_header("https", 443); d.rewrite_norm_location_response_header("https", 443);
auto location = d.get_norm_response_header("location"); auto location = d.get_norm_response_header("location");
CU_ASSERT("https://localhost/" == (*location).second); CU_ASSERT("https://localhost/" == (*location).value);
} }
} }
......
...@@ -356,21 +356,21 @@ int Http2DownstreamConnection::push_request_headers() ...@@ -356,21 +356,21 @@ int Http2DownstreamConnection::push_request_headers()
auto transfer_encoding = auto transfer_encoding =
downstream_->get_norm_request_header("transfer-encoding"); downstream_->get_norm_request_header("transfer-encoding");
if(transfer_encoding != end_headers && if(transfer_encoding != end_headers &&
util::strieq((*transfer_encoding).second.c_str(), "chunked")) { util::strieq((*transfer_encoding).value.c_str(), "chunked")) {
chunked_encoding = true; chunked_encoding = true;
} }
auto xff = downstream_->get_norm_request_header("x-forwarded-for"); auto xff = downstream_->get_norm_request_header("x-forwarded-for");
if(get_config()->add_x_forwarded_for) { if(get_config()->add_x_forwarded_for) {
if(xff != end_headers) { if(xff != end_headers) {
xff_value = (*xff).second; xff_value = (*xff).value;
xff_value += ", "; xff_value += ", ";
} }
xff_value += downstream_->get_upstream()->get_client_handler()-> xff_value += downstream_->get_upstream()->get_client_handler()->
get_ipaddr(); get_ipaddr();
nva.push_back(http2::make_nv_ls("x-forwarded-for", xff_value)); nva.push_back(http2::make_nv_ls("x-forwarded-for", xff_value));
} else if(xff != end_headers) { } else if(xff != end_headers) {
nva.push_back(http2::make_nv_ls("x-forwarded-for", (*xff).second)); nva.push_back(http2::make_nv_ls("x-forwarded-for", (*xff).value));
} }
if(downstream_->get_request_method() != "CONNECT") { if(downstream_->get_request_method() != "CONNECT") {
...@@ -389,11 +389,11 @@ int Http2DownstreamConnection::push_request_headers() ...@@ -389,11 +389,11 @@ int Http2DownstreamConnection::push_request_headers()
auto via = downstream_->get_norm_request_header("via"); auto via = downstream_->get_norm_request_header("via");
if(get_config()->no_via) { if(get_config()->no_via) {
if(via != end_headers) { if(via != end_headers) {
nva.push_back(http2::make_nv_ls("via", (*via).second)); nva.push_back(http2::make_nv_ls("via", (*via).value));
} }
} else { } else {
if(via != end_headers) { if(via != end_headers) {
via_value = (*via).second; via_value = (*via).value;
via_value += ", "; via_value += ", ";
} }
via_value += http::create_via_header_value via_value += http::create_via_header_value
......
...@@ -814,7 +814,8 @@ int on_header_callback(nghttp2_session *session, ...@@ -814,7 +814,8 @@ int on_header_callback(nghttp2_session *session,
if(!http2::check_nv(name, namelen, value, valuelen)) { if(!http2::check_nv(name, namelen, value, valuelen)) {
return 0; return 0;
} }
downstream->split_add_response_header(name, namelen, value, valuelen); downstream->split_add_response_header(name, namelen, value, valuelen,
flags & NGHTTP2_NV_FLAG_NO_INDEX);
return 0; return 0;
} }
} // namespace } // namespace
...@@ -886,7 +887,7 @@ int on_response_headers(Http2Session *http2session, ...@@ -886,7 +887,7 @@ int on_response_headers(Http2Session *http2session,
call_downstream_readcb(http2session, downstream); call_downstream_readcb(http2session, downstream);
return 0; return 0;
} }
downstream->set_response_http_status(strtoul(status->second.c_str(), downstream->set_response_http_status(strtoul(status->value.c_str(),
nullptr, 10)); nullptr, 10));
downstream->set_response_major(2); downstream->set_response_major(2);
downstream->set_response_minor(0); downstream->set_response_minor(0);
...@@ -916,7 +917,7 @@ int on_response_headers(Http2Session *http2session, ...@@ -916,7 +917,7 @@ int on_response_headers(Http2Session *http2session,
if(LOG_ENABLED(INFO)) { if(LOG_ENABLED(INFO)) {
std::stringstream ss; std::stringstream ss;
for(auto& nv : nva) { for(auto& nv : nva) {
ss << TTY_HTTP_HD << nv.first << TTY_RST << ": " << nv.second << "\n"; ss << TTY_HTTP_HD << nv.name << TTY_RST << ": " << nv.value << "\n";
} }
SSLOG(INFO, http2session) << "HTTP response headers. stream_id=" SSLOG(INFO, http2session) << "HTTP response headers. stream_id="
<< frame->hd.stream_id << frame->hd.stream_id
......
...@@ -101,8 +101,8 @@ int Http2Upstream::upgrade_upstream(HttpsUpstream *http) ...@@ -101,8 +101,8 @@ int Http2Upstream::upgrade_upstream(HttpsUpstream *http)
std::string settings_payload; std::string settings_payload;
auto downstream = http->get_downstream(); auto downstream = http->get_downstream();
for(auto& hd : downstream->get_request_headers()) { for(auto& hd : downstream->get_request_headers()) {
if(util::strieq(hd.first.c_str(), "http2-settings")) { if(util::strieq(hd.name.c_str(), "http2-settings")) {
auto val = hd.second; auto val = hd.value;
util::to_base64(val); util::to_base64(val);
settings_payload = base64::decode(std::begin(val), std::end(val)); settings_payload = base64::decode(std::begin(val), std::end(val));
break; break;
...@@ -205,7 +205,8 @@ int on_header_callback(nghttp2_session *session, ...@@ -205,7 +205,8 @@ int on_header_callback(nghttp2_session *session,
if(!http2::check_nv(name, namelen, value, valuelen)) { if(!http2::check_nv(name, namelen, value, valuelen)) {
return 0; return 0;
} }
downstream->split_add_request_header(name, namelen, value, valuelen); downstream->split_add_request_header(name, namelen, value, valuelen,
flags & NGHTTP2_NV_FLAG_NO_INDEX);
return 0; return 0;
} }
} // namespace } // namespace
...@@ -259,7 +260,7 @@ int on_request_headers(Http2Upstream *upstream, ...@@ -259,7 +260,7 @@ int on_request_headers(Http2Upstream *upstream,
if(LOG_ENABLED(INFO)) { if(LOG_ENABLED(INFO)) {
std::stringstream ss; std::stringstream ss;
for(auto& nv : nva) { for(auto& nv : nva) {
ss << TTY_HTTP_HD << nv.first << TTY_RST << ": " << nv.second << "\n"; ss << TTY_HTTP_HD << nv.name << TTY_RST << ": " << nv.value << "\n";
} }
ULOG(INFO, upstream) << "HTTP request headers. stream_id=" ULOG(INFO, upstream) << "HTTP request headers. stream_id="
<< downstream->get_stream_id() << downstream->get_stream_id()
...@@ -280,7 +281,7 @@ int on_request_headers(Http2Upstream *upstream, ...@@ -280,7 +281,7 @@ int on_request_headers(Http2Upstream *upstream,
auto path = http2::get_unique_header(nva, ":path"); auto path = http2::get_unique_header(nva, ":path");
auto method = http2::get_unique_header(nva, ":method"); auto method = http2::get_unique_header(nva, ":method");
auto scheme = http2::get_unique_header(nva, ":scheme"); auto scheme = http2::get_unique_header(nva, ":scheme");
bool is_connect = method && "CONNECT" == method->second; bool is_connect = method && "CONNECT" == method->value;
bool having_host = http2::non_empty_value(host); bool having_host = http2::non_empty_value(host);
bool having_authority = http2::non_empty_value(authority); bool having_authority = http2::non_empty_value(authority);
...@@ -1014,11 +1015,11 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) ...@@ -1014,11 +1015,11 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream)
auto via = downstream->get_norm_response_header("via"); auto via = downstream->get_norm_response_header("via");
if(get_config()->no_via) { if(get_config()->no_via) {
if(via != end_headers) { if(via != end_headers) {
nva.push_back(http2::make_nv_ls("via", (*via).second)); nva.push_back(http2::make_nv_ls("via", (*via).value));
} }
} else { } else {
if(via != end_headers) { if(via != end_headers) {
via_value = (*via).second; via_value = (*via).value;
via_value += ", "; via_value += ", ";
} }
via_value += http::create_via_header_value via_value += http::create_via_header_value
......
...@@ -171,16 +171,16 @@ int HttpDownstreamConnection::push_request_headers() ...@@ -171,16 +171,16 @@ int HttpDownstreamConnection::push_request_headers()
if(get_config()->add_x_forwarded_for) { if(get_config()->add_x_forwarded_for) {
hdrs += "X-Forwarded-For: "; hdrs += "X-Forwarded-For: ";
if(xff != end_headers) { if(xff != end_headers) {
hdrs += (*xff).second; hdrs += (*xff).value;
http2::sanitize_header_value(hdrs, hdrs.size() - (*xff).second.size()); http2::sanitize_header_value(hdrs, hdrs.size() - (*xff).value.size());
hdrs += ", "; hdrs += ", ";
} }
hdrs += client_handler_->get_ipaddr(); hdrs += client_handler_->get_ipaddr();
hdrs += "\r\n"; hdrs += "\r\n";
} else if(xff != end_headers) { } else if(xff != end_headers) {
hdrs += "X-Forwarded-For: "; hdrs += "X-Forwarded-For: ";
hdrs += (*xff).second; hdrs += (*xff).value;
http2::sanitize_header_value(hdrs, hdrs.size() - (*xff).second.size()); http2::sanitize_header_value(hdrs, hdrs.size() - (*xff).value.size());
hdrs += "\r\n"; hdrs += "\r\n";
} }
if(downstream_->get_request_method() != "CONNECT") { if(downstream_->get_request_method() != "CONNECT") {
...@@ -196,25 +196,25 @@ int HttpDownstreamConnection::push_request_headers() ...@@ -196,25 +196,25 @@ int HttpDownstreamConnection::push_request_headers()
} }
auto expect = downstream_->get_norm_request_header("expect"); auto expect = downstream_->get_norm_request_header("expect");
if(expect != end_headers && if(expect != end_headers &&
!util::strifind((*expect).second.c_str(), "100-continue")) { !util::strifind((*expect).value.c_str(), "100-continue")) {
hdrs += "Expect: "; hdrs += "Expect: ";
hdrs += (*expect).second; hdrs += (*expect).value;
http2::sanitize_header_value(hdrs, hdrs.size() - (*expect).second.size()); http2::sanitize_header_value(hdrs, hdrs.size() - (*expect).value.size());
hdrs += "\r\n"; hdrs += "\r\n";
} }
auto via = downstream_->get_norm_request_header("via"); auto via = downstream_->get_norm_request_header("via");
if(get_config()->no_via) { if(get_config()->no_via) {
if(via != end_headers) { if(via != end_headers) {
hdrs += "Via: "; hdrs += "Via: ";
hdrs += (*via).second; hdrs += (*via).value;
http2::sanitize_header_value(hdrs, hdrs.size() - (*via).second.size()); http2::sanitize_header_value(hdrs, hdrs.size() - (*via).value.size());
hdrs += "\r\n"; hdrs += "\r\n";
} }
} else { } else {
hdrs += "Via: "; hdrs += "Via: ";
if(via != end_headers) { if(via != end_headers) {
hdrs += (*via).second; hdrs += (*via).value;
http2::sanitize_header_value(hdrs, hdrs.size() - (*via).second.size()); http2::sanitize_header_value(hdrs, hdrs.size() - (*via).value.size());
hdrs += ", "; hdrs += ", ";
} }
hdrs += http::create_via_header_value(downstream_->get_request_major(), hdrs += http::create_via_header_value(downstream_->get_request_major(),
......
...@@ -159,8 +159,8 @@ int htp_hdrs_completecb(http_parser *htp) ...@@ -159,8 +159,8 @@ int htp_hdrs_completecb(http_parser *htp)
<< downstream->get_request_minor() << "\n"; << downstream->get_request_minor() << "\n";
const auto& headers = downstream->get_request_headers(); const auto& headers = downstream->get_request_headers();
for(size_t i = 0; i < headers.size(); ++i) { for(size_t i = 0; i < headers.size(); ++i) {
ss << TTY_HTTP_HD << headers[i].first << TTY_RST << ": " ss << TTY_HTTP_HD << headers[i].name << TTY_RST << ": "
<< headers[i].second << "\n"; << headers[i].value << "\n";
} }
ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str(); ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
} }
...@@ -682,15 +682,15 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) ...@@ -682,15 +682,15 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream)
if(get_config()->no_via) { if(get_config()->no_via) {
if(via != end_headers) { if(via != end_headers) {
hdrs += "Via: "; hdrs += "Via: ";
hdrs += (*via).second; hdrs += (*via).value;
http2::sanitize_header_value(hdrs, hdrs.size() - (*via).second.size()); http2::sanitize_header_value(hdrs, hdrs.size() - (*via).value.size());
hdrs += "\r\n"; hdrs += "\r\n";
} }
} else { } else {
hdrs += "Via: "; hdrs += "Via: ";
if(via != end_headers) { if(via != end_headers) {
hdrs += (*via).second; hdrs += (*via).value;
http2::sanitize_header_value(hdrs, hdrs.size() - (*via).second.size()); http2::sanitize_header_value(hdrs, hdrs.size() - (*via).value.size());
hdrs += ", "; hdrs += ", ";
} }
hdrs += http::create_via_header_value hdrs += http::create_via_header_value
......
...@@ -864,18 +864,18 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) ...@@ -864,18 +864,18 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream)
nv[hdidx++] = ":version"; nv[hdidx++] = ":version";
nv[hdidx++] = "HTTP/1.1"; nv[hdidx++] = "HTTP/1.1";
for(auto& hd : downstream->get_response_headers()) { for(auto& hd : downstream->get_response_headers()) {
if(hd.first.empty() || hd.first.c_str()[0] == ':' || if(hd.name.empty() || hd.name.c_str()[0] == ':' ||
util::strieq(hd.first.c_str(), "transfer-encoding") || util::strieq(hd.name.c_str(), "transfer-encoding") ||
util::strieq(hd.first.c_str(), "keep-alive") || // HTTP/1.0? util::strieq(hd.name.c_str(), "keep-alive") || // HTTP/1.0?
util::strieq(hd.first.c_str(), "connection") || util::strieq(hd.name.c_str(), "connection") ||
util::strieq(hd.first.c_str(), "proxy-connection")) { util::strieq(hd.name.c_str(), "proxy-connection")) {
// These are ignored // These are ignored
} else if(!get_config()->no_via && } else if(!get_config()->no_via &&
util::strieq(hd.first.c_str(), "via")) { util::strieq(hd.name.c_str(), "via")) {
via_value = hd.second; via_value = hd.value;
} else { } else {
nv[hdidx++] = hd.first.c_str(); nv[hdidx++] = hd.name.c_str();
nv[hdidx++] = hd.second.c_str(); nv[hdidx++] = hd.value.c_str();
} }
} }
if(!get_config()->no_via) { if(!get_config()->no_via) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment