nghttpx: Use NGHTTP2_NV_FLAG_NO_COPY_NAME and NGHTTP2_NV_FLAG_NO_COPY_VALUE
For both HTTP/2 frontend and backend. Also adds http2::stringify_status to optimize status code serialization.
This commit is contained in:
parent
43b230685f
commit
ac41946533
140
src/http2.cc
140
src/http2.cc
|
@ -132,6 +132,108 @@ std::string get_status_string(unsigned int status_code) {
|
|||
}
|
||||
}
|
||||
|
||||
const char *stringify_status(unsigned int status_code) {
|
||||
switch (status_code) {
|
||||
case 100:
|
||||
return "100";
|
||||
case 101:
|
||||
return "101";
|
||||
case 200:
|
||||
return "200";
|
||||
case 201:
|
||||
return "201";
|
||||
case 202:
|
||||
return "202";
|
||||
case 203:
|
||||
return "203";
|
||||
case 204:
|
||||
return "204";
|
||||
case 205:
|
||||
return "205";
|
||||
case 206:
|
||||
return "206";
|
||||
case 300:
|
||||
return "300";
|
||||
case 301:
|
||||
return "301";
|
||||
case 302:
|
||||
return "302";
|
||||
case 303:
|
||||
return "303";
|
||||
case 304:
|
||||
return "304";
|
||||
case 305:
|
||||
return "305";
|
||||
// case 306: return "306";
|
||||
case 307:
|
||||
return "307";
|
||||
case 308:
|
||||
return "308";
|
||||
case 400:
|
||||
return "400";
|
||||
case 401:
|
||||
return "401";
|
||||
case 402:
|
||||
return "402";
|
||||
case 403:
|
||||
return "403";
|
||||
case 404:
|
||||
return "404";
|
||||
case 405:
|
||||
return "405";
|
||||
case 406:
|
||||
return "406";
|
||||
case 407:
|
||||
return "407";
|
||||
case 408:
|
||||
return "408";
|
||||
case 409:
|
||||
return "409";
|
||||
case 410:
|
||||
return "410";
|
||||
case 411:
|
||||
return "411";
|
||||
case 412:
|
||||
return "412";
|
||||
case 413:
|
||||
return "413";
|
||||
case 414:
|
||||
return "414";
|
||||
case 415:
|
||||
return "415";
|
||||
case 416:
|
||||
return "416";
|
||||
case 417:
|
||||
return "417";
|
||||
case 421:
|
||||
return "421";
|
||||
case 426:
|
||||
return "426";
|
||||
case 428:
|
||||
return "428";
|
||||
case 429:
|
||||
return "429";
|
||||
case 431:
|
||||
return "431";
|
||||
case 500:
|
||||
return "500";
|
||||
case 501:
|
||||
return "501";
|
||||
case 502:
|
||||
return "502";
|
||||
case 503:
|
||||
return "503";
|
||||
case 504:
|
||||
return "504";
|
||||
case 505:
|
||||
return "505";
|
||||
case 511:
|
||||
return "511";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void capitalize(DefaultMemchunks *buf, const std::string &s) {
|
||||
buf->append(util::upcase(s[0]));
|
||||
for (size_t i = 1; i < s.size(); ++i) {
|
||||
|
@ -207,17 +309,34 @@ bool non_empty_value(const Headers::value_type *nv) {
|
|||
return nv && !nv->value.empty();
|
||||
}
|
||||
|
||||
nghttp2_nv make_nv(const std::string &name, const std::string &value,
|
||||
bool no_index) {
|
||||
namespace {
|
||||
nghttp2_nv make_nv_internal(const std::string &name, const std::string &value,
|
||||
bool no_index, uint8_t nv_flags) {
|
||||
uint8_t flags;
|
||||
|
||||
flags = no_index ? NGHTTP2_NV_FLAG_NO_INDEX : NGHTTP2_NV_FLAG_NONE;
|
||||
flags =
|
||||
nv_flags | (no_index ? NGHTTP2_NV_FLAG_NO_INDEX : NGHTTP2_NV_FLAG_NONE);
|
||||
|
||||
return {(uint8_t *)name.c_str(), (uint8_t *)value.c_str(), name.size(),
|
||||
value.size(), flags};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void copy_headers_to_nva(std::vector<nghttp2_nv> &nva, const Headers &headers) {
|
||||
nghttp2_nv make_nv(const std::string &name, const std::string &value,
|
||||
bool no_index) {
|
||||
return make_nv_internal(name, value, no_index, NGHTTP2_NV_FLAG_NONE);
|
||||
}
|
||||
|
||||
nghttp2_nv make_nv_nocopy(const std::string &name, const std::string &value,
|
||||
bool no_index) {
|
||||
return make_nv_internal(name, value, no_index,
|
||||
NGHTTP2_NV_FLAG_NO_COPY_NAME |
|
||||
NGHTTP2_NV_FLAG_NO_COPY_VALUE);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void copy_headers_to_nva_internal(std::vector<nghttp2_nv> &nva,
|
||||
const Headers &headers, uint8_t nv_flags) {
|
||||
for (auto &kv : headers) {
|
||||
if (kv.name.empty() || kv.name[0] == ':') {
|
||||
continue;
|
||||
|
@ -238,9 +357,20 @@ void copy_headers_to_nva(std::vector<nghttp2_nv> &nva, const Headers &headers) {
|
|||
case HD_X_FORWARDED_PROTO:
|
||||
continue;
|
||||
}
|
||||
nva.push_back(make_nv(kv.name, kv.value, kv.no_index));
|
||||
nva.push_back(make_nv_internal(kv.name, kv.value, kv.no_index, nv_flags));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void copy_headers_to_nva(std::vector<nghttp2_nv> &nva, const Headers &headers) {
|
||||
copy_headers_to_nva_internal(nva, headers, NGHTTP2_NV_FLAG_NONE);
|
||||
}
|
||||
|
||||
void copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> &nva,
|
||||
const Headers &headers) {
|
||||
copy_headers_to_nva_internal(nva, headers, NGHTTP2_NV_FLAG_NO_COPY_NAME |
|
||||
NGHTTP2_NV_FLAG_NO_COPY_VALUE);
|
||||
}
|
||||
|
||||
void build_http1_headers_from_headers(DefaultMemchunks *buf,
|
||||
const Headers &headers) {
|
||||
|
|
30
src/http2.h
30
src/http2.h
|
@ -70,6 +70,10 @@ namespace http2 {
|
|||
|
||||
std::string get_status_string(unsigned int status_code);
|
||||
|
||||
// Returns string version of |status_code|. This function can handle
|
||||
// only predefined status code. Otherwise, returns nullptr.
|
||||
const char *stringify_status(unsigned int status_code);
|
||||
|
||||
void capitalize(DefaultMemchunks *buf, const std::string &s);
|
||||
|
||||
// Returns true if |value| is LWS
|
||||
|
@ -110,18 +114,27 @@ bool non_empty_value(const Headers::value_type *nv);
|
|||
nghttp2_nv make_nv(const std::string &name, const std::string &value,
|
||||
bool no_index = false);
|
||||
|
||||
nghttp2_nv make_nv_nocopy(const std::string &name, const std::string &value,
|
||||
bool no_index = false);
|
||||
|
||||
// Create nghttp2_nv from string literal |name| and |value|.
|
||||
template <size_t N, size_t M>
|
||||
constexpr nghttp2_nv make_nv_ll(const char (&name)[N], const char (&value)[M]) {
|
||||
return {(uint8_t *)name, (uint8_t *)value, N - 1, M - 1,
|
||||
NGHTTP2_NV_FLAG_NONE};
|
||||
NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
|
||||
}
|
||||
|
||||
// Create nghttp2_nv from string literal |name| and c-string |value|.
|
||||
template <size_t N>
|
||||
nghttp2_nv make_nv_lc(const char (&name)[N], const char *value) {
|
||||
return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
|
||||
NGHTTP2_NV_FLAG_NONE};
|
||||
NGHTTP2_NV_FLAG_NO_COPY_NAME};
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
nghttp2_nv make_nv_lc_nocopy(const char (&name)[N], const char *value) {
|
||||
return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
|
||||
NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
|
||||
}
|
||||
|
||||
// Create nghttp2_nv from string literal |name| and std::string
|
||||
|
@ -129,7 +142,13 @@ nghttp2_nv make_nv_lc(const char (&name)[N], const char *value) {
|
|||
template <size_t N>
|
||||
nghttp2_nv make_nv_ls(const char (&name)[N], const std::string &value) {
|
||||
return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
|
||||
NGHTTP2_NV_FLAG_NONE};
|
||||
NGHTTP2_NV_FLAG_NO_COPY_NAME};
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
nghttp2_nv make_nv_ls_nocopy(const char (&name)[N], const std::string &value) {
|
||||
return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
|
||||
NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE};
|
||||
}
|
||||
|
||||
// Appends headers in |headers| to |nv|. |headers| must be indexed
|
||||
|
@ -138,6 +157,11 @@ nghttp2_nv make_nv_ls(const char (&name)[N], const std::string &value) {
|
|||
// which require special handling (i.e. via), are not copied.
|
||||
void copy_headers_to_nva(std::vector<nghttp2_nv> &nva, const Headers &headers);
|
||||
|
||||
// Just like copy_headers_to_nva(), but this adds
|
||||
// NGHTTP2_NV_FLAG_NO_COPY_NAME and NGHTTP2_NV_FLAG_NO_COPY_VALUE.
|
||||
void copy_headers_to_nva_nocopy(std::vector<nghttp2_nv> &nva,
|
||||
const Headers &headers);
|
||||
|
||||
// Appends HTTP/1.1 style header lines to |buf| from headers in
|
||||
// |headers|. |headers| must be indexed before this call (its
|
||||
// element's token field is assigned). Certain headers, which
|
||||
|
|
|
@ -151,10 +151,26 @@ auto headers =
|
|||
} // namespace
|
||||
|
||||
void test_http2_copy_headers_to_nva(void) {
|
||||
auto ans = std::vector<int>{0, 1, 4, 5, 6, 7, 12};
|
||||
std::vector<nghttp2_nv> nva;
|
||||
|
||||
http2::copy_headers_to_nva_nocopy(nva, headers);
|
||||
CU_ASSERT(7 == nva.size());
|
||||
for (size_t i = 0; i < ans.size(); ++i) {
|
||||
check_nv(headers[ans[i]], &nva[i]);
|
||||
|
||||
if (ans[i] == 0) {
|
||||
CU_ASSERT((NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE |
|
||||
NGHTTP2_NV_FLAG_NO_INDEX) == nva[i].flags);
|
||||
} else {
|
||||
CU_ASSERT((NGHTTP2_NV_FLAG_NO_COPY_NAME |
|
||||
NGHTTP2_NV_FLAG_NO_COPY_VALUE) == nva[i].flags);
|
||||
}
|
||||
}
|
||||
|
||||
nva.clear();
|
||||
http2::copy_headers_to_nva(nva, headers);
|
||||
CU_ASSERT(7 == nva.size());
|
||||
auto ans = std::vector<int>{0, 1, 4, 5, 6, 7, 12};
|
||||
for (size_t i = 0; i < ans.size(); ++i) {
|
||||
check_nv(headers[ans[i]], &nva[i]);
|
||||
|
||||
|
|
|
@ -288,7 +288,12 @@ std::pair<std::string, std::string> parse_header(const char *optarg) {
|
|||
for (; *value == '\t' || *value == ' '; ++value)
|
||||
;
|
||||
|
||||
return {std::string(optarg, colon), std::string(value, strlen(value))};
|
||||
auto p = std::make_pair(std::string(optarg, colon),
|
||||
std::string(value, strlen(value)));
|
||||
util::inp_strlower(p.first);
|
||||
util::inp_strlower(p.second);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -277,8 +277,33 @@ void Downstream::assemble_request_cookie() {
|
|||
}
|
||||
}
|
||||
|
||||
Headers Downstream::crumble_request_cookie() {
|
||||
Headers cookie_hdrs;
|
||||
size_t Downstream::count_crumble_request_cookie() {
|
||||
size_t n = 0;
|
||||
for (auto &kv : request_headers_) {
|
||||
if (kv.name.size() != 6 || kv.name[5] != 'e' ||
|
||||
!util::streq_l("cooki", kv.name.c_str(), 5)) {
|
||||
continue;
|
||||
}
|
||||
size_t last = kv.value.size();
|
||||
|
||||
for (size_t j = 0; j < last;) {
|
||||
j = kv.value.find_first_not_of("\t ;", j);
|
||||
if (j == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
j = kv.value.find(';', j);
|
||||
if (j == std::string::npos) {
|
||||
j = last;
|
||||
}
|
||||
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void Downstream::crumble_request_cookie(std::vector<nghttp2_nv> &nva) {
|
||||
for (auto &kv : request_headers_) {
|
||||
if (kv.name.size() != 6 || kv.name[5] != 'e' ||
|
||||
!util::streq_l("cooki", kv.name.c_str(), 5)) {
|
||||
|
@ -298,11 +323,13 @@ Headers Downstream::crumble_request_cookie() {
|
|||
j = last;
|
||||
}
|
||||
|
||||
cookie_hdrs.push_back(
|
||||
Header("cookie", kv.value.substr(first, j - first), kv.no_index));
|
||||
nva.push_back({(uint8_t *)"cookie", (uint8_t *)kv.value.c_str() + first,
|
||||
str_size("cookie"), j - first,
|
||||
(uint8_t)(NGHTTP2_NV_FLAG_NO_COPY_NAME |
|
||||
NGHTTP2_NV_FLAG_NO_COPY_VALUE |
|
||||
(kv.no_index ? NGHTTP2_NV_FLAG_NO_INDEX : 0))});
|
||||
}
|
||||
}
|
||||
return cookie_hdrs;
|
||||
}
|
||||
|
||||
const std::string &Downstream::get_assembled_request_cookie() const {
|
||||
|
|
|
@ -97,9 +97,11 @@ public:
|
|||
// downstream request API
|
||||
const Headers &get_request_headers() const;
|
||||
Headers &get_request_headers();
|
||||
// Crumbles (split cookie by ";") in request_headers_ and returns
|
||||
// them. Headers::no_index is inherited.
|
||||
Headers crumble_request_cookie();
|
||||
// Count number of crumbled cookies
|
||||
size_t count_crumble_request_cookie();
|
||||
// Crumbles (split cookie by ";") in request_headers_ and adds them
|
||||
// in |nva|. Headers::no_index is inherited.
|
||||
void crumble_request_cookie(std::vector<nghttp2_nv> &nva);
|
||||
void assemble_request_cookie();
|
||||
const std::string &get_assembled_request_cookie() const;
|
||||
// Lower the request header field names and indexes request headers.
|
||||
|
|
|
@ -108,13 +108,29 @@ void test_downstream_crumble_request_cookie(void) {
|
|||
reinterpret_cast<const uint8_t *>(val), strlen(val), true, -1);
|
||||
d.add_request_header("cookie", ";delta");
|
||||
d.add_request_header("cookie", "echo");
|
||||
auto cookies = d.crumble_request_cookie();
|
||||
|
||||
std::vector<nghttp2_nv> nva;
|
||||
d.crumble_request_cookie(nva);
|
||||
|
||||
auto num_cookies = d.count_crumble_request_cookie();
|
||||
|
||||
CU_ASSERT(5 == nva.size());
|
||||
CU_ASSERT(5 == num_cookies);
|
||||
|
||||
Headers cookies;
|
||||
std::transform(std::begin(nva), std::end(nva), std::back_inserter(cookies),
|
||||
[](const nghttp2_nv &nv) {
|
||||
return Header(std::string(nv.name, nv.name + nv.namelen),
|
||||
std::string(nv.value, nv.value + nv.valuelen),
|
||||
nv.flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||
});
|
||||
|
||||
Headers ans = {{"cookie", "alpha"},
|
||||
{"cookie", "bravo"},
|
||||
{"cookie", "charlie"},
|
||||
{"cookie", "delta"},
|
||||
{"cookie", "echo"}};
|
||||
|
||||
CU_ASSERT(ans == cookies);
|
||||
CU_ASSERT(cookies[0].no_index);
|
||||
CU_ASSERT(cookies[1].no_index);
|
||||
|
|
|
@ -205,6 +205,8 @@ ssize_t http2_data_read_callback(nghttp2_session *session, int32_t stream_id,
|
|||
if (!trailers.empty()) {
|
||||
std::vector<nghttp2_nv> nva;
|
||||
nva.reserve(trailers.size());
|
||||
// We cannot use nocopy version, since nva may be touched after
|
||||
// Downstream object is deleted.
|
||||
http2::copy_headers_to_nva(nva, trailers);
|
||||
if (!nva.empty()) {
|
||||
rv = nghttp2_submit_trailer(session, stream_id, nva.data(), nva.size());
|
||||
|
@ -273,17 +275,13 @@ int Http2DownstreamConnection::push_request_headers() {
|
|||
authority = req_authority.c_str();
|
||||
}
|
||||
|
||||
if (!authority) {
|
||||
authority = downstream_hostport;
|
||||
}
|
||||
|
||||
downstream_->set_request_downstream_host(authority);
|
||||
|
||||
auto nheader = downstream_->get_request_headers().size();
|
||||
|
||||
Headers cookies;
|
||||
size_t num_cookies = 0;
|
||||
if (!get_config()->http2_no_cookie_crumbling) {
|
||||
cookies = downstream_->crumble_request_cookie();
|
||||
num_cookies = downstream_->count_crumble_request_cookie();
|
||||
}
|
||||
|
||||
// 8 means:
|
||||
|
@ -296,29 +294,30 @@ int Http2DownstreamConnection::push_request_headers() {
|
|||
// 7. x-forwarded-proto (optional)
|
||||
// 8. te (optional)
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(nheader + 8 + cookies.size() +
|
||||
nva.reserve(nheader + 8 + num_cookies +
|
||||
get_config()->add_request_headers.size());
|
||||
|
||||
nva.push_back(http2::make_nv_lc(":method", http2::to_method_string(method)));
|
||||
nva.push_back(
|
||||
http2::make_nv_lc_nocopy(":method", http2::to_method_string(method)));
|
||||
|
||||
auto &scheme = downstream_->get_request_http2_scheme();
|
||||
|
||||
nva.push_back(http2::make_nv_lc(":authority", authority));
|
||||
nva.push_back(http2::make_nv_lc_nocopy(":authority", authority));
|
||||
|
||||
if (method != HTTP_CONNECT) {
|
||||
assert(!scheme.empty());
|
||||
|
||||
nva.push_back(http2::make_nv_ls(":scheme", scheme));
|
||||
nva.push_back(http2::make_nv_ls_nocopy(":scheme", scheme));
|
||||
|
||||
auto &path = downstream_->get_request_path();
|
||||
if (method == HTTP_OPTIONS && path.empty()) {
|
||||
nva.push_back(http2::make_nv_ll(":path", "*"));
|
||||
} else {
|
||||
nva.push_back(http2::make_nv_ls(":path", path));
|
||||
nva.push_back(http2::make_nv_ls_nocopy(":path", path));
|
||||
}
|
||||
}
|
||||
|
||||
http2::copy_headers_to_nva(nva, downstream_->get_request_headers());
|
||||
http2::copy_headers_to_nva_nocopy(nva, downstream_->get_request_headers());
|
||||
|
||||
bool chunked_encoding = false;
|
||||
auto transfer_encoding =
|
||||
|
@ -328,8 +327,8 @@ int Http2DownstreamConnection::push_request_headers() {
|
|||
chunked_encoding = true;
|
||||
}
|
||||
|
||||
for (auto &nv : cookies) {
|
||||
nva.push_back(http2::make_nv(nv.name, nv.value, nv.no_index));
|
||||
if (!get_config()->http2_no_cookie_crumbling) {
|
||||
downstream_->crumble_request_cookie(nva);
|
||||
}
|
||||
|
||||
std::string xff_value;
|
||||
|
@ -343,20 +342,20 @@ int Http2DownstreamConnection::push_request_headers() {
|
|||
downstream_->get_upstream()->get_client_handler()->get_ipaddr();
|
||||
nva.push_back(http2::make_nv_ls("x-forwarded-for", xff_value));
|
||||
} else if (xff && !get_config()->strip_incoming_x_forwarded_for) {
|
||||
nva.push_back(http2::make_nv_ls("x-forwarded-for", (*xff).value));
|
||||
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-for", (*xff).value));
|
||||
}
|
||||
|
||||
if (!get_config()->http2_proxy && !get_config()->client_proxy &&
|
||||
downstream_->get_request_method() != HTTP_CONNECT) {
|
||||
// We use same protocol with :scheme header field
|
||||
nva.push_back(http2::make_nv_ls("x-forwarded-proto", scheme));
|
||||
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-proto", scheme));
|
||||
}
|
||||
|
||||
std::string via_value;
|
||||
auto via = downstream_->get_request_header(http2::HD_VIA);
|
||||
if (get_config()->no_via) {
|
||||
if (via) {
|
||||
nva.push_back(http2::make_nv_ls("via", (*via).value));
|
||||
nva.push_back(http2::make_nv_ls_nocopy("via", (*via).value));
|
||||
}
|
||||
} else {
|
||||
if (via) {
|
||||
|
@ -377,7 +376,7 @@ int Http2DownstreamConnection::push_request_headers() {
|
|||
}
|
||||
|
||||
for (auto &p : get_config()->add_request_headers) {
|
||||
nva.push_back(http2::make_nv(p.first, p.second));
|
||||
nva.push_back(http2::make_nv_nocopy(p.first, p.second));
|
||||
}
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
|
|
|
@ -1259,7 +1259,7 @@ ssize_t downstream_data_read_callback(nghttp2_session *session,
|
|||
if (!trailers.empty()) {
|
||||
std::vector<nghttp2_nv> nva;
|
||||
nva.reserve(trailers.size());
|
||||
http2::copy_headers_to_nva(nva, trailers);
|
||||
http2::copy_headers_to_nva_nocopy(nva, trailers);
|
||||
if (!nva.empty()) {
|
||||
rv = nghttp2_submit_trailer(session, stream_id, nva.data(),
|
||||
nva.size());
|
||||
|
@ -1295,13 +1295,20 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
|
|||
data_prd_ptr = &data_prd;
|
||||
}
|
||||
|
||||
auto status_code_str = util::utos(downstream->get_response_http_status());
|
||||
auto &headers = downstream->get_response_headers();
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
// 2 for :status and server
|
||||
nva.reserve(2 + headers.size());
|
||||
|
||||
nva.push_back(http2::make_nv_ls(":status", status_code_str));
|
||||
std::string status_code_str;
|
||||
auto response_status_const =
|
||||
http2::stringify_status(downstream->get_response_http_status());
|
||||
if (response_status_const) {
|
||||
nva.push_back(http2::make_nv_lc_nocopy(":status", response_status_const));
|
||||
} else {
|
||||
status_code_str = util::utos(downstream->get_response_http_status());
|
||||
nva.push_back(http2::make_nv_ls(":status", status_code_str));
|
||||
}
|
||||
|
||||
for (auto &kv : headers) {
|
||||
if (kv.name.empty() || kv.name[0] == ':') {
|
||||
|
@ -1316,11 +1323,12 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
|
|||
case http2::HD_UPGRADE:
|
||||
continue;
|
||||
}
|
||||
nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index));
|
||||
nva.push_back(http2::make_nv_nocopy(kv.name, kv.value, kv.no_index));
|
||||
}
|
||||
|
||||
if (!downstream->get_response_header(http2::HD_SERVER)) {
|
||||
nva.push_back(http2::make_nv_lc("server", get_config()->server_name));
|
||||
nva.push_back(
|
||||
http2::make_nv_lc_nocopy("server", get_config()->server_name));
|
||||
}
|
||||
|
||||
rv = nghttp2_submit_response(session_, downstream->get_stream_id(),
|
||||
|
@ -1356,14 +1364,20 @@ int Http2Upstream::error_reply(Downstream *downstream,
|
|||
auto lgconf = log_config();
|
||||
lgconf->update_tstamp(std::chrono::system_clock::now());
|
||||
|
||||
auto response_status_const = http2::stringify_status(status_code);
|
||||
auto content_length = util::utos(html.size());
|
||||
auto status_code_str = util::utos(status_code);
|
||||
auto nva =
|
||||
make_array(http2::make_nv_ls(":status", status_code_str),
|
||||
http2::make_nv_ll("content-type", "text/html; charset=UTF-8"),
|
||||
http2::make_nv_lc("server", get_config()->server_name),
|
||||
http2::make_nv_ls("content-length", content_length),
|
||||
http2::make_nv_ls("date", lgconf->time_http_str));
|
||||
|
||||
std::string status_code_str;
|
||||
|
||||
auto nva = make_array(
|
||||
response_status_const
|
||||
? http2::make_nv_lc_nocopy(":status", response_status_const)
|
||||
: http2::make_nv_ls(":status",
|
||||
(status_code_str = util::utos(status_code))),
|
||||
http2::make_nv_ll("content-type", "text/html; charset=UTF-8"),
|
||||
http2::make_nv_lc_nocopy("server", get_config()->server_name),
|
||||
http2::make_nv_ls("content-length", content_length),
|
||||
http2::make_nv_ls("date", lgconf->time_http_str));
|
||||
|
||||
rv = nghttp2_submit_response(session_, downstream->get_stream_id(),
|
||||
nva.data(), nva.size(), &data_prd);
|
||||
|
@ -1445,10 +1459,18 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
|||
// field.
|
||||
nva.reserve(nheader + 4 + get_config()->add_response_headers.size());
|
||||
std::string via_value;
|
||||
auto response_status = util::utos(downstream->get_response_http_status());
|
||||
nva.push_back(http2::make_nv_ls(":status", response_status));
|
||||
std::string response_status;
|
||||
|
||||
http2::copy_headers_to_nva(nva, downstream->get_response_headers());
|
||||
auto response_status_const =
|
||||
http2::stringify_status(downstream->get_response_http_status());
|
||||
if (response_status_const) {
|
||||
nva.push_back(http2::make_nv_lc_nocopy(":status", response_status_const));
|
||||
} else {
|
||||
response_status = util::utos(downstream->get_response_http_status());
|
||||
nva.push_back(http2::make_nv_ls(":status", response_status));
|
||||
}
|
||||
|
||||
http2::copy_headers_to_nva_nocopy(nva, downstream->get_response_headers());
|
||||
|
||||
if (downstream->get_non_final_response()) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
|
@ -1470,18 +1492,19 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
|||
}
|
||||
|
||||
if (!get_config()->http2_proxy && !get_config()->client_proxy) {
|
||||
nva.push_back(http2::make_nv_lc("server", get_config()->server_name));
|
||||
nva.push_back(
|
||||
http2::make_nv_lc_nocopy("server", get_config()->server_name));
|
||||
} else {
|
||||
auto server = downstream->get_response_header(http2::HD_SERVER);
|
||||
if (server) {
|
||||
nva.push_back(http2::make_nv_ls("server", (*server).value));
|
||||
nva.push_back(http2::make_nv_ls_nocopy("server", (*server).value));
|
||||
}
|
||||
}
|
||||
|
||||
auto via = downstream->get_response_header(http2::HD_VIA);
|
||||
if (get_config()->no_via) {
|
||||
if (via) {
|
||||
nva.push_back(http2::make_nv_ls("via", (*via).value));
|
||||
nva.push_back(http2::make_nv_ls_nocopy("via", (*via).value));
|
||||
}
|
||||
} else {
|
||||
if (via) {
|
||||
|
@ -1494,7 +1517,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
|||
}
|
||||
|
||||
for (auto &p : get_config()->add_response_headers) {
|
||||
nva.push_back(http2::make_nv(p.first, p.second));
|
||||
nva.push_back(http2::make_nv_nocopy(p.first, p.second));
|
||||
}
|
||||
|
||||
if (downstream->get_stream_id() % 2 == 0) {
|
||||
|
@ -1797,7 +1820,7 @@ int Http2Upstream::submit_push_promise(const std::string &scheme,
|
|||
case http2::HD_CACHE_CONTROL:
|
||||
case http2::HD_HOST:
|
||||
case http2::HD_USER_AGENT:
|
||||
nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index));
|
||||
nva.push_back(http2::make_nv_nocopy(kv.name, kv.value, kv.no_index));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue