LCOV - code coverage report
Current view: top level - source/common/http/http2 - protocol_constraints.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 64 95 67.4 %
Date: 2024-01-05 06:35:25 Functions: 9 10 90.0 %

          Line data    Source code
       1             : #include "source/common/http/http2/protocol_constraints.h"
       2             : 
       3             : #include "source/common/common/assert.h"
       4             : #include "source/common/common/dump_state_utils.h"
       5             : 
       6             : namespace Envoy {
       7             : namespace Http {
       8             : namespace Http2 {
       9             : 
      10             : ProtocolConstraints::ProtocolConstraints(
      11             :     CodecStats& stats, const envoy::config::core::v3::Http2ProtocolOptions& http2_options)
      12             :     : stats_(stats), max_outbound_frames_(http2_options.max_outbound_frames().value()),
      13       44839 :       frame_buffer_releasor_([this]() { releaseOutboundFrame(); }),
      14             :       max_outbound_control_frames_(http2_options.max_outbound_control_frames().value()),
      15        2553 :       control_frame_buffer_releasor_([this]() { releaseOutboundControlFrame(); }),
      16             :       max_consecutive_inbound_frames_with_empty_payload_(
      17             :           http2_options.max_consecutive_inbound_frames_with_empty_payload().value()),
      18             :       max_inbound_priority_frames_per_stream_(
      19             :           http2_options.max_inbound_priority_frames_per_stream().value()),
      20             :       max_inbound_window_update_frames_per_data_frame_sent_(
      21        2860 :           http2_options.max_inbound_window_update_frames_per_data_frame_sent().value()) {}
      22             : 
      23             : ProtocolConstraints::ReleasorProc
      24       47392 : ProtocolConstraints::incrementOutboundFrameCount(bool is_outbound_flood_monitored_control_frame) {
      25       47392 :   ++outbound_frames_;
      26       47392 :   stats_.outbound_frames_active_.set(outbound_frames_);
      27       47392 :   if (is_outbound_flood_monitored_control_frame) {
      28        2553 :     ++outbound_control_frames_;
      29        2553 :     stats_.outbound_control_frames_active_.set(outbound_control_frames_);
      30        2553 :   }
      31       47392 :   return is_outbound_flood_monitored_control_frame ? control_frame_buffer_releasor_
      32       47392 :                                                    : frame_buffer_releasor_;
      33       47392 : }
      34             : 
      35       47392 : void ProtocolConstraints::releaseOutboundFrame() {
      36       47392 :   ASSERT(outbound_frames_ >= 1);
      37       47392 :   --outbound_frames_;
      38       47392 :   stats_.outbound_frames_active_.set(outbound_frames_);
      39       47392 : }
      40             : 
      41        2553 : void ProtocolConstraints::releaseOutboundControlFrame() {
      42        2553 :   ASSERT(outbound_control_frames_ >= 1);
      43        2553 :   --outbound_control_frames_;
      44        2553 :   stats_.outbound_control_frames_active_.set(outbound_control_frames_);
      45        2553 :   releaseOutboundFrame();
      46        2553 : }
      47             : 
      48       96972 : Status ProtocolConstraints::checkOutboundFrameLimits() {
      49             :   // Stop checking for further violations after the first failure.
      50       96972 :   if (!status_.ok()) {
      51           0 :     return status_;
      52           0 :   }
      53             : 
      54       96972 :   if (outbound_frames_ > max_outbound_frames_) {
      55           0 :     stats_.outbound_flood_.inc();
      56           0 :     return status_ = bufferFloodError("Too many frames in the outbound queue.");
      57           0 :   }
      58       96972 :   if (outbound_control_frames_ > max_outbound_control_frames_) {
      59           0 :     stats_.outbound_control_flood_.inc();
      60           0 :     return status_ = bufferFloodError("Too many control frames in the outbound queue.");
      61           0 :   }
      62       96972 :   return okStatus();
      63       96972 : }
      64             : 
      65             : Status ProtocolConstraints::trackInboundFrames(size_t length, uint8_t type, uint8_t flags,
      66       44919 :                                                uint32_t padding_length) {
      67       44919 :   switch (type) {
      68        1764 :   case NGHTTP2_HEADERS:
      69        1771 :   case NGHTTP2_CONTINUATION:
      70       23952 :   case NGHTTP2_DATA:
      71             :     // Track frames with an empty payload and no end stream flag.
      72       23952 :     if (length - padding_length == 0 && !(flags & NGHTTP2_FLAG_END_STREAM)) {
      73           1 :       consecutive_inbound_frames_with_empty_payload_++;
      74       23951 :     } else {
      75       23951 :       consecutive_inbound_frames_with_empty_payload_ = 0;
      76       23951 :     }
      77       23952 :     break;
      78          21 :   case NGHTTP2_PRIORITY:
      79          21 :     inbound_priority_frames_++;
      80          21 :     break;
      81       16620 :   case NGHTTP2_WINDOW_UPDATE:
      82       16620 :     inbound_window_update_frames_++;
      83       16620 :     break;
      84        4326 :   default:
      85        4326 :     break;
      86       44919 :   }
      87             : 
      88       44919 :   status_.Update(checkInboundFrameLimits());
      89       44919 :   return status_;
      90       44919 : }
      91             : 
      92       44919 : Status ProtocolConstraints::checkInboundFrameLimits() {
      93             :   // Stop checking for further violations after the first failure.
      94       44919 :   if (!status_.ok()) {
      95           0 :     return status_;
      96           0 :   }
      97             : 
      98       44919 :   if (consecutive_inbound_frames_with_empty_payload_ >
      99       44919 :       max_consecutive_inbound_frames_with_empty_payload_) {
     100           0 :     stats_.inbound_empty_frames_flood_.inc();
     101           0 :     return inboundFramesWithEmptyPayloadError();
     102           0 :   }
     103             : 
     104       44919 :   if (inbound_priority_frames_ >
     105       44919 :       static_cast<uint64_t>(max_inbound_priority_frames_per_stream_) * (1 + opened_streams_)) {
     106           0 :     stats_.inbound_priority_frames_flood_.inc();
     107           0 :     return bufferFloodError("Too many PRIORITY frames");
     108           0 :   }
     109             : 
     110       44919 :   if (inbound_window_update_frames_ >
     111       44919 :       5 + 2 * (opened_streams_ +
     112       44919 :                max_inbound_window_update_frames_per_data_frame_sent_ * outbound_data_frames_)) {
     113           0 :     stats_.inbound_window_update_frames_flood_.inc();
     114           0 :     return bufferFloodError("Too many WINDOW_UPDATE frames");
     115           0 :   }
     116             : 
     117       44919 :   return okStatus();
     118       44919 : }
     119             : 
     120           0 : void ProtocolConstraints::dumpState(std::ostream& os, int indent_level) const {
     121           0 :   const char* spaces = spacesForLevel(indent_level);
     122             : 
     123           0 :   os << spaces << "ProtocolConstraints " << this << DUMP_MEMBER(outbound_frames_)
     124           0 :      << DUMP_MEMBER(max_outbound_frames_) << DUMP_MEMBER(outbound_control_frames_)
     125           0 :      << DUMP_MEMBER(max_outbound_control_frames_)
     126           0 :      << DUMP_MEMBER(consecutive_inbound_frames_with_empty_payload_)
     127           0 :      << DUMP_MEMBER(max_consecutive_inbound_frames_with_empty_payload_)
     128           0 :      << DUMP_MEMBER(opened_streams_) << DUMP_MEMBER(inbound_priority_frames_)
     129           0 :      << DUMP_MEMBER(max_inbound_priority_frames_per_stream_)
     130           0 :      << DUMP_MEMBER(inbound_window_update_frames_) << DUMP_MEMBER(outbound_data_frames_)
     131           0 :      << DUMP_MEMBER(max_inbound_window_update_frames_per_data_frame_sent_) << '\n';
     132           0 : }
     133             : 
     134             : } // namespace Http2
     135             : } // namespace Http
     136             : } // namespace Envoy

Generated by: LCOV version 1.15