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_;