LCOV - code coverage report
Current view: top level - source/common/quic - envoy_quic_utils.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 20 61 32.8 %
Date: 2024-01-05 06:35:25 Functions: 2 5 40.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "envoy/common/platform.h"
       4             : #include "envoy/config/listener/v3/quic_config.pb.h"
       5             : #include "envoy/http/codec.h"
       6             : 
       7             : #include "source/common/common/assert.h"
       8             : #include "source/common/http/header_map_impl.h"
       9             : #include "source/common/http/header_utility.h"
      10             : #include "source/common/network/address_impl.h"
      11             : #include "source/common/network/connection_socket_impl.h"
      12             : #include "source/common/quic/quic_io_handle_wrapper.h"
      13             : 
      14             : #include "openssl/ssl.h"
      15             : #include "quiche/quic/core/http/quic_header_list.h"
      16             : #include "quiche/quic/core/quic_config.h"
      17             : #include "quiche/quic/core/quic_error_codes.h"
      18             : #include "quiche/quic/core/quic_types.h"
      19             : #include "quiche/quic/platform/api/quic_ip_address.h"
      20             : #include "quiche/quic/platform/api/quic_socket_address.h"
      21             : #include "quiche/spdy/core/http2_header_block.h"
      22             : 
      23             : namespace Envoy {
      24             : namespace Quic {
      25             : 
      26             : // Changes or additions to details should be reflected in
      27             : // docs/root/configuration/http/http_conn_man/response_code_details.rst
      28             : class Http3ResponseCodeDetailValues {
      29             : public:
      30             :   // Invalid HTTP header field was received and stream is going to be
      31             :   // closed.
      32             :   static constexpr absl::string_view invalid_http_header = "http3.invalid_header_field";
      33             :   // The size of headers (or trailers) exceeded the configured limits.
      34             :   static constexpr absl::string_view headers_too_large = "http3.headers_too_large";
      35             :   // Envoy was configured to drop requests with header keys beginning with underscores.
      36             :   static constexpr absl::string_view invalid_underscore = "http3.unexpected_underscore";
      37             :   // The peer refused the stream.
      38             :   static constexpr absl::string_view remote_refused = "http3.remote_refuse";
      39             :   // The peer reset the stream.
      40             :   static constexpr absl::string_view remote_reset = "http3.remote_reset";
      41             :   // Too many trailers were sent.
      42             :   static constexpr absl::string_view too_many_trailers = "http3.too_many_trailers";
      43             :   // Too many headers were sent.
      44             :   static constexpr absl::string_view too_many_headers = "http3.too_many_headers";
      45             :   // The payload size is different from what the content-length header indicated.
      46             :   static constexpr absl::string_view inconsistent_content_length =
      47             :       "http3.inconsistent_content_length";
      48             : };
      49             : 
      50             : // TODO(danzh): this is called on each write. Consider to return an address instance on the stack if
      51             : // the heap allocation is too expensive.
      52             : Network::Address::InstanceConstSharedPtr
      53             : quicAddressToEnvoyAddressInstance(const quic::QuicSocketAddress& quic_address);
      54             : 
      55             : quic::QuicSocketAddress envoyIpAddressToQuicSocketAddress(const Network::Address::Ip* envoy_ip);
      56             : 
      57             : class HeaderValidator {
      58             : public:
      59         232 :   virtual ~HeaderValidator() = default;
      60             :   virtual Http::HeaderUtility::HeaderValidationResult
      61             :   validateHeader(absl::string_view name, absl::string_view header_value) = 0;
      62             : };
      63             : 
      64             : // The returned header map has all keys in lower case.
      65             : template <class T>
      66             : std::unique_ptr<T>
      67             : quicHeadersToEnvoyHeaders(const quic::QuicHeaderList& header_list, HeaderValidator& validator,
      68             :                           uint32_t max_headers_kb, uint32_t max_headers_allowed,
      69           2 :                           absl::string_view& details, quic::QuicRstStreamErrorCode& rst) {
      70           2 :   auto headers = T::create(max_headers_kb, max_headers_allowed);
      71          20 :   for (const auto& entry : header_list) {
      72          20 :     if (max_headers_allowed == 0) {
      73           0 :       details = Http3ResponseCodeDetailValues::too_many_headers;
      74           0 :       rst = quic::QUIC_STREAM_EXCESSIVE_LOAD;
      75           0 :       return nullptr;
      76           0 :     }
      77          20 :     max_headers_allowed--;
      78          20 :     Http::HeaderUtility::HeaderValidationResult result =
      79          20 :         validator.validateHeader(entry.first, entry.second);
      80          20 :     switch (result) {
      81           2 :     case Http::HeaderUtility::HeaderValidationResult::REJECT:
      82           2 :       rst = quic::QUIC_BAD_APPLICATION_PAYLOAD;
      83             :       // The validator sets the details to Http3ResponseCodeDetailValues::invalid_underscore
      84           2 :       return nullptr;
      85           0 :     case Http::HeaderUtility::HeaderValidationResult::DROP:
      86           0 :       continue;
      87          18 :     case Http::HeaderUtility::HeaderValidationResult::ACCEPT:
      88          18 :       auto key = Http::LowerCaseString(entry.first);
      89          18 :       if (key != Http::Headers::get().Cookie) {
      90             :         // TODO(danzh): Avoid copy by referencing entry as header_list is already validated by QUIC.
      91          18 :         headers->addCopy(key, entry.second);
      92          18 :       } else {
      93             :         // QUICHE breaks "cookie" header into crumbs. Coalesce them by appending current one to
      94             :         // existing one if there is any.
      95           0 :         headers->appendCopy(key, entry.second);
      96           0 :       }
      97          20 :     }
      98          20 :   }
      99           0 :   return headers;
     100           2 : }
     101             : 
     102             : template <class T>
     103             : std::unique_ptr<T>
     104             : http2HeaderBlockToEnvoyTrailers(const spdy::Http2HeaderBlock& header_block, uint32_t max_headers_kb,
     105             :                                 uint32_t max_headers_allowed, HeaderValidator& validator,
     106           0 :                                 absl::string_view& details, quic::QuicRstStreamErrorCode& rst) {
     107           0 :   auto headers = T::create(max_headers_kb, max_headers_allowed);
     108           0 :   if (header_block.size() > max_headers_allowed) {
     109           0 :     details = Http3ResponseCodeDetailValues::too_many_trailers;
     110           0 :     rst = quic::QUIC_STREAM_EXCESSIVE_LOAD;
     111           0 :     return nullptr;
     112           0 :   }
     113           0 :   for (auto entry : header_block) {
     114             :     // TODO(danzh): Avoid temporary strings and addCopy() with string_view.
     115           0 :     std::string key(entry.first);
     116             :     // QUICHE coalesces multiple trailer values with the same key with '\0'.
     117           0 :     std::vector<absl::string_view> values = absl::StrSplit(entry.second, '\0');
     118           0 :     for (const absl::string_view& value : values) {
     119           0 :       if (max_headers_allowed == 0) {
     120           0 :         details = Http3ResponseCodeDetailValues::too_many_trailers;
     121           0 :         rst = quic::QUIC_STREAM_EXCESSIVE_LOAD;
     122           0 :         return nullptr;
     123           0 :       }
     124           0 :       max_headers_allowed--;
     125           0 :       Http::HeaderUtility::HeaderValidationResult result =
     126           0 :           validator.validateHeader(entry.first, value);
     127           0 :       switch (result) {
     128           0 :       case Http::HeaderUtility::HeaderValidationResult::REJECT:
     129           0 :         rst = quic::QUIC_BAD_APPLICATION_PAYLOAD;
     130           0 :         return nullptr;
     131           0 :       case Http::HeaderUtility::HeaderValidationResult::DROP:
     132           0 :         continue;
     133           0 :       case Http::HeaderUtility::HeaderValidationResult::ACCEPT:
     134           0 :         headers->addCopy(Http::LowerCaseString(key), value);
     135           0 :       }
     136           0 :     }
     137           0 :   }
     138           0 :   return headers;
     139           0 : }
     140             : 
     141             : spdy::Http2HeaderBlock envoyHeadersToHttp2HeaderBlock(const Http::HeaderMap& headers);
     142             : 
     143             : // Called when Envoy wants to reset the underlying QUIC stream.
     144             : quic::QuicRstStreamErrorCode envoyResetReasonToQuicRstError(Http::StreamResetReason reason);
     145             : 
     146             : // Called when a RST_STREAM frame is received.
     147             : Http::StreamResetReason quicRstErrorToEnvoyLocalResetReason(quic::QuicRstStreamErrorCode rst_err);
     148             : 
     149             : // Called when a QUIC stack reset the stream.
     150             : Http::StreamResetReason quicRstErrorToEnvoyRemoteResetReason(quic::QuicRstStreamErrorCode rst_err);
     151             : 
     152             : // Called when underlying QUIC connection is closed locally.
     153             : Http::StreamResetReason quicErrorCodeToEnvoyLocalResetReason(quic::QuicErrorCode error,
     154             :                                                              bool connected);
     155             : 
     156             : // Called when underlying QUIC connection is closed by peer.
     157             : Http::StreamResetReason quicErrorCodeToEnvoyRemoteResetReason(quic::QuicErrorCode error);
     158             : 
     159             : // Create a connection socket instance and apply given socket options to the
     160             : // socket. IP_PKTINFO and SO_RXQ_OVFL is always set if supported.
     161             : Network::ConnectionSocketPtr
     162             : createConnectionSocket(const Network::Address::InstanceConstSharedPtr& peer_addr,
     163             :                        Network::Address::InstanceConstSharedPtr& local_addr,
     164             :                        const Network::ConnectionSocket::OptionsSharedPtr& options);
     165             : 
     166             : // Convert a cert in string form to X509 object.
     167             : // Return nullptr if the bytes passed cannot be passed.
     168             : bssl::UniquePtr<X509> parseDERCertificate(const std::string& der_bytes, std::string* error_details);
     169             : 
     170             : // Deduce the suitable signature algorithm according to the public key.
     171             : // Return the sign algorithm id works with the public key; If the public key is
     172             : // not supported, return 0 with error_details populated correspondingly.
     173             : int deduceSignatureAlgorithmFromPublicKey(const EVP_PKEY* public_key, std::string* error_details);
     174             : 
     175             : // Return a connection socket which read and write via io_handle, but doesn't close it when the
     176             : // socket gets closed nor set options on the socket.
     177             : Network::ConnectionSocketPtr
     178             : createServerConnectionSocket(Network::IoHandle& io_handle,
     179             :                              const quic::QuicSocketAddress& self_address,
     180             :                              const quic::QuicSocketAddress& peer_address,
     181             :                              const std::string& hostname, absl::string_view alpn);
     182             : 
     183             : // Alter QuicConfig based on all the options in the supplied config.
     184             : void convertQuicConfig(const envoy::config::core::v3::QuicProtocolOptions& config,
     185             :                        quic::QuicConfig& quic_config);
     186             : 
     187             : // Set initial flow control windows in quic_config according to the given Envoy config.
     188             : void configQuicInitialFlowControlWindow(const envoy::config::core::v3::QuicProtocolOptions& config,
     189             :                                         quic::QuicConfig& quic_config);
     190             : 
     191             : // Modify new_connection_id according to given old_connection_id to make sure packets with the new
     192             : // one can be routed to the same listener.
     193             : void adjustNewConnectionIdForRouting(quic::QuicConnectionId& new_connection_id,
     194             :                                      const quic::QuicConnectionId& old_connection_id);
     195             : 
     196             : } // namespace Quic
     197             : } // namespace Envoy

Generated by: LCOV version 1.15