LCOV - code coverage report
Current view: top level - source/extensions/transport_sockets/http_11_proxy - connect.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 108 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 10 0.0 %

          Line data    Source code
       1             : #include "source/extensions/transport_sockets/http_11_proxy/connect.h"
       2             : 
       3             : #include <sstream>
       4             : 
       5             : #include "envoy/network/transport_socket.h"
       6             : 
       7             : #include "source/common/buffer/buffer_impl.h"
       8             : #include "source/common/common/scalar_to_byte_vector.h"
       9             : #include "source/common/common/utility.h"
      10             : #include "source/common/network/address_impl.h"
      11             : #include "source/common/runtime/runtime_features.h"
      12             : 
      13             : namespace Envoy {
      14             : namespace Extensions {
      15             : namespace TransportSockets {
      16             : namespace Http11Connect {
      17             : 
      18             : bool UpstreamHttp11ConnectSocket::isValidConnectResponse(absl::string_view response_payload,
      19             :                                                          bool& headers_complete,
      20           0 :                                                          size_t& bytes_processed) {
      21           0 :   SelfContainedParser parser;
      22             : 
      23           0 :   bytes_processed = parser.parser().execute(response_payload.data(), response_payload.length());
      24           0 :   headers_complete = parser.headersComplete();
      25             : 
      26           0 :   return parser.parser().getStatus() != Http::Http1::ParserStatus::Error &&
      27           0 :          parser.headersComplete() && parser.parser().statusCode() == Http::Code::OK;
      28           0 : }
      29             : 
      30             : UpstreamHttp11ConnectSocket::UpstreamHttp11ConnectSocket(
      31             :     Network::TransportSocketPtr&& transport_socket,
      32             :     Network::TransportSocketOptionsConstSharedPtr options)
      33           0 :     : PassthroughSocket(std::move(transport_socket)), options_(options) {
      34           0 :   if (options_ && options_->http11ProxyInfo() && transport_socket_->ssl()) {
      35           0 :     header_buffer_.add(
      36           0 :         absl::StrCat("CONNECT ", options_->http11ProxyInfo()->hostname, ":443 HTTP/1.1\r\n\r\n"));
      37           0 :     need_to_strip_connect_response_ = true;
      38           0 :   }
      39           0 : }
      40             : 
      41             : void UpstreamHttp11ConnectSocket::setTransportSocketCallbacks(
      42           0 :     Network::TransportSocketCallbacks& callbacks) {
      43           0 :   transport_socket_->setTransportSocketCallbacks(callbacks);
      44           0 :   callbacks_ = &callbacks;
      45           0 : }
      46             : 
      47           0 : Network::IoResult UpstreamHttp11ConnectSocket::doWrite(Buffer::Instance& buffer, bool end_stream) {
      48           0 :   if (header_buffer_.length() > 0) {
      49           0 :     return writeHeader();
      50           0 :   }
      51           0 :   if (!need_to_strip_connect_response_) {
      52             :     // Don't pass events up until the connect response is read because TLS reads
      53             :     // kick off writes which don't pass through the transport socket.
      54           0 :     return transport_socket_->doWrite(buffer, end_stream);
      55           0 :   }
      56           0 :   return Network::IoResult{Network::PostIoAction::KeepOpen, 0, false};
      57           0 : }
      58             : 
      59           0 : Network::IoResult UpstreamHttp11ConnectSocket::doRead(Buffer::Instance& buffer) {
      60           0 :   if (need_to_strip_connect_response_) {
      61             :     // Limit the CONNECT response headers to an arbitrary 2000 bytes.
      62           0 :     constexpr uint32_t MAX_RESPONSE_HEADER_SIZE = 2000;
      63           0 :     char peek_buf[MAX_RESPONSE_HEADER_SIZE];
      64           0 :     Api::IoCallUint64Result result =
      65           0 :         callbacks_->ioHandle().recv(peek_buf, MAX_RESPONSE_HEADER_SIZE, MSG_PEEK);
      66           0 :     if (!result.ok() && result.err_->getErrorCode() != Api::IoError::IoErrorCode::Again) {
      67           0 :       return {Network::PostIoAction::Close, 0, false};
      68           0 :     }
      69           0 :     absl::string_view peek_data(peek_buf, result.return_value_);
      70           0 :     size_t bytes_processed = 0;
      71           0 :     bool headers_complete = false;
      72           0 :     bool is_valid_connect_response =
      73           0 :         isValidConnectResponse(peek_data, headers_complete, bytes_processed);
      74             : 
      75           0 :     if (!headers_complete) {
      76           0 :       if (peek_data.size() == MAX_RESPONSE_HEADER_SIZE) {
      77           0 :         ENVOY_CONN_LOG(trace, "failed to receive CONNECT headers within {} bytes",
      78           0 :                        callbacks_->connection(), MAX_RESPONSE_HEADER_SIZE);
      79           0 :         return {Network::PostIoAction::Close, 0, false};
      80           0 :       }
      81           0 :       ENVOY_CONN_LOG(trace, "Incomplete CONNECT header: {} bytes received",
      82           0 :                      callbacks_->connection(), peek_data.size());
      83           0 :       return Network::IoResult{Network::PostIoAction::KeepOpen, 0, false};
      84           0 :     }
      85           0 :     if (!is_valid_connect_response) {
      86           0 :       ENVOY_CONN_LOG(trace, "Response does not appear to be a successful CONNECT upgrade",
      87           0 :                      callbacks_->connection());
      88           0 :       return {Network::PostIoAction::Close, 0, false};
      89           0 :     }
      90             : 
      91           0 :     result = callbacks_->ioHandle().read(buffer, bytes_processed);
      92           0 :     if (!result.ok() || result.return_value_ != bytes_processed) {
      93           0 :       ENVOY_CONN_LOG(trace, "failed to drain CONNECT header", callbacks_->connection());
      94           0 :       return {Network::PostIoAction::Close, 0, false};
      95           0 :     }
      96           0 :     buffer.drain(bytes_processed);
      97             : 
      98           0 :     ENVOY_CONN_LOG(trace, "Successfully stripped {} bytes of CONNECT header",
      99           0 :                    callbacks_->connection(), bytes_processed);
     100           0 :     need_to_strip_connect_response_ = false;
     101           0 :   }
     102           0 :   return transport_socket_->doRead(buffer);
     103           0 : }
     104             : 
     105           0 : Network::IoResult UpstreamHttp11ConnectSocket::writeHeader() {
     106           0 :   Network::PostIoAction action = Network::PostIoAction::KeepOpen;
     107           0 :   uint64_t bytes_written = 0;
     108           0 :   do {
     109           0 :     if (header_buffer_.length() == 0) {
     110           0 :       break;
     111           0 :     }
     112             : 
     113           0 :     Api::IoCallUint64Result result = callbacks_->ioHandle().write(header_buffer_);
     114             : 
     115           0 :     if (!result.ok()) {
     116           0 :       ENVOY_CONN_LOG(trace, "Failed writing CONNECT header. write error: {}",
     117           0 :                      callbacks_->connection(), result.err_->getErrorDetails());
     118           0 :       if (result.err_->getErrorCode() != Api::IoError::IoErrorCode::Again) {
     119           0 :         action = Network::PostIoAction::Close;
     120           0 :       }
     121           0 :       break;
     122           0 :     }
     123           0 :     ENVOY_CONN_LOG(trace, "Writing CONNECT header. write returned: {}", callbacks_->connection(),
     124           0 :                    result.return_value_);
     125           0 :     bytes_written += result.return_value_;
     126           0 :   } while (true);
     127             : 
     128           0 :   return {action, bytes_written, false};
     129           0 : }
     130             : 
     131             : UpstreamHttp11ConnectSocketFactory::UpstreamHttp11ConnectSocketFactory(
     132             :     Network::UpstreamTransportSocketFactoryPtr transport_socket_factory)
     133           0 :     : PassthroughFactory(std::move(transport_socket_factory)) {}
     134             : 
     135             : Network::TransportSocketPtr UpstreamHttp11ConnectSocketFactory::createTransportSocket(
     136             :     Network::TransportSocketOptionsConstSharedPtr options,
     137           0 :     std::shared_ptr<const Upstream::HostDescription> host) const {
     138           0 :   auto inner_socket = transport_socket_factory_->createTransportSocket(options, host);
     139           0 :   if (inner_socket == nullptr) {
     140           0 :     return nullptr;
     141           0 :   }
     142           0 :   return std::make_unique<UpstreamHttp11ConnectSocket>(std::move(inner_socket), options);
     143           0 : }
     144             : 
     145             : void UpstreamHttp11ConnectSocketFactory::hashKey(
     146           0 :     std::vector<uint8_t>& key, Network::TransportSocketOptionsConstSharedPtr options) const {
     147           0 :   PassthroughFactory::hashKey(key, options);
     148           0 :   if (options && options->http11ProxyInfo().has_value()) {
     149           0 :     pushScalarToByteVector(
     150           0 :         StringUtil::CaseInsensitiveHash()(options->http11ProxyInfo()->proxy_address->asString()),
     151           0 :         key);
     152           0 :     pushScalarToByteVector(StringUtil::CaseInsensitiveHash()(options->http11ProxyInfo()->hostname),
     153           0 :                            key);
     154           0 :   }
     155           0 : }
     156             : 
     157             : } // namespace Http11Connect
     158             : } // namespace TransportSockets
     159             : } // namespace Extensions
     160             : } // namespace Envoy

Generated by: LCOV version 1.15