Refactoring in preparation for some changes to data frame generation. Protected by not protected, does not affect the GFE binary. PiperOrigin-RevId: 598949749
diff --git a/quiche/http2/adapter/oghttp2_session.cc b/quiche/http2/adapter/oghttp2_session.cc index ad67a18..bd9464f 100644 --- a/quiche/http2/adapter/oghttp2_session.cc +++ b/quiche/http2/adapter/oghttp2_session.cc
@@ -815,51 +815,50 @@ static_cast<int32_t>(max_frame_payload_)}); while (connection_can_write == SendResult::SEND_OK && available_window > 0 && state.outbound_body != nullptr && !state.data_deferred) { - auto [length, end_data] = - state.outbound_body->SelectPayloadLength(available_window); - QUICHE_VLOG(2) << "WriteForStream | length: " << length - << " end_data: " << end_data + DataFrameInfo info = GetDataFrameInfo(stream_id, available_window, state); + QUICHE_VLOG(2) << "WriteForStream | length: " << info.payload_length + << " end_data: " << info.end_data << " trailers: " << state.trailers.get(); - if (length == 0 && !end_data && + if (info.payload_length == 0 && !info.end_data && (options_.trailers_require_end_data || state.trailers == nullptr)) { // An unproductive call to SelectPayloadLength() results in this stream // entering the "deferred" state only if either no trailers are available // to send, or trailers require an explicit end_data before being sent. state.data_deferred = true; break; - } else if (length == DataFrameSource::kError) { + } else if (info.payload_length == DataFrameSource::kError) { // TODO(birenroy,diannahu): Consider queuing a RST_STREAM INTERNAL_ERROR // instead. CloseStream(stream_id, Http2ErrorCode::INTERNAL_ERROR); // No more work on the stream; it has been closed. break; } - const bool fin = end_data ? state.outbound_body->send_fin() : false; - if (length > 0 || fin) { + if (info.payload_length > 0 || info.send_fin) { spdy::SpdyDataIR data(stream_id); - data.set_fin(fin); - data.SetDataShallow(length); + data.set_fin(info.send_fin); + data.SetDataShallow(info.payload_length); spdy::SpdySerializedFrame header = spdy::SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField( data); QUICHE_DCHECK(buffered_data_.empty() && frames_.empty()); data.Visit(&send_logger_); - const bool success = - state.outbound_body->Send(absl::string_view(header), length); + const bool success = SendDataFrame(stream_id, absl::string_view(header), + info.payload_length, state); if (!success) { connection_can_write = SendResult::SEND_BLOCKED; break; } - connection_send_window_ -= length; - state.send_window -= length; + connection_send_window_ -= info.payload_length; + state.send_window -= info.payload_length; available_window = std::min({connection_send_window_, state.send_window, static_cast<int32_t>(max_frame_payload_)}); - if (fin) { + if (info.send_fin) { state.half_closed_local = true; MaybeFinWithRstStream(it); } - const bool ok = AfterFrameSent(/* DATA */ 0, stream_id, length, - fin ? END_STREAM_FLAG : 0x0, 0); + const bool ok = + AfterFrameSent(/* DATA */ 0, stream_id, info.payload_length, + info.send_fin ? END_STREAM_FLAG : 0x0, 0); if (!ok) { LatchErrorAndNotify(Http2ErrorCode::INTERNAL_ERROR, ConnectionError::kSendError); @@ -870,14 +869,15 @@ break; } } - if (end_data || (length == 0 && state.trailers != nullptr && - !options_.trailers_require_end_data)) { + if (info.end_data || + (info.payload_length == 0 && state.trailers != nullptr && + !options_.trailers_require_end_data)) { // If SelectPayloadLength() returned {0, false}, and there are trailers to // send, and the safety feature is disabled, it's okay to send the // trailers. if (state.trailers != nullptr) { auto block_ptr = std::move(state.trailers); - if (fin) { + if (info.send_fin) { QUICHE_LOG(ERROR) << "Sent fin; can't send trailers."; // TODO(birenroy,diannahu): Consider queuing a RST_STREAM @@ -2028,5 +2028,23 @@ } } +OgHttp2Session::DataFrameInfo OgHttp2Session::GetDataFrameInfo( + Http2StreamId /*stream_id*/, size_t flow_control_available, + StreamState& stream_state) { + DataFrameInfo info; + std::tie(info.payload_length, info.end_data) = + stream_state.outbound_body->SelectPayloadLength(flow_control_available); + info.send_fin = + info.end_data ? stream_state.outbound_body->send_fin() : false; + return info; +} + +bool OgHttp2Session::SendDataFrame(Http2StreamId /*stream_id*/, + absl::string_view frame_header, + size_t payload_length, + StreamState& stream_state) { + return stream_state.outbound_body->Send(frame_header, payload_length); +} + } // namespace adapter } // namespace http2
diff --git a/quiche/http2/adapter/oghttp2_session.h b/quiche/http2/adapter/oghttp2_session.h index 16e4db4..8213ed6 100644 --- a/quiche/http2/adapter/oghttp2_session.h +++ b/quiche/http2/adapter/oghttp2_session.h
@@ -446,6 +446,20 @@ // initial window. void UpdateStreamReceiveWindowSizes(uint32_t new_value); + // Gathers information required to construct a DATA frame header. + struct DataFrameInfo { + int64_t payload_length; + bool end_data; + bool send_fin; + }; + DataFrameInfo GetDataFrameInfo(Http2StreamId stream_id, + size_t flow_control_available, + StreamState& stream_state); + + // Invokes the appropriate API to send a DATA frame header and payload. + bool SendDataFrame(Http2StreamId stream_id, absl::string_view frame_header, + size_t payload_length, StreamState& stream_state); + // Receives events when inbound frames are parsed. Http2VisitorInterface& visitor_;