Repository: envoyproxy/envoy
File: source/common/http/http2/codec_impl.cc (C++)

Code before:
  // If this results in buffering too much data, the watermark buffer will call
  // pendingRecvBufferHighWatermark, resulting in ++read_disable_count_
  stream->pending_recv_data_->add(data, len);
  // Update the window to the peer unless some consumer of this stream's data has hit a flow control
  // limit and disabled reads on this stream
  if (stream->shouldAllowPeerAdditionalStreamWindow()) {
    adapter_->MarkDataConsumedForStream(stream_id, len);
  } else {
    stream->unconsumed_bytes_ += len;
  }
  return 0;
}

void ConnectionImpl::goAway() {
  adapter_->SubmitGoAway(adapter_->GetHighestReceivedStreamId(),
                         http2::adapter::Http2ErrorCode::HTTP2_NO_ERROR, "");
  stats_.goaway_sent_.inc();
  if (sendPendingFramesAndHandleError()) {
    // Intended to check through coverage that this error case is tested
    return;
  }
}

void ConnectionImpl::shutdownNotice() {
  adapter_->SubmitShutdownNotice();
  stats_.goaway_sent_.inc();
  if (sendPendingFramesAndHandleError()) {
    // Intended to check through coverage that this error case is tested
    return;
  }
}

Status ConnectionImpl::protocolErrorForTest() {
  adapter_->SubmitGoAway(adapter_->GetHighestReceivedStreamId(),
                         http2::adapter::Http2ErrorCode::PROTOCOL_ERROR, "");

  return sendPendingFrames();
}

Status ConnectionImpl::onBeforeFrameReceived(int32_t stream_id, size_t length, uint8_t type,
                                             uint8_t flags) {
  ENVOY_CONN_LOG(trace, "about to recv frame type={}, flags={}, stream_id={}", connection_,
                 static_cast<uint64_t>(type), static_cast<uint64_t>(flags), stream_id);
  ASSERT(connection_.state() == Network::Connection::State::Open);

  current_stream_id_ = stream_id;
  if (type == OGHTTP2_PING_FRAME_TYPE && (flags & FLAG_ACK)) {
    return okStatus();
  }

  // In slow networks, HOL blocking can prevent the ping response from coming in a reasonable

Review comment (suggestion):
I inclined don't to do that. If we do need a stat for shutdownNotice, we should add one for that. (although I inclined we needn't that for now)

Code after:
    if (stream->stream_id_ == stream_id) {
      return true;
    }
  }

  return false;
}

Http::Status ConnectionImpl::dispatch(Buffer::Instance& data) {
  ScopeTrackerScopeState scope(this, connection_.dispatcher());
  ENVOY_CONN_LOG(trace, "dispatching {} bytes", connection_, data.length());
  // Make sure that dispatching_ is set to false after dispatching, even when
  // ConnectionImpl::dispatch returns early or throws an exception (consider removing if there is a
  // single return after exception removal (#10878)).
  Cleanup cleanup([this]() {
    dispatching_ = false;
    current_slice_ = nullptr;
    current_stream_id_.reset();
  });
  last_received_data_time_ = connection_.dispatcher().timeSource().monotonicTime();
  for (const Buffer::RawSlice& slice : data.getRawSlices()) {
    current_slice_ = &slice;
    dispatching_ = true;
    ssize_t rc;
    rc = adapter_->ProcessBytes(absl::string_view(static_cast<char*>(slice.mem_), slice.len_));
    if (!codec_callback_status_.ok()) {
      return codec_callback_status_;
    }
#ifdef ENVOY_NGHTTP2
    // This error is returned when nghttp2 library detected a frame flood by one of its
    // internal mechanisms. Most flood protection is done by Envoy's codec and this error
    // should never be returned. However it is handled here in case nghttp2 has some flood
    // protections that Envoy's codec does not have.
    static const int ERR_FLOODED = -904;
    if (rc == ERR_FLOODED) {
      return bufferFloodError(
          "Flooding was detected in this HTTP/2 session, and it must be closed"); // LCOV_EXCL_LINE
    }
#endif
    if (rc != static_cast<ssize_t>(slice.len_)) {
      return codecProtocolError(codecStrError(rc));
    }

    current_slice_ = nullptr;
    dispatching_ = false;
    current_stream_id_.reset();
  }

  ENVOY_CONN_LOG(trace, "dispatched {} bytes", connection_, data.length());
  data.drain(data.length());