nghttpx: Fix bug that altered authority and path affect backend selection

Fix bug that altered authority and path by per-pattern mruby script
affect backend selection on retry.
This commit is contained in:
Tatsuhiro Tsujikawa 2019-04-16 21:31:32 +09:00
parent 5a30fafdda
commit a35059e3f1
2 changed files with 33 additions and 8 deletions

View File

@ -893,7 +893,7 @@ ClientHandler::get_downstream_connection(int &err, Downstream *downstream) {
auto catch_all = downstreamconf.addr_group_catch_all;
auto &groups = worker_->get_downstream_addr_groups();
const auto &req = downstream->request();
auto &req = downstream->request();
err = 0;
@ -908,11 +908,14 @@ ClientHandler::get_downstream_connection(int &err, Downstream *downstream) {
auto &balloc = downstream->get_block_allocator();
// Fast path. If we have one group, it must be catch-all group.
if (groups.size() == 1) {
group_idx = 0;
StringRef authority, path;
if (req.forwarded_once) {
if (groups.size() != 1) {
authority = req.orig_authority;
path = req.orig_path;
}
} else {
StringRef authority;
if (faddr_->sni_fwd) {
authority = sni_;
} else if (!req.authority.empty()) {
@ -924,13 +927,24 @@ ClientHandler::get_downstream_connection(int &err, Downstream *downstream) {
}
}
StringRef path;
// CONNECT method does not have path. But we requires path in
// host-path mapping. As workaround, we assume that path is "/".
// host-path mapping. As workaround, we assume that path is
// "/".
if (!req.regular_connect_method()) {
path = req.path;
}
// Cache the authority and path used for the first-time backend
// selection because per-pattern mruby script can change them.
req.orig_authority = authority;
req.orig_path = path;
req.forwarded_once = true;
}
// Fast path. If we have one group, it must be catch-all group.
if (groups.size() == 1) {
group_idx = 0;
} else {
group_idx = match_downstream_addr_group(routerconf, authority, path, groups,
catch_all, balloc);
}

View File

@ -153,7 +153,8 @@ struct Request {
http2_upgrade_seen(false),
connection_close(false),
http2_expect_body(false),
no_authority(false) {}
no_authority(false),
forwarded_once(false) {}
void consume(size_t len) {
assert(unconsumed_body_length >= len);
@ -184,6 +185,12 @@ struct Request {
// request-target. For HTTP/2, this is :path header field value.
// For CONNECT request, this is empty.
StringRef path;
// This is original authority which cannot be changed by per-pattern
// mruby script.
StringRef orig_authority;
// This is original path which cannot be changed by per-pattern
// mruby script.
StringRef orig_path;
// the length of request body received so far
int64_t recv_body_length;
// The number of bytes not consumed by the application yet.
@ -209,6 +216,10 @@ struct Request {
// This happens when: For HTTP/2 request, :authority is missing.
// For HTTP/1 request, origin or asterisk form is used.
bool no_authority;
// true if backend selection is done for request once.
// orig_authority and orig_path have the authority and path which
// are used for the first backend selection.
bool forwarded_once;
};
struct Response {