Line data Source code
1 : #include "source/common/http/mixed_conn_pool.h" 2 : 3 : #include "source/common/http/codec_client.h" 4 : #include "source/common/http/http1/conn_pool.h" 5 : #include "source/common/http/http2/conn_pool.h" 6 : #include "source/common/http/utility.h" 7 : #include "source/common/runtime/runtime_features.h" 8 : #include "source/common/tcp/conn_pool.h" 9 : 10 : namespace Envoy { 11 : namespace Http { 12 : 13 0 : Envoy::ConnectionPool::ActiveClientPtr HttpConnPoolImplMixed::instantiateActiveClient() { 14 0 : uint32_t initial_streams = Http2::ActiveClient::calculateInitialStreamsLimit( 15 0 : http_server_properties_cache_, origin_, host()); 16 0 : return std::make_unique<Tcp::ActiveTcpClient>( 17 0 : *this, Envoy::ConnectionPool::ConnPoolImplBase::host(), initial_streams, absl::nullopt); 18 0 : } 19 : 20 : CodecClientPtr 21 0 : HttpConnPoolImplMixed::createCodecClient(Upstream::Host::CreateConnectionData& data) { 22 0 : auto protocol = protocol_ == Protocol::Http11 ? CodecType::HTTP1 : CodecType::HTTP2; 23 0 : CodecClientPtr codec{new CodecClientProd(protocol, std::move(data.connection_), 24 0 : data.host_description_, dispatcher_, random_generator_, 25 0 : transportSocketOptions())}; 26 0 : return codec; 27 0 : } 28 : 29 0 : void HttpConnPoolImplMixed::onConnected(Envoy::ConnectionPool::ActiveClient& client) { 30 : // onConnected is called under the stack of the Network::Connection raising 31 : // the Connected event. The first time it is called, it's called for a TCP 32 : // client, the TCP client is detached from the connection and discarded, and an 33 : // HTTP client is associated with that connection. When the first call returns, the 34 : // Network::Connection will inform the new callback (the HTTP client) that it 35 : // is connected. The early return is to ignore that second call. 36 0 : if (client.protocol() != absl::nullopt) { 37 0 : return; 38 0 : } 39 : 40 : // If an old TLS stack does not negotiate alpn, it likely does not support 41 : // HTTP/2. Fail over to HTTP/1. 42 0 : protocol_ = Protocol::Http11; 43 0 : ASSERT(dynamic_cast<Tcp::ActiveTcpClient*>(&client) != nullptr); 44 0 : auto tcp_client = static_cast<Tcp::ActiveTcpClient*>(&client); 45 0 : std::string alpn = tcp_client->connection_->nextProtocol(); 46 0 : if (!alpn.empty()) { 47 0 : if (alpn == Http::Utility::AlpnNames::get().Http11) { 48 0 : protocol_ = Http::Protocol::Http11; 49 0 : } else if (alpn == Http::Utility::AlpnNames::get().Http2) { 50 0 : protocol_ = Http::Protocol::Http2; 51 0 : } 52 0 : } 53 : 54 0 : uint32_t old_effective_limit = client.effectiveConcurrentStreamLimit(); 55 0 : if (protocol_ == Http::Protocol::Http11 && client.concurrent_stream_limit_ != 1) { 56 : // The estimates were all based on assuming HTTP/2 would be negotiated. Adjust down. 57 0 : uint32_t delta = client.concurrent_stream_limit_ - 1; 58 0 : client.concurrent_stream_limit_ = 1; 59 0 : decrConnectingAndConnectedStreamCapacity(delta, client); 60 0 : if (http_server_properties_cache_ && origin_.has_value()) { 61 0 : http_server_properties_cache_->setConcurrentStreams(origin_.value(), 1); 62 0 : } 63 0 : } 64 : 65 0 : Upstream::Host::CreateConnectionData data{std::move(tcp_client->connection_), 66 0 : client.real_host_description_}; 67 : // As this connection comes from the tcp connection pool, it will be 68 : // read-disabled to handle TCP traffic where upstream sends data first. Undo 69 : // this as it is not necessary for HTTP/HTTPS. 70 0 : data.connection_->readDisable(false); 71 0 : data.connection_->removeConnectionCallbacks(*tcp_client); 72 0 : data.connection_->removeReadFilter(tcp_client->read_filter_handle_); 73 0 : dispatcher_.deferredDelete(client.removeFromList(owningList(client.state()))); 74 : 75 0 : std::unique_ptr<ActiveClient> new_client; 76 0 : if (protocol_ == Http::Protocol::Http11) { 77 0 : new_client = std::make_unique<Http1::ActiveClient>(*this, data); 78 0 : } else { 79 0 : new_client = std::make_unique<Http2::ActiveClient>(*this, data); 80 0 : } 81 : // When we switch from TCP to HTTP clients, the base class onConnectionEvent 82 : // will be called for both, so add to the connecting stream capacity to 83 : // balance it being decremented. 84 0 : connecting_stream_capacity_ += new_client->effectiveConcurrentStreamLimit(); 85 : // The global capacity is not adjusted in onConnectionEvent, so simply update 86 : // it to reflect any difference between the TCP stream limits and HTTP/2 87 : // stream limits. 88 0 : if (new_client->effectiveConcurrentStreamLimit() > old_effective_limit) { 89 0 : state_.incrConnectingAndConnectedStreamCapacity(new_client->effectiveConcurrentStreamLimit() - 90 0 : old_effective_limit); 91 0 : } 92 0 : new_client->setState(ActiveClient::State::Connecting); 93 0 : LinkedList::moveIntoList(std::move(new_client), owningList(new_client->state())); 94 0 : } 95 : 96 : } // namespace Http 97 : } // namespace Envoy