diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index ea8cea16..472db835 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -938,7 +938,8 @@ uint32_t ClientHandler::get_affinity_cookie(Downstream *downstream, } std::unique_ptr -ClientHandler::get_downstream_connection(int &err, Downstream *downstream) { +ClientHandler::get_downstream_connection(int &err, Downstream *downstream, + shrpx_proto pref_proto) { size_t group_idx; auto &downstreamconf = *worker_->get_downstream_config(); auto &routerconf = downstreamconf.router; @@ -1041,7 +1042,8 @@ ClientHandler::get_downstream_connection(int &err, Downstream *downstream) { i = 0; } addr = &shared_addr->addrs[shared_addr->affinity_hash[i].idx]; - if (addr->connect_blocker->blocked()) { + if (addr->connect_blocker->blocked() || + (pref_proto != PROTO_NONE && pref_proto != addr->proto)) { continue; } break; @@ -1081,7 +1083,15 @@ ClientHandler::get_downstream_connection(int &err, Downstream *downstream) { auto proto = PROTO_NONE; - if (http1_weight > 0 && http2_weight > 0) { + if (pref_proto == PROTO_HTTP1) { + if (http1_weight > 0) { + proto = PROTO_HTTP1; + } + } else if (pref_proto == PROTO_HTTP2) { + if (http2_weight > 0) { + proto = PROTO_HTTP2; + } + } else if (http1_weight > 0 && http2_weight > 0) { // We only advance cycle if both weight has nonzero to keep its // distance under WEIGHT_MAX. if (pri_less(shared_addr->http1_pri, shared_addr->http2_pri)) { diff --git a/src/shrpx_client_handler.h b/src/shrpx_client_handler.h index 8d4073b7..9e1153bd 100644 --- a/src/shrpx_client_handler.h +++ b/src/shrpx_client_handler.h @@ -102,9 +102,11 @@ public: // Returns DownstreamConnection object based on request path. This // function returns non-null DownstreamConnection, and assigns 0 to // |err| if it succeeds, or returns nullptr, and assigns negative - // error code to |err|. + // error code to |err|. If |pref_proto| is not PROTO_NONE, choose + // backend whose protocol is |pref_proto|. std::unique_ptr - get_downstream_connection(int &err, Downstream *downstream); + get_downstream_connection(int &err, Downstream *downstream, + shrpx_proto pref_proto = PROTO_NONE); MemchunkPool *get_mcpool(); SSL *get_ssl() const; // Call this function when HTTP/2 connection header is received at diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index 0bcc41ad..29f01791 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -87,7 +87,11 @@ void retry_downstream_connection(Downstream *downstream, downstream->pop_downstream_connection(); int rv; - auto ndconn = handler->get_downstream_connection(rv, downstream); + // We have to use h1 backend for retry if we have already written h1 + // request in request buffer. + auto ndconn = handler->get_downstream_connection( + rv, downstream, + downstream->get_request_header_sent() ? PROTO_HTTP1 : PROTO_NONE); if (ndconn) { if (downstream->attach_downstream_connection(std::move(ndconn)) == 0 && downstream->push_request_headers() == 0) {