Index: net/quic/core/quic_packet_creator.cc |
diff --git a/net/quic/core/quic_packet_creator.cc b/net/quic/core/quic_packet_creator.cc |
index 05508cb570d3137f9c8b45850d87dc25720f7cc5..84413a9a4219acc74dd4ff2c524c8829dc71446f 100644 |
--- a/net/quic/core/quic_packet_creator.cc |
+++ b/net/quic/core/quic_packet_creator.cc |
@@ -16,6 +16,7 @@ |
#include "net/quic/platform/api/quic_flag_utils.h" |
#include "net/quic/platform/api/quic_flags.h" |
#include "net/quic/platform/api/quic_logging.h" |
+#include "net/quic/platform/api/quic_ptr_util.h" |
#include "net/quic/platform/api/quic_string_piece.h" |
using std::string; |
@@ -47,7 +48,8 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id, |
latched_flag_no_stop_waiting_frames_( |
FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames), |
pending_padding_bytes_(0), |
- needs_full_padding_(false) { |
+ needs_full_padding_(false), |
+ delegate_saves_data_(false) { |
SetMaxPacketLength(kDefaultMaxPacketSize); |
} |
@@ -130,22 +132,17 @@ bool QuicPacketCreator::ConsumeData(QuicStreamId id, |
} |
CreateStreamFrame(id, iov, iov_offset, offset, fin, frame); |
// Explicitly disallow multi-packet CHLOs. |
- if (id == kCryptoStreamId && |
- frame->stream_frame->data_length >= sizeof(kCHLO) && |
- strncmp(frame->stream_frame->data_buffer, |
- reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) == 0) { |
- DCHECK_EQ(0u, iov_offset); |
- if (FLAGS_quic_enforce_single_packet_chlo && |
- frame->stream_frame->data_length < iov.iov->iov_len) { |
- const string error_details = "Client hello won't fit in a single packet."; |
- QUIC_BUG << error_details << " Constructed stream frame length: " |
- << frame->stream_frame->data_length |
- << " CHLO length: " << iov.iov->iov_len; |
- delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details, |
- ConnectionCloseSource::FROM_SELF); |
- delete frame->stream_frame; |
- return false; |
- } |
+ if (StreamFrameStartsWithChlo(iov, iov_offset, *frame->stream_frame) && |
+ FLAGS_quic_enforce_single_packet_chlo && |
+ frame->stream_frame->data_length < iov.iov->iov_len) { |
+ const string error_details = "Client hello won't fit in a single packet."; |
+ QUIC_BUG << error_details << " Constructed stream frame length: " |
+ << frame->stream_frame->data_length |
+ << " CHLO length: " << iov.iov->iov_len; |
+ delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details, |
+ ConnectionCloseSource::FROM_SELF); |
+ delete frame->stream_frame; |
+ return false; |
} |
if (!AddFrame(*frame, /*save_retransmittable_frames=*/true)) { |
// Fails if we try to write unencrypted stream data. |
@@ -211,6 +208,14 @@ void QuicPacketCreator::CreateStreamFrame(QuicStreamId id, |
std::min<size_t>(BytesFree() - min_frame_size, data_size); |
bool set_fin = fin && bytes_consumed == data_size; // Last frame. |
+ if (delegate_saves_data_) { |
+ *frame = |
+ QuicFrame(new QuicStreamFrame(id, set_fin, offset, bytes_consumed)); |
+ if (bytes_consumed > 0) { |
+ delegate_->SaveStreamData(id, iov, iov_offset, offset, bytes_consumed); |
+ } |
+ return; |
+ } |
UniqueStreamBuffer buffer = |
NewStreamBuffer(buffer_allocator_, bytes_consumed); |
QuicUtils::CopyToBuffer(iov, iov_offset, bytes_consumed, buffer.get()); |
@@ -332,11 +337,22 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( |
std::min<size_t>(available_size, remaining_data_size); |
const bool set_fin = fin && (bytes_consumed == remaining_data_size); |
- UniqueStreamBuffer stream_buffer = |
- NewStreamBuffer(buffer_allocator_, bytes_consumed); |
- QuicUtils::CopyToBuffer(iov, iov_offset, bytes_consumed, stream_buffer.get()); |
- std::unique_ptr<QuicStreamFrame> frame(new QuicStreamFrame( |
- id, set_fin, stream_offset, bytes_consumed, std::move(stream_buffer))); |
+ std::unique_ptr<QuicStreamFrame> frame; |
+ if (delegate_saves_data_) { |
+ frame = QuicMakeUnique<QuicStreamFrame>(id, set_fin, stream_offset, |
+ bytes_consumed); |
+ if (bytes_consumed > 0) { |
+ delegate_->SaveStreamData(id, iov, iov_offset, stream_offset, |
+ bytes_consumed); |
+ } |
+ } else { |
+ UniqueStreamBuffer stream_buffer = |
+ NewStreamBuffer(buffer_allocator_, bytes_consumed); |
+ QuicUtils::CopyToBuffer(iov, iov_offset, bytes_consumed, |
+ stream_buffer.get()); |
+ frame = QuicMakeUnique<QuicStreamFrame>( |
+ id, set_fin, stream_offset, bytes_consumed, std::move(stream_buffer)); |
+ } |
QUIC_DVLOG(1) << ENDPOINT << "Adding frame: " << *frame; |
// TODO(ianswett): AppendTypeByte and AppendStreamFrame could be optimized |
@@ -347,7 +363,8 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( |
return; |
} |
if (!framer_->AppendStreamFrame(*frame, /* no stream frame length */ true, |
- &writer)) { |
+ &writer, |
+ delegate_saves_data_ ? delegate_ : nullptr)) { |
QUIC_BUG << "AppendStreamFrame failed"; |
return; |
} |
@@ -438,8 +455,9 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer, |
DCHECK_GE(max_plaintext_size_, packet_size_); |
// Use the packet_size_ instead of the buffer size to ensure smaller |
// packet sizes are properly used. |
- size_t length = framer_->BuildDataPacket(header, queued_frames_, |
- encrypted_buffer, packet_size_); |
+ size_t length = framer_->BuildDataPacket( |
+ header, queued_frames_, encrypted_buffer, packet_size_, |
+ delegate_saves_data_ ? delegate_ : nullptr); |
if (length == 0) { |
QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames."; |
return; |
@@ -609,4 +627,30 @@ void QuicPacketCreator::AddPendingPadding(QuicByteCount size) { |
pending_padding_bytes_ += size; |
} |
+bool QuicPacketCreator::StreamFrameStartsWithChlo( |
+ QuicIOVector iov, |
+ size_t iov_offset, |
+ const QuicStreamFrame& frame) const { |
+ if (!delegate_saves_data_) { |
+ return frame.stream_id == kCryptoStreamId && |
+ frame.data_length >= sizeof(kCHLO) && |
+ strncmp(frame.data_buffer, reinterpret_cast<const char*>(&kCHLO), |
+ sizeof(kCHLO)) == 0; |
+ } |
+ |
+ if (framer_->perspective() == Perspective::IS_SERVER || |
+ frame.stream_id != kCryptoStreamId || iov_offset != 0 || |
+ frame.data_length < sizeof(kCHLO)) { |
+ return false; |
+ } |
+ |
+ if (iov.iov[0].iov_len < sizeof(kCHLO)) { |
+ QUIC_BUG << "iov length " << iov.iov[0].iov_len << " is less than " |
+ << sizeof(kCHLO); |
+ return false; |
+ } |
+ return strncmp(reinterpret_cast<const char*>(iov.iov[0].iov_base), |
+ reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) == 0; |
+} |
+ |
} // namespace net |