summaryrefslogtreecommitdiff
path: root/chromium/net/quic/core
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-20 10:33:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-22 11:45:12 +0000
commitbe59a35641616a4cf23c4a13fa0632624b021c1b (patch)
tree9da183258bdf9cc413f7562079d25ace6955467f /chromium/net/quic/core
parentd702e4b6a64574e97fc7df8fe3238cde70242080 (diff)
downloadqtwebengine-chromium-be59a35641616a4cf23c4a13fa0632624b021c1b.tar.gz
BASELINE: Update Chromium to 62.0.3202.101
Change-Id: I2d5eca8117600df6d331f6166ab24d943d9814ac Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/net/quic/core')
-rw-r--r--chromium/net/quic/core/congestion_control/bandwidth_sampler.cc114
-rw-r--r--chromium/net/quic/core/congestion_control/bandwidth_sampler.h91
-rw-r--r--chromium/net/quic/core/congestion_control/bandwidth_sampler_test.cc11
-rw-r--r--chromium/net/quic/core/congestion_control/bbr_sender.cc111
-rw-r--r--chromium/net/quic/core/congestion_control/bbr_sender.h19
-rw-r--r--chromium/net/quic/core/congestion_control/bbr_sender_test.cc159
-rw-r--r--chromium/net/quic/core/congestion_control/pacing_sender.cc2
-rw-r--r--chromium/net/quic/core/congestion_control/pacing_sender.h2
-rw-r--r--chromium/net/quic/core/congestion_control/pacing_sender_test.cc18
-rw-r--r--chromium/net/quic/core/congestion_control/send_algorithm_interface.h39
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc44
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h11
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc90
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc86
-rw-r--r--chromium/net/quic/core/crypto/crypto_framer.h17
-rw-r--r--chromium/net/quic/core/crypto/crypto_framer_test.cc5
-rw-r--r--chromium/net/quic/core/crypto/crypto_handshake.cc2
-rw-r--r--chromium/net/quic/core/crypto/crypto_handshake.h2
-rw-r--r--chromium/net/quic/core/crypto/crypto_handshake_message_test.cc9
-rw-r--r--chromium/net/quic/core/crypto/crypto_message_parser.h32
-rw-r--r--chromium/net/quic/core/crypto/crypto_protocol.h8
-rw-r--r--chromium/net/quic/core/crypto/crypto_server_config_protobuf.h2
-rw-r--r--chromium/net/quic/core/crypto/proof_source.h37
-rw-r--r--chromium/net/quic/core/frames/quic_ack_frame.cc130
-rw-r--r--chromium/net/quic/core/frames/quic_ack_frame.h4
-rw-r--r--chromium/net/quic/core/frames/quic_frames_test.cc217
-rw-r--r--chromium/net/quic/core/frames/quic_stream_frame.h6
-rw-r--r--chromium/net/quic/core/quic_buffered_packet_store.cc1
-rw-r--r--chromium/net/quic/core/quic_buffered_packet_store_test.cc100
-rw-r--r--chromium/net/quic/core/quic_client_promised_info.cc12
-rw-r--r--chromium/net/quic/core/quic_client_promised_info.h10
-rw-r--r--chromium/net/quic/core/quic_client_promised_info_test.cc17
-rw-r--r--chromium/net/quic/core/quic_client_push_promise_index.h2
-rw-r--r--chromium/net/quic/core/quic_client_push_promise_index_test.cc19
-rw-r--r--chromium/net/quic/core/quic_connection.cc74
-rw-r--r--chromium/net/quic/core/quic_connection.h13
-rw-r--r--chromium/net/quic/core/quic_connection_test.cc144
-rw-r--r--chromium/net/quic/core/quic_constants.h5
-rw-r--r--chromium/net/quic/core/quic_crypto_client_handshaker.cc698
-rw-r--r--chromium/net/quic/core/quic_crypto_client_handshaker.h240
-rw-r--r--chromium/net/quic/core/quic_crypto_client_stream.cc677
-rw-r--r--chromium/net/quic/core/quic_crypto_client_stream.h222
-rw-r--r--chromium/net/quic/core/quic_crypto_client_stream_test.cc3
-rw-r--r--chromium/net/quic/core/quic_crypto_handshaker.cc51
-rw-r--r--chromium/net/quic/core/quic_crypto_handshaker.h42
-rw-r--r--chromium/net/quic/core/quic_crypto_server_handshaker.cc482
-rw-r--r--chromium/net/quic/core/quic_crypto_server_handshaker.h240
-rw-r--r--chromium/net/quic/core/quic_crypto_server_stream.cc469
-rw-r--r--chromium/net/quic/core/quic_crypto_server_stream.h224
-rw-r--r--chromium/net/quic/core/quic_crypto_stream.cc39
-rw-r--r--chromium/net/quic/core/quic_crypto_stream.h28
-rw-r--r--chromium/net/quic/core/quic_data_writer.cc11
-rw-r--r--chromium/net/quic/core/quic_data_writer.h4
-rw-r--r--chromium/net/quic/core/quic_data_writer_test.cc29
-rw-r--r--chromium/net/quic/core/quic_flags_list.h123
-rw-r--r--chromium/net/quic/core/quic_framer.cc535
-rw-r--r--chromium/net/quic/core/quic_framer.h23
-rw-r--r--chromium/net/quic/core/quic_framer_test.cc1561
-rw-r--r--chromium/net/quic/core/quic_header_list.cc43
-rw-r--r--chromium/net/quic/core/quic_header_list.h18
-rw-r--r--chromium/net/quic/core/quic_header_list_test.cc14
-rw-r--r--chromium/net/quic/core/quic_headers_stream.cc65
-rw-r--r--chromium/net/quic/core/quic_headers_stream.h9
-rw-r--r--chromium/net/quic/core/quic_headers_stream_test.cc114
-rw-r--r--chromium/net/quic/core/quic_packet_creator.cc54
-rw-r--r--chromium/net/quic/core/quic_packet_creator.h1
-rw-r--r--chromium/net/quic/core/quic_packet_creator_test.cc110
-rw-r--r--chromium/net/quic/core/quic_packet_generator.cc34
-rw-r--r--chromium/net/quic/core/quic_packet_generator.h11
-rw-r--r--chromium/net/quic/core/quic_packet_generator_test.cc260
-rw-r--r--chromium/net/quic/core/quic_packets.cc20
-rw-r--r--chromium/net/quic/core/quic_packets.h2
-rw-r--r--chromium/net/quic/core/quic_sent_packet_manager.cc48
-rw-r--r--chromium/net/quic/core/quic_sent_packet_manager.h7
-rw-r--r--chromium/net/quic/core/quic_sent_packet_manager_test.cc115
-rw-r--r--chromium/net/quic/core/quic_server_session_base.cc5
-rw-r--r--chromium/net/quic/core/quic_server_session_base_test.cc42
-rw-r--r--chromium/net/quic/core/quic_session.cc103
-rw-r--r--chromium/net/quic/core/quic_session.h60
-rw-r--r--chromium/net/quic/core/quic_session_test.cc26
-rw-r--r--chromium/net/quic/core/quic_spdy_client_session_base.cc (renamed from chromium/net/quic/core/quic_client_session_base.cc)43
-rw-r--r--chromium/net/quic/core/quic_spdy_client_session_base.h (renamed from chromium/net/quic/core/quic_client_session_base.h)18
-rw-r--r--chromium/net/quic/core/quic_spdy_session.cc106
-rw-r--r--chromium/net/quic/core/quic_spdy_session.h32
-rw-r--r--chromium/net/quic/core/quic_spdy_stream.cc3
-rw-r--r--chromium/net/quic/core/quic_spdy_stream_test.cc5
-rw-r--r--chromium/net/quic/core/quic_stream.cc191
-rw-r--r--chromium/net/quic/core/quic_stream.h57
-rw-r--r--chromium/net/quic/core/quic_stream_frame_data_producer.h9
-rw-r--r--chromium/net/quic/core/quic_stream_send_buffer.cc36
-rw-r--r--chromium/net/quic/core/quic_stream_send_buffer.h21
-rw-r--r--chromium/net/quic/core/quic_stream_send_buffer_test.cc12
-rw-r--r--chromium/net/quic/core/quic_stream_sequencer_test.cc3
-rw-r--r--chromium/net/quic/core/quic_stream_test.cc154
-rw-r--r--chromium/net/quic/core/quic_time.h3
-rw-r--r--chromium/net/quic/core/quic_types.h8
-rw-r--r--chromium/net/quic/core/quic_utils.cc2
-rw-r--r--chromium/net/quic/core/quic_version_manager.cc9
-rw-r--r--chromium/net/quic/core/quic_version_manager.h4
-rw-r--r--chromium/net/quic/core/quic_version_manager_test.cc27
-rw-r--r--chromium/net/quic/core/quic_versions.cc14
-rw-r--r--chromium/net/quic/core/quic_versions.h9
-rw-r--r--chromium/net/quic/core/spdy_utils.cc1
-rw-r--r--chromium/net/quic/core/spdy_utils.h2
104 files changed, 5804 insertions, 3492 deletions
diff --git a/chromium/net/quic/core/congestion_control/bandwidth_sampler.cc b/chromium/net/quic/core/congestion_control/bandwidth_sampler.cc
index f95fdd71816..47b64ef8c21 100644
--- a/chromium/net/quic/core/congestion_control/bandwidth_sampler.cc
+++ b/chromium/net/quic/core/congestion_control/bandwidth_sampler.cc
@@ -20,10 +20,7 @@ BandwidthSampler::BandwidthSampler()
last_sent_packet_(0),
is_app_limited_(false),
end_of_app_limited_phase_(0),
- connection_state_map_(),
- connection_state_map_new_(),
- use_new_connection_state_map_(
- FLAGS_quic_reloadable_flag_quic_faster_bandwidth_sampler) {}
+ connection_state_map_() {}
BandwidthSampler::~BandwidthSampler() {}
@@ -56,61 +53,33 @@ void BandwidthSampler::OnPacketSent(
last_acked_packet_sent_time_ = sent_time;
}
- if (use_new_connection_state_map_) {
- if (!connection_state_map_new_.IsEmpty() &&
- packet_number >
- connection_state_map_new_.last_packet() + kMaxTrackedPackets) {
- QUIC_BUG << "BandwidthSampler in-flight packet map has exceeded maximum "
- "number "
- "of tracked packets.";
- }
-
- bool success = connection_state_map_new_.Emplace(packet_number, sent_time,
- bytes, *this);
- QUIC_BUG_IF(!success) << "BandwidthSampler failed to insert the packet "
- "into the map, most likely because it's already "
- "in it.";
- return;
+ if (!connection_state_map_.IsEmpty() &&
+ packet_number >
+ connection_state_map_.last_packet() + kMaxTrackedPackets) {
+ QUIC_BUG << "BandwidthSampler in-flight packet map has exceeded maximum "
+ "number "
+ "of tracked packets.";
}
- DCHECK(connection_state_map_.find(packet_number) ==
- connection_state_map_.end());
- connection_state_map_.emplace(
- packet_number, ConnectionStateOnSentPacket(sent_time, bytes, *this));
-
- QUIC_BUG_IF(connection_state_map_.size() > kMaxTrackedPackets)
- << "BandwidthSampler in-flight packet map has exceeded maximum number "
- "of tracked packets.";
+ bool success =
+ connection_state_map_.Emplace(packet_number, sent_time, bytes, *this);
+ QUIC_BUG_IF(!success) << "BandwidthSampler failed to insert the packet "
+ "into the map, most likely because it's already "
+ "in it.";
}
BandwidthSample BandwidthSampler::OnPacketAcknowledged(
QuicTime ack_time,
QuicPacketNumber packet_number) {
- if (use_new_connection_state_map_) {
- ConnectionStateOnSentPacket* sent_packet_pointer =
- connection_state_map_new_.GetEntry(packet_number);
- if (sent_packet_pointer == nullptr) {
- // See the TODO below.
- return BandwidthSample();
- }
- BandwidthSample sample = OnPacketAcknowledgedInner(ack_time, packet_number,
- *sent_packet_pointer);
- connection_state_map_new_.Remove(packet_number);
- QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_faster_bandwidth_sampler, 1, 2);
- return sample;
- }
-
- auto it = connection_state_map_.find(packet_number);
- if (it == connection_state_map_.end()) {
- // TODO(vasilvv): currently, this can happen because the congestion
- // controller can be created while some of the handshake packets are still
- // in flight. Once the sampler is fully integrated with unacked packet map,
- // this should be a QUIC_BUG equivalent.
+ ConnectionStateOnSentPacket* sent_packet_pointer =
+ connection_state_map_.GetEntry(packet_number);
+ if (sent_packet_pointer == nullptr) {
+ // See the TODO below.
return BandwidthSample();
}
BandwidthSample sample =
- OnPacketAcknowledgedInner(ack_time, packet_number, it->second);
- connection_state_map_.erase(it);
+ OnPacketAcknowledgedInner(ack_time, packet_number, *sent_packet_pointer);
+ connection_state_map_.Remove(packet_number);
return sample;
}
@@ -172,23 +141,10 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner(
}
void BandwidthSampler::OnPacketLost(QuicPacketNumber packet_number) {
- if (use_new_connection_state_map_) {
- // TODO(vasilvv): see the comment for the case of missing packets in
- // BandwidthSampler::OnPacketAcknowledged on why this does not raise a
- // QUIC_BUG when removal fails.
- connection_state_map_new_.Remove(packet_number);
- QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_faster_bandwidth_sampler, 2, 2);
- return;
- }
-
- auto it = connection_state_map_.find(packet_number);
- if (it == connection_state_map_.end()) {
- // TODO(vasilvv): see the comment for the same case in
- // BandwidthSampler::OnPacketAcknowledged.
- return;
- }
-
- connection_state_map_.erase(it);
+ // TODO(vasilvv): see the comment for the case of missing packets in
+ // BandwidthSampler::OnPacketAcknowledged on why this does not raise a
+ // QUIC_BUG when removal fails.
+ connection_state_map_.Remove(packet_number);
}
void BandwidthSampler::OnAppLimited() {
@@ -197,18 +153,22 @@ void BandwidthSampler::OnAppLimited() {
}
void BandwidthSampler::RemoveObsoletePackets(QuicPacketNumber least_unacked) {
- if (use_new_connection_state_map_) {
- while (!connection_state_map_new_.IsEmpty() &&
- connection_state_map_new_.first_packet() < least_unacked) {
- connection_state_map_new_.Remove(
- connection_state_map_new_.first_packet());
- }
- return;
- }
- while (!connection_state_map_.empty() &&
- connection_state_map_.begin()->first < least_unacked) {
- connection_state_map_.pop_front();
+ while (!connection_state_map_.IsEmpty() &&
+ connection_state_map_.first_packet() < least_unacked) {
+ connection_state_map_.Remove(connection_state_map_.first_packet());
}
}
+QuicByteCount BandwidthSampler::total_bytes_acked() const {
+ return total_bytes_acked_;
+}
+
+bool BandwidthSampler::is_app_limited() const {
+ return is_app_limited_;
+}
+
+QuicPacketNumber BandwidthSampler::end_of_app_limited_phase() const {
+ return end_of_app_limited_phase_;
+}
+
} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/bandwidth_sampler.h b/chromium/net/quic/core/congestion_control/bandwidth_sampler.h
index 75845404186..b42e8b91569 100644
--- a/chromium/net/quic/core/congestion_control/bandwidth_sampler.h
+++ b/chromium/net/quic/core/congestion_control/bandwidth_sampler.h
@@ -37,6 +37,50 @@ struct QUIC_EXPORT_PRIVATE BandwidthSample {
is_app_limited(false) {}
};
+// An interface common to any class that can provide bandwidth samples from the
+// information per individual acknowledged packet.
+class QUIC_EXPORT_PRIVATE BandwidthSamplerInterface {
+ public:
+ virtual ~BandwidthSamplerInterface() {}
+
+ // Inputs the sent packet information into the sampler. Assumes that all
+ // packets are sent in order. The information about the packet will not be
+ // released from the sampler until it the packet is either acknowledged or
+ // declared lost.
+ virtual void OnPacketSent(
+ QuicTime sent_time,
+ QuicPacketNumber packet_number,
+ QuicByteCount bytes,
+ QuicByteCount bytes_in_flight,
+ HasRetransmittableData has_retransmittable_data) = 0;
+
+ // Notifies the sampler that the |packet_number| is acknowledged. Returns a
+ // bandwidth sample. If no bandwidth sample is available,
+ // QuicBandwidth::Zero() is returned.
+ virtual BandwidthSample OnPacketAcknowledged(
+ QuicTime ack_time,
+ QuicPacketNumber packet_number) = 0;
+
+ // Informs the sampler that a packet is considered lost and it should no
+ // longer keep track of it.
+ virtual void OnPacketLost(QuicPacketNumber packet_number) = 0;
+
+ // Informs the sampler that the connection is currently app-limited, causing
+ // the sampler to enter the app-limited phase. The phase will expire by
+ // itself.
+ virtual void OnAppLimited() = 0;
+
+ // Remove all the packets lower than the specified packet number.
+ virtual void RemoveObsoletePackets(QuicPacketNumber least_unacked) = 0;
+
+ // Total number of bytes currently acknowledged by the receiver.
+ virtual QuicByteCount total_bytes_acked() const = 0;
+
+ // Application-limited information exported for debugging.
+ virtual bool is_app_limited() const = 0;
+ virtual QuicPacketNumber end_of_app_limited_phase() const = 0;
+};
+
// BandwidthSampler keeps track of sent and acknowledged packets and outputs a
// bandwidth sample for every packet acknowledged. The samples are taken for
// individual packets, and are not filtered; the consumer has to filter the
@@ -117,42 +161,27 @@ struct QUIC_EXPORT_PRIVATE BandwidthSample {
// up until an ack for a packet that was sent after OnAppLimited() was called.
// Note that while the scenario above is not the only scenario when the
// connection is app-limited, the approach works in other cases too.
-class QUIC_EXPORT_PRIVATE BandwidthSampler {
+class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
public:
BandwidthSampler();
- ~BandwidthSampler();
+ ~BandwidthSampler() override;
- // Inputs the sent packet information into the sampler. Assumes that all
- // packets are sent in order. The information about the packet will not be
- // released from the sampler until it the packet is either acknowledged or
- // declared lost.
void OnPacketSent(QuicTime sent_time,
QuicPacketNumber packet_number,
QuicByteCount bytes,
QuicByteCount bytes_in_flight,
- HasRetransmittableData has_retransmittable_data);
- // Notifies the sampler that the |packet_number| is acknowledged. Returns a
- // bandwidth sample. If no bandwidth sample is available,
- // QuicBandwidth::Zero() is returned.
+ HasRetransmittableData has_retransmittable_data) override;
BandwidthSample OnPacketAcknowledged(QuicTime ack_time,
- QuicPacketNumber packet_number);
- // Informs the sampler that a packet is considered lost and it should no
- // longer keep track of it.
- void OnPacketLost(QuicPacketNumber packet_number);
+ QuicPacketNumber packet_number) override;
+ void OnPacketLost(QuicPacketNumber packet_number) override;
- // Informs the sampler that the connection is currently app-limited, causing
- // the sampler to enter the app-limited phase. The phase will expire by itself
- // (see |is_app_limited_| documentation for details).
- void OnAppLimited();
+ void OnAppLimited() override;
- // Remove all the packets lower than the specified packet number.
- void RemoveObsoletePackets(QuicPacketNumber least_unacked);
+ void RemoveObsoletePackets(QuicPacketNumber least_unacked) override;
- QuicByteCount total_bytes_acked() const { return total_bytes_acked_; }
- bool is_app_limited() const { return is_app_limited_; }
- QuicPacketNumber end_of_app_limited_phase() const {
- return end_of_app_limited_phase_;
- }
+ QuicByteCount total_bytes_acked() const override;
+ bool is_app_limited() const override;
+ QuicPacketNumber end_of_app_limited_phase() const override;
private:
friend class test::BandwidthSamplerPeer;
@@ -212,8 +241,13 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler {
// PacketNumberIndexedQueue.
ConnectionStateOnSentPacket()
: sent_time(QuicTime::Zero()),
+ size(0),
+ total_bytes_sent(0),
+ total_bytes_sent_at_last_acked_packet(0),
last_acked_packet_sent_time(QuicTime::Zero()),
- last_acked_packet_ack_time(QuicTime::Zero()) {}
+ last_acked_packet_ack_time(QuicTime::Zero()),
+ total_bytes_acked_at_the_last_acked_packet(0),
+ is_app_limited(false) {}
};
typedef QuicLinkedHashMap<QuicPacketNumber, ConnectionStateOnSentPacket>
@@ -249,10 +283,7 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler {
// Record of the connection state at the point where each packet in flight was
// sent, indexed by the packet number.
- ConnectionStateMap connection_state_map_;
- PacketNumberIndexedQueue<ConnectionStateOnSentPacket>
- connection_state_map_new_;
- const bool use_new_connection_state_map_;
+ PacketNumberIndexedQueue<ConnectionStateOnSentPacket> connection_state_map_;
// Handles the actual bandwidth calculations, whereas the outer method handles
// retrieving and removing |sent_packet|.
diff --git a/chromium/net/quic/core/congestion_control/bandwidth_sampler_test.cc b/chromium/net/quic/core/congestion_control/bandwidth_sampler_test.cc
index 517ab552cb8..503e39ff3d4 100644
--- a/chromium/net/quic/core/congestion_control/bandwidth_sampler_test.cc
+++ b/chromium/net/quic/core/congestion_control/bandwidth_sampler_test.cc
@@ -14,19 +14,12 @@ namespace test {
class BandwidthSamplerPeer {
public:
static size_t GetNumberOfTrackedPackets(const BandwidthSampler& sampler) {
- if (FLAGS_quic_reloadable_flag_quic_faster_bandwidth_sampler) {
- return sampler.connection_state_map_new_.number_of_present_entries();
- }
- return sampler.connection_state_map_.size();
+ return sampler.connection_state_map_.number_of_present_entries();
}
static QuicByteCount GetPacketSize(const BandwidthSampler& sampler,
QuicPacketNumber packet_number) {
- if (FLAGS_quic_reloadable_flag_quic_faster_bandwidth_sampler) {
- return sampler.connection_state_map_new_.GetEntry(packet_number)->size;
- }
- auto iterator = sampler.connection_state_map_.find(packet_number);
- return iterator->second.size;
+ return sampler.connection_state_map_.GetEntry(packet_number)->size;
}
};
diff --git a/chromium/net/quic/core/congestion_control/bbr_sender.cc b/chromium/net/quic/core/congestion_control/bbr_sender.cc
index e8dadc9b337..710c1600a1c 100644
--- a/chromium/net/quic/core/congestion_control/bbr_sender.cc
+++ b/chromium/net/quic/core/congestion_control/bbr_sender.cc
@@ -63,7 +63,7 @@ BbrSender::DebugState::DebugState(const BbrSender& sender)
recovery_state(sender.recovery_state_),
recovery_window(sender.recovery_window_),
last_sample_is_app_limited(sender.last_sample_is_app_limited_),
- end_of_app_limited_phase(sender.sampler_.end_of_app_limited_phase()) {}
+ end_of_app_limited_phase(sender.sampler_->end_of_app_limited_phase()) {}
BbrSender::DebugState::DebugState(const DebugState& state) = default;
@@ -76,7 +76,7 @@ BbrSender::BbrSender(const RttStats* rtt_stats,
unacked_packets_(unacked_packets),
random_(random),
mode_(STARTUP),
- sampler_(),
+ sampler_(new BandwidthSampler()),
round_trip_count_(0),
last_sent_packet_(0),
current_round_trip_end_(0),
@@ -85,6 +85,7 @@ BbrSender::BbrSender(const RttStats* rtt_stats,
aggregation_epoch_start_time_(QuicTime::Zero()),
aggregation_epoch_bytes_(0),
bytes_acked_since_queue_drained_(0),
+ max_aggregation_bytes_multiplier_(0),
min_rtt_(QuicTime::Delta::Zero()),
min_rtt_timestamp_(QuicTime::Zero()),
congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS),
@@ -99,6 +100,7 @@ BbrSender::BbrSender(const RttStats* rtt_stats,
rtt_variance_weight_(
static_cast<float>(FLAGS_quic_bbr_rtt_variation_weight)),
num_startup_rtts_(kRoundTripsWithoutGrowthBeforeExitingStartup),
+ exit_startup_on_loss_(false),
cycle_current_offset_(0),
last_cycle_start_(QuicTime::Zero()),
is_at_full_bandwidth_(false),
@@ -128,12 +130,16 @@ bool BbrSender::OnPacketSent(QuicTime sent_time,
HasRetransmittableData is_retransmittable) {
last_sent_packet_ = packet_number;
- if (bytes_in_flight == 0 && sampler_.is_app_limited()) {
+ if (bytes_in_flight == 0 && sampler_->is_app_limited()) {
exiting_quiescence_ = true;
}
- sampler_.OnPacketSent(sent_time, packet_number, bytes, bytes_in_flight,
- is_retransmittable);
+ if (!aggregation_epoch_start_time_.IsInitialized()) {
+ aggregation_epoch_start_time_ = sent_time;
+ }
+
+ sampler_->OnPacketSent(sent_time, packet_number, bytes, bytes_in_flight,
+ is_retransmittable);
return is_retransmittable == HAS_RETRANSMITTABLE_DATA;
}
@@ -177,8 +183,17 @@ bool BbrSender::InRecovery() const {
return recovery_state_ != NOT_IN_RECOVERY;
}
+bool BbrSender::IsProbingForMoreBandwidth() const {
+ return mode_ == PROBE_BW && pacing_gain_ > 1;
+}
+
void BbrSender::SetFromConfig(const QuicConfig& config,
Perspective perspective) {
+ if (FLAGS_quic_reloadable_flag_quic_bbr_exit_startup_on_loss &&
+ config.HasClientRequestedIndependentOption(kLRTT, perspective)) {
+ QUIC_FLAG_COUNT(quic_reloadable_flag_quic_bbr_exit_startup_on_loss);
+ exit_startup_on_loss_ = true;
+ }
if (config.HasClientRequestedIndependentOption(k1RTT, perspective)) {
num_startup_rtts_ = 1;
}
@@ -189,25 +204,31 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
config.HasClientRequestedIndependentOption(kBBRR, perspective)) {
rate_based_recovery_ = true;
}
+ if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes4 &&
+ config.HasClientRequestedIndependentOption(kBBR1, perspective)) {
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes4, 1,
+ 2);
+ max_aggregation_bytes_multiplier_ = 1.5;
+ }
+ if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes4 &&
+ config.HasClientRequestedIndependentOption(kBBR2, perspective)) {
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes4, 2,
+ 2);
+ max_aggregation_bytes_multiplier_ = 2;
+ }
}
-void BbrSender::ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) {
+void BbrSender::AdjustNetworkParameters(QuicBandwidth bandwidth,
+ QuicTime::Delta rtt) {
if (!FLAGS_quic_reloadable_flag_quic_bbr_bandwidth_resumption) {
return;
}
QUIC_FLAG_COUNT(quic_reloadable_flag_quic_bbr_bandwidth_resumption);
- QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(
- max_bandwidth_resumption
- ? cached_network_params.max_bandwidth_estimate_bytes_per_second()
- : cached_network_params.bandwidth_estimate_bytes_per_second());
- QuicTime::Delta rtt =
- QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms());
-
- max_bandwidth_.Update(bandwidth, round_trip_count_);
+ if (!bandwidth.IsZero()) {
+ max_bandwidth_.Update(bandwidth, round_trip_count_);
+ }
if (!rtt.IsZero() && (min_rtt_ > rtt || min_rtt_.IsZero())) {
min_rtt_ = rtt;
}
@@ -216,9 +237,9 @@ void BbrSender::ResumeConnectionState(
void BbrSender::OnCongestionEvent(bool /*rtt_updated*/,
QuicByteCount prior_in_flight,
QuicTime event_time,
- const CongestionVector& acked_packets,
+ const AckedPacketVector& acked_packets,
const CongestionVector& lost_packets) {
- const QuicByteCount total_bytes_acked_before = sampler_.total_bytes_acked();
+ const QuicByteCount total_bytes_acked_before = sampler_->total_bytes_acked();
bool is_round_start = false;
bool min_rtt_expired = false;
@@ -227,26 +248,17 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/,
// Input the new data into the BBR model of the connection.
if (!acked_packets.empty()) {
- QuicPacketNumber last_acked_packet = acked_packets.rbegin()->first;
+ QuicPacketNumber last_acked_packet = acked_packets.rbegin()->packet_number;
is_round_start = UpdateRoundTripCounter(last_acked_packet);
min_rtt_expired = UpdateBandwidthAndMinRtt(event_time, acked_packets);
UpdateRecoveryState(last_acked_packet, !lost_packets.empty(),
is_round_start);
const QuicByteCount bytes_acked =
- sampler_.total_bytes_acked() - total_bytes_acked_before;
+ sampler_->total_bytes_acked() - total_bytes_acked_before;
UpdateAckAggregationBytes(event_time, bytes_acked);
- if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2 ||
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes3) {
- if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2) {
- QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2,
- 1, 2);
- }
- if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes3) {
- QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes3,
- 1, 2);
- }
+ if (max_aggregation_bytes_multiplier_ > 0) {
if (unacked_packets_->bytes_in_flight() <=
1.25 * GetTargetCongestionWindow(pacing_gain_)) {
bytes_acked_since_queue_drained_ = 0;
@@ -272,7 +284,7 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/,
// Calculate number of packets acked and lost.
QuicByteCount bytes_acked =
- sampler_.total_bytes_acked() - total_bytes_acked_before;
+ sampler_->total_bytes_acked() - total_bytes_acked_before;
QuicByteCount bytes_lost = 0;
for (const auto& packet : lost_packets) {
bytes_lost += packet.second;
@@ -285,7 +297,7 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/,
CalculateRecoveryWindow(bytes_acked, bytes_lost);
// Cleanup internal state.
- sampler_.RemoveObsoletePackets(unacked_packets_->GetLeastUnacked());
+ sampler_->RemoveObsoletePackets(unacked_packets_->GetLeastUnacked());
}
CongestionControlType BbrSender::GetCongestionControlType() const {
@@ -334,7 +346,7 @@ void BbrSender::EnterProbeBandwidthMode(QuicTime now) {
void BbrSender::DiscardLostPackets(const CongestionVector& lost_packets) {
for (const auto& packet : lost_packets) {
- sampler_.OnPacketLost(packet.first);
+ sampler_->OnPacketLost(packet.first);
}
}
@@ -350,11 +362,11 @@ bool BbrSender::UpdateRoundTripCounter(QuicPacketNumber last_acked_packet) {
bool BbrSender::UpdateBandwidthAndMinRtt(
QuicTime now,
- const CongestionVector& acked_packets) {
+ const AckedPacketVector& acked_packets) {
QuicTime::Delta sample_min_rtt = QuicTime::Delta::Infinite();
for (const auto& packet : acked_packets) {
BandwidthSample bandwidth_sample =
- sampler_.OnPacketAcknowledged(now, packet.first);
+ sampler_->OnPacketAcknowledged(now, packet.packet_number);
last_sample_is_app_limited_ = bandwidth_sample.is_app_limited;
if (!bandwidth_sample.rtt.IsZero()) {
sample_min_rtt = std::min(sample_min_rtt, bandwidth_sample.rtt);
@@ -431,7 +443,8 @@ void BbrSender::CheckIfFullBandwidthReached() {
}
rounds_without_bandwidth_gain_++;
- if (rounds_without_bandwidth_gain_ >= num_startup_rtts_) {
+ if ((rounds_without_bandwidth_gain_ >= num_startup_rtts_) ||
+ (exit_startup_on_loss_ && InRecovery())) {
is_at_full_bandwidth_ = true;
}
}
@@ -460,7 +473,7 @@ void BbrSender::MaybeEnterOrExitProbeRtt(QuicTime now,
}
if (mode_ == PROBE_RTT) {
- sampler_.OnAppLimited();
+ sampler_->OnAppLimited();
if (exit_probe_rtt_at_ == QuicTime::Zero()) {
// If the window has reached the appropriate size, schedule exiting
@@ -588,25 +601,15 @@ void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked) {
if (rtt_variance_weight_ > 0.f && !BandwidthEstimate().IsZero()) {
target_window += rtt_variance_weight_ * rtt_stats_->mean_deviation() *
BandwidthEstimate();
- } else if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2 &&
- is_at_full_bandwidth_) {
- QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2, 2,
- 2);
- if (2 * max_ack_height_.GetBest() > bytes_acked_since_queue_drained_) {
- target_window +=
- 2 * max_ack_height_.GetBest() - bytes_acked_since_queue_drained_;
- }
- } else if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes3 &&
- is_at_full_bandwidth_) {
- QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes3, 2,
- 2);
+ } else if (max_aggregation_bytes_multiplier_ > 0 && is_at_full_bandwidth_) {
// Subtracting only half the bytes_acked_since_queue_drained ensures sending
// doesn't completely stop for a long period of time if the queue hasn't
// been drained recently.
- if (1.5 * max_ack_height_.GetBest() >
+ if (max_aggregation_bytes_multiplier_ * max_ack_height_.GetBest() >
bytes_acked_since_queue_drained_ / 2) {
- target_window += 1.5 * max_ack_height_.GetBest() -
- bytes_acked_since_queue_drained_ / 2;
+ target_window +=
+ max_aggregation_bytes_multiplier_ * max_ack_height_.GetBest() -
+ bytes_acked_since_queue_drained_ / 2;
}
} else if (is_at_full_bandwidth_) {
target_window += max_ack_height_.GetBest();
@@ -635,7 +638,7 @@ void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked) {
congestion_window_ =
std::min(target_window, congestion_window_ + bytes_acked);
} else if (congestion_window_ < target_window ||
- sampler_.total_bytes_acked() < initial_congestion_window_) {
+ sampler_->total_bytes_acked() < initial_congestion_window_) {
// If the connection is not yet out of startup phase, do not decrease the
// window.
congestion_window_ = congestion_window_ + bytes_acked;
@@ -693,7 +696,7 @@ void BbrSender::OnApplicationLimited(QuicByteCount bytes_in_flight) {
return;
}
- sampler_.OnAppLimited();
+ sampler_->OnAppLimited();
QUIC_DVLOG(2) << "Becoming application limited. Last sent packet: "
<< last_sent_packet_ << ", CWND: " << GetCongestionWindow();
}
diff --git a/chromium/net/quic/core/congestion_control/bbr_sender.h b/chromium/net/quic/core/congestion_control/bbr_sender.h
index 71405ddeeef..c170db6c7a9 100644
--- a/chromium/net/quic/core/congestion_control/bbr_sender.h
+++ b/chromium/net/quic/core/congestion_control/bbr_sender.h
@@ -98,18 +98,18 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
// Start implementation of SendAlgorithmInterface.
bool InSlowStart() const override;
bool InRecovery() const override;
+ bool IsProbingForMoreBandwidth() const override;
void SetFromConfig(const QuicConfig& config,
Perspective perspective) override;
- void ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) override;
+ void AdjustNetworkParameters(QuicBandwidth bandwidth,
+ QuicTime::Delta rtt) override;
void SetNumEmulatedConnections(int num_connections) override {}
void OnCongestionEvent(bool rtt_updated,
QuicByteCount prior_in_flight,
QuicTime event_time,
- const CongestionVector& acked_packets,
+ const AckedPacketVector& acked_packets,
const CongestionVector& lost_packets) override;
bool OnPacketSent(QuicTime sent_time,
QuicByteCount bytes_in_flight,
@@ -175,7 +175,7 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
// Updates the current bandwidth and min_rtt estimate based on the samples for
// the received acknowledgements. Returns true if min_rtt has expired.
bool UpdateBandwidthAndMinRtt(QuicTime now,
- const CongestionVector& acked_packets);
+ const AckedPacketVector& acked_packets);
// Updates the current gain used in PROBE_BW mode.
void UpdateGainCyclePhase(QuicTime now,
QuicByteCount prior_in_flight,
@@ -217,7 +217,7 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
// Bandwidth sampler provides BBR with the bandwidth measurements at
// individual points.
- BandwidthSampler sampler_;
+ std::unique_ptr<BandwidthSamplerInterface> sampler_;
// The number of the round trips that have occurred during the connection.
QuicRoundTripCount round_trip_count_;
@@ -243,6 +243,10 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
// dropped below the target window.
QuicByteCount bytes_acked_since_queue_drained_;
+ // The muliplier for calculating the max amount of extra CWND to add to
+ // compensate for ack aggregation.
+ float max_aggregation_bytes_multiplier_;
+
// Minimum RTT estimate. Automatically expires within 10 seconds (and
// triggers PROBE_RTT mode) if no new value is sampled during that period.
QuicTime::Delta min_rtt_;
@@ -274,6 +278,9 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
const float rtt_variance_weight_;
// The number of RTTs to stay in STARTUP mode. Defaults to 3.
QuicRoundTripCount num_startup_rtts_;
+ // If true, exit startup if 1RTT has passed with no bandwidth increase and
+ // the connection is in recovery.
+ bool exit_startup_on_loss_;
// Number of round-trips in PROBE_BW mode, used for determining the current
// pacing gain cycle.
diff --git a/chromium/net/quic/core/congestion_control/bbr_sender_test.cc b/chromium/net/quic/core/congestion_control/bbr_sender_test.cc
index a3a4d2314db..69e151bfb12 100644
--- a/chromium/net/quic/core/congestion_control/bbr_sender_test.cc
+++ b/chromium/net/quic/core/congestion_control/bbr_sender_test.cc
@@ -92,6 +92,7 @@ class BbrSenderTest : public QuicTest {
{&receiver_, &competing_receiver_}) {
// These will be changed by the appropriate tests as necessary.
FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false;
+ FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes4 = true;
rtt_stats_ = bbr_sender_.connection()->sent_packet_manager().GetRttStats();
sender_ = SetupBbrSender(&bbr_sender_);
@@ -239,6 +240,14 @@ class BbrSenderTest : public QuicTest {
simulator_.RunFor(wait_time + kTestRtt);
ASSERT_EQ(0u, bbr_sender_.bytes_to_transfer());
}
+
+ void SetConnectionOption(QuicTag option) {
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(option);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ }
};
// Test a simple long data transfer in the default setup.
@@ -292,7 +301,6 @@ TEST_F(BbrSenderTest, SimpleTransferSmallBuffer) {
// Test a simple long data transfer with 2 rtts of aggregation.
TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) {
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2 = false;
FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false;
CreateDefaultSetup();
// 2 RTTs of aggregation, with a max of 10kb.
@@ -318,7 +326,6 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) {
// Test a simple long data transfer with 2 rtts of aggregation.
TEST_F(BbrSenderTest, SimpleTransferAckDecimation) {
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2 = false;
// Decrease the CWND gain so extra CWND is required with stretch acks.
FLAGS_quic_bbr_cwnd_gain = 1.0;
sender_ = new BbrSender(
@@ -353,73 +360,13 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) {
}
// Test a simple long data transfer with 2 rtts of aggregation.
-TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes2) {
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2 = true;
+TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes4) {
FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false;
- CreateDefaultSetup();
- // 2 RTTs of aggregation, with a max of 10kb.
- EnableAggregation(10 * 1024, 2 * kTestRtt);
-
- // Transfer 12MB.
- DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
- EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
- // It's possible to read a bandwidth as much as 50% too high with aggregation.
- EXPECT_LE(kTestLinkBandwidth * 0.99f,
- sender_->ExportDebugState().max_bandwidth);
- // TODO(ianswett): Tighten this bound once we understand why BBR is
- // overestimating bandwidth with aggregation. b/36022633
- EXPECT_GE(kTestLinkBandwidth * 1.5f,
- sender_->ExportDebugState().max_bandwidth);
- // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures
- // bandwidth higher than the link rate.
- // The margin here is high, because the aggregation greatly increases
- // smoothed rtt.
- EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt());
- ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.33f);
-}
-// Test a simple long data transfer with 2 rtts of aggregation.
-TEST_F(BbrSenderTest, SimpleTransferAckDecimation2) {
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2 = true;
- // Decrease the CWND gain so extra CWND is required with stretch acks.
- FLAGS_quic_bbr_cwnd_gain = 1.0;
- sender_ = new BbrSender(
- rtt_stats_,
- QuicSentPacketManagerPeer::GetUnackedPacketMap(
- QuicConnectionPeer::GetSentPacketManager(bbr_sender_.connection())),
- kInitialCongestionWindowPackets, kDefaultMaxCongestionWindowPackets,
- &random_);
- QuicConnectionPeer::SetSendAlgorithm(bbr_sender_.connection(), sender_);
- // Enable Ack Decimation on the receiver.
- QuicConnectionPeer::SetAckMode(receiver_.connection(),
- QuicConnection::AckMode::ACK_DECIMATION);
CreateDefaultSetup();
+ // Enable ack aggregation that forces the queue to be drained.
+ SetConnectionOption(kBBR1);
- // Transfer 12MB.
- DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
- EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
- // It's possible to read a bandwidth as much as 50% too high with aggregation.
- EXPECT_LE(kTestLinkBandwidth * 0.99f,
- sender_->ExportDebugState().max_bandwidth);
- // TODO(ianswett): Tighten this bound once we understand why BBR is
- // overestimating bandwidth with aggregation. b/36022633
- EXPECT_GE(kTestLinkBandwidth * 1.5f,
- sender_->ExportDebugState().max_bandwidth);
- // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures
- // bandwidth higher than the link rate.
- EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
- // The margin here is high, because the aggregation greatly increases
- // smoothed rtt.
- EXPECT_GE(kTestRtt * 2, rtt_stats_->smoothed_rtt());
- ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.1f);
-}
-
-// Test a simple long data transfer with 2 rtts of aggregation.
-TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes3) {
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2 = false;
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes3 = true;
- FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false;
- CreateDefaultSetup();
// 2 RTTs of aggregation, with a max of 10kb.
EnableAggregation(10 * 1024, 2 * kTestRtt);
@@ -442,9 +389,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes3) {
}
// Test a simple long data transfer with 2 rtts of aggregation.
-TEST_F(BbrSenderTest, SimpleTransferAckDecimation3) {
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2 = false;
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes3 = true;
+TEST_F(BbrSenderTest, SimpleTransferAckDecimation4) {
// Decrease the CWND gain so extra CWND is required with stretch acks.
FLAGS_quic_bbr_cwnd_gain = 1.0;
sender_ = new BbrSender(
@@ -458,6 +403,8 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation3) {
QuicConnectionPeer::SetAckMode(receiver_.connection(),
QuicConnection::AckMode::ACK_DECIMATION);
CreateDefaultSetup();
+ // Enable ack aggregation that forces the queue to be drained.
+ SetConnectionOption(kBBR1);
// Transfer 12MB.
DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
@@ -727,11 +674,7 @@ TEST_F(BbrSenderTest, NoBandwidthDropOnStartup) {
TEST_F(BbrSenderTest, SimpleTransfer1RTTStartup) {
CreateDefaultSetup();
- QuicConfig config;
- QuicTagVector options;
- options.push_back(k1RTT);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ SetConnectionOption(k1RTT);
EXPECT_EQ(1u, sender_->num_startup_rtts());
// Run until the full bandwidth is reached and check how many rounds it was.
@@ -761,11 +704,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTStartup) {
FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false;
CreateDefaultSetup();
- QuicConfig config;
- QuicTagVector options;
- options.push_back(k2RTT);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ SetConnectionOption(k2RTT);
EXPECT_EQ(2u, sender_->num_startup_rtts());
// Run until the full bandwidth is reached and check how many rounds it was.
@@ -789,6 +728,64 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTStartup) {
EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
}
+// Test exiting STARTUP earlier upon loss due to the LRTT connection option.
+TEST_F(BbrSenderTest, SimpleTransferLRTTStartup) {
+ FLAGS_quic_reloadable_flag_quic_bbr_exit_startup_on_loss = true;
+ CreateDefaultSetup();
+
+ SetConnectionOption(kLRTT);
+ EXPECT_EQ(3u, sender_->num_startup_rtts());
+
+ // Run until the full bandwidth is reached and check how many rounds it was.
+ bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024);
+ QuicRoundTripCount max_bw_round = 0;
+ QuicBandwidth max_bw(QuicBandwidth::Zero());
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this, &max_bw, &max_bw_round]() {
+ if (max_bw < sender_->ExportDebugState().max_bandwidth) {
+ max_bw = sender_->ExportDebugState().max_bandwidth;
+ max_bw_round = sender_->ExportDebugState().round_trip_count;
+ }
+ return sender_->ExportDebugState().is_at_full_bandwidth;
+ },
+ QuicTime::Delta::FromSeconds(5));
+ ASSERT_TRUE(simulator_result);
+ EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode);
+ EXPECT_EQ(3u, sender_->ExportDebugState().round_trip_count - max_bw_round);
+ EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain);
+ EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost);
+ EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
+}
+
+// Test exiting STARTUP earlier upon loss due to the LRTT connection option.
+TEST_F(BbrSenderTest, SimpleTransferLRTTStartupSmallBuffer) {
+ FLAGS_quic_reloadable_flag_quic_bbr_exit_startup_on_loss = true;
+ CreateSmallBufferSetup();
+
+ SetConnectionOption(kLRTT);
+ EXPECT_EQ(3u, sender_->num_startup_rtts());
+
+ // Run until the full bandwidth is reached and check how many rounds it was.
+ bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024);
+ QuicRoundTripCount max_bw_round = 0;
+ QuicBandwidth max_bw(QuicBandwidth::Zero());
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this, &max_bw, &max_bw_round]() {
+ if (max_bw < sender_->ExportDebugState().max_bandwidth) {
+ max_bw = sender_->ExportDebugState().max_bandwidth;
+ max_bw_round = sender_->ExportDebugState().round_trip_count;
+ }
+ return sender_->ExportDebugState().is_at_full_bandwidth;
+ },
+ QuicTime::Delta::FromSeconds(5));
+ ASSERT_TRUE(simulator_result);
+ EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode);
+ EXPECT_EQ(2u, sender_->ExportDebugState().round_trip_count - max_bw_round);
+ EXPECT_EQ(1u, sender_->ExportDebugState().rounds_without_bandwidth_gain);
+ EXPECT_NE(0u, bbr_sender_.connection()->GetStats().packets_lost);
+ EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
+}
+
// Test that two BBR flows started slightly apart from each other terminate.
TEST_F(BbrSenderTest, SimpleCompetition) {
const QuicByteCount transfer_size = 10 * 1024 * 1024;
@@ -821,11 +818,7 @@ TEST_F(BbrSenderTest, ResumeConnectionState) {
FLAGS_quic_reloadable_flag_quic_bbr_bandwidth_resumption = true;
CreateDefaultSetup();
- CachedNetworkParameters params;
- params.set_bandwidth_estimate_bytes_per_second(
- kTestLinkBandwidth.ToBytesPerSecond());
- params.set_min_rtt_ms(kTestRtt.ToMilliseconds());
- sender_->ResumeConnectionState(params, false);
+ sender_->AdjustNetworkParameters(kTestLinkBandwidth, kTestRtt);
EXPECT_EQ(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth);
EXPECT_EQ(kTestLinkBandwidth, sender_->BandwidthEstimate());
ExpectApproxEq(kTestRtt, sender_->ExportDebugState().min_rtt, 0.01f);
diff --git a/chromium/net/quic/core/congestion_control/pacing_sender.cc b/chromium/net/quic/core/congestion_control/pacing_sender.cc
index c645b8a8b41..d7b7b55dfda 100644
--- a/chromium/net/quic/core/congestion_control/pacing_sender.cc
+++ b/chromium/net/quic/core/congestion_control/pacing_sender.cc
@@ -38,7 +38,7 @@ void PacingSender::OnCongestionEvent(
bool rtt_updated,
QuicByteCount bytes_in_flight,
QuicTime event_time,
- const SendAlgorithmInterface::CongestionVector& acked_packets,
+ const SendAlgorithmInterface::AckedPacketVector& acked_packets,
const SendAlgorithmInterface::CongestionVector& lost_packets) {
DCHECK(sender_ != nullptr);
if (!lost_packets.empty()) {
diff --git a/chromium/net/quic/core/congestion_control/pacing_sender.h b/chromium/net/quic/core/congestion_control/pacing_sender.h
index 65047210b91..c749d3f0962 100644
--- a/chromium/net/quic/core/congestion_control/pacing_sender.h
+++ b/chromium/net/quic/core/congestion_control/pacing_sender.h
@@ -43,7 +43,7 @@ class QUIC_EXPORT_PRIVATE PacingSender {
bool rtt_updated,
QuicByteCount bytes_in_flight,
QuicTime event_time,
- const SendAlgorithmInterface::CongestionVector& acked_packets,
+ const SendAlgorithmInterface::AckedPacketVector& acked_packets,
const SendAlgorithmInterface::CongestionVector& lost_packets);
bool OnPacketSent(QuicTime sent_time,
diff --git a/chromium/net/quic/core/congestion_control/pacing_sender_test.cc b/chromium/net/quic/core/congestion_control/pacing_sender_test.cc
index 174d93da223..a339355260d 100644
--- a/chromium/net/quic/core/congestion_control/pacing_sender_test.cc
+++ b/chromium/net/quic/core/congestion_control/pacing_sender_test.cc
@@ -13,6 +13,7 @@
#include "net/quic/test_tools/quic_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::IsEmpty;
using testing::Return;
using testing::StrictMock;
using testing::_;
@@ -47,7 +48,7 @@ class PacingSenderTest : public QuicTest {
EXPECT_CALL(*mock_sender_, OnCongestionEvent(_, _, _, _, _));
SendAlgorithmInterface::CongestionVector lost_packets;
lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
- SendAlgorithmInterface::CongestionVector empty;
+ SendAlgorithmInterface::AckedPacketVector empty;
pacing_sender_->OnCongestionEvent(true, 1234, clock_.Now(), empty,
lost_packets);
} else if (burst_size != kInitialBurstPackets) {
@@ -103,9 +104,10 @@ class PacingSenderTest : public QuicTest {
void UpdateRtt() {
EXPECT_CALL(*mock_sender_,
OnCongestionEvent(true, kBytesInFlight, _, _, _));
- SendAlgorithmInterface::CongestionVector empty_map;
+ SendAlgorithmInterface::AckedPacketVector empty_acked;
+ SendAlgorithmInterface::CongestionVector empty_lost;
pacing_sender_->OnCongestionEvent(true, kBytesInFlight, clock_.Now(),
- empty_map, empty_map);
+ empty_acked, empty_lost);
}
const QuicTime::Delta zero_time_;
@@ -320,11 +322,11 @@ TEST_F(PacingSenderTest, NoBurstEnteringRecovery) {
// Losing a packet will set clear burst tokens.
SendAlgorithmInterface::CongestionVector lost_packets;
lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
- SendAlgorithmInterface::CongestionVector empty;
- EXPECT_CALL(*mock_sender_,
- OnCongestionEvent(true, kMaxPacketSize, _, empty, lost_packets));
- pacing_sender_->OnCongestionEvent(true, kMaxPacketSize, clock_.Now(), empty,
- lost_packets);
+ SendAlgorithmInterface::AckedPacketVector empty_acked;
+ EXPECT_CALL(*mock_sender_, OnCongestionEvent(true, kMaxPacketSize, _,
+ IsEmpty(), lost_packets));
+ pacing_sender_->OnCongestionEvent(true, kMaxPacketSize, clock_.Now(),
+ empty_acked, lost_packets);
// One packet is sent immediately, because of 1ms pacing granularity.
CheckPacketIsSentImmediately();
// Ensure packets are immediately paced.
diff --git a/chromium/net/quic/core/congestion_control/send_algorithm_interface.h b/chromium/net/quic/core/congestion_control/send_algorithm_interface.h
index 5abb3e94761..f1557817665 100644
--- a/chromium/net/quic/core/congestion_control/send_algorithm_interface.h
+++ b/chromium/net/quic/core/congestion_control/send_algorithm_interface.h
@@ -29,6 +29,26 @@ const QuicPacketCount kDefaultMaxCongestionWindowPackets = 2000;
class QUIC_EXPORT_PRIVATE SendAlgorithmInterface {
public:
+ struct AckedPacket {
+ AckedPacket(QuicPacketNumber packet_number,
+ QuicPacketLength bytes_acked,
+ QuicTime receive_timestamp)
+ : packet_number(packet_number),
+ bytes_acked(bytes_acked),
+ receive_timestamp(receive_timestamp) {}
+
+ QuicPacketNumber packet_number;
+ // Number of bytes sent in the packet that was acknowledged.
+ QuicPacketLength bytes_acked;
+ // The time |packet_number| was received by the peer, according to the
+ // optional timestamp the peer included in the ACK frame which acknowledged
+ // |packet_number|. Zero if no timestamp was available for this packet.
+ QuicTime receive_timestamp;
+ };
+
+ // A vector of acked packets.
+ typedef std::vector<AckedPacket> AckedPacketVector;
+
// A sorted vector of packets.
typedef std::vector<std::pair<QuicPacketNumber, QuicPacketLength>>
CongestionVector;
@@ -59,7 +79,7 @@ class QUIC_EXPORT_PRIVATE SendAlgorithmInterface {
virtual void OnCongestionEvent(bool rtt_updated,
QuicByteCount prior_in_flight,
QuicTime event_time,
- const CongestionVector& acked_packets,
+ const AckedPacketVector& acked_packets,
const CongestionVector& lost_packets) = 0;
// Inform that we sent |bytes| to the wire, and if the packet is
@@ -104,18 +124,21 @@ class QUIC_EXPORT_PRIVATE SendAlgorithmInterface {
// Whether the send algorithm is currently in recovery.
virtual bool InRecovery() const = 0;
+ // True when the congestion control is probing for more bandwidth and needs
+ // enough data to not be app-limited to do so.
+ virtual bool IsProbingForMoreBandwidth() const = 0;
+
// Returns the size of the slow start congestion window in bytes,
- // aka ssthresh. Some send algorithms do not define a slow start
- // threshold and will return 0.
+ // aka ssthresh. Only defined for Cubic and Reno, other algorithms return 0.
virtual QuicByteCount GetSlowStartThreshold() const = 0;
virtual CongestionControlType GetCongestionControlType() const = 0;
- // Called by the Session when we get a bandwidth estimate from the client.
- // Uses the max bandwidth in the params if |max_bandwidth_resumption| is true.
- virtual void ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) = 0;
+ // Notifies the congestion control algorithm of an external network
+ // measurement or prediction. Either |bandwidth| or |rtt| may be zero if no
+ // sample is available.
+ virtual void AdjustNetworkParameters(QuicBandwidth bandwidth,
+ QuicTime::Delta rtt) = 0;
// Retrieves debugging information about the current state of the
// send algorithm.
diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
index d56fbf8394c..de05e72d54c 100644
--- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
@@ -21,7 +21,6 @@ namespace {
const QuicByteCount kMaxBurstBytes = 3 * kDefaultTCPMSS;
const float kRenoBeta = 0.7f; // Reno backoff factor.
const uint32_t kDefaultNumConnections = 2; // N-connection emulation.
-const float kRateBasedExtraCwnd = 1.5f; // CWND for rate based sending.
} // namespace
TcpCubicSenderBase::TcpCubicSenderBase(const QuicClock* clock,
@@ -38,7 +37,6 @@ TcpCubicSenderBase::TcpCubicSenderBase(const QuicClock* clock,
min4_mode_(false),
last_cutback_exited_slowstart_(false),
slow_start_large_reduction_(false),
- rate_based_sending_(false),
no_prr_(false) {}
TcpCubicSenderBase::~TcpCubicSenderBase() {}
@@ -87,23 +85,14 @@ void TcpCubicSenderBase::SetFromConfig(const QuicConfig& config,
// Use unity pacing instead of PRR.
no_prr_ = true;
}
- if (config.HasReceivedConnectionOptions() &&
- ContainsQuicTag(config.ReceivedConnectionOptions(), kRATE)) {
- // Rate based sending experiment
- rate_based_sending_ = true;
- }
}
}
-void TcpCubicSenderBase::ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) {
- QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(
- max_bandwidth_resumption
- ? cached_network_params.max_bandwidth_estimate_bytes_per_second()
- : cached_network_params.bandwidth_estimate_bytes_per_second());
- QuicTime::Delta rtt =
- QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms());
+void TcpCubicSenderBase::AdjustNetworkParameters(QuicBandwidth bandwidth,
+ QuicTime::Delta rtt) {
+ if (bandwidth.IsZero() || rtt.IsZero()) {
+ return;
+ }
SetCongestionWindowFromBandwidthAndRtt(bandwidth, rtt);
}
@@ -124,7 +113,7 @@ void TcpCubicSenderBase::OnCongestionEvent(
bool rtt_updated,
QuicByteCount prior_in_flight,
QuicTime event_time,
- const CongestionVector& acked_packets,
+ const AckedPacketVector& acked_packets,
const CongestionVector& lost_packets) {
if (rtt_updated && InSlowStart() &&
hybrid_slow_start_.ShouldExitSlowStart(
@@ -136,9 +125,9 @@ void TcpCubicSenderBase::OnCongestionEvent(
it != lost_packets.end(); ++it) {
OnPacketLost(it->first, it->second, prior_in_flight);
}
- for (CongestionVector::const_iterator it = acked_packets.begin();
- it != acked_packets.end(); ++it) {
- OnPacketAcked(it->first, it->second, prior_in_flight, event_time);
+ for (const SendAlgorithmInterface::AckedPacket acked_packet : acked_packets) {
+ OnPacketAcked(acked_packet.packet_number, acked_packet.bytes_acked,
+ prior_in_flight, event_time);
}
}
@@ -200,15 +189,11 @@ QuicTime::Delta TcpCubicSenderBase::TimeUntilSend(
if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) {
return QuicTime::Delta::Zero();
}
- if (rate_based_sending_ &&
- GetCongestionWindow() * kRateBasedExtraCwnd > bytes_in_flight) {
- return QuicTime::Delta::Zero();
- }
return QuicTime::Delta::Infinite();
}
QuicBandwidth TcpCubicSenderBase::PacingRate(
- QuicByteCount bytes_in_flight) const {
+ QuicByteCount /* bytes_in_flight */) const {
// We pace at twice the rate of the underlying sender's bandwidth estimate
// during slow start and 1.25x during congestion avoidance to ensure pacing
// doesn't prevent us from filling the window.
@@ -218,11 +203,6 @@ QuicBandwidth TcpCubicSenderBase::PacingRate(
}
const QuicBandwidth bandwidth =
QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt);
- if (rate_based_sending_ && bytes_in_flight > GetCongestionWindow()) {
- // Rate based sending allows sending more than CWND, but reduces the pacing
- // rate when the bytes in flight is more than the CWND to 75% of bandwidth.
- return 0.75 * bandwidth;
- }
return bandwidth * (InSlowStart() ? 2 : (no_prr_ && InRecovery() ? 1 : 1.25));
}
@@ -255,6 +235,10 @@ bool TcpCubicSenderBase::InRecovery() const {
largest_acked_packet_number_ != 0;
}
+bool TcpCubicSenderBase::IsProbingForMoreBandwidth() const {
+ return false;
+}
+
void TcpCubicSenderBase::OnRetransmissionTimeout(bool packets_retransmitted) {
largest_sent_at_last_cutback_ = 0;
if (!packets_retransmitted) {
diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h
index 2488bf2536c..e60f782ab64 100644
--- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h
@@ -45,14 +45,13 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBase : public SendAlgorithmInterface {
// Start implementation of SendAlgorithmInterface.
void SetFromConfig(const QuicConfig& config,
Perspective perspective) override;
- void ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) override;
+ void AdjustNetworkParameters(QuicBandwidth bandwidth,
+ QuicTime::Delta rtt) override;
void SetNumEmulatedConnections(int num_connections) override;
void OnCongestionEvent(bool rtt_updated,
QuicByteCount prior_in_flight,
QuicTime event_time,
- const CongestionVector& acked_packets,
+ const AckedPacketVector& acked_packets,
const CongestionVector& lost_packets) override;
bool OnPacketSent(QuicTime sent_time,
QuicByteCount bytes_in_flight,
@@ -67,6 +66,7 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBase : public SendAlgorithmInterface {
QuicBandwidth BandwidthEstimate() const override;
bool InSlowStart() const override;
bool InRecovery() const override;
+ bool IsProbingForMoreBandwidth() const override;
std::string GetDebugState() const override;
void OnApplicationLimited(QuicByteCount bytes_in_flight) override;
@@ -148,9 +148,6 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBase : public SendAlgorithmInterface {
// When true, exit slow start with large cutback of congestion window.
bool slow_start_large_reduction_;
- // When true, use rate based sending instead of only sending if there's CWND.
- bool rate_based_sending_;
-
// When true, use unity pacing instead of PRR.
bool no_prr_;
diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
index b35cb2b7dbb..9798de95e6c 100644
--- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
@@ -84,12 +84,12 @@ class TcpCubicSenderBytesTest : public QuicTest {
void AckNPackets(int n) {
sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60),
QuicTime::Delta::Zero(), clock_.Now());
- SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::AckedPacketVector acked_packets;
SendAlgorithmInterface::CongestionVector lost_packets;
for (int i = 0; i < n; ++i) {
++acked_packet_number_;
- acked_packets.push_back(
- std::make_pair(acked_packet_number_, kDefaultTCPMSS));
+ acked_packets.push_back(SendAlgorithmInterface::AckedPacket(
+ acked_packet_number_, kDefaultTCPMSS, QuicTime::Zero()));
}
sender_->OnCongestionEvent(true, bytes_in_flight_, clock_.Now(),
acked_packets, lost_packets);
@@ -100,7 +100,7 @@ class TcpCubicSenderBytesTest : public QuicTest {
void LoseNPackets(int n) { LoseNPackets(n, kDefaultTCPMSS); }
void LoseNPackets(int n, QuicPacketLength packet_length) {
- SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::AckedPacketVector acked_packets;
SendAlgorithmInterface::CongestionVector lost_packets;
for (int i = 0; i < n; ++i) {
++acked_packet_number_;
@@ -114,7 +114,7 @@ class TcpCubicSenderBytesTest : public QuicTest {
// Does not increment acked_packet_number_.
void LosePacket(QuicPacketNumber packet_number) {
- SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::AckedPacketVector acked_packets;
SendAlgorithmInterface::CongestionVector lost_packets;
lost_packets.push_back(std::make_pair(packet_number, kDefaultTCPMSS));
sender_->OnCongestionEvent(false, bytes_in_flight_, clock_.Now(),
@@ -675,40 +675,27 @@ TEST_F(TcpCubicSenderBytesTest, 1ConnectionCongestionAvoidanceAtEndOfRecovery) {
TEST_F(TcpCubicSenderBytesTest, BandwidthResumption) {
// Test that when provided with CachedNetworkParameters and opted in to the
- // bandwidth resumption experiment, that the TcpCubicSender sets initial CWND
- // appropriately.
+ // bandwidth resumption experiment, that the TcpCubicSenderPackets sets
+ // initial CWND appropriately.
// Set some common values.
- CachedNetworkParameters cached_network_params;
const QuicPacketCount kNumberOfPackets = 123;
- const int kBandwidthEstimateBytesPerSecond =
- kNumberOfPackets * kDefaultTCPMSS;
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- kBandwidthEstimateBytesPerSecond);
- cached_network_params.set_min_rtt_ms(1000);
-
- // Make sure that a bandwidth estimate results in a changed CWND.
- cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
- (kNumSecondsPerHour - 1));
- sender_->ResumeConnectionState(cached_network_params, false);
+ const QuicBandwidth kBandwidthEstimate =
+ QuicBandwidth::FromBytesPerSecond(kNumberOfPackets * kDefaultTCPMSS);
+ const QuicTime::Delta kRttEstimate = QuicTime::Delta::FromSeconds(1);
+ sender_->AdjustNetworkParameters(kBandwidthEstimate, kRttEstimate);
EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow());
- // Resumed CWND is limited to be in a sensible range.
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- (kMaxCongestionWindowPackets + 1) * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
- sender_->GetCongestionWindow());
-
- // Resume with an illegal value of 0 and verify the server uses 1 instead.
- cached_network_params.set_bandwidth_estimate_bytes_per_second(0);
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(sender_->min_congestion_window(), sender_->GetCongestionWindow());
+ // Resume with an illegal value of 0 and verify the server ignores it.
+ sender_->AdjustNetworkParameters(QuicBandwidth::Zero(), kRttEstimate);
+ EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow());
- // Resume to the max value.
- cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
- kMaxCongestionWindowPackets * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, true);
+ // Resumed CWND is limited to be in a sensible range.
+ const QuicBandwidth kUnreasonableBandwidth =
+ QuicBandwidth::FromBytesPerSecond((kMaxCongestionWindowPackets + 1) *
+ kDefaultTCPMSS);
+ sender_->AdjustNetworkParameters(kUnreasonableBandwidth,
+ QuicTime::Delta::FromSeconds(1));
EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
sender_->GetCongestionWindow());
}
@@ -764,38 +751,6 @@ TEST_F(TcpCubicSenderBytesTest, NoPRR) {
sender_->PacingRate(kRenoBeta * kDefaultWindowTCP));
}
-TEST_F(TcpCubicSenderBytesTest, PaceSlowerAboveCwnd) {
- QuicTime::Delta rtt(QuicTime::Delta::FromMilliseconds(60));
- sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), clock_.Now());
-
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kRATE);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- EXPECT_EQ(10 * kDefaultTCPMSS, sender_->GetCongestionWindow());
- sender_->SetNumEmulatedConnections(1);
- // Lose a packet to exit slow start.
- LoseNPackets(1);
- const QuicPacketCount cwnd = 7;
- EXPECT_EQ(cwnd * kDefaultTCPMSS, sender_->GetCongestionWindow());
-
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
- EXPECT_EQ(
- sender_->PacingRate(kDefaultTCPMSS),
- QuicBandwidth::FromBytesAndTimeDelta(7 * kDefaultTCPMSS, rtt) * 1.25);
- for (QuicPacketCount i = cwnd + 1; i < 1.5 * cwnd; ++i) {
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), i * kDefaultTCPMSS).IsZero());
- EXPECT_EQ(sender_->PacingRate(i * kDefaultTCPMSS),
- QuicBandwidth::FromBytesAndTimeDelta(cwnd * kDefaultTCPMSS, rtt) *
- 0.75);
- }
- EXPECT_FALSE(
- sender_->TimeUntilSend(QuicTime::Zero(), 11 * kDefaultTCPMSS).IsZero());
-}
-
TEST_F(TcpCubicSenderBytesTest, ResetAfterConnectionMigration) {
// Starts from slow start.
sender_->SetNumEmulatedConnections(1);
@@ -834,11 +789,12 @@ TEST_F(TcpCubicSenderBytesTest, DefaultMaxCwnd) {
&clock_, &rtt_stats, /*unacked_packets=*/nullptr, kCubicBytes,
QuicRandom::GetInstance(), &stats, kInitialCongestionWindow));
- SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::AckedPacketVector acked_packets;
SendAlgorithmInterface::CongestionVector missing_packets;
for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) {
acked_packets.clear();
- acked_packets.push_back(std::make_pair(i, 1350));
+ acked_packets.push_back(
+ SendAlgorithmInterface::AckedPacket(i, 1350, QuicTime::Zero()));
sender->OnCongestionEvent(true, sender->GetCongestionWindow(), clock_.Now(),
acked_packets, missing_packets);
}
diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc
index 66afc3fd4ed..d7807c9ba07 100644
--- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc
@@ -93,12 +93,12 @@ class TcpCubicSenderPacketsTest : public QuicTest {
void AckNPackets(int n) {
sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60),
QuicTime::Delta::Zero(), clock_.Now());
- SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::AckedPacketVector acked_packets;
SendAlgorithmInterface::CongestionVector lost_packets;
for (int i = 0; i < n; ++i) {
++acked_packet_number_;
- acked_packets.push_back(
- std::make_pair(acked_packet_number_, kDefaultTCPMSS));
+ acked_packets.push_back(SendAlgorithmInterface::AckedPacket(
+ acked_packet_number_, kDefaultTCPMSS, QuicTime::Zero()));
}
sender_->OnCongestionEvent(true, bytes_in_flight_, clock_.Now(),
acked_packets, lost_packets);
@@ -109,7 +109,7 @@ class TcpCubicSenderPacketsTest : public QuicTest {
void LoseNPackets(int n) { LoseNPackets(n, kDefaultTCPMSS); }
void LoseNPackets(int n, QuicPacketLength packet_length) {
- SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::AckedPacketVector acked_packets;
SendAlgorithmInterface::CongestionVector lost_packets;
for (int i = 0; i < n; ++i) {
++acked_packet_number_;
@@ -123,7 +123,7 @@ class TcpCubicSenderPacketsTest : public QuicTest {
// Does not increment acked_packet_number_.
void LosePacket(QuicPacketNumber packet_number) {
- SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::AckedPacketVector acked_packets;
SendAlgorithmInterface::CongestionVector lost_packets;
lost_packets.push_back(std::make_pair(packet_number, kDefaultTCPMSS));
sender_->OnCongestionEvent(false, bytes_in_flight_, clock_.Now(),
@@ -783,37 +783,24 @@ TEST_F(TcpCubicSenderPacketsTest, BandwidthResumption) {
// initial CWND appropriately.
// Set some common values.
- CachedNetworkParameters cached_network_params;
const QuicPacketCount kNumberOfPackets = 123;
- const int kBandwidthEstimateBytesPerSecond =
- kNumberOfPackets * kDefaultTCPMSS;
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- kBandwidthEstimateBytesPerSecond);
- cached_network_params.set_min_rtt_ms(1000);
-
- // Make sure that a bandwidth estimate results in a changed CWND.
- cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
- (kNumSecondsPerHour - 1));
- sender_->ResumeConnectionState(cached_network_params, false);
+ const QuicBandwidth kBandwidthEstimate =
+ QuicBandwidth::FromBytesPerSecond(kNumberOfPackets * kDefaultTCPMSS);
+ const QuicTime::Delta kRttEstimate = QuicTime::Delta::FromSeconds(1);
+ sender_->AdjustNetworkParameters(kBandwidthEstimate, kRttEstimate);
+ EXPECT_EQ(kNumberOfPackets, sender_->congestion_window());
+
+ // Resume with an illegal value of 0 and verify the server ignores it.
+ sender_->AdjustNetworkParameters(QuicBandwidth::Zero(), kRttEstimate);
EXPECT_EQ(kNumberOfPackets, sender_->congestion_window());
// Resumed CWND is limited to be in a sensible range.
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- (kMaxCongestionWindowPackets + 1) * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, false);
+ const QuicBandwidth kUnreasonableBandwidth =
+ QuicBandwidth::FromBytesPerSecond((kMaxCongestionWindowPackets + 1) *
+ kDefaultTCPMSS);
+ sender_->AdjustNetworkParameters(kUnreasonableBandwidth,
+ QuicTime::Delta::FromSeconds(1));
EXPECT_EQ(kMaxCongestionWindowPackets, sender_->congestion_window());
-
- // Resume with an illegal value of 0 and verify the server uses 1 instead.
- cached_network_params.set_bandwidth_estimate_bytes_per_second(0);
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(sender_->min_congestion_window(), sender_->congestion_window());
-
- // Resume to the max value.
- cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
- kMaxCongestionWindowPackets * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, true);
- EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
- sender_->GetCongestionWindow());
}
TEST_F(TcpCubicSenderPacketsTest, PaceBelowCWND) {
@@ -867,38 +854,6 @@ TEST_F(TcpCubicSenderPacketsTest, NoPRR) {
sender_->PacingRate(kRenoBeta * kDefaultWindowTCP));
}
-TEST_F(TcpCubicSenderPacketsTest, PaceSlowerAboveCwnd) {
- QuicTime::Delta rtt(QuicTime::Delta::FromMilliseconds(60));
- sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), clock_.Now());
-
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kRATE);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- EXPECT_EQ(10u, sender_->congestion_window());
- sender_->SetNumEmulatedConnections(1);
- // Lose a packet to exit slow start.
- LoseNPackets(1);
- const QuicPacketCount cwnd = 7;
- EXPECT_EQ(cwnd * kDefaultTCPMSS, sender_->GetCongestionWindow());
-
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
- EXPECT_EQ(
- sender_->PacingRate(kDefaultTCPMSS),
- QuicBandwidth::FromBytesAndTimeDelta(7 * kDefaultTCPMSS, rtt) * 1.25);
- for (QuicPacketCount i = cwnd + 1; i < 1.5 * cwnd; ++i) {
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), i * kDefaultTCPMSS).IsZero());
- EXPECT_EQ(sender_->PacingRate(i * kDefaultTCPMSS),
- QuicBandwidth::FromBytesAndTimeDelta(cwnd * kDefaultTCPMSS, rtt) *
- 0.75);
- }
- EXPECT_FALSE(
- sender_->TimeUntilSend(QuicTime::Zero(), 11 * kDefaultTCPMSS).IsZero());
-}
-
TEST_F(TcpCubicSenderPacketsTest, ResetAfterConnectionMigration) {
EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
EXPECT_EQ(kMaxCongestionWindowPackets, sender_->slowstart_threshold());
@@ -940,11 +895,12 @@ TEST_F(TcpCubicSenderPacketsTest, DefaultMaxCwnd) {
&clock_, &rtt_stats, /*unacked_packets=*/nullptr, kCubic,
QuicRandom::GetInstance(), &stats, kInitialCongestionWindow));
- SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::AckedPacketVector acked_packets;
SendAlgorithmInterface::CongestionVector missing_packets;
for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) {
acked_packets.clear();
- acked_packets.push_back(std::make_pair(i, 1350));
+ acked_packets.push_back(
+ SendAlgorithmInterface::AckedPacket(i, 1350, QuicTime::Zero()));
sender->OnCongestionEvent(true, sender->GetCongestionWindow(), clock_.Now(),
acked_packets, missing_packets);
}
diff --git a/chromium/net/quic/core/crypto/crypto_framer.h b/chromium/net/quic/core/crypto/crypto_framer.h
index 3daf862ef13..9ff70361959 100644
--- a/chromium/net/quic/core/crypto/crypto_framer.h
+++ b/chromium/net/quic/core/crypto/crypto_framer.h
@@ -12,6 +12,7 @@
#include <vector>
#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_message_parser.h"
#include "net/quic/core/quic_packets.h"
#include "net/quic/platform/api/quic_export.h"
@@ -32,22 +33,6 @@ class QUIC_EXPORT_PRIVATE CryptoFramerVisitorInterface {
virtual void OnHandshakeMessage(const CryptoHandshakeMessage& message) = 0;
};
-class QUIC_EXPORT_PRIVATE CryptoMessageParser {
- public:
- virtual ~CryptoMessageParser() {}
-
- virtual QuicErrorCode error() const = 0;
- virtual const std::string& error_detail() const = 0;
-
- // Processes input data, which must be delivered in order. Returns
- // false if there was an error, and true otherwise.
- virtual bool ProcessInput(QuicStringPiece input, Perspective perspective) = 0;
-
- // Returns the number of bytes of buffered input data remaining to be
- // parsed.
- virtual size_t InputBytesRemaining() const = 0;
-};
-
// A class for framing the crypto messages that are exchanged in a QUIC
// session.
class QUIC_EXPORT_PRIVATE CryptoFramer : public CryptoMessageParser {
diff --git a/chromium/net/quic/core/crypto/crypto_framer_test.cc b/chromium/net/quic/core/crypto/crypto_framer_test.cc
index 846f91f4be1..9d61aa4ecf1 100644
--- a/chromium/net/quic/core/crypto/crypto_framer_test.cc
+++ b/chromium/net/quic/core/crypto/crypto_framer_test.cc
@@ -47,6 +47,11 @@ class TestCryptoVisitor : public CryptoFramerVisitorInterface {
std::vector<CryptoHandshakeMessage> messages_;
};
+INSTANTIATE_TEST_CASE_P(Tests,
+ CryptoFramerTest,
+ ::testing::ValuesIn({Perspective::IS_CLIENT,
+ Perspective::IS_SERVER}));
+
TEST_P(CryptoFramerTest, ConstructHandshakeMessage) {
CryptoHandshakeMessage message;
message.set_tag(0xFFAA7733);
diff --git a/chromium/net/quic/core/crypto/crypto_handshake.cc b/chromium/net/quic/core/crypto/crypto_handshake.cc
index f1d8998ca06..a8313c27eec 100644
--- a/chromium/net/quic/core/crypto/crypto_handshake.cc
+++ b/chromium/net/quic/core/crypto/crypto_handshake.cc
@@ -15,8 +15,6 @@ QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
: key_exchange(0),
aead(0),
token_binding_key_param(0),
- x509_ecdsa_supported(false),
- x509_supported(false),
sct_supported_by_client(false) {}
QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {}
diff --git a/chromium/net/quic/core/crypto/crypto_handshake.h b/chromium/net/quic/core/crypto/crypto_handshake.h
index b646c58e693..cef859be08b 100644
--- a/chromium/net/quic/core/crypto/crypto_handshake.h
+++ b/chromium/net/quic/core/crypto/crypto_handshake.h
@@ -137,8 +137,6 @@ struct QUIC_EXPORT_PRIVATE QuicCryptoNegotiatedParameters
QuicTag token_binding_key_param;
// Used when generating proof signature when sending server config updates.
- bool x509_ecdsa_supported;
- bool x509_supported;
// Used to generate cert chain when sending server config updates.
std::string client_common_set_hashes;
diff --git a/chromium/net/quic/core/crypto/crypto_handshake_message_test.cc b/chromium/net/quic/core/crypto/crypto_handshake_message_test.cc
index a44e64af5c0..1f5660b939a 100644
--- a/chromium/net/quic/core/crypto/crypto_handshake_message_test.cc
+++ b/chromium/net/quic/core/crypto/crypto_handshake_message_test.cc
@@ -6,6 +6,7 @@
#include "net/quic/core/crypto/crypto_handshake.h"
#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/platform/api/quic_endian.h"
#include "net/quic/platform/api/quic_test.h"
namespace net {
@@ -14,6 +15,11 @@ namespace {
class CryptoHandshakeMessageTest : public QuicTestWithParam<Perspective> {};
+INSTANTIATE_TEST_CASE_P(Perspective,
+ CryptoHandshakeMessageTest,
+ ::testing::ValuesIn({Perspective::IS_CLIENT,
+ Perspective::IS_SERVER}));
+
TEST_P(CryptoHandshakeMessageTest, DebugString) {
const char* str = "SHLO<\n>";
@@ -99,7 +105,8 @@ TEST_P(CryptoHandshakeMessageTest, ServerDesignatedConnectionId) {
CryptoHandshakeMessage message;
message.set_tag(kSREJ);
- message.SetValue(kRCID, UINT64_C(18364758544493064720));
+ message.SetValue(kRCID,
+ QuicEndian::NetToHost64(UINT64_C(18364758544493064720)));
EXPECT_EQ(str, message.DebugString(GetParam()));
// Test copy
diff --git a/chromium/net/quic/core/crypto/crypto_message_parser.h b/chromium/net/quic/core/crypto/crypto_message_parser.h
new file mode 100644
index 00000000000..3f08b351aca
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_message_parser.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CORE_CRYPTO_CRYPTO_MESSAGE_PARSER_H_
+#define NET_QUIC_CORE_CRYPTO_CRYPTO_MESSAGE_PARSER_H_
+
+#include "net/quic/core/quic_error_codes.h"
+#include "net/quic/core/quic_types.h"
+#include "net/quic/platform/api/quic_string_piece.h"
+
+namespace net {
+
+class QUIC_EXPORT_PRIVATE CryptoMessageParser {
+ public:
+ virtual ~CryptoMessageParser() {}
+
+ virtual QuicErrorCode error() const = 0;
+ virtual const std::string& error_detail() const = 0;
+
+ // Processes input data, which must be delivered in order. Returns
+ // false if there was an error, and true otherwise.
+ virtual bool ProcessInput(QuicStringPiece input, Perspective perspective) = 0;
+
+ // Returns the number of bytes of buffered input data remaining to be
+ // parsed.
+ virtual size_t InputBytesRemaining() const = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CORE_CRYPTO_CRYPTO_MESSAGE_PARSER_H_
diff --git a/chromium/net/quic/core/crypto/crypto_protocol.h b/chromium/net/quic/core/crypto/crypto_protocol.h
index 56d8e63844c..1a54cd8e76a 100644
--- a/chromium/net/quic/core/crypto/crypto_protocol.h
+++ b/chromium/net/quic/core/crypto/crypto_protocol.h
@@ -82,12 +82,14 @@ const QuicTag kIFWA = TAG('I', 'F', 'W', 'a'); // Set initial size
const QuicTag kTBBR = TAG('T', 'B', 'B', 'R'); // Reduced Buffer Bloat TCP
const QuicTag k1RTT = TAG('1', 'R', 'T', 'T'); // STARTUP in BBR for 1 RTT
const QuicTag k2RTT = TAG('2', 'R', 'T', 'T'); // STARTUP in BBR for 2 RTTs
+const QuicTag kLRTT = TAG('L', 'R', 'T', 'T'); // Exit STARTUP in BBR on loss
const QuicTag kBBRR = TAG('B', 'B', 'R', 'R'); // Rate-based recovery in BBR
+const QuicTag kBBR1 = TAG('B', 'B', 'R', '1'); // Ack aggregatation v1
+const QuicTag kBBR2 = TAG('B', 'B', 'R', '2'); // Ack aggregatation v2
const QuicTag kRENO = TAG('R', 'E', 'N', 'O'); // Reno Congestion Control
const QuicTag kTPCC = TAG('P', 'C', 'C', '\0'); // Performance-Oriented
// Congestion Control
const QuicTag kBYTE = TAG('B', 'Y', 'T', 'E'); // TCP cubic or reno in bytes
-const QuicTag kRATE = TAG('R', 'A', 'T', 'E'); // TCP cubic rate based sending
const QuicTag kIW03 = TAG('I', 'W', '0', '3'); // Force ICWND to 3
const QuicTag kIW10 = TAG('I', 'W', '1', '0'); // Force ICWND to 10
const QuicTag kIW20 = TAG('I', 'W', '2', '0'); // Force ICWND to 20
@@ -96,8 +98,6 @@ const QuicTag k1CON = TAG('1', 'C', 'O', 'N'); // Emulate a single connection
const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe
const QuicTag kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl
const QuicTag kNRTO = TAG('N', 'R', 'T', 'O'); // CWND reduction on loss
-const QuicTag kUNDO = TAG('U', 'N', 'D', 'O'); // Undo any pending retransmits
- // if they're likely spurious.
const QuicTag kTIME = TAG('T', 'I', 'M', 'E'); // Time based loss detection
const QuicTag kATIM = TAG('A', 'T', 'I', 'M'); // Adaptive time loss detection
const QuicTag kMIN1 = TAG('M', 'I', 'N', '1'); // Min CWND of 1 packet
@@ -112,6 +112,8 @@ const QuicTag kAKD3 = TAG('A', 'K', 'D', '3'); // Ack decimation style acking
// with 1/8 RTT acks.
const QuicTag kAKD4 = TAG('A', 'K', 'D', '4'); // Ack decimation with 1/8 RTT
// tolerating out of order.
+const QuicTag kAKDU = TAG('A', 'K', 'D', 'U'); // Unlimited number of packets
+ // receieved before acking
const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction.
const QuicTag kNPRR = TAG('N', 'P', 'R', 'R'); // Pace at unity instead of PRR
const QuicTag k5RTO = TAG('5', 'R', 'T', 'O'); // Close connection on 5 RTOs
diff --git a/chromium/net/quic/core/crypto/crypto_server_config_protobuf.h b/chromium/net/quic/core/crypto/crypto_server_config_protobuf.h
index fe0cc4eaa4f..0077f3b2102 100644
--- a/chromium/net/quic/core/crypto/crypto_server_config_protobuf.h
+++ b/chromium/net/quic/core/crypto/crypto_server_config_protobuf.h
@@ -56,7 +56,7 @@ class QUIC_EXPORT_PRIVATE QuicServerConfigProtobuf {
void set_config(QuicStringPiece config) { config.CopyToString(&config_); }
QuicServerConfigProtobuf::PrivateKey* add_key() {
- keys_.push_back(base::MakeUnique<PrivateKey>());
+ keys_.push_back(std::make_unique<PrivateKey>());
return keys_.back().get();
}
diff --git a/chromium/net/quic/core/crypto/proof_source.h b/chromium/net/quic/core/crypto/proof_source.h
index eb5d70bb920..d44591c03c6 100644
--- a/chromium/net/quic/core/crypto/proof_source.h
+++ b/chromium/net/quic/core/crypto/proof_source.h
@@ -74,6 +74,25 @@ class QUIC_EXPORT_PRIVATE ProofSource {
Callback& operator=(const Callback&) = delete;
};
+ // Base class for signalling the completion of a call to ComputeTlsSignature.
+ class SignatureCallback {
+ public:
+ SignatureCallback() {}
+ virtual ~SignatureCallback() = default;
+
+ // Invoked upon completion of ComputeTlsSignature.
+ //
+ // |ok| indicates whether the operation completed successfully.
+ //
+ // |signature| contains the signature of the data provided to
+ // ComputeTlsSignature. Its value is undefined if |ok| is false.
+ virtual void Run(bool ok, std::string signature) = 0;
+
+ private:
+ SignatureCallback(const SignatureCallback&) = delete;
+ SignatureCallback& operator=(const SignatureCallback&) = delete;
+ };
+
virtual ~ProofSource() {}
// GetProof finds a certificate chain for |hostname| (in leaf-first order),
@@ -101,6 +120,24 @@ class QUIC_EXPORT_PRIVATE ProofSource {
QuicStringPiece chlo_hash,
const QuicTagVector& connection_options,
std::unique_ptr<Callback> callback) = 0;
+
+ // Returns the certificate chain for |hostname| in leaf-first order.
+ virtual QuicReferenceCountedPointer<Chain> GetCertChain(
+ const QuicSocketAddress& server_address,
+ const std::string& hostname) = 0;
+
+ // Computes a signature using the private key of the certificate for
+ // |hostname|. The value in |in| is signed using the algorithm specified by
+ // |signature_algorithm|, which is an |SSL_SIGN_*| value (as defined in TLS
+ // 1.3).
+ //
+ // Callers should expect that |callback| might be invoked synchronously.
+ virtual void ComputeTlsSignature(
+ const QuicSocketAddress& server_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ QuicStringPiece in,
+ std::unique_ptr<SignatureCallback> callback) = 0;
};
} // namespace net
diff --git a/chromium/net/quic/core/frames/quic_ack_frame.cc b/chromium/net/quic/core/frames/quic_ack_frame.cc
index 77016b9d386..c9c4d2eead5 100644
--- a/chromium/net/quic/core/frames/quic_ack_frame.cc
+++ b/chromium/net/quic/core/frames/quic_ack_frame.cc
@@ -4,10 +4,15 @@
#include "net/quic/core/frames/quic_ack_frame.h"
+#include <algorithm>
+
#include "net/quic/core/quic_constants.h"
#include "net/quic/platform/api/quic_bug_tracker.h"
#include "net/quic/platform/api/quic_flag_utils.h"
+using std::max;
+using std::min;
+
namespace net {
PacketNumberQueue::const_iterator::const_iterator(const const_iterator& other) =
@@ -67,9 +72,9 @@ std::ostream& operator<<(std::ostream& os, const QuicAckFrame& ack_frame) {
return os;
}
PacketNumberQueue::PacketNumberQueue()
- : use_deque_(FLAGS_quic_reloadable_flag_quic_frames_deque) {
+ : use_deque_(FLAGS_quic_reloadable_flag_quic_frames_deque2) {
if (use_deque_) {
- QUIC_FLAG_COUNT(quic_reloadable_flag_quic_frames_deque);
+ QUIC_FLAG_COUNT(quic_reloadable_flag_quic_frames_deque2);
}
}
@@ -90,27 +95,30 @@ void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
Interval<QuicPacketNumber>(packet_number, packet_number + 1));
return;
}
+ Interval<QuicPacketNumber> back = packet_number_deque_.back();
// Check for the typical case,
// when the next packet in order is acked
- if ((packet_number_deque_.back()).max() == packet_number) {
- (packet_number_deque_.back()).SetMax(packet_number + 1);
+ if (back.max() == packet_number) {
+ packet_number_deque_.back().SetMax(packet_number + 1);
return;
}
// Check if the next packet in order is skipped
- if ((packet_number_deque_.back()).max() < packet_number) {
+ if (back.max() < packet_number) {
packet_number_deque_.push_back(
Interval<QuicPacketNumber>(packet_number, packet_number + 1));
return;
}
+
+ Interval<QuicPacketNumber> front = packet_number_deque_.front();
// Check if the packet can be popped on the front
- if ((packet_number_deque_.front()).min() > packet_number + 1) {
+ if (front.min() > packet_number + 1) {
packet_number_deque_.push_front(
Interval<QuicPacketNumber>(packet_number, packet_number + 1));
return;
}
- if ((packet_number_deque_.front()).min() == packet_number + 1) {
- (packet_number_deque_.front()).SetMin(packet_number);
+ if (front.min() == packet_number + 1) {
+ packet_number_deque_.front().SetMin(packet_number);
return;
}
@@ -118,36 +126,33 @@ void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
// Iterating through the queue backwards
// to find a proper place for the packet
while (i >= 0) {
+ Interval<QuicPacketNumber> packet_interval = packet_number_deque_[i];
+ DCHECK(packet_interval.min() < packet_interval.max());
// Check if the packet is contained in an interval already
- if (packet_number_deque_[i].max() > packet_number &&
- packet_number_deque_[i].min() <= packet_number) {
+ if (packet_interval.Contains(packet_number)) {
return;
}
- // Check if the packet can extend an interval
- // and merges two intervals if needed
- if (packet_number_deque_[i].max() == packet_number) {
+ // Check if the packet can extend an interval.
+ if (packet_interval.max() == packet_number) {
packet_number_deque_[i].SetMax(packet_number + 1);
- if (static_cast<size_t>(i) < packet_number_deque_.size() - 1 &&
- packet_number_deque_[i].max() ==
- packet_number_deque_[i + 1].min()) {
- packet_number_deque_[i].SetMax(packet_number_deque_[i + 1].max());
- packet_number_deque_.erase(packet_number_deque_.begin() + i + 1);
- }
return;
}
- if (packet_number_deque_[i].min() == packet_number + 1) {
+ // Check if the packet can extend an interval
+ // and merge two intervals if needed.
+ // There is no need to merge an interval in the previous
+ // if statement, as all merges will happen here.
+ if (packet_interval.min() == packet_number + 1) {
packet_number_deque_[i].SetMin(packet_number);
- if (i > 0 && packet_number_deque_[i].min() ==
- packet_number_deque_[i - 1].max()) {
- packet_number_deque_[i - 1].SetMax(packet_number_deque_[i].max());
+ if (i > 0 && packet_number == packet_number_deque_[i - 1].max()) {
+ packet_number_deque_[i - 1].SetMax(packet_interval.max());
packet_number_deque_.erase(packet_number_deque_.begin() + i);
}
return;
}
// Check if we need to make a new interval for the packet
- if (packet_number_deque_[i].max() < packet_number + 1) {
+ if (packet_interval.max() < packet_number + 1) {
packet_number_deque_.insert(
packet_number_deque_.begin() + i + 1,
Interval<QuicPacketNumber>(packet_number, packet_number + 1));
@@ -160,7 +165,8 @@ void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
}
}
-void PacketNumberQueue::Add(QuicPacketNumber lower, QuicPacketNumber higher) {
+void PacketNumberQueue::AddRange(QuicPacketNumber lower,
+ QuicPacketNumber higher) {
if (lower >= higher) {
return;
}
@@ -168,26 +174,47 @@ void PacketNumberQueue::Add(QuicPacketNumber lower, QuicPacketNumber higher) {
if (packet_number_deque_.empty()) {
packet_number_deque_.push_front(
Interval<QuicPacketNumber>(lower, higher));
+ return;
+ }
+ Interval<QuicPacketNumber> back = packet_number_deque_.back();
- } else if ((packet_number_deque_.back()).max() == lower) {
+ if (back.max() == lower) {
// Check for the typical case,
// when the next packet in order is acked
- (packet_number_deque_.back()).SetMax(higher);
-
- } else if ((packet_number_deque_.back()).max() < lower) {
+ packet_number_deque_.back().SetMax(higher);
+ return;
+ }
+ if (back.max() < lower) {
// Check if the next packet in order is skipped
packet_number_deque_.push_back(Interval<QuicPacketNumber>(lower, higher));
-
- // Check if the packets are being added in reverse order
- } else if ((packet_number_deque_.front()).min() == higher) {
- (packet_number_deque_.front()).SetMax(lower);
- } else if ((packet_number_deque_.front()).min() > higher) {
+ return;
+ }
+ Interval<QuicPacketNumber> front = packet_number_deque_.front();
+ // Check if the packets are being added in reverse order
+ if (front.min() == higher) {
+ packet_number_deque_.front().SetMin(lower);
+ } else if (front.min() > higher) {
packet_number_deque_.push_front(
Interval<QuicPacketNumber>(lower, higher));
} else {
// Iterating through the interval and adding packets one by one
- for (size_t i = lower; i != higher; i++) {
+ QUIC_BUG << "In the slowpath of AddRange. Adding [" << lower << ", "
+ << higher << "), in a deque of size "
+ << packet_number_deque_.size() << ", whose largest element is "
+ << back.max() << " and smallest " << front.min() << ".\n";
+ // Check if the first and/or the last interval of the deque can be
+ // extended, which would reduce the compexity of the following for loop.
+ if (higher >= back.max()) {
+ packet_number_deque_.back().SetMax(higher);
+ higher = max(lower, back.min());
+ }
+ if (lower < front.min()) {
+ packet_number_deque_.front().SetMin(lower);
+ lower = min(higher, front.max());
+ }
+
+ for (size_t i = lower; i < higher; i++) {
PacketNumberQueue::Add(i);
}
}
@@ -203,12 +230,12 @@ bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) {
const QuicPacketNumber old_min = Min();
if (use_deque_) {
while (!packet_number_deque_.empty()) {
- if (packet_number_deque_[0].max() < higher) {
+ Interval<QuicPacketNumber> front = packet_number_deque_.front();
+ if (front.max() < higher) {
packet_number_deque_.pop_front();
- } else if (packet_number_deque_[0].min() < higher &&
- packet_number_deque_[0].max() >= higher) {
- packet_number_deque_[0].SetMin(higher);
- if (packet_number_deque_[0].max() == packet_number_deque_[0].min()) {
+ } else if (front.min() < higher && front.max() >= higher) {
+ packet_number_deque_.front().SetMin(higher);
+ if (front.max() == higher) {
packet_number_deque_.pop_front();
}
break;
@@ -239,16 +266,15 @@ void PacketNumberQueue::RemoveSmallestInterval() {
bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const {
if (use_deque_) {
- // TODO(lilika): Consider using std::binary_search based on profiles
- // http://www.cplusplus.com/reference/algorithm/binary_search/
if (packet_number_deque_.empty()) {
return false;
}
+ if (packet_number_deque_.front().min() > packet_number ||
+ packet_number_deque_.back().max() <= packet_number) {
+ return false;
+ }
for (Interval<QuicPacketNumber> interval : packet_number_deque_) {
- if (packet_number < interval.min()) {
- return false;
- }
- if (interval.min() <= packet_number && interval.max() > packet_number) {
+ if (interval.Contains(packet_number)) {
return true;
}
}
@@ -269,7 +295,7 @@ bool PacketNumberQueue::Empty() const {
QuicPacketNumber PacketNumberQueue::Min() const {
DCHECK(!Empty());
if (use_deque_) {
- return packet_number_deque_[0].min();
+ return packet_number_deque_.front().min();
} else {
return packet_number_intervals_.begin()->min();
}
@@ -278,7 +304,7 @@ QuicPacketNumber PacketNumberQueue::Min() const {
QuicPacketNumber PacketNumberQueue::Max() const {
DCHECK(!Empty());
if (use_deque_) {
- return packet_number_deque_[packet_number_deque_.size() - 1].max() - 1;
+ return packet_number_deque_.back().max() - 1;
} else {
return packet_number_intervals_.rbegin()->max() - 1;
}
@@ -286,9 +312,9 @@ QuicPacketNumber PacketNumberQueue::Max() const {
size_t PacketNumberQueue::NumPacketsSlow() const {
if (use_deque_) {
- size_t n_packets = 0;
- for (size_t i = 0; i < packet_number_deque_.size(); i++) {
- n_packets += packet_number_deque_[i].Length();
+ int n_packets = 0;
+ for (Interval<QuicPacketNumber> interval : packet_number_deque_) {
+ n_packets += interval.Length();
}
return n_packets;
} else {
@@ -343,7 +369,7 @@ PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rend() const {
QuicPacketNumber PacketNumberQueue::LastIntervalLength() const {
DCHECK(!Empty());
if (use_deque_) {
- return packet_number_deque_[packet_number_deque_.size() - 1].Length();
+ return packet_number_deque_.back().Length();
} else {
return packet_number_intervals_.rbegin()->Length();
}
diff --git a/chromium/net/quic/core/frames/quic_ack_frame.h b/chromium/net/quic/core/frames/quic_ack_frame.h
index c7584c1e27b..54f95a3ffb0 100644
--- a/chromium/net/quic/core/frames/quic_ack_frame.h
+++ b/chromium/net/quic/core/frames/quic_ack_frame.h
@@ -198,7 +198,7 @@ class QUIC_EXPORT_PRIVATE PacketNumberQueue {
// Adds packets between [lower, higher) to the set of packets in the queue. It
// is undefined behavior to call this with |higher| < |lower|.
- void Add(QuicPacketNumber lower, QuicPacketNumber higher);
+ void AddRange(QuicPacketNumber lower, QuicPacketNumber higher);
// Removes packets with values less than |higher| from the set of packets in
// the queue. Returns true if packets were removed.
@@ -244,7 +244,7 @@ class QUIC_EXPORT_PRIVATE PacketNumberQueue {
private:
// TODO(lilika): Remove QuicIntervalSet<QuicPacketNumber>
- // once FLAGS_quic_reloadable_flag_quic_frames_deque is removed
+ // once FLAGS_quic_reloadable_flag_quic_frames_deque2 is removed
QuicIntervalSet<QuicPacketNumber> packet_number_intervals_;
std::deque<Interval<QuicPacketNumber>> packet_number_deque_;
bool use_deque_;
diff --git a/chromium/net/quic/core/frames/quic_frames_test.cc b/chromium/net/quic/core/frames/quic_frames_test.cc
index 70cbfcb3259..323e8cdd7fd 100644
--- a/chromium/net/quic/core/frames/quic_frames_test.cc
+++ b/chromium/net/quic/core/frames/quic_frames_test.cc
@@ -15,6 +15,7 @@
#include "net/quic/core/frames/quic_stream_frame.h"
#include "net/quic/core/frames/quic_window_update_frame.h"
#include "net/quic/platform/api/quic_test.h"
+#include "net/quic/test_tools/quic_test_utils.h"
namespace net {
namespace test {
@@ -117,7 +118,7 @@ TEST_F(QuicFramesTest, StopWaitingFrameToString) {
TEST_F(QuicFramesTest, IsAwaitingPacket) {
QuicAckFrame ack_frame1;
ack_frame1.largest_observed = 10u;
- ack_frame1.packets.Add(1, 11);
+ ack_frame1.packets.AddRange(1, 11);
EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u));
EXPECT_FALSE(IsAwaitingPacket(ack_frame1, 1u, 0u));
@@ -126,12 +127,12 @@ TEST_F(QuicFramesTest, IsAwaitingPacket) {
QuicAckFrame ack_frame2;
ack_frame2.largest_observed = 100u;
- ack_frame2.packets.Add(21, 100);
+ ack_frame2.packets.AddRange(21, 100);
EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 11u, 20u));
EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 80u, 20u));
EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u));
- ack_frame2.packets.Add(102, 200);
+ ack_frame2.packets.AddRange(102, 200);
EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u));
}
@@ -207,8 +208,8 @@ TEST_F(QuicFramesTest, AddPacket) {
TEST_F(QuicFramesTest, AddInterval) {
QuicAckFrame ack_frame1;
- ack_frame1.packets.Add(1, 10);
- ack_frame1.packets.Add(50, 100);
+ ack_frame1.packets.AddRange(1, 10);
+ ack_frame1.packets.AddRange(50, 100);
EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
EXPECT_EQ(1u, ack_frame1.packets.Min());
@@ -223,7 +224,12 @@ TEST_F(QuicFramesTest, AddInterval) {
EXPECT_EQ(expected_intervals, actual_intervals);
- ack_frame1.packets.Add(20, 30);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(20, 30), "");
+ } else {
+ ack_frame1.packets.AddRange(20, 30);
+ }
+
const std::vector<Interval<QuicPacketNumber>> actual_intervals2(
ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -235,8 +241,13 @@ TEST_F(QuicFramesTest, AddInterval) {
EXPECT_EQ(3u, ack_frame1.packets.NumIntervals());
EXPECT_EQ(expected_intervals2, actual_intervals2);
- ack_frame1.packets.Add(15, 20);
- ack_frame1.packets.Add(30, 35);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(15, 20), "");
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(30, 35), "");
+ } else {
+ ack_frame1.packets.AddRange(15, 20);
+ ack_frame1.packets.AddRange(30, 35);
+ }
const std::vector<Interval<QuicPacketNumber>> actual_intervals3(
ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -248,15 +259,23 @@ TEST_F(QuicFramesTest, AddInterval) {
EXPECT_EQ(expected_intervals3, actual_intervals3);
- ack_frame1.packets.Add(20, 35);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(20, 35), "");
+ } else {
+ ack_frame1.packets.AddRange(20, 35);
+ }
const std::vector<Interval<QuicPacketNumber>> actual_intervals4(
ack_frame1.packets.begin(), ack_frame1.packets.end());
EXPECT_EQ(expected_intervals3, actual_intervals4);
-
- ack_frame1.packets.Add(12, 20);
- ack_frame1.packets.Add(30, 38);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(12, 20), "");
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(30, 38), "");
+ } else {
+ ack_frame1.packets.AddRange(12, 20);
+ ack_frame1.packets.AddRange(30, 38);
+ }
const std::vector<Interval<QuicPacketNumber>> actual_intervals5(
ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -267,8 +286,11 @@ TEST_F(QuicFramesTest, AddInterval) {
expected_intervals5.push_back(Interval<QuicPacketNumber>(50, 100));
EXPECT_EQ(expected_intervals5, actual_intervals5);
-
- ack_frame1.packets.Add(8, 55);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(8, 55), "");
+ } else {
+ ack_frame1.packets.AddRange(8, 55);
+ }
const std::vector<Interval<QuicPacketNumber>> actual_intervals6(
ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -278,7 +300,11 @@ TEST_F(QuicFramesTest, AddInterval) {
EXPECT_EQ(expected_intervals6, actual_intervals6);
- ack_frame1.packets.Add(0, 200);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(0, 200), "");
+ } else {
+ ack_frame1.packets.AddRange(0, 200);
+ }
const std::vector<Interval<QuicPacketNumber>> actual_intervals7(
ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -289,11 +315,11 @@ TEST_F(QuicFramesTest, AddInterval) {
EXPECT_EQ(expected_intervals7, actual_intervals7);
QuicAckFrame ack_frame2;
- ack_frame2.packets.Add(20, 25);
- ack_frame2.packets.Add(40, 45);
- ack_frame2.packets.Add(60, 65);
- ack_frame2.packets.Add(10, 15);
- ack_frame2.packets.Add(80, 85);
+ ack_frame2.packets.AddRange(20, 25);
+ ack_frame2.packets.AddRange(40, 45);
+ ack_frame2.packets.AddRange(60, 65);
+ ack_frame2.packets.AddRange(10, 15);
+ ack_frame2.packets.AddRange(80, 85);
const std::vector<Interval<QuicPacketNumber>> actual_intervals8(
ack_frame2.packets.begin(), ack_frame2.packets.end());
@@ -308,12 +334,131 @@ TEST_F(QuicFramesTest, AddInterval) {
EXPECT_EQ(expected_intervals8, actual_intervals8);
}
+TEST_F(QuicFramesTest, AddAdjacentReverse) {
+ QuicAckFrame ack_frame1;
+ ack_frame1.packets.AddRange(70, 100);
+ ack_frame1.packets.AddRange(60, 70);
+ ack_frame1.packets.AddRange(50, 60);
+ ack_frame1.packets.Add(49);
+
+ std::vector<Interval<QuicPacketNumber>> expected_intervals;
+ expected_intervals.push_back(Interval<QuicPacketNumber>(49, 100));
+
+ const std::vector<Interval<QuicPacketNumber>> actual_intervals(
+ ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+ EXPECT_EQ(expected_intervals, actual_intervals);
+}
+
+TEST_F(QuicFramesTest, AddMerges) {
+ QuicAckFrame ack_frame1;
+ ack_frame1.packets.AddRange(110, 112);
+ ack_frame1.packets.AddRange(106, 108);
+ ack_frame1.packets.AddRange(102, 104);
+ ack_frame1.packets.AddRange(1, 2);
+ ack_frame1.packets.AddRange(4, 7);
+ ack_frame1.packets.AddRange(10, 20);
+ ack_frame1.packets.AddRange(21, 30);
+ ack_frame1.packets.Add(20);
+ ack_frame1.packets.AddRange(40, 50);
+ ack_frame1.packets.AddRange(30, 35);
+ ack_frame1.packets.AddRange(35, 40);
+ ack_frame1.packets.AddRange(108, 110);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(50, 106), "");
+ } else {
+ ack_frame1.packets.AddRange(50, 106);
+ }
+ ack_frame1.packets.AddRange(2, 4);
+ ack_frame1.packets.AddRange(7, 11);
+ std::vector<Interval<QuicPacketNumber>> expected_intervals;
+ expected_intervals.push_back(Interval<QuicPacketNumber>(1, 112));
+
+ const std::vector<Interval<QuicPacketNumber>> actual_intervals(
+ ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+ EXPECT_EQ(expected_intervals, actual_intervals);
+}
+
+TEST_F(QuicFramesTest, AddIntervalBig) {
+ QuicAckFrame ack_frame1;
+ ack_frame1.packets.AddRange(20, 30);
+ ack_frame1.packets.AddRange(70, 100);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(56, 58), "");
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(65, 69), "");
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(59, 64), "");
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(50, 55), "");
+ } else {
+ ack_frame1.packets.AddRange(56, 58);
+ ack_frame1.packets.AddRange(65, 69);
+ ack_frame1.packets.AddRange(59, 64);
+ ack_frame1.packets.AddRange(50, 55);
+ }
+
+ std::vector<Interval<QuicPacketNumber>> expected_intervals;
+ expected_intervals.push_back(Interval<QuicPacketNumber>(20, 30));
+ expected_intervals.push_back(Interval<QuicPacketNumber>(50, 55));
+ expected_intervals.push_back(Interval<QuicPacketNumber>(56, 58));
+ expected_intervals.push_back(Interval<QuicPacketNumber>(59, 64));
+ expected_intervals.push_back(Interval<QuicPacketNumber>(65, 69));
+ expected_intervals.push_back(Interval<QuicPacketNumber>(70, 100));
+
+ const std::vector<Interval<QuicPacketNumber>> actual_intervals(
+ ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+ EXPECT_EQ(expected_intervals, actual_intervals);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(10, 60), "");
+ } else {
+ ack_frame1.packets.AddRange(10, 60);
+ }
+
+ std::vector<Interval<QuicPacketNumber>> expected_intervals2;
+ expected_intervals2.push_back(Interval<QuicPacketNumber>(10, 64));
+ expected_intervals2.push_back(Interval<QuicPacketNumber>(65, 69));
+ expected_intervals2.push_back(Interval<QuicPacketNumber>(70, 100));
+
+ const std::vector<Interval<QuicPacketNumber>> actual_intervals2(
+ ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+ EXPECT_EQ(expected_intervals2, actual_intervals2);
+
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(68, 1000), "");
+ } else {
+ ack_frame1.packets.AddRange(68, 1000);
+ }
+
+ std::vector<Interval<QuicPacketNumber>> expected_intervals3;
+ expected_intervals3.push_back(Interval<QuicPacketNumber>(10, 64));
+ expected_intervals3.push_back(Interval<QuicPacketNumber>(65, 1000));
+
+ const std::vector<Interval<QuicPacketNumber>> actual_intervals3(
+ ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+ EXPECT_EQ(expected_intervals3, actual_intervals3);
+ if (FLAGS_quic_reloadable_flag_quic_frames_deque2) {
+ EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(0, 10000), "");
+ } else {
+ ack_frame1.packets.AddRange(0, 10000);
+ }
+
+ std::vector<Interval<QuicPacketNumber>> expected_intervals4;
+ expected_intervals4.push_back(Interval<QuicPacketNumber>(0, 10000));
+
+ const std::vector<Interval<QuicPacketNumber>> actual_intervals4(
+ ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+ EXPECT_EQ(expected_intervals4, actual_intervals4);
+}
+
TEST_F(QuicFramesTest, RemoveSmallestInterval) {
QuicAckFrame ack_frame1;
ack_frame1.largest_observed = 100u;
- ack_frame1.packets.Add(51, 60);
- ack_frame1.packets.Add(71, 80);
- ack_frame1.packets.Add(91, 100);
+ ack_frame1.packets.AddRange(51, 60);
+ ack_frame1.packets.AddRange(71, 80);
+ ack_frame1.packets.AddRange(91, 100);
ack_frame1.packets.RemoveSmallestInterval();
EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
EXPECT_EQ(71u, ack_frame1.packets.Min());
@@ -330,7 +475,7 @@ class PacketNumberQueueTest : public QuicTest {};
// Tests that a queue contains the expected data after calls to Add().
TEST_F(PacketNumberQueueTest, AddRange) {
PacketNumberQueue queue;
- queue.Add(1, 51);
+ queue.AddRange(1, 51);
queue.Add(53);
EXPECT_FALSE(queue.Contains(0));
@@ -353,7 +498,7 @@ TEST_F(PacketNumberQueueTest, AddRange) {
TEST_F(PacketNumberQueueTest, Contains) {
PacketNumberQueue queue;
EXPECT_FALSE(queue.Contains(0));
- queue.Add(5, 10);
+ queue.AddRange(5, 10);
queue.Add(20);
for (int i = 1; i < 5; ++i) {
@@ -389,7 +534,7 @@ TEST_F(PacketNumberQueueTest, Contains) {
TEST_F(PacketNumberQueueTest, Removal) {
PacketNumberQueue queue;
EXPECT_FALSE(queue.Contains(51));
- queue.Add(0, 100);
+ queue.AddRange(0, 100);
EXPECT_TRUE(queue.RemoveUpTo(51));
EXPECT_FALSE(queue.RemoveUpTo(51));
@@ -406,7 +551,7 @@ TEST_F(PacketNumberQueueTest, Removal) {
EXPECT_EQ(99u, queue.Max());
PacketNumberQueue queue2;
- queue2.Add(0, 5);
+ queue2.AddRange(0, 5);
EXPECT_TRUE(queue2.RemoveUpTo(3));
EXPECT_TRUE(queue2.RemoveUpTo(50));
EXPECT_TRUE(queue2.Empty());
@@ -418,7 +563,7 @@ TEST_F(PacketNumberQueueTest, Empty) {
EXPECT_TRUE(queue.Empty());
EXPECT_EQ(0u, queue.NumPacketsSlow());
- queue.Add(1, 100);
+ queue.AddRange(1, 100);
EXPECT_TRUE(queue.RemoveUpTo(100));
EXPECT_TRUE(queue.Empty());
EXPECT_EQ(0u, queue.NumPacketsSlow());
@@ -431,21 +576,21 @@ TEST_F(PacketNumberQueueTest, LogDoesNotCrash) {
oss << queue;
queue.Add(1);
- queue.Add(50, 100);
+ queue.AddRange(50, 100);
oss << queue;
}
// Tests that the iterators returned from a packet queue iterate over the queue.
TEST_F(PacketNumberQueueTest, Iterators) {
PacketNumberQueue queue;
- queue.Add(1, 100);
+ queue.AddRange(1, 100);
const std::vector<Interval<QuicPacketNumber>> actual_intervals(queue.begin(),
queue.end());
PacketNumberQueue queue2;
for (int i = 1; i < 100; i++) {
- queue2.Add(i, i + 1);
+ queue2.AddRange(i, i + 1);
}
const std::vector<Interval<QuicPacketNumber>> actual_intervals2(
@@ -460,10 +605,10 @@ TEST_F(PacketNumberQueueTest, Iterators) {
TEST_F(PacketNumberQueueTest, ReversedIterators) {
PacketNumberQueue queue;
- queue.Add(1, 100);
+ queue.AddRange(1, 100);
PacketNumberQueue queue2;
for (int i = 1; i < 100; i++) {
- queue2.Add(i, i + 1);
+ queue2.AddRange(i, i + 1);
}
const std::vector<Interval<QuicPacketNumber>> actual_intervals(queue.rbegin(),
queue.rend());
@@ -495,9 +640,9 @@ TEST_F(PacketNumberQueueTest, ReversedIterators) {
TEST_F(PacketNumberQueueTest, IntervalLengthAndRemoveInterval) {
PacketNumberQueue queue;
- queue.Add(1, 10);
- queue.Add(20, 30);
- queue.Add(40, 50);
+ queue.AddRange(1, 10);
+ queue.AddRange(20, 30);
+ queue.AddRange(40, 50);
EXPECT_EQ(3u, queue.NumIntervals());
EXPECT_EQ(10u, queue.LastIntervalLength());
diff --git a/chromium/net/quic/core/frames/quic_stream_frame.h b/chromium/net/quic/core/frames/quic_stream_frame.h
index 90cfbfe8d2c..4d280fcf0ec 100644
--- a/chromium/net/quic/core/frames/quic_stream_frame.h
+++ b/chromium/net/quic/core/frames/quic_stream_frame.h
@@ -65,9 +65,9 @@ struct QUIC_EXPORT_PRIVATE QuicStreamFrame {
const char* data_buffer;
QuicStreamOffset offset; // Location of this data in the stream.
// TODO(fayang): When deprecating
- // FLAGS_quic_reloadable_flag_quic_stream_owns_data: (1) Remove buffer from
- // QuicStreamFrame; (2) remove the constructor uses UniqueStreamBuffer and (3)
- // Move definition of UniqueStreamBuffer to QuicStreamSendBuffer.
+ // quic_reloadable_flag_quic_save_data_before_consumption2: (1) Remove buffer
+ // from QuicStreamFrame; (2) remove the constructor uses UniqueStreamBuffer
+ // and (3) Move definition of UniqueStreamBuffer to QuicStreamSendBuffer.
// nullptr when the QuicStreamFrame is received, and non-null when sent.
UniqueStreamBuffer buffer;
diff --git a/chromium/net/quic/core/quic_buffered_packet_store.cc b/chromium/net/quic/core/quic_buffered_packet_store.cc
index 0ed808761a8..72186af8c79 100644
--- a/chromium/net/quic/core/quic_buffered_packet_store.cc
+++ b/chromium/net/quic/core/quic_buffered_packet_store.cc
@@ -197,7 +197,6 @@ bool QuicBufferedPacketStore::ShouldBufferPacket(bool is_chlo) {
size_t num_connections_without_chlo =
undecryptable_packets_.size() - connections_with_chlo_.size();
bool reach_non_chlo_limit =
- FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop &&
num_connections_without_chlo >= kMaxConnectionsWithoutCHLO;
return is_store_full || reach_non_chlo_limit;
diff --git a/chromium/net/quic/core/quic_buffered_packet_store_test.cc b/chromium/net/quic/core/quic_buffered_packet_store_test.cc
index 935d7ac2786..743535cda7c 100644
--- a/chromium/net/quic/core/quic_buffered_packet_store_test.cc
+++ b/chromium/net/quic/core/quic_buffered_packet_store_test.cc
@@ -129,13 +129,11 @@ TEST_F(QuicBufferedPacketStoreTest,
// buffered.
size_t num_packets = kDefaultMaxUndecryptablePackets + 1;
QuicConnectionId connection_id = 1;
- if (FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop) {
- // Arrived CHLO packet shouldn't affect how many non-CHLO pacekts store can
- // keep.
- EXPECT_EQ(QuicBufferedPacketStore::SUCCESS,
- store_.EnqueuePacket(connection_id, packet_, server_address_,
- client_address_, true, ""));
- }
+ // Arrived CHLO packet shouldn't affect how many non-CHLO pacekts store can
+ // keep.
+ EXPECT_EQ(QuicBufferedPacketStore::SUCCESS,
+ store_.EnqueuePacket(connection_id, packet_, server_address_,
+ client_address_, true, ""));
for (size_t i = 1; i <= num_packets; ++i) {
// Only first |kDefaultMaxUndecryptablePackets packets| will be buffered.
EnqueuePacketResult result = store_.EnqueuePacket(
@@ -149,30 +147,19 @@ TEST_F(QuicBufferedPacketStoreTest,
// Only first |kDefaultMaxUndecryptablePackets| non-CHLO packets and CHLO are
// buffered.
- EXPECT_EQ(
- kDefaultMaxUndecryptablePackets +
- (FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop
- ? 1
- : 0),
- store_.DeliverPackets(connection_id).buffered_packets.size());
+ EXPECT_EQ(kDefaultMaxUndecryptablePackets + 1,
+ store_.DeliverPackets(connection_id).buffered_packets.size());
}
TEST_F(QuicBufferedPacketStoreTest, ReachNonChloConnectionUpperLimit) {
// Tests that store can only keep early arrived packets for limited number of
// connections.
- const size_t kNumConnections =
- (FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop
- ? kMaxConnectionsWithoutCHLO
- : kDefaultMaxConnectionsInStore) +
- 1;
+ const size_t kNumConnections = kMaxConnectionsWithoutCHLO + 1;
for (size_t connection_id = 1; connection_id <= kNumConnections;
++connection_id) {
EnqueuePacketResult result = store_.EnqueuePacket(
connection_id, packet_, server_address_, client_address_, false, "");
- if (connection_id <=
- (FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop
- ? kMaxConnectionsWithoutCHLO
- : kDefaultMaxConnectionsInStore)) {
+ if (connection_id <= kMaxConnectionsWithoutCHLO) {
EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
} else {
EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, result);
@@ -183,10 +170,7 @@ TEST_F(QuicBufferedPacketStoreTest, ReachNonChloConnectionUpperLimit) {
++connection_id) {
std::list<BufferedPacket> queue =
store_.DeliverPackets(connection_id).buffered_packets;
- if (connection_id <=
- (FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop
- ? kMaxConnectionsWithoutCHLO
- : kDefaultMaxConnectionsInStore)) {
+ if (connection_id <= kMaxConnectionsWithoutCHLO) {
EXPECT_EQ(1u, queue.size());
} else {
EXPECT_EQ(0u, queue.size());
@@ -196,7 +180,6 @@ TEST_F(QuicBufferedPacketStoreTest, ReachNonChloConnectionUpperLimit) {
TEST_F(QuicBufferedPacketStoreTest,
FullStoreFailToBufferDataPacketOnNewConnection) {
- FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop = true;
// Send enough CHLOs so that store gets full before number of connections
// without CHLO reaches its upper limit.
size_t num_chlos =
@@ -222,7 +205,6 @@ TEST_F(QuicBufferedPacketStoreTest,
}
TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) {
- FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop = true;
// Buffer data packets on different connections upto limit.
for (QuicConnectionId conn_id = 1; conn_id <= kMaxConnectionsWithoutCHLO;
++conn_id) {
@@ -273,69 +255,15 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) {
EXPECT_FALSE(store_.HasChlosBuffered());
}
-TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery1) {
- FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop = false;
- QuicConnectionId connection_id = 1;
- store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
- false, "");
- // Packet for another connection arrive 1ms later.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- QuicConnectionId connection_id2 = 2;
- // Use different client address to differetiate packets from different
- // connections.
- QuicSocketAddress another_client_address(QuicIpAddress::Any4(), 255);
- store_.EnqueuePacket(connection_id2, packet_, server_address_,
- another_client_address, false, "");
- // Advance clock to the time when connection 1 expires.
- clock_.AdvanceTime(
- QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
- clock_.ApproximateNow());
- ASSERT_GE(clock_.ApproximateNow(),
- QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline());
- // Fire alarm to remove long-staying connection 1 packets.
- alarm_factory_.FireAlarm(
- QuicBufferedPacketStorePeer::expiration_alarm(&store_));
- EXPECT_EQ(1u, visitor_.last_expired_packet_queue_.buffered_packets.size());
- // Try to deliver packets, but packet queue has been removed so no
- // packets can be returned.
- ASSERT_EQ(0u, store_.DeliverPackets(connection_id).buffered_packets.size());
-
- // Deliver packets on connection 2. And the queue for connection 2 should be
- // returned.
- std::list<BufferedPacket> queue =
- store_.DeliverPackets(connection_id2).buffered_packets;
- ASSERT_EQ(1u, queue.size());
- // Packets in connection 2 should use another client address.
- EXPECT_EQ(another_client_address, queue.front().client_address);
-
- // Test the alarm is reset by enqueueing 2 packets for 3rd connection and wait
- // for them to expire.
- QuicConnectionId connection_id3 = 3;
- store_.EnqueuePacket(connection_id3, packet_, server_address_,
- client_address_, false, "");
- store_.EnqueuePacket(connection_id3, packet_, server_address_,
- client_address_, false, "");
- clock_.AdvanceTime(
- QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
- clock_.ApproximateNow());
- alarm_factory_.FireAlarm(
- QuicBufferedPacketStorePeer::expiration_alarm(&store_));
- // |last_expired_packet_queue_| should be updated.
- EXPECT_EQ(2u, visitor_.last_expired_packet_queue_.buffered_packets.size());
-}
-
// Tests that store expires long-staying connections appropriately for
// connections both with and without CHLOs.
-TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery2) {
- FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop = true;
+TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) {
QuicConnectionId connection_id = 1;
store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
false, "");
- if (FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop) {
- EXPECT_EQ(EnqueuePacketResult::SUCCESS,
- store_.EnqueuePacket(connection_id, packet_, server_address_,
- client_address_, true, ""));
- }
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS,
+ store_.EnqueuePacket(connection_id, packet_, server_address_,
+ client_address_, true, ""));
QuicConnectionId connection_id2 = 2;
EXPECT_EQ(EnqueuePacketResult::SUCCESS,
store_.EnqueuePacket(connection_id2, packet_, server_address_,
diff --git a/chromium/net/quic/core/quic_client_promised_info.cc b/chromium/net/quic/core/quic_client_promised_info.cc
index ca8334be778..f6f5ef3af0c 100644
--- a/chromium/net/quic/core/quic_client_promised_info.cc
+++ b/chromium/net/quic/core/quic_client_promised_info.cc
@@ -4,16 +4,20 @@
#include "net/quic/core/quic_client_promised_info.h"
+#include <utility>
+
#include "net/quic/core/spdy_utils.h"
#include "net/quic/platform/api/quic_logging.h"
+#include "net/spdy/core/spdy_protocol.h"
using std::string;
namespace net {
-QuicClientPromisedInfo::QuicClientPromisedInfo(QuicClientSessionBase* session,
- QuicStreamId id,
- string url)
+QuicClientPromisedInfo::QuicClientPromisedInfo(
+ QuicSpdyClientSessionBase* session,
+ QuicStreamId id,
+ string url)
: session_(session),
id_(id),
url_(std::move(url)),
@@ -38,7 +42,7 @@ void QuicClientPromisedInfo::Init() {
void QuicClientPromisedInfo::OnPromiseHeaders(const SpdyHeaderBlock& headers) {
// RFC7540, Section 8.2, requests MUST be safe [RFC7231], Section
// 4.2.1. GET and HEAD are the methods that are safe and required.
- SpdyHeaderBlock::const_iterator it = headers.find(":method");
+ SpdyHeaderBlock::const_iterator it = headers.find(kHttp2MethodHeader);
if (it == headers.end()) {
QUIC_DVLOG(1) << "Promise for stream " << id_ << " has no method";
Reset(QUIC_INVALID_PROMISE_METHOD);
diff --git a/chromium/net/quic/core/quic_client_promised_info.h b/chromium/net/quic/core/quic_client_promised_info.h
index 1f755fe45c1..1946956e812 100644
--- a/chromium/net/quic/core/quic_client_promised_info.h
+++ b/chromium/net/quic/core/quic_client_promised_info.h
@@ -10,16 +10,14 @@
#include "net/quic/core/quic_alarm.h"
#include "net/quic/core/quic_client_push_promise_index.h"
-#include "net/quic/core/quic_client_session_base.h"
#include "net/quic/core/quic_packets.h"
+#include "net/quic/core/quic_spdy_client_session_base.h"
#include "net/quic/core/quic_spdy_stream.h"
#include "net/quic/platform/api/quic_export.h"
#include "net/spdy/core/spdy_framer.h"
namespace net {
-class QuicClientSessionBase;
-
namespace test {
class QuicClientPromisedInfoPeer;
} // namespace test
@@ -32,7 +30,7 @@ class QUIC_EXPORT_PRIVATE QuicClientPromisedInfo
: public QuicClientPushPromiseIndex::TryHandle {
public:
// Interface to QuicSpdyClientStream
- QuicClientPromisedInfo(QuicClientSessionBase* session,
+ QuicClientPromisedInfo(QuicSpdyClientSessionBase* session,
QuicStreamId id,
std::string url);
virtual ~QuicClientPromisedInfo();
@@ -60,7 +58,7 @@ class QUIC_EXPORT_PRIVATE QuicClientPromisedInfo
// uing the |promised_by_url| map. The push can be cross-origin, so
// the client should validate that the session is authoritative for
// the promised URL. If not, it should call |RejectUnauthorized|.
- QuicClientSessionBase* session() { return session_; }
+ QuicSpdyClientSessionBase* session() { return session_; }
// If the promised response contains Vary header, then the fields
// specified by Vary must match between the client request header
@@ -94,7 +92,7 @@ class QUIC_EXPORT_PRIVATE QuicClientPromisedInfo
QuicAsyncStatus FinalValidation();
- QuicClientSessionBase* session_;
+ QuicSpdyClientSessionBase* session_;
QuicStreamId id_;
std::string url_;
std::unique_ptr<SpdyHeaderBlock> request_headers_;
diff --git a/chromium/net/quic/core/quic_client_promised_info_test.cc b/chromium/net/quic/core/quic_client_promised_info_test.cc
index 59e87c9882d..9d5d758cdaa 100644
--- a/chromium/net/quic/core/quic_client_promised_info_test.cc
+++ b/chromium/net/quic/core/quic_client_promised_info_test.cc
@@ -15,7 +15,7 @@
#include "net/quic/test_tools/quic_client_promised_info_peer.h"
#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/test/gtest_util.h"
-#include "net/tools/quic/quic_client_session.h"
+#include "net/tools/quic/quic_spdy_client_session.h"
using std::string;
using testing::StrictMock;
@@ -24,11 +24,12 @@ namespace net {
namespace test {
namespace {
-class MockQuicClientSession : public QuicClientSession {
+class MockQuicSpdyClientSession : public QuicSpdyClientSession {
public:
- explicit MockQuicClientSession(QuicConnection* connection,
- QuicClientPushPromiseIndex* push_promise_index)
- : QuicClientSession(
+ explicit MockQuicSpdyClientSession(
+ QuicConnection* connection,
+ QuicClientPushPromiseIndex* push_promise_index)
+ : QuicSpdyClientSession(
DefaultQuicConfig(),
connection,
QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED),
@@ -36,7 +37,7 @@ class MockQuicClientSession : public QuicClientSession {
push_promise_index),
crypto_config_(crypto_test_utils::ProofVerifierForTesting()),
authorized_(true) {}
- ~MockQuicClientSession() override {}
+ ~MockQuicSpdyClientSession() override {}
bool IsAuthorized(const string& authority) override { return authorized_; }
@@ -49,7 +50,7 @@ class MockQuicClientSession : public QuicClientSession {
bool authorized_;
- DISALLOW_COPY_AND_ASSIGN(MockQuicClientSession);
+ DISALLOW_COPY_AND_ASSIGN(MockQuicSpdyClientSession);
};
class QuicClientPromisedInfoTest : public QuicTest {
@@ -104,7 +105,7 @@ class QuicClientPromisedInfoTest : public QuicTest {
StrictMock<MockQuicConnection>* connection_;
QuicClientPushPromiseIndex push_promise_index_;
- MockQuicClientSession session_;
+ MockQuicSpdyClientSession session_;
std::unique_ptr<QuicSpdyClientStream> stream_;
std::unique_ptr<StreamVisitor> stream_visitor_;
std::unique_ptr<QuicSpdyClientStream> promised_stream_;
diff --git a/chromium/net/quic/core/quic_client_push_promise_index.h b/chromium/net/quic/core/quic_client_push_promise_index.h
index 38dc1fc8218..2609ae143de 100644
--- a/chromium/net/quic/core/quic_client_push_promise_index.h
+++ b/chromium/net/quic/core/quic_client_push_promise_index.h
@@ -7,7 +7,7 @@
#include <string>
-#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_spdy_client_session_base.h"
#include "net/quic/core/quic_types.h"
#include "net/quic/platform/api/quic_export.h"
diff --git a/chromium/net/quic/core/quic_client_push_promise_index_test.cc b/chromium/net/quic/core/quic_client_push_promise_index_test.cc
index 0a93cf177e2..9f980f14da5 100644
--- a/chromium/net/quic/core/quic_client_push_promise_index_test.cc
+++ b/chromium/net/quic/core/quic_client_push_promise_index_test.cc
@@ -12,36 +12,37 @@
#include "net/quic/test_tools/mock_quic_client_promised_info.h"
#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/tools/quic/quic_client_session.h"
+#include "net/tools/quic/quic_spdy_client_session.h"
-using testing::_;
using testing::Return;
using testing::StrictMock;
+using testing::_;
using std::string;
namespace net {
namespace test {
namespace {
-class MockQuicClientSession : public QuicClientSession {
+class MockQuicSpdyClientSession : public QuicSpdyClientSession {
public:
- explicit MockQuicClientSession(QuicConnection* connection,
- QuicClientPushPromiseIndex* push_promise_index)
- : QuicClientSession(
+ explicit MockQuicSpdyClientSession(
+ QuicConnection* connection,
+ QuicClientPushPromiseIndex* push_promise_index)
+ : QuicSpdyClientSession(
DefaultQuicConfig(),
connection,
QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED),
&crypto_config_,
push_promise_index),
crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {}
- ~MockQuicClientSession() override {}
+ ~MockQuicSpdyClientSession() override {}
MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
private:
QuicCryptoClientConfig crypto_config_;
- DISALLOW_COPY_AND_ASSIGN(MockQuicClientSession);
+ DISALLOW_COPY_AND_ASSIGN(MockQuicSpdyClientSession);
};
class QuicClientPushPromiseIndexTest : public QuicTest {
@@ -66,7 +67,7 @@ class QuicClientPushPromiseIndexTest : public QuicTest {
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
StrictMock<MockQuicConnection>* connection_;
- MockQuicClientSession session_;
+ MockQuicSpdyClientSession session_;
QuicClientPushPromiseIndex index_;
SpdyHeaderBlock request_;
string url_;
diff --git a/chromium/net/quic/core/quic_connection.cc b/chromium/net/quic/core/quic_connection.cc
index 99a12803858..d566cd58403 100644
--- a/chromium/net/quic/core/quic_connection.cc
+++ b/chromium/net/quic/core/quic_connection.cc
@@ -216,6 +216,7 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
stop_waiting_count_(0),
ack_mode_(TCP_ACKING),
ack_decimation_delay_(kAckDecimationDelay),
+ unlimited_ack_decimation_(false),
delay_setting_retransmission_alarm_(false),
pending_retransmission_alarm_(false),
defer_send_in_response_to_packets_(false),
@@ -246,7 +247,7 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
packet_generator_(connection_id_,
&framer_,
random_generator_,
- helper->GetBufferAllocator(),
+ helper->GetStreamFrameBufferAllocator(),
this),
idle_network_timeout_(QuicTime::Delta::Infinite()),
handshake_timeout_(QuicTime::Delta::Infinite()),
@@ -270,7 +271,7 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
largest_received_packet_size_(0),
goaway_sent_(false),
goaway_received_(false),
- write_error_occured_(false),
+ write_error_occurred_(false),
no_stop_waiting_frames_(false),
consecutive_num_packets_with_no_retransmittable_frames_(0) {
QUIC_DLOG(INFO) << ENDPOINT
@@ -354,6 +355,12 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
ack_decimation_delay_ = kShortAckDecimationDelay;
}
+ if (FLAGS_quic_reloadable_flag_quic_ack_decimation) {
+ QUIC_FLAG_COUNT(quic_reloadable_flag_quic_ack_decimation);
+ if (config.HasClientSentConnectionOption(kAKDU, perspective_)) {
+ unlimited_ack_decimation_ = true;
+ }
+ }
if (config.HasClientSentConnectionOption(k5RTO, perspective_)) {
close_connection_after_five_rtos_ = true;
}
@@ -536,6 +543,8 @@ void QuicConnection::OnVersionNegotiationPacket(
return;
}
+ server_supported_versions_ = packet.versions;
+
if (!SelectMutualVersion(packet.versions)) {
CloseConnection(
QUIC_INVALID_VERSION,
@@ -549,7 +558,6 @@ void QuicConnection::OnVersionNegotiationPacket(
QUIC_DLOG(INFO) << ENDPOINT
<< "Negotiated version: " << QuicVersionToString(version());
- server_supported_versions_ = packet.versions;
version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
}
@@ -634,16 +642,26 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
return false;
}
- // Only migrate connection to a new peer address if a change is not underway.
PeerAddressChangeType peer_migration_type =
QuicUtils::DetermineAddressChangeType(peer_address_,
last_packet_source_address_);
- // Do not migrate connection if the changed address packet is a reordered
- // packet.
- if (active_peer_migration_type_ == NO_CHANGE &&
- peer_migration_type != NO_CHANGE &&
- header.packet_number > received_packet_manager_.GetLargestObserved()) {
- StartPeerMigration(peer_migration_type);
+ // Initiate connection migration if a non-reordered packet is received from a
+ // new address.
+ if (header.packet_number > received_packet_manager_.GetLargestObserved() &&
+ peer_migration_type != NO_CHANGE) {
+ if (FLAGS_quic_reloadable_flag_quic_disable_peer_migration_on_client &&
+ perspective_ == Perspective::IS_CLIENT) {
+ QUIC_FLAG_COUNT_N(
+ quic_reloadable_flag_quic_disable_peer_migration_on_client, 1, 2);
+ QUIC_DLOG(INFO) << ENDPOINT << "Peer's ip:port changed from "
+ << peer_address_.ToString() << " to "
+ << last_packet_source_address_.ToString();
+ peer_address_ = last_packet_source_address_;
+ } else if (active_peer_migration_type_ == NO_CHANGE) {
+ // Only migrate connection to a new peer address if there is no
+ // pending change underway.
+ StartPeerMigration(peer_migration_type);
+ }
}
--stats_.packets_dropped;
@@ -897,7 +915,7 @@ bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
DCHECK(connected_);
if (debug_visitor_ != nullptr) {
- debug_visitor_->OnWindowUpdateFrame(frame);
+ debug_visitor_->OnWindowUpdateFrame(frame, time_of_last_received_packet_);
}
QUIC_DLOG(INFO) << ENDPOINT << "WINDOW_UPDATE_FRAME received for stream: "
<< frame.stream_id
@@ -968,9 +986,10 @@ void QuicConnection::MaybeQueueAck(bool was_missing) {
++num_retransmittable_packets_received_since_last_ack_sent_;
if (ack_mode_ != TCP_ACKING &&
last_header_.packet_number > kMinReceivedBeforeAckDecimation) {
- // Ack up to 10 packets at once.
- if (num_retransmittable_packets_received_since_last_ack_sent_ >=
- kMaxRetransmittablePacketsBeforeAck) {
+ // Ack up to 10 packets at once unless ack decimation is unlimited.
+ if (!unlimited_ack_decimation_ &&
+ num_retransmittable_packets_received_since_last_ack_sent_ >=
+ kMaxRetransmittablePacketsBeforeAck) {
ack_queued_ = true;
} else if (!ack_alarm_->IsSet()) {
// Wait the minimum of a quarter min_rtt and the delayed ack time.
@@ -1091,14 +1110,17 @@ QuicConsumedData QuicConnection::SendStreamData(
ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
// The optimized path may be used for data only packets which fit into a
// standard buffer and don't need padding.
- if (id != kCryptoStreamId && !packet_generator_.HasQueuedFrames() &&
+ const bool flag_run_fast_path =
+ FLAGS_quic_reloadable_flag_quic_consuming_data_faster;
+ if (!flag_run_fast_path && id != kCryptoStreamId &&
+ !packet_generator_.HasQueuedFrames() &&
iov.total_length > kMaxPacketSize && state != FIN_AND_PADDING) {
// Use the fast path to send full data packets.
return packet_generator_.ConsumeDataFastPath(
- id, iov, offset, state != NO_FIN, std::move(ack_listener));
+ id, iov, offset, state != NO_FIN, 0, ack_listener);
}
- return packet_generator_.ConsumeData(id, iov, offset, state,
- std::move(ack_listener));
+ return packet_generator_.ConsumeData(
+ id, iov, offset, state, std::move(ack_listener), flag_run_fast_path);
}
void QuicConnection::SendRstStream(QuicStreamId id,
@@ -1236,7 +1258,15 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address,
if (active_peer_migration_type_ != NO_CHANGE &&
sent_packet_manager_.GetLargestObserved() >
highest_packet_sent_before_peer_migration_) {
- OnPeerMigrationValidated();
+ if (FLAGS_quic_reloadable_flag_quic_disable_peer_migration_on_client) {
+ QUIC_FLAG_COUNT_N(
+ quic_reloadable_flag_quic_disable_peer_migration_on_client, 2, 2);
+ if (perspective_ == Perspective::IS_SERVER) {
+ OnPeerMigrationValidated();
+ }
+ } else {
+ OnPeerMigrationValidated();
+ }
}
MaybeProcessUndecryptablePackets();
MaybeSendInResponseToPacket();
@@ -1531,7 +1561,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) {
if (result.status == WRITE_STATUS_BLOCKED) {
visitor_->OnWriteBlocked();
- // If the socket buffers the the data, then the packet should not
+ // If the socket buffers the data, then the packet should not
// be queued and sent again, which would result in an unnecessary
// duplicate packet being sent. The helper must call OnCanWrite
// when the write completes, and OnWriteError if an error occurs.
@@ -1633,11 +1663,11 @@ bool QuicConnection::AllowSelfAddressChange() const {
}
void QuicConnection::OnWriteError(int error_code) {
- if (write_error_occured_) {
+ if (write_error_occurred_) {
// A write error already occurred. The connection is being closed.
return;
}
- write_error_occured_ = true;
+ write_error_occurred_ = true;
const string error_details = QuicStrCat(
"Write failed with error: ", error_code, " (", strerror(error_code), ")");
diff --git a/chromium/net/quic/core/quic_connection.h b/chromium/net/quic/core/quic_connection.h
index 6ed662289a5..fc180415b17 100644
--- a/chromium/net/quic/core/quic_connection.h
+++ b/chromium/net/quic/core/quic_connection.h
@@ -230,7 +230,8 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor
virtual void OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) {}
// Called when a WindowUpdate has been parsed.
- virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {}
+ virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
+ const QuicTime& receive_time) {}
// Called when a BlockedFrame has been parsed.
virtual void OnBlockedFrame(const QuicBlockedFrame& frame) {}
@@ -282,7 +283,10 @@ class QUIC_EXPORT_PRIVATE QuicConnectionHelperInterface {
virtual QuicRandom* GetRandomGenerator() = 0;
// Returns a QuicBufferAllocator to be used for all stream frame buffers.
- virtual QuicBufferAllocator* GetBufferAllocator() = 0;
+ virtual QuicBufferAllocator* GetStreamFrameBufferAllocator() = 0;
+
+ // Returns a QuicBufferAllocator to be used for stream send buffers.
+ virtual QuicBufferAllocator* GetStreamSendBufferAllocator() = 0;
};
class QUIC_EXPORT_PRIVATE QuicConnection
@@ -957,6 +961,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection
AckMode ack_mode_;
// The max delay in fraction of min_rtt to use when sending decimated acks.
float ack_decimation_delay_;
+ // When true, removes ack decimation's max number of packets(10) before
+ // sending an ack.
+ bool unlimited_ack_decimation_;
// Indicates the retransmit alarm is going to be set by the
// ScopedRetransmitAlarmDelayer
@@ -1092,7 +1099,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// Indicates whether a write error is encountered currently. This is used to
// avoid infinite write errors.
- bool write_error_occured_;
+ bool write_error_occurred_;
// Indicates not to send or process stop waiting frames.
bool no_stop_waiting_frames_;
diff --git a/chromium/net/quic/core/quic_connection_test.cc b/chromium/net/quic/core/quic_connection_test.cc
index ec9ebb406a8..771491c8af0 100644
--- a/chromium/net/quic/core/quic_connection_test.cc
+++ b/chromium/net/quic/core/quic_connection_test.cc
@@ -230,7 +230,11 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
QuicRandom* GetRandomGenerator() override { return random_generator_; }
- QuicBufferAllocator* GetBufferAllocator() override {
+ QuicBufferAllocator* GetStreamFrameBufferAllocator() override {
+ return &buffer_allocator_;
+ }
+
+ QuicBufferAllocator* GetStreamSendBufferAllocator() override {
return &buffer_allocator_;
}
@@ -995,7 +999,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
const QuicAckFrame InitAckFrame(QuicPacketNumber largest_observed) {
QuicAckFrame frame(MakeAckFrame(largest_observed));
if (largest_observed > 0) {
- frame.packets.Add(1, largest_observed + 1);
+ frame.packets.AddRange(1, largest_observed + 1);
}
return frame;
}
@@ -1013,12 +1017,12 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> {
QuicPacketNumber missing) {
QuicAckFrame ack_frame;
if (largest_acked > missing) {
- ack_frame.packets.Add(1, missing);
- ack_frame.packets.Add(missing + 1, largest_acked + 1);
+ ack_frame.packets.AddRange(1, missing);
+ ack_frame.packets.AddRange(missing + 1, largest_acked + 1);
ack_frame.largest_observed = largest_acked;
}
if (largest_acked == missing) {
- ack_frame.packets.Add(1, missing);
+ ack_frame.packets.AddRange(1, missing);
ack_frame.largest_observed = largest_acked;
}
return ack_frame;
@@ -1202,6 +1206,58 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) {
kPeerAddress);
}
+TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ set_perspective(Perspective::IS_SERVER);
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+
+ // Clear peer address.
+ QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress());
+ EXPECT_FALSE(connection_.peer_address().IsInitialized());
+
+ QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
+ kPeerAddress);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+
+ // Process another packet with a different peer address on server side will
+ // start connection migration.
+ const QuicSocketAddress kNewPeerAddress =
+ QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
+ EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1);
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
+ kNewPeerAddress);
+ EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
+}
+
+TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) {
+ FLAGS_quic_reloadable_flag_quic_disable_peer_migration_on_client = true;
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ set_perspective(Perspective::IS_CLIENT);
+ EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
+
+ // Clear peer address.
+ QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress());
+ EXPECT_FALSE(connection_.peer_address().IsInitialized());
+
+ QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
+ kPeerAddress);
+ EXPECT_EQ(kPeerAddress, connection_.peer_address());
+
+ // Process another packet with a different peer address on client side will
+ // only update peer address.
+ const QuicSocketAddress kNewPeerAddress =
+ QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
+ EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
+ kNewPeerAddress);
+ EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
+}
+
TEST_P(QuicConnectionTest, MaxPacketSize) {
EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
EXPECT_EQ(1350u, connection_.max_packet_length());
@@ -3147,12 +3203,12 @@ TEST_P(QuicConnectionTest, MtuDiscoveryFailed) {
mtu_discovery_packets.end());
QuicPacketNumber max_packet = *max_element(mtu_discovery_packets.begin(),
mtu_discovery_packets.end());
- ack.packets.Add(1, min_packet);
- ack.packets.Add(max_packet + 1, creator_->packet_number() + 1);
+ ack.packets.AddRange(1, min_packet);
+ ack.packets.AddRange(max_packet + 1, creator_->packet_number() + 1);
ack.largest_observed = creator_->packet_number();
} else {
- ack.packets.Add(1, creator_->packet_number() + 1);
+ ack.packets.AddRange(1, creator_->packet_number() + 1);
ack.largest_observed = creator_->packet_number();
}
@@ -3321,7 +3377,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) {
SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, FIN, nullptr);
EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
- // Now send more data. This will not move the timeout becase
+ // Now send more data. This will not move the timeout because
// no data has been recieved since the previous write.
clock_.AdvanceTime(five_ms);
SendStreamDataToPeer(kClientDataStreamId1, "foo", 3, FIN, nullptr);
@@ -3458,7 +3514,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) {
SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, FIN, nullptr);
EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
- // Now send more data. This will not move the timeout becase
+ // Now send more data. This will not move the timeout because
// no data has been recieved since the previous write.
clock_.AdvanceTime(five_ms);
SendStreamDataToPeer(kClientDataStreamId1, "foo", 3, FIN, nullptr);
@@ -3842,6 +3898,64 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) {
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
}
+TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) {
+ FLAGS_quic_reloadable_flag_quic_ack_decimation = true;
+ EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kACKD);
+ // No limit on the number of packets received before sending an ack.
+ connection_options.push_back(kAKDU);
+ config.SetConnectionOptionsToSend(connection_options);
+ connection_.SetFromConfig(config);
+
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ // The ack time should be based on min_rtt/4, since it's less than the
+ // default delayed ack time.
+ QuicTime ack_time = clock_.ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ const uint8_t tag = 0x07;
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ // Process a packet from the non-crypto stream.
+ frame1_.stream_id = 3;
+
+ // Process all the initial packets in order so there aren't missing packets.
+ QuicPacketNumber kFirstDecimatedPacket = 101;
+ for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ }
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // instead of ENCRYPTION_NONE.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+
+ // Check if delayed ack timer is running for the expected interval.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // 18 packets will not cause an ack to be sent. 19 will because when
+ // stop waiting frames are in use, we ack every 20 packets no matter what.
+ for (int i = 0; i < 18; ++i) {
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+ }
+ // The delayed ack timer should still be set to the expected deadline.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+}
+
TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) {
EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION);
@@ -5255,6 +5369,16 @@ TEST_P(QuicConnectionTest, CloseConnectionForStatelessReject) {
ConnectionCloseBehavior::SILENT_CLOSE);
}
+// Regression test for b/63620844.
+TEST_P(QuicConnectionTest, FailedToWriteHandshakePacket) {
+ FLAGS_quic_reloadable_flag_quic_clear_packet_before_handed_over = true;
+ SimulateNextPacketTooLarge();
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PACKET_WRITE_ERROR, _,
+ ConnectionCloseSource::FROM_SELF))
+ .Times(1);
+ connection_.SendCryptoStreamData();
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/core/quic_constants.h b/chromium/net/quic/core/quic_constants.h
index 8fcf115de00..9dd96c78baf 100644
--- a/chromium/net/quic/core/quic_constants.h
+++ b/chromium/net/quic/core/quic_constants.h
@@ -183,6 +183,11 @@ const QuicPacketNumber kMaxPacketGap = 5000;
// The maximum number of random padding bytes to add.
const QuicByteCount kMaxNumRandomPaddingBytes = 256;
+// The size of stream send buffer data slice size in bytes. A data slice is
+// piece of stream data stored in contiguous memory, and a stream frame can
+// contain data from multiple data slices.
+const QuicByteCount kQuicStreamSendBufferSliceSize = 4 * 1024;
+
} // namespace net
#endif // NET_QUIC_CORE_QUIC_CONSTANTS_H_
diff --git a/chromium/net/quic/core/quic_crypto_client_handshaker.cc b/chromium/net/quic/core/quic_crypto_client_handshaker.cc
new file mode 100644
index 00000000000..2fe6c6f6828
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_client_handshaker.cc
@@ -0,0 +1,698 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_crypto_client_handshaker.h"
+
+#include <memory>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/platform/api/quic_flags.h"
+#include "net/quic/platform/api/quic_logging.h"
+#include "net/quic/platform/api/quic_str_cat.h"
+
+using std::string;
+
+namespace net {
+
+QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::
+ ChannelIDSourceCallbackImpl(QuicCryptoClientHandshaker* parent)
+ : parent_(parent) {}
+
+QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::
+ ~ChannelIDSourceCallbackImpl() {}
+
+void QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::Run(
+ std::unique_ptr<ChannelIDKey>* channel_id_key) {
+ if (parent_ == nullptr) {
+ return;
+ }
+
+ parent_->channel_id_key_ = std::move(*channel_id_key);
+ parent_->channel_id_source_callback_run_ = true;
+ parent_->channel_id_source_callback_ = nullptr;
+ parent_->DoHandshakeLoop(nullptr);
+
+ // The ChannelIDSource owns this object and will delete it when this method
+ // returns.
+}
+
+void QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::Cancel() {
+ parent_ = nullptr;
+}
+
+QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::
+ ProofVerifierCallbackImpl(QuicCryptoClientHandshaker* parent)
+ : parent_(parent) {}
+
+QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::
+ ~ProofVerifierCallbackImpl() {}
+
+void QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::Run(
+ bool ok,
+ const string& error_details,
+ std::unique_ptr<ProofVerifyDetails>* details) {
+ if (parent_ == nullptr) {
+ return;
+ }
+
+ parent_->verify_ok_ = ok;
+ parent_->verify_error_details_ = error_details;
+ parent_->verify_details_ = std::move(*details);
+ parent_->proof_verify_callback_ = nullptr;
+ parent_->DoHandshakeLoop(nullptr);
+
+ // The ProofVerifier owns this object and will delete it when this method
+ // returns.
+}
+
+void QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::Cancel() {
+ parent_ = nullptr;
+}
+
+QuicCryptoClientHandshaker::QuicCryptoClientHandshaker(
+ const QuicServerId& server_id,
+ QuicCryptoClientStream* stream,
+ QuicSession* session,
+ ProofVerifyContext* verify_context,
+ QuicCryptoClientConfig* crypto_config,
+ QuicCryptoClientStream::ProofHandler* proof_handler)
+ : QuicCryptoHandshaker(stream, session),
+ stream_(stream),
+ session_(session),
+ next_state_(STATE_IDLE),
+ num_client_hellos_(0),
+ crypto_config_(crypto_config),
+ server_id_(server_id),
+ generation_counter_(0),
+ channel_id_sent_(false),
+ channel_id_source_callback_run_(false),
+ channel_id_source_callback_(nullptr),
+ verify_context_(verify_context),
+ proof_verify_callback_(nullptr),
+ proof_handler_(proof_handler),
+ verify_ok_(false),
+ stateless_reject_received_(false),
+ num_scup_messages_received_(0),
+ encryption_established_(false),
+ handshake_confirmed_(false),
+ crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {}
+
+QuicCryptoClientHandshaker::~QuicCryptoClientHandshaker() {
+ if (channel_id_source_callback_) {
+ channel_id_source_callback_->Cancel();
+ }
+ if (proof_verify_callback_) {
+ proof_verify_callback_->Cancel();
+ }
+}
+
+void QuicCryptoClientHandshaker::OnHandshakeMessage(
+ const CryptoHandshakeMessage& message) {
+ QuicCryptoHandshaker::OnHandshakeMessage(message);
+ if (message.tag() == kSCUP) {
+ if (!handshake_confirmed()) {
+ stream_->CloseConnectionWithDetails(
+ QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE,
+ "Early SCUP disallowed");
+ return;
+ }
+
+ // |message| is an update from the server, so we treat it differently from a
+ // handshake message.
+ HandleServerConfigUpdateMessage(message);
+ num_scup_messages_received_++;
+ return;
+ }
+
+ // Do not process handshake messages after the handshake is confirmed.
+ if (handshake_confirmed()) {
+ stream_->CloseConnectionWithDetails(
+ QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
+ "Unexpected handshake message");
+ return;
+ }
+
+ DoHandshakeLoop(&message);
+}
+
+bool QuicCryptoClientHandshaker::CryptoConnect() {
+ next_state_ = STATE_INITIALIZE;
+ DoHandshakeLoop(nullptr);
+ return session()->connection()->connected();
+}
+
+int QuicCryptoClientHandshaker::num_sent_client_hellos() const {
+ return num_client_hellos_;
+}
+
+int QuicCryptoClientHandshaker::num_scup_messages_received() const {
+ return num_scup_messages_received_;
+}
+
+bool QuicCryptoClientHandshaker::WasChannelIDSent() const {
+ return channel_id_sent_;
+}
+
+bool QuicCryptoClientHandshaker::WasChannelIDSourceCallbackRun() const {
+ return channel_id_source_callback_run_;
+}
+
+string QuicCryptoClientHandshaker::chlo_hash() const {
+ return chlo_hash_;
+}
+
+bool QuicCryptoClientHandshaker::encryption_established() const {
+ return encryption_established_;
+}
+
+bool QuicCryptoClientHandshaker::handshake_confirmed() const {
+ return handshake_confirmed_;
+}
+
+const QuicCryptoNegotiatedParameters&
+QuicCryptoClientHandshaker::crypto_negotiated_params() const {
+ return *crypto_negotiated_params_;
+}
+
+CryptoMessageParser* QuicCryptoClientHandshaker::crypto_message_parser() {
+ return QuicCryptoHandshaker::crypto_message_parser();
+}
+
+void QuicCryptoClientHandshaker::HandleServerConfigUpdateMessage(
+ const CryptoHandshakeMessage& server_config_update) {
+ DCHECK(server_config_update.tag() == kSCUP);
+ string error_details;
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config_->LookupOrCreate(server_id_);
+ QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
+ server_config_update, session()->connection()->clock()->WallNow(),
+ session()->connection()->version(), chlo_hash_, cached,
+ crypto_negotiated_params_, &error_details);
+
+ if (error != QUIC_NO_ERROR) {
+ stream_->CloseConnectionWithDetails(
+ error, "Server config update invalid: " + error_details);
+ return;
+ }
+
+ DCHECK(handshake_confirmed());
+ if (proof_verify_callback_) {
+ proof_verify_callback_->Cancel();
+ }
+ next_state_ = STATE_INITIALIZE_SCUP;
+ DoHandshakeLoop(nullptr);
+}
+
+void QuicCryptoClientHandshaker::DoHandshakeLoop(
+ const CryptoHandshakeMessage* in) {
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config_->LookupOrCreate(server_id_);
+
+ QuicAsyncStatus rv = QUIC_SUCCESS;
+ do {
+ CHECK_NE(STATE_NONE, next_state_);
+ const State state = next_state_;
+ next_state_ = STATE_IDLE;
+ rv = QUIC_SUCCESS;
+ switch (state) {
+ case STATE_INITIALIZE:
+ DoInitialize(cached);
+ break;
+ case STATE_SEND_CHLO:
+ DoSendCHLO(cached);
+ return; // return waiting to hear from server.
+ case STATE_RECV_REJ:
+ DoReceiveREJ(in, cached);
+ break;
+ case STATE_VERIFY_PROOF:
+ rv = DoVerifyProof(cached);
+ break;
+ case STATE_VERIFY_PROOF_COMPLETE:
+ DoVerifyProofComplete(cached);
+ break;
+ case STATE_GET_CHANNEL_ID:
+ rv = DoGetChannelID(cached);
+ break;
+ case STATE_GET_CHANNEL_ID_COMPLETE:
+ DoGetChannelIDComplete();
+ break;
+ case STATE_RECV_SHLO:
+ DoReceiveSHLO(in, cached);
+ break;
+ case STATE_IDLE:
+ // This means that the peer sent us a message that we weren't expecting.
+ stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+ "Handshake in idle state");
+ return;
+ case STATE_INITIALIZE_SCUP:
+ DoInitializeServerConfigUpdate(cached);
+ break;
+ case STATE_NONE:
+ QUIC_NOTREACHED();
+ return; // We are done.
+ }
+ } while (rv != QUIC_PENDING && next_state_ != STATE_NONE);
+}
+
+void QuicCryptoClientHandshaker::DoInitialize(
+ QuicCryptoClientConfig::CachedState* cached) {
+ if (!cached->IsEmpty() && !cached->signature().empty()) {
+ // Note that we verify the proof even if the cached proof is valid.
+ // This allows us to respond to CA trust changes or certificate
+ // expiration because it may have been a while since we last verified
+ // the proof.
+ DCHECK(crypto_config_->proof_verifier());
+ // Track proof verification time when cached server config is used.
+ proof_verify_start_time_ = base::TimeTicks::Now();
+ chlo_hash_ = cached->chlo_hash();
+ // If the cached state needs to be verified, do it now.
+ next_state_ = STATE_VERIFY_PROOF;
+ } else {
+ next_state_ = STATE_GET_CHANNEL_ID;
+ }
+}
+
+void QuicCryptoClientHandshaker::DoSendCHLO(
+ QuicCryptoClientConfig::CachedState* cached) {
+ if (stateless_reject_received_) {
+ // If we've gotten to this point, we've sent at least one hello
+ // and received a stateless reject in response. We cannot
+ // continue to send hellos because the server has abandoned state
+ // for this connection. Abandon further handshakes.
+ next_state_ = STATE_NONE;
+ if (session()->connection()->connected()) {
+ session()->connection()->CloseConnection(
+ QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject received",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ }
+ return;
+ }
+
+ // Send the client hello in plaintext.
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
+ encryption_established_ = false;
+ if (num_client_hellos_ > QuicCryptoClientStream::kMaxClientHellos) {
+ stream_->CloseConnectionWithDetails(
+ QUIC_CRYPTO_TOO_MANY_REJECTS,
+ QuicStrCat("More than ", QuicCryptoClientStream::kMaxClientHellos,
+ " rejects"));
+ return;
+ }
+ num_client_hellos_++;
+
+ CryptoHandshakeMessage out;
+ DCHECK(session() != nullptr);
+ DCHECK(session()->config() != nullptr);
+ // Send all the options, regardless of whether we're sending an
+ // inchoate or subsequent hello.
+ session()->config()->ToHandshakeMessage(&out);
+
+ // Send a local timestamp to the server.
+ out.SetValue(kCTIM,
+ session()->connection()->clock()->WallNow().ToUNIXSeconds());
+
+ if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
+ crypto_config_->FillInchoateClientHello(
+ server_id_, session()->connection()->supported_versions().front(),
+ cached, session()->connection()->random_generator(),
+ /* demand_x509_proof= */ true, crypto_negotiated_params_, &out);
+ // Pad the inchoate client hello to fill up a packet.
+ const QuicByteCount kFramingOverhead = 50; // A rough estimate.
+ const QuicByteCount max_packet_size =
+ session()->connection()->max_packet_length();
+ if (max_packet_size <= kFramingOverhead) {
+ QUIC_DLOG(DFATAL) << "max_packet_length (" << max_packet_size
+ << ") has no room for framing overhead.";
+ stream_->CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
+ "max_packet_size too smalll");
+ return;
+ }
+ if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
+ QUIC_DLOG(DFATAL) << "Client hello won't fit in a single packet.";
+ stream_->CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
+ "CHLO too large");
+ return;
+ }
+ // TODO(rch): Remove this when we remove:
+ // FLAGS_quic_reloadable_flag_quic_use_chlo_packet_size
+ out.set_minimum_size(
+ static_cast<size_t>(max_packet_size - kFramingOverhead));
+ next_state_ = STATE_RECV_REJ;
+ CryptoUtils::HashHandshakeMessage(out, &chlo_hash_, Perspective::IS_CLIENT);
+ SendHandshakeMessage(out);
+ return;
+ }
+
+ // If the server nonce is empty, copy over the server nonce from a previous
+ // SREJ, if there is one.
+ if (FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support &&
+ crypto_negotiated_params_->server_nonce.empty() &&
+ cached->has_server_nonce()) {
+ crypto_negotiated_params_->server_nonce = cached->GetNextServerNonce();
+ DCHECK(!crypto_negotiated_params_->server_nonce.empty());
+ }
+
+ string error_details;
+ QuicErrorCode error = crypto_config_->FillClientHello(
+ server_id_, session()->connection()->connection_id(),
+ session()->connection()->supported_versions().front(), cached,
+ session()->connection()->clock()->WallNow(),
+ session()->connection()->random_generator(), channel_id_key_.get(),
+ crypto_negotiated_params_, &out, &error_details);
+ if (error != QUIC_NO_ERROR) {
+ // Flush the cached config so that, if it's bad, the server has a
+ // chance to send us another in the future.
+ cached->InvalidateServerConfig();
+ stream_->CloseConnectionWithDetails(error, error_details);
+ return;
+ }
+ CryptoUtils::HashHandshakeMessage(out, &chlo_hash_, Perspective::IS_CLIENT);
+ channel_id_sent_ = (channel_id_key_.get() != nullptr);
+ if (cached->proof_verify_details()) {
+ proof_handler_->OnProofVerifyDetailsAvailable(
+ *cached->proof_verify_details());
+ }
+ next_state_ = STATE_RECV_SHLO;
+ SendHandshakeMessage(out);
+ // Be prepared to decrypt with the new server write key.
+ session()->connection()->SetAlternativeDecrypter(
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_->initial_crypters.decrypter.release(),
+ true /* latch once used */);
+ // Send subsequent packets under encryption on the assumption that the
+ // server will accept the handshake.
+ session()->connection()->SetEncrypter(
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_->initial_crypters.encrypter.release());
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+
+ // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and
+ // ENCRYPTION_FIRST_ESTABLSIHED
+ encryption_established_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED);
+}
+
+void QuicCryptoClientHandshaker::DoReceiveREJ(
+ const CryptoHandshakeMessage* in,
+ QuicCryptoClientConfig::CachedState* cached) {
+ // We sent a dummy CHLO because we didn't have enough information to
+ // perform a handshake, or we sent a full hello that the server
+ // rejected. Here we hope to have a REJ that contains the information
+ // that we need.
+ if ((in->tag() != kREJ) && (in->tag() != kSREJ)) {
+ next_state_ = STATE_NONE;
+ stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+ "Expected REJ");
+ return;
+ }
+
+ QuicTagVector reject_reasons;
+ static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
+ if (in->GetTaglist(kRREJ, &reject_reasons) == QUIC_NO_ERROR) {
+ uint32_t packed_error = 0;
+ for (size_t i = 0; i < reject_reasons.size(); ++i) {
+ // HANDSHAKE_OK is 0 and don't report that as error.
+ if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
+ continue;
+ }
+ HandshakeFailureReason reason =
+ static_cast<HandshakeFailureReason>(reject_reasons[i]);
+ packed_error |= 1 << (reason - 1);
+ }
+ DVLOG(1) << "Reasons for rejection: " << packed_error;
+ if (num_client_hellos_ == QuicCryptoClientStream::kMaxClientHellos) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.TooMany",
+ packed_error);
+ }
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
+ packed_error);
+ }
+
+ // Receipt of a REJ message means that the server received the CHLO
+ // so we can cancel and retransmissions.
+ session()->connection()->NeuterUnencryptedPackets();
+
+ stateless_reject_received_ = in->tag() == kSREJ;
+ string error_details;
+ QuicErrorCode error = crypto_config_->ProcessRejection(
+ *in, session()->connection()->clock()->WallNow(),
+ session()->connection()->version(), chlo_hash_, cached,
+ crypto_negotiated_params_, &error_details);
+
+ if (error != QUIC_NO_ERROR) {
+ next_state_ = STATE_NONE;
+ stream_->CloseConnectionWithDetails(error, error_details);
+ return;
+ }
+ if (!cached->proof_valid()) {
+ if (!cached->signature().empty()) {
+ // Note that we only verify the proof if the cached proof is not
+ // valid. If the cached proof is valid here, someone else must have
+ // just added the server config to the cache and verified the proof,
+ // so we can assume no CA trust changes or certificate expiration
+ // has happened since then.
+ next_state_ = STATE_VERIFY_PROOF;
+ return;
+ }
+ }
+ next_state_ = STATE_GET_CHANNEL_ID;
+}
+
+QuicAsyncStatus QuicCryptoClientHandshaker::DoVerifyProof(
+ QuicCryptoClientConfig::CachedState* cached) {
+ ProofVerifier* verifier = crypto_config_->proof_verifier();
+ DCHECK(verifier);
+ next_state_ = STATE_VERIFY_PROOF_COMPLETE;
+ generation_counter_ = cached->generation_counter();
+
+ ProofVerifierCallbackImpl* proof_verify_callback =
+ new ProofVerifierCallbackImpl(this);
+
+ verify_ok_ = false;
+
+ QuicAsyncStatus status = verifier->VerifyProof(
+ server_id_.host(), server_id_.port(), cached->server_config(),
+ session()->connection()->version(), chlo_hash_, cached->certs(),
+ cached->cert_sct(), cached->signature(), verify_context_.get(),
+ &verify_error_details_, &verify_details_,
+ std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
+
+ switch (status) {
+ case QUIC_PENDING:
+ proof_verify_callback_ = proof_verify_callback;
+ QUIC_DVLOG(1) << "Doing VerifyProof";
+ break;
+ case QUIC_FAILURE:
+ break;
+ case QUIC_SUCCESS:
+ verify_ok_ = true;
+ break;
+ }
+ return status;
+}
+
+void QuicCryptoClientHandshaker::DoVerifyProofComplete(
+ QuicCryptoClientConfig::CachedState* cached) {
+ if (!proof_verify_start_time_.is_null()) {
+ UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.CachedServerConfig",
+ base::TimeTicks::Now() - proof_verify_start_time_);
+ }
+ if (!verify_ok_) {
+ if (verify_details_.get()) {
+ proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_);
+ }
+ if (num_client_hellos_ == 0) {
+ cached->Clear();
+ next_state_ = STATE_INITIALIZE;
+ return;
+ }
+ next_state_ = STATE_NONE;
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
+ handshake_confirmed());
+ stream_->CloseConnectionWithDetails(
+ QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
+ return;
+ }
+
+ // Check if generation_counter has changed between STATE_VERIFY_PROOF and
+ // STATE_VERIFY_PROOF_COMPLETE state changes.
+ if (generation_counter_ != cached->generation_counter()) {
+ next_state_ = STATE_VERIFY_PROOF;
+ } else {
+ SetCachedProofValid(cached);
+ cached->SetProofVerifyDetails(verify_details_.release());
+ if (!handshake_confirmed()) {
+ next_state_ = STATE_GET_CHANNEL_ID;
+ } else {
+ // TODO: Enable Expect-Staple. https://crbug.com/631101
+ next_state_ = STATE_NONE;
+ }
+ }
+}
+
+QuicAsyncStatus QuicCryptoClientHandshaker::DoGetChannelID(
+ QuicCryptoClientConfig::CachedState* cached) {
+ next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
+ channel_id_key_.reset();
+ if (!RequiresChannelID(cached)) {
+ next_state_ = STATE_SEND_CHLO;
+ return QUIC_SUCCESS;
+ }
+
+ ChannelIDSourceCallbackImpl* channel_id_source_callback =
+ new ChannelIDSourceCallbackImpl(this);
+ QuicAsyncStatus status = crypto_config_->channel_id_source()->GetChannelIDKey(
+ server_id_.host(), &channel_id_key_, channel_id_source_callback);
+
+ switch (status) {
+ case QUIC_PENDING:
+ channel_id_source_callback_ = channel_id_source_callback;
+ QUIC_DVLOG(1) << "Looking up channel ID";
+ break;
+ case QUIC_FAILURE:
+ next_state_ = STATE_NONE;
+ delete channel_id_source_callback;
+ stream_->CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
+ "Channel ID lookup failed");
+ break;
+ case QUIC_SUCCESS:
+ delete channel_id_source_callback;
+ break;
+ }
+ return status;
+}
+
+void QuicCryptoClientHandshaker::DoGetChannelIDComplete() {
+ if (!channel_id_key_.get()) {
+ next_state_ = STATE_NONE;
+ stream_->CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
+ "Channel ID lookup failed");
+ return;
+ }
+ next_state_ = STATE_SEND_CHLO;
+}
+
+void QuicCryptoClientHandshaker::DoReceiveSHLO(
+ const CryptoHandshakeMessage* in,
+ QuicCryptoClientConfig::CachedState* cached) {
+ next_state_ = STATE_NONE;
+ // We sent a CHLO that we expected to be accepted and now we're
+ // hoping for a SHLO from the server to confirm that. First check
+ // to see whether the response was a reject, and if so, move on to
+ // the reject-processing state.
+ if ((in->tag() == kREJ) || (in->tag() == kSREJ)) {
+ // alternative_decrypter will be nullptr if the original alternative
+ // decrypter latched and became the primary decrypter. That happens
+ // if we received a message encrypted with the INITIAL key.
+ if (session()->connection()->alternative_decrypter() == nullptr) {
+ // The rejection was sent encrypted!
+ stream_->CloseConnectionWithDetails(
+ QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, "encrypted REJ message");
+ return;
+ }
+ next_state_ = STATE_RECV_REJ;
+ return;
+ }
+
+ if (in->tag() != kSHLO) {
+ stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+ "Expected SHLO or REJ");
+ return;
+ }
+
+ // alternative_decrypter will be nullptr if the original alternative
+ // decrypter latched and became the primary decrypter. That happens
+ // if we received a message encrypted with the INITIAL key.
+ if (session()->connection()->alternative_decrypter() != nullptr) {
+ // The server hello was sent without encryption.
+ stream_->CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
+ "unencrypted SHLO message");
+ return;
+ }
+
+ string error_details;
+ QuicErrorCode error = crypto_config_->ProcessServerHello(
+ *in, session()->connection()->connection_id(),
+ session()->connection()->version(),
+ session()->connection()->server_supported_versions(), cached,
+ crypto_negotiated_params_, &error_details);
+
+ if (error != QUIC_NO_ERROR) {
+ stream_->CloseConnectionWithDetails(
+ error, "Server hello invalid: " + error_details);
+ return;
+ }
+ error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
+ if (error != QUIC_NO_ERROR) {
+ stream_->CloseConnectionWithDetails(
+ error, "Server hello invalid: " + error_details);
+ return;
+ }
+ session()->OnConfigNegotiated();
+
+ CrypterPair* crypters = &crypto_negotiated_params_->forward_secure_crypters;
+ // TODO(agl): we don't currently latch this decrypter because the idea
+ // has been floated that the server shouldn't send packets encrypted
+ // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
+ // packet from the client.
+ session()->connection()->SetAlternativeDecrypter(
+ ENCRYPTION_FORWARD_SECURE, crypters->decrypter.release(),
+ false /* don't latch */);
+ session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ crypters->encrypter.release());
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
+ session()->connection()->OnHandshakeComplete();
+}
+
+void QuicCryptoClientHandshaker::DoInitializeServerConfigUpdate(
+ QuicCryptoClientConfig::CachedState* cached) {
+ bool update_ignored = false;
+ if (!cached->IsEmpty() && !cached->signature().empty()) {
+ // Note that we verify the proof even if the cached proof is valid.
+ DCHECK(crypto_config_->proof_verifier());
+ next_state_ = STATE_VERIFY_PROOF;
+ } else {
+ update_ignored = true;
+ next_state_ = STATE_NONE;
+ }
+ UMA_HISTOGRAM_COUNTS_1M("Net.QuicNumServerConfig.UpdateMessagesIgnored",
+ update_ignored);
+}
+
+void QuicCryptoClientHandshaker::SetCachedProofValid(
+ QuicCryptoClientConfig::CachedState* cached) {
+ cached->SetProofValid();
+ proof_handler_->OnProofValid(*cached);
+}
+
+bool QuicCryptoClientHandshaker::RequiresChannelID(
+ QuicCryptoClientConfig::CachedState* cached) {
+ if (server_id_.privacy_mode() == PRIVACY_MODE_ENABLED ||
+ !crypto_config_->channel_id_source()) {
+ return false;
+ }
+ const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
+ if (!scfg) { // scfg may be null then we send an inchoate CHLO.
+ return false;
+ }
+ QuicTagVector their_proof_demands;
+ if (scfg->GetTaglist(kPDMD, &their_proof_demands) != QUIC_NO_ERROR) {
+ return false;
+ }
+ for (const QuicTag tag : their_proof_demands) {
+ if (tag == kCHID) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_client_handshaker.h b/chromium/net/quic/core/quic_crypto_client_handshaker.h
new file mode 100644
index 00000000000..ad5e79b4fc5
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_client_handshaker.h
@@ -0,0 +1,240 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CORE_QUIC_CRYPTO_CLIENT_HANDSHAKER_H_
+#define NET_QUIC_CORE_QUIC_CRYPTO_CLIENT_HANDSHAKER_H_
+
+#include "net/quic/core/crypto/channel_id.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/platform/api/quic_export.h"
+
+namespace net {
+
+namespace test {
+class QuicChromiumClientSessionPeer;
+} // namespace test
+
+// An implementation of QuicCryptoClientStream::HandshakerDelegate which uses
+// QUIC crypto as the crypto handshake protocol.
+class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker
+ : public QuicCryptoClientStream::HandshakerDelegate,
+ public QuicCryptoHandshaker {
+ public:
+ QuicCryptoClientHandshaker(
+ const QuicServerId& server_id,
+ QuicCryptoClientStream* stream,
+ QuicSession* session,
+ ProofVerifyContext* verify_context,
+ QuicCryptoClientConfig* crypto_config,
+ QuicCryptoClientStream::ProofHandler* proof_handler);
+
+ ~QuicCryptoClientHandshaker() override;
+
+ // From QuicCryptoClientStream::HandshakerDelegate
+ bool CryptoConnect() override;
+ int num_sent_client_hellos() const override;
+ int num_scup_messages_received() const override;
+ bool WasChannelIDSent() const override;
+ bool WasChannelIDSourceCallbackRun() const override;
+ std::string chlo_hash() const override;
+ bool encryption_established() const override;
+ bool handshake_confirmed() const override;
+ const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
+ const override;
+ CryptoMessageParser* crypto_message_parser() override;
+
+ // From QuicCryptoHandshaker
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
+
+ private:
+ // ChannelIDSourceCallbackImpl is passed as the callback method to
+ // GetChannelIDKey. The ChannelIDSource calls this class with the result of
+ // channel ID lookup when lookup is performed asynchronously.
+ class ChannelIDSourceCallbackImpl : public ChannelIDSourceCallback {
+ public:
+ explicit ChannelIDSourceCallbackImpl(QuicCryptoClientHandshaker* parent);
+ ~ChannelIDSourceCallbackImpl() override;
+
+ // ChannelIDSourceCallback interface.
+ void Run(std::unique_ptr<ChannelIDKey>* channel_id_key) override;
+
+ // Cancel causes any future callbacks to be ignored. It must be called on
+ // the same thread as the callback will be made on.
+ void Cancel();
+
+ private:
+ QuicCryptoClientHandshaker* parent_;
+ };
+
+ // ProofVerifierCallbackImpl is passed as the callback method to VerifyProof.
+ // The ProofVerifier calls this class with the result of proof verification
+ // when verification is performed asynchronously.
+ class ProofVerifierCallbackImpl : public ProofVerifierCallback {
+ public:
+ explicit ProofVerifierCallbackImpl(QuicCryptoClientHandshaker* parent);
+ ~ProofVerifierCallbackImpl() override;
+
+ // ProofVerifierCallback interface.
+ void Run(bool ok,
+ const std::string& error_details,
+ std::unique_ptr<ProofVerifyDetails>* details) override;
+
+ // Cancel causes any future callbacks to be ignored. It must be called on
+ // the same thread as the callback will be made on.
+ void Cancel();
+
+ private:
+ QuicCryptoClientHandshaker* parent_;
+ };
+
+ friend class test::QuicChromiumClientSessionPeer;
+
+ enum State {
+ STATE_IDLE,
+ STATE_INITIALIZE,
+ STATE_SEND_CHLO,
+ STATE_RECV_REJ,
+ STATE_VERIFY_PROOF,
+ STATE_VERIFY_PROOF_COMPLETE,
+ STATE_GET_CHANNEL_ID,
+ STATE_GET_CHANNEL_ID_COMPLETE,
+ STATE_RECV_SHLO,
+ STATE_INITIALIZE_SCUP,
+ STATE_NONE,
+ };
+
+ // Handles new server config and optional source-address token provided by the
+ // server during a connection.
+ void HandleServerConfigUpdateMessage(
+ const CryptoHandshakeMessage& server_config_update);
+
+ // DoHandshakeLoop performs a step of the handshake state machine. Note that
+ // |in| may be nullptr if the call did not result from a received message.
+ void DoHandshakeLoop(const CryptoHandshakeMessage* in);
+
+ // Start the handshake process.
+ void DoInitialize(QuicCryptoClientConfig::CachedState* cached);
+
+ // Send either InchoateClientHello or ClientHello message to the server.
+ void DoSendCHLO(QuicCryptoClientConfig::CachedState* cached);
+
+ // Process REJ message from the server.
+ void DoReceiveREJ(const CryptoHandshakeMessage* in,
+ QuicCryptoClientConfig::CachedState* cached);
+
+ // Start the proof verification process. Returns the QuicAsyncStatus returned
+ // by the ProofVerifier's VerifyProof.
+ QuicAsyncStatus DoVerifyProof(QuicCryptoClientConfig::CachedState* cached);
+
+ // If proof is valid then it sets the proof as valid (which persists the
+ // server config). If not, it closes the connection.
+ void DoVerifyProofComplete(QuicCryptoClientConfig::CachedState* cached);
+
+ // Start the look up of Channel ID process. Returns either QUIC_SUCCESS if
+ // RequiresChannelID returns false or QuicAsyncStatus returned by
+ // GetChannelIDKey.
+ QuicAsyncStatus DoGetChannelID(QuicCryptoClientConfig::CachedState* cached);
+
+ // If there is no channel ID, then close the connection otherwise transtion to
+ // STATE_SEND_CHLO state.
+ void DoGetChannelIDComplete();
+
+ // Process SHLO message from the server.
+ void DoReceiveSHLO(const CryptoHandshakeMessage* in,
+ QuicCryptoClientConfig::CachedState* cached);
+
+ // Start the proof verification if |server_id_| is https and |cached| has
+ // signature.
+ void DoInitializeServerConfigUpdate(
+ QuicCryptoClientConfig::CachedState* cached);
+
+ // Called to set the proof of |cached| valid. Also invokes the session's
+ // OnProofValid() method.
+ void SetCachedProofValid(QuicCryptoClientConfig::CachedState* cached);
+
+ // Returns true if the server crypto config in |cached| requires a ChannelID
+ // and the client config settings also allow sending a ChannelID.
+ bool RequiresChannelID(QuicCryptoClientConfig::CachedState* cached);
+
+ // Returns the QuicSession that this stream belongs to.
+ QuicSession* session() const { return session_; }
+
+ QuicCryptoClientStream* stream_;
+
+ QuicSession* session_;
+
+ State next_state_;
+ // num_client_hellos_ contains the number of client hello messages that this
+ // connection has sent.
+ int num_client_hellos_;
+
+ QuicCryptoClientConfig* const crypto_config_;
+
+ // SHA-256 hash of the most recently sent CHLO.
+ std::string chlo_hash_;
+
+ // Server's (hostname, port, is_https, privacy_mode) tuple.
+ const QuicServerId server_id_;
+
+ // Generation counter from QuicCryptoClientConfig's CachedState.
+ uint64_t generation_counter_;
+
+ // True if a channel ID was sent.
+ bool channel_id_sent_;
+
+ // True if channel_id_source_callback_ was run.
+ bool channel_id_source_callback_run_;
+
+ // channel_id_source_callback_ contains the callback object that we passed
+ // to an asynchronous channel ID lookup. The ChannelIDSource owns this
+ // object.
+ ChannelIDSourceCallbackImpl* channel_id_source_callback_;
+
+ // These members are used to store the result of an asynchronous channel ID
+ // lookup. These members must not be used after
+ // STATE_GET_CHANNEL_ID_COMPLETE.
+ std::unique_ptr<ChannelIDKey> channel_id_key_;
+
+ // verify_context_ contains the context object that we pass to asynchronous
+ // proof verifications.
+ std::unique_ptr<ProofVerifyContext> verify_context_;
+
+ // proof_verify_callback_ contains the callback object that we passed to an
+ // asynchronous proof verification. The ProofVerifier owns this object.
+ ProofVerifierCallbackImpl* proof_verify_callback_;
+ // proof_handler_ contains the callback object used by a quic client
+ // for proof verification. It is not owned by this class.
+ QuicCryptoClientStream::ProofHandler* proof_handler_;
+
+ // These members are used to store the result of an asynchronous proof
+ // verification. These members must not be used after
+ // STATE_VERIFY_PROOF_COMPLETE.
+ bool verify_ok_;
+ std::string verify_error_details_;
+ std::unique_ptr<ProofVerifyDetails> verify_details_;
+
+ // True if the server responded to a previous CHLO with a stateless
+ // reject. Used for book-keeping between the STATE_RECV_REJ,
+ // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state.
+ bool stateless_reject_received_;
+
+ // Only used in chromium, not internally.
+ base::TimeTicks proof_verify_start_time_;
+
+ int num_scup_messages_received_;
+
+ bool encryption_established_;
+ bool handshake_confirmed_;
+ QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters>
+ crypto_negotiated_params_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientHandshaker);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CORE_QUIC_CRYPTO_CLIENT_HANDSHAKER_H_
diff --git a/chromium/net/quic/core/quic_crypto_client_stream.cc b/chromium/net/quic/core/quic_crypto_client_stream.cc
index 251d13019cd..1599716cac8 100644
--- a/chromium/net/quic/core/quic_crypto_client_stream.cc
+++ b/chromium/net/quic/core/quic_crypto_client_stream.cc
@@ -11,6 +11,7 @@
#include "net/quic/core/crypto/crypto_protocol.h"
#include "net/quic/core/crypto/crypto_utils.h"
#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/quic_crypto_client_handshaker.h"
#include "net/quic/core/quic_packets.h"
#include "net/quic/core/quic_session.h"
#include "net/quic/core/quic_utils.h"
@@ -27,61 +28,6 @@ const int QuicCryptoClientStream::kMaxClientHellos;
QuicCryptoClientStreamBase::QuicCryptoClientStreamBase(QuicSession* session)
: QuicCryptoStream(session) {}
-QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::
- ChannelIDSourceCallbackImpl(QuicCryptoClientHandshaker* parent)
- : parent_(parent) {}
-
-QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::
- ~ChannelIDSourceCallbackImpl() {}
-
-void QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::Run(
- std::unique_ptr<ChannelIDKey>* channel_id_key) {
- if (parent_ == nullptr) {
- return;
- }
-
- parent_->channel_id_key_ = std::move(*channel_id_key);
- parent_->channel_id_source_callback_run_ = true;
- parent_->channel_id_source_callback_ = nullptr;
- parent_->DoHandshakeLoop(nullptr);
-
- // The ChannelIDSource owns this object and will delete it when this method
- // returns.
-}
-
-void QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::Cancel() {
- parent_ = nullptr;
-}
-
-QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::
- ProofVerifierCallbackImpl(QuicCryptoClientHandshaker* parent)
- : parent_(parent) {}
-
-QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::
- ~ProofVerifierCallbackImpl() {}
-
-void QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::Run(
- bool ok,
- const string& error_details,
- std::unique_ptr<ProofVerifyDetails>* details) {
- if (parent_ == nullptr) {
- return;
- }
-
- parent_->verify_ok_ = ok;
- parent_->verify_error_details_ = error_details;
- parent_->verify_details_ = std::move(*details);
- parent_->proof_verify_callback_ = nullptr;
- parent_->DoHandshakeLoop(nullptr);
-
- // The ProofVerifier owns this object and will delete it when this method
- // returns.
-}
-
-void QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::Cancel() {
- parent_ = nullptr;
-}
-
QuicCryptoClientStream::QuicCryptoClientStream(
const QuicServerId& server_id,
QuicSession* session,
@@ -137,625 +83,4 @@ string QuicCryptoClientStream::chlo_hash() const {
return handshaker_->chlo_hash();
}
-QuicCryptoClientHandshaker::QuicCryptoClientHandshaker(
- const QuicServerId& server_id,
- QuicCryptoClientStream* stream,
- QuicSession* session,
- ProofVerifyContext* verify_context,
- QuicCryptoClientConfig* crypto_config,
- QuicCryptoClientStream::ProofHandler* proof_handler)
- : QuicCryptoHandshaker(stream, session),
- stream_(stream),
- session_(session),
- next_state_(STATE_IDLE),
- num_client_hellos_(0),
- crypto_config_(crypto_config),
- server_id_(server_id),
- generation_counter_(0),
- channel_id_sent_(false),
- channel_id_source_callback_run_(false),
- channel_id_source_callback_(nullptr),
- verify_context_(verify_context),
- proof_verify_callback_(nullptr),
- proof_handler_(proof_handler),
- verify_ok_(false),
- stateless_reject_received_(false),
- num_scup_messages_received_(0),
- encryption_established_(false),
- handshake_confirmed_(false),
- crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {}
-
-QuicCryptoClientHandshaker::~QuicCryptoClientHandshaker() {
- if (channel_id_source_callback_) {
- channel_id_source_callback_->Cancel();
- }
- if (proof_verify_callback_) {
- proof_verify_callback_->Cancel();
- }
-}
-
-void QuicCryptoClientHandshaker::OnHandshakeMessage(
- const CryptoHandshakeMessage& message) {
- QuicCryptoHandshaker::OnHandshakeMessage(message);
- if (message.tag() == kSCUP) {
- if (!handshake_confirmed()) {
- stream_->CloseConnectionWithDetails(
- QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE,
- "Early SCUP disallowed");
- return;
- }
-
- // |message| is an update from the server, so we treat it differently from a
- // handshake message.
- HandleServerConfigUpdateMessage(message);
- num_scup_messages_received_++;
- return;
- }
-
- // Do not process handshake messages after the handshake is confirmed.
- if (handshake_confirmed()) {
- stream_->CloseConnectionWithDetails(
- QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
- "Unexpected handshake message");
- return;
- }
-
- DoHandshakeLoop(&message);
-}
-
-bool QuicCryptoClientHandshaker::CryptoConnect() {
- next_state_ = STATE_INITIALIZE;
- DoHandshakeLoop(nullptr);
- return session()->connection()->connected();
-}
-
-int QuicCryptoClientHandshaker::num_sent_client_hellos() const {
- return num_client_hellos_;
-}
-
-int QuicCryptoClientHandshaker::num_scup_messages_received() const {
- return num_scup_messages_received_;
-}
-
-bool QuicCryptoClientHandshaker::WasChannelIDSent() const {
- return channel_id_sent_;
-}
-
-bool QuicCryptoClientHandshaker::WasChannelIDSourceCallbackRun() const {
- return channel_id_source_callback_run_;
-}
-
-string QuicCryptoClientHandshaker::chlo_hash() const {
- return chlo_hash_;
-}
-
-bool QuicCryptoClientHandshaker::encryption_established() const {
- return encryption_established_;
-}
-
-bool QuicCryptoClientHandshaker::handshake_confirmed() const {
- return handshake_confirmed_;
-}
-
-const QuicCryptoNegotiatedParameters&
-QuicCryptoClientHandshaker::crypto_negotiated_params() const {
- return *crypto_negotiated_params_;
-}
-
-CryptoMessageParser* QuicCryptoClientHandshaker::crypto_message_parser() {
- return QuicCryptoHandshaker::crypto_message_parser();
-}
-
-void QuicCryptoClientHandshaker::HandleServerConfigUpdateMessage(
- const CryptoHandshakeMessage& server_config_update) {
- DCHECK(server_config_update.tag() == kSCUP);
- string error_details;
- QuicCryptoClientConfig::CachedState* cached =
- crypto_config_->LookupOrCreate(server_id_);
- QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
- server_config_update, session()->connection()->clock()->WallNow(),
- session()->connection()->version(), chlo_hash_, cached,
- crypto_negotiated_params_, &error_details);
-
- if (error != QUIC_NO_ERROR) {
- stream_->CloseConnectionWithDetails(
- error, "Server config update invalid: " + error_details);
- return;
- }
-
- DCHECK(handshake_confirmed());
- if (proof_verify_callback_) {
- proof_verify_callback_->Cancel();
- }
- next_state_ = STATE_INITIALIZE_SCUP;
- DoHandshakeLoop(nullptr);
-}
-
-void QuicCryptoClientHandshaker::DoHandshakeLoop(
- const CryptoHandshakeMessage* in) {
- QuicCryptoClientConfig::CachedState* cached =
- crypto_config_->LookupOrCreate(server_id_);
-
- QuicAsyncStatus rv = QUIC_SUCCESS;
- do {
- CHECK_NE(STATE_NONE, next_state_);
- const State state = next_state_;
- next_state_ = STATE_IDLE;
- rv = QUIC_SUCCESS;
- switch (state) {
- case STATE_INITIALIZE:
- DoInitialize(cached);
- break;
- case STATE_SEND_CHLO:
- DoSendCHLO(cached);
- return; // return waiting to hear from server.
- case STATE_RECV_REJ:
- DoReceiveREJ(in, cached);
- break;
- case STATE_VERIFY_PROOF:
- rv = DoVerifyProof(cached);
- break;
- case STATE_VERIFY_PROOF_COMPLETE:
- DoVerifyProofComplete(cached);
- break;
- case STATE_GET_CHANNEL_ID:
- rv = DoGetChannelID(cached);
- break;
- case STATE_GET_CHANNEL_ID_COMPLETE:
- DoGetChannelIDComplete();
- break;
- case STATE_RECV_SHLO:
- DoReceiveSHLO(in, cached);
- break;
- case STATE_IDLE:
- // This means that the peer sent us a message that we weren't expecting.
- stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
- "Handshake in idle state");
- return;
- case STATE_INITIALIZE_SCUP:
- DoInitializeServerConfigUpdate(cached);
- break;
- case STATE_NONE:
- QUIC_NOTREACHED();
- return; // We are done.
- }
- } while (rv != QUIC_PENDING && next_state_ != STATE_NONE);
-}
-
-void QuicCryptoClientHandshaker::DoInitialize(
- QuicCryptoClientConfig::CachedState* cached) {
- if (!cached->IsEmpty() && !cached->signature().empty()) {
- // Note that we verify the proof even if the cached proof is valid.
- // This allows us to respond to CA trust changes or certificate
- // expiration because it may have been a while since we last verified
- // the proof.
- DCHECK(crypto_config_->proof_verifier());
- // Track proof verification time when cached server config is used.
- proof_verify_start_time_ = base::TimeTicks::Now();
- chlo_hash_ = cached->chlo_hash();
- // If the cached state needs to be verified, do it now.
- next_state_ = STATE_VERIFY_PROOF;
- } else {
- next_state_ = STATE_GET_CHANNEL_ID;
- }
-}
-
-void QuicCryptoClientHandshaker::DoSendCHLO(
- QuicCryptoClientConfig::CachedState* cached) {
- if (stateless_reject_received_) {
- // If we've gotten to this point, we've sent at least one hello
- // and received a stateless reject in response. We cannot
- // continue to send hellos because the server has abandoned state
- // for this connection. Abandon further handshakes.
- next_state_ = STATE_NONE;
- if (session()->connection()->connected()) {
- session()->connection()->CloseConnection(
- QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject received",
- ConnectionCloseBehavior::SILENT_CLOSE);
- }
- return;
- }
-
- // Send the client hello in plaintext.
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
- encryption_established_ = false;
- if (num_client_hellos_ > QuicCryptoClientStream::kMaxClientHellos) {
- stream_->CloseConnectionWithDetails(
- QUIC_CRYPTO_TOO_MANY_REJECTS,
- QuicStrCat("More than ", QuicCryptoClientStream::kMaxClientHellos,
- " rejects"));
- return;
- }
- num_client_hellos_++;
-
- CryptoHandshakeMessage out;
- DCHECK(session() != nullptr);
- DCHECK(session()->config() != nullptr);
- // Send all the options, regardless of whether we're sending an
- // inchoate or subsequent hello.
- session()->config()->ToHandshakeMessage(&out);
-
- // Send a local timestamp to the server.
- out.SetValue(kCTIM,
- session()->connection()->clock()->WallNow().ToUNIXSeconds());
-
- if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
- crypto_config_->FillInchoateClientHello(
- server_id_, session()->connection()->supported_versions().front(),
- cached, session()->connection()->random_generator(),
- /* demand_x509_proof= */ true, crypto_negotiated_params_, &out);
- // Pad the inchoate client hello to fill up a packet.
- const QuicByteCount kFramingOverhead = 50; // A rough estimate.
- const QuicByteCount max_packet_size =
- session()->connection()->max_packet_length();
- if (max_packet_size <= kFramingOverhead) {
- QUIC_DLOG(DFATAL) << "max_packet_length (" << max_packet_size
- << ") has no room for framing overhead.";
- stream_->CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
- "max_packet_size too smalll");
- return;
- }
- if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
- QUIC_DLOG(DFATAL) << "Client hello won't fit in a single packet.";
- stream_->CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
- "CHLO too large");
- return;
- }
- // TODO(rch): Remove this when we remove:
- // FLAGS_quic_reloadable_flag_quic_use_chlo_packet_size
- out.set_minimum_size(
- static_cast<size_t>(max_packet_size - kFramingOverhead));
- next_state_ = STATE_RECV_REJ;
- CryptoUtils::HashHandshakeMessage(out, &chlo_hash_, Perspective::IS_CLIENT);
- SendHandshakeMessage(out);
- return;
- }
-
- // If the server nonce is empty, copy over the server nonce from a previous
- // SREJ, if there is one.
- if (FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support &&
- crypto_negotiated_params_->server_nonce.empty() &&
- cached->has_server_nonce()) {
- crypto_negotiated_params_->server_nonce = cached->GetNextServerNonce();
- DCHECK(!crypto_negotiated_params_->server_nonce.empty());
- }
-
- string error_details;
- QuicErrorCode error = crypto_config_->FillClientHello(
- server_id_, session()->connection()->connection_id(),
- session()->connection()->supported_versions().front(), cached,
- session()->connection()->clock()->WallNow(),
- session()->connection()->random_generator(), channel_id_key_.get(),
- crypto_negotiated_params_, &out, &error_details);
- if (error != QUIC_NO_ERROR) {
- // Flush the cached config so that, if it's bad, the server has a
- // chance to send us another in the future.
- cached->InvalidateServerConfig();
- stream_->CloseConnectionWithDetails(error, error_details);
- return;
- }
- CryptoUtils::HashHandshakeMessage(out, &chlo_hash_, Perspective::IS_CLIENT);
- channel_id_sent_ = (channel_id_key_.get() != nullptr);
- if (cached->proof_verify_details()) {
- proof_handler_->OnProofVerifyDetailsAvailable(
- *cached->proof_verify_details());
- }
- next_state_ = STATE_RECV_SHLO;
- SendHandshakeMessage(out);
- // Be prepared to decrypt with the new server write key.
- session()->connection()->SetAlternativeDecrypter(
- ENCRYPTION_INITIAL,
- crypto_negotiated_params_->initial_crypters.decrypter.release(),
- true /* latch once used */);
- // Send subsequent packets under encryption on the assumption that the
- // server will accept the handshake.
- session()->connection()->SetEncrypter(
- ENCRYPTION_INITIAL,
- crypto_negotiated_params_->initial_crypters.encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
-
- // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and
- // ENCRYPTION_FIRST_ESTABLSIHED
- encryption_established_ = true;
- session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED);
-}
-
-void QuicCryptoClientHandshaker::DoReceiveREJ(
- const CryptoHandshakeMessage* in,
- QuicCryptoClientConfig::CachedState* cached) {
- // We sent a dummy CHLO because we didn't have enough information to
- // perform a handshake, or we sent a full hello that the server
- // rejected. Here we hope to have a REJ that contains the information
- // that we need.
- if ((in->tag() != kREJ) && (in->tag() != kSREJ)) {
- next_state_ = STATE_NONE;
- stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
- "Expected REJ");
- return;
- }
-
- QuicTagVector reject_reasons;
- static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
- if (in->GetTaglist(kRREJ, &reject_reasons) == QUIC_NO_ERROR) {
- uint32_t packed_error = 0;
- for (size_t i = 0; i < reject_reasons.size(); ++i) {
- // HANDSHAKE_OK is 0 and don't report that as error.
- if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
- continue;
- }
- HandshakeFailureReason reason =
- static_cast<HandshakeFailureReason>(reject_reasons[i]);
- packed_error |= 1 << (reason - 1);
- }
- DVLOG(1) << "Reasons for rejection: " << packed_error;
- if (num_client_hellos_ == QuicCryptoClientStream::kMaxClientHellos) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.TooMany",
- packed_error);
- }
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
- packed_error);
- }
-
- // Receipt of a REJ message means that the server received the CHLO
- // so we can cancel and retransmissions.
- session()->connection()->NeuterUnencryptedPackets();
-
- stateless_reject_received_ = in->tag() == kSREJ;
- string error_details;
- QuicErrorCode error = crypto_config_->ProcessRejection(
- *in, session()->connection()->clock()->WallNow(),
- session()->connection()->version(), chlo_hash_, cached,
- crypto_negotiated_params_, &error_details);
-
- if (error != QUIC_NO_ERROR) {
- next_state_ = STATE_NONE;
- stream_->CloseConnectionWithDetails(error, error_details);
- return;
- }
- if (!cached->proof_valid()) {
- if (!cached->signature().empty()) {
- // Note that we only verify the proof if the cached proof is not
- // valid. If the cached proof is valid here, someone else must have
- // just added the server config to the cache and verified the proof,
- // so we can assume no CA trust changes or certificate expiration
- // has happened since then.
- next_state_ = STATE_VERIFY_PROOF;
- return;
- }
- }
- next_state_ = STATE_GET_CHANNEL_ID;
-}
-
-QuicAsyncStatus QuicCryptoClientHandshaker::DoVerifyProof(
- QuicCryptoClientConfig::CachedState* cached) {
- ProofVerifier* verifier = crypto_config_->proof_verifier();
- DCHECK(verifier);
- next_state_ = STATE_VERIFY_PROOF_COMPLETE;
- generation_counter_ = cached->generation_counter();
-
- ProofVerifierCallbackImpl* proof_verify_callback =
- new ProofVerifierCallbackImpl(this);
-
- verify_ok_ = false;
-
- QuicAsyncStatus status = verifier->VerifyProof(
- server_id_.host(), server_id_.port(), cached->server_config(),
- session()->connection()->version(), chlo_hash_, cached->certs(),
- cached->cert_sct(), cached->signature(), verify_context_.get(),
- &verify_error_details_, &verify_details_,
- std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
-
- switch (status) {
- case QUIC_PENDING:
- proof_verify_callback_ = proof_verify_callback;
- QUIC_DVLOG(1) << "Doing VerifyProof";
- break;
- case QUIC_FAILURE:
- break;
- case QUIC_SUCCESS:
- verify_ok_ = true;
- break;
- }
- return status;
-}
-
-void QuicCryptoClientHandshaker::DoVerifyProofComplete(
- QuicCryptoClientConfig::CachedState* cached) {
- if (!proof_verify_start_time_.is_null()) {
- UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.CachedServerConfig",
- base::TimeTicks::Now() - proof_verify_start_time_);
- }
- if (!verify_ok_) {
- if (verify_details_.get()) {
- proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_);
- }
- if (num_client_hellos_ == 0) {
- cached->Clear();
- next_state_ = STATE_INITIALIZE;
- return;
- }
- next_state_ = STATE_NONE;
- UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
- handshake_confirmed());
- stream_->CloseConnectionWithDetails(
- QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
- return;
- }
-
- // Check if generation_counter has changed between STATE_VERIFY_PROOF and
- // STATE_VERIFY_PROOF_COMPLETE state changes.
- if (generation_counter_ != cached->generation_counter()) {
- next_state_ = STATE_VERIFY_PROOF;
- } else {
- SetCachedProofValid(cached);
- cached->SetProofVerifyDetails(verify_details_.release());
- if (!handshake_confirmed()) {
- next_state_ = STATE_GET_CHANNEL_ID;
- } else {
- // TODO: Enable Expect-Staple. https://crbug.com/631101
- next_state_ = STATE_NONE;
- }
- }
-}
-
-QuicAsyncStatus QuicCryptoClientHandshaker::DoGetChannelID(
- QuicCryptoClientConfig::CachedState* cached) {
- next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
- channel_id_key_.reset();
- if (!RequiresChannelID(cached)) {
- next_state_ = STATE_SEND_CHLO;
- return QUIC_SUCCESS;
- }
-
- ChannelIDSourceCallbackImpl* channel_id_source_callback =
- new ChannelIDSourceCallbackImpl(this);
- QuicAsyncStatus status = crypto_config_->channel_id_source()->GetChannelIDKey(
- server_id_.host(), &channel_id_key_, channel_id_source_callback);
-
- switch (status) {
- case QUIC_PENDING:
- channel_id_source_callback_ = channel_id_source_callback;
- QUIC_DVLOG(1) << "Looking up channel ID";
- break;
- case QUIC_FAILURE:
- next_state_ = STATE_NONE;
- delete channel_id_source_callback;
- stream_->CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
- "Channel ID lookup failed");
- break;
- case QUIC_SUCCESS:
- delete channel_id_source_callback;
- break;
- }
- return status;
-}
-
-void QuicCryptoClientHandshaker::DoGetChannelIDComplete() {
- if (!channel_id_key_.get()) {
- next_state_ = STATE_NONE;
- stream_->CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
- "Channel ID lookup failed");
- return;
- }
- next_state_ = STATE_SEND_CHLO;
-}
-
-void QuicCryptoClientHandshaker::DoReceiveSHLO(
- const CryptoHandshakeMessage* in,
- QuicCryptoClientConfig::CachedState* cached) {
- next_state_ = STATE_NONE;
- // We sent a CHLO that we expected to be accepted and now we're
- // hoping for a SHLO from the server to confirm that. First check
- // to see whether the response was a reject, and if so, move on to
- // the reject-processing state.
- if ((in->tag() == kREJ) || (in->tag() == kSREJ)) {
- // alternative_decrypter will be nullptr if the original alternative
- // decrypter latched and became the primary decrypter. That happens
- // if we received a message encrypted with the INITIAL key.
- if (session()->connection()->alternative_decrypter() == nullptr) {
- // The rejection was sent encrypted!
- stream_->CloseConnectionWithDetails(
- QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, "encrypted REJ message");
- return;
- }
- next_state_ = STATE_RECV_REJ;
- return;
- }
-
- if (in->tag() != kSHLO) {
- stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
- "Expected SHLO or REJ");
- return;
- }
-
- // alternative_decrypter will be nullptr if the original alternative
- // decrypter latched and became the primary decrypter. That happens
- // if we received a message encrypted with the INITIAL key.
- if (session()->connection()->alternative_decrypter() != nullptr) {
- // The server hello was sent without encryption.
- stream_->CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
- "unencrypted SHLO message");
- return;
- }
-
- string error_details;
- QuicErrorCode error = crypto_config_->ProcessServerHello(
- *in, session()->connection()->connection_id(),
- session()->connection()->version(),
- session()->connection()->server_supported_versions(), cached,
- crypto_negotiated_params_, &error_details);
-
- if (error != QUIC_NO_ERROR) {
- stream_->CloseConnectionWithDetails(
- error, "Server hello invalid: " + error_details);
- return;
- }
- error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
- if (error != QUIC_NO_ERROR) {
- stream_->CloseConnectionWithDetails(
- error, "Server hello invalid: " + error_details);
- return;
- }
- session()->OnConfigNegotiated();
-
- CrypterPair* crypters = &crypto_negotiated_params_->forward_secure_crypters;
- // TODO(agl): we don't currently latch this decrypter because the idea
- // has been floated that the server shouldn't send packets encrypted
- // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
- // packet from the client.
- session()->connection()->SetAlternativeDecrypter(
- ENCRYPTION_FORWARD_SECURE, crypters->decrypter.release(),
- false /* don't latch */);
- session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
- crypters->encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
-
- handshake_confirmed_ = true;
- session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
- session()->connection()->OnHandshakeComplete();
-}
-
-void QuicCryptoClientHandshaker::DoInitializeServerConfigUpdate(
- QuicCryptoClientConfig::CachedState* cached) {
- bool update_ignored = false;
- if (!cached->IsEmpty() && !cached->signature().empty()) {
- // Note that we verify the proof even if the cached proof is valid.
- DCHECK(crypto_config_->proof_verifier());
- next_state_ = STATE_VERIFY_PROOF;
- } else {
- update_ignored = true;
- next_state_ = STATE_NONE;
- }
- UMA_HISTOGRAM_COUNTS_1M("Net.QuicNumServerConfig.UpdateMessagesIgnored",
- update_ignored);
-}
-
-void QuicCryptoClientHandshaker::SetCachedProofValid(
- QuicCryptoClientConfig::CachedState* cached) {
- cached->SetProofValid();
- proof_handler_->OnProofValid(*cached);
-}
-
-bool QuicCryptoClientHandshaker::RequiresChannelID(
- QuicCryptoClientConfig::CachedState* cached) {
- if (server_id_.privacy_mode() == PRIVACY_MODE_ENABLED ||
- !crypto_config_->channel_id_source()) {
- return false;
- }
- const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
- if (!scfg) { // scfg may be null then we send an inchoate CHLO.
- return false;
- }
- QuicTagVector their_proof_demands;
- if (scfg->GetTaglist(kPDMD, &their_proof_demands) != QUIC_NO_ERROR) {
- return false;
- }
- for (const QuicTag tag : their_proof_demands) {
- if (tag == kCHID) {
- return true;
- }
- }
- return false;
-}
-
} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_client_stream.h b/chromium/net/quic/core/quic_crypto_client_stream.h
index ecb06e05c51..af47c9b3f76 100644
--- a/chromium/net/quic/core/quic_crypto_client_stream.h
+++ b/chromium/net/quic/core/quic_crypto_client_stream.h
@@ -14,16 +14,13 @@
#include "net/quic/core/crypto/proof_verifier.h"
#include "net/quic/core/crypto/quic_crypto_client_config.h"
#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_crypto_handshaker.h"
#include "net/quic/core/quic_crypto_stream.h"
#include "net/quic/core/quic_server_id.h"
#include "net/quic/platform/api/quic_export.h"
namespace net {
-namespace test {
-class QuicChromiumClientSessionPeer;
-} // namespace test
-
class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream {
public:
explicit QuicCryptoClientStreamBase(QuicSession* session);
@@ -163,223 +160,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream);
};
-// An implementation of QuicCryptoClientStream::HandshakerDelegate which uses
-// QUIC crypto as the crypto handshake protocol.
-class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker
- : public QuicCryptoClientStream::HandshakerDelegate,
- public QuicCryptoHandshaker {
- public:
- QuicCryptoClientHandshaker(
- const QuicServerId& server_id,
- QuicCryptoClientStream* stream,
- QuicSession* session,
- ProofVerifyContext* verify_context,
- QuicCryptoClientConfig* crypto_config,
- QuicCryptoClientStream::ProofHandler* proof_handler);
-
- ~QuicCryptoClientHandshaker() override;
-
- // From QuicCryptoClientStream::HandshakerDelegate
- bool CryptoConnect() override;
- int num_sent_client_hellos() const override;
- int num_scup_messages_received() const override;
- bool WasChannelIDSent() const override;
- bool WasChannelIDSourceCallbackRun() const override;
- std::string chlo_hash() const override;
- bool encryption_established() const override;
- bool handshake_confirmed() const override;
- const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
- const override;
- CryptoMessageParser* crypto_message_parser() override;
-
- // From QuicCryptoHandshaker
- void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
-
- private:
- // ChannelIDSourceCallbackImpl is passed as the callback method to
- // GetChannelIDKey. The ChannelIDSource calls this class with the result of
- // channel ID lookup when lookup is performed asynchronously.
- class ChannelIDSourceCallbackImpl : public ChannelIDSourceCallback {
- public:
- explicit ChannelIDSourceCallbackImpl(QuicCryptoClientHandshaker* parent);
- ~ChannelIDSourceCallbackImpl() override;
-
- // ChannelIDSourceCallback interface.
- void Run(std::unique_ptr<ChannelIDKey>* channel_id_key) override;
-
- // Cancel causes any future callbacks to be ignored. It must be called on
- // the same thread as the callback will be made on.
- void Cancel();
-
- private:
- QuicCryptoClientHandshaker* parent_;
- };
-
- // ProofVerifierCallbackImpl is passed as the callback method to VerifyProof.
- // The ProofVerifier calls this class with the result of proof verification
- // when verification is performed asynchronously.
- class ProofVerifierCallbackImpl : public ProofVerifierCallback {
- public:
- explicit ProofVerifierCallbackImpl(QuicCryptoClientHandshaker* parent);
- ~ProofVerifierCallbackImpl() override;
-
- // ProofVerifierCallback interface.
- void Run(bool ok,
- const std::string& error_details,
- std::unique_ptr<ProofVerifyDetails>* details) override;
-
- // Cancel causes any future callbacks to be ignored. It must be called on
- // the same thread as the callback will be made on.
- void Cancel();
-
- private:
- QuicCryptoClientHandshaker* parent_;
- };
-
- friend class test::QuicChromiumClientSessionPeer;
-
- enum State {
- STATE_IDLE,
- STATE_INITIALIZE,
- STATE_SEND_CHLO,
- STATE_RECV_REJ,
- STATE_VERIFY_PROOF,
- STATE_VERIFY_PROOF_COMPLETE,
- STATE_GET_CHANNEL_ID,
- STATE_GET_CHANNEL_ID_COMPLETE,
- STATE_RECV_SHLO,
- STATE_INITIALIZE_SCUP,
- STATE_NONE,
- };
-
- // Handles new server config and optional source-address token provided by the
- // server during a connection.
- void HandleServerConfigUpdateMessage(
- const CryptoHandshakeMessage& server_config_update);
-
- // DoHandshakeLoop performs a step of the handshake state machine. Note that
- // |in| may be nullptr if the call did not result from a received message.
- void DoHandshakeLoop(const CryptoHandshakeMessage* in);
-
- // Start the handshake process.
- void DoInitialize(QuicCryptoClientConfig::CachedState* cached);
-
- // Send either InchoateClientHello or ClientHello message to the server.
- void DoSendCHLO(QuicCryptoClientConfig::CachedState* cached);
-
- // Process REJ message from the server.
- void DoReceiveREJ(const CryptoHandshakeMessage* in,
- QuicCryptoClientConfig::CachedState* cached);
-
- // Start the proof verification process. Returns the QuicAsyncStatus returned
- // by the ProofVerifier's VerifyProof.
- QuicAsyncStatus DoVerifyProof(QuicCryptoClientConfig::CachedState* cached);
-
- // If proof is valid then it sets the proof as valid (which persists the
- // server config). If not, it closes the connection.
- void DoVerifyProofComplete(QuicCryptoClientConfig::CachedState* cached);
-
- // Start the look up of Channel ID process. Returns either QUIC_SUCCESS if
- // RequiresChannelID returns false or QuicAsyncStatus returned by
- // GetChannelIDKey.
- QuicAsyncStatus DoGetChannelID(QuicCryptoClientConfig::CachedState* cached);
-
- // If there is no channel ID, then close the connection otherwise transtion to
- // STATE_SEND_CHLO state.
- void DoGetChannelIDComplete();
-
- // Process SHLO message from the server.
- void DoReceiveSHLO(const CryptoHandshakeMessage* in,
- QuicCryptoClientConfig::CachedState* cached);
-
- // Start the proof verification if |server_id_| is https and |cached| has
- // signature.
- void DoInitializeServerConfigUpdate(
- QuicCryptoClientConfig::CachedState* cached);
-
- // Called to set the proof of |cached| valid. Also invokes the session's
- // OnProofValid() method.
- void SetCachedProofValid(QuicCryptoClientConfig::CachedState* cached);
-
- // Returns true if the server crypto config in |cached| requires a ChannelID
- // and the client config settings also allow sending a ChannelID.
- bool RequiresChannelID(QuicCryptoClientConfig::CachedState* cached);
-
- // Returns the QuicSession that this stream belongs to.
- QuicSession* session() const { return session_; }
-
- QuicCryptoClientStream* stream_;
-
- QuicSession* session_;
-
- State next_state_;
- // num_client_hellos_ contains the number of client hello messages that this
- // connection has sent.
- int num_client_hellos_;
-
- QuicCryptoClientConfig* const crypto_config_;
-
- // SHA-256 hash of the most recently sent CHLO.
- std::string chlo_hash_;
-
- // Server's (hostname, port, is_https, privacy_mode) tuple.
- const QuicServerId server_id_;
-
- // Generation counter from QuicCryptoClientConfig's CachedState.
- uint64_t generation_counter_;
-
- // True if a channel ID was sent.
- bool channel_id_sent_;
-
- // True if channel_id_source_callback_ was run.
- bool channel_id_source_callback_run_;
-
- // channel_id_source_callback_ contains the callback object that we passed
- // to an asynchronous channel ID lookup. The ChannelIDSource owns this
- // object.
- ChannelIDSourceCallbackImpl* channel_id_source_callback_;
-
- // These members are used to store the result of an asynchronous channel ID
- // lookup. These members must not be used after
- // STATE_GET_CHANNEL_ID_COMPLETE.
- std::unique_ptr<ChannelIDKey> channel_id_key_;
-
- // verify_context_ contains the context object that we pass to asynchronous
- // proof verifications.
- std::unique_ptr<ProofVerifyContext> verify_context_;
-
- // proof_verify_callback_ contains the callback object that we passed to an
- // asynchronous proof verification. The ProofVerifier owns this object.
- ProofVerifierCallbackImpl* proof_verify_callback_;
- // proof_handler_ contains the callback object used by a quic client
- // for proof verification. It is not owned by this class.
- QuicCryptoClientStream::ProofHandler* proof_handler_;
-
- // These members are used to store the result of an asynchronous proof
- // verification. These members must not be used after
- // STATE_VERIFY_PROOF_COMPLETE.
- bool verify_ok_;
- std::string verify_error_details_;
- std::unique_ptr<ProofVerifyDetails> verify_details_;
-
- // True if the server responded to a previous CHLO with a stateless
- // reject. Used for book-keeping between the STATE_RECV_REJ,
- // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state.
- bool stateless_reject_received_;
-
- // Only used in chromium, not internally.
- base::TimeTicks proof_verify_start_time_;
-
- int num_scup_messages_received_;
-
- bool encryption_established_;
- bool handshake_confirmed_;
- QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters>
- crypto_negotiated_params_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientHandshaker);
-};
-
} // namespace net
#endif // NET_QUIC_CORE_QUIC_CRYPTO_CLIENT_STREAM_H_
diff --git a/chromium/net/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/quic/core/quic_crypto_client_stream_test.cc
index 2453761d4b7..0c04daa2283 100644
--- a/chromium/net/quic/core/quic_crypto_client_stream_test.cc
+++ b/chromium/net/quic/core/quic_crypto_client_stream_test.cc
@@ -225,8 +225,7 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
reinterpret_cast<char*>(scfg), arraysize(scfg));
QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(stream());
- EXPECT_NE(FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer,
- QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+ EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
}
TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) {
diff --git a/chromium/net/quic/core/quic_crypto_handshaker.cc b/chromium/net/quic/core/quic_crypto_handshaker.cc
new file mode 100644
index 00000000000..39a9a4e9c9b
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_handshaker.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_crypto_handshaker.h"
+
+#include "net/quic/core/quic_session.h"
+
+namespace net {
+
+#define ENDPOINT \
+ (session()->perspective() == Perspective::IS_SERVER ? "Server: " \
+ : "Client:" \
+ " ")
+
+QuicCryptoHandshaker::QuicCryptoHandshaker(QuicCryptoStream* stream,
+ QuicSession* session)
+ : stream_(stream), session_(session) {
+ crypto_framer_.set_visitor(this);
+}
+
+QuicCryptoHandshaker::~QuicCryptoHandshaker() {}
+
+void QuicCryptoHandshaker::SendHandshakeMessage(
+ const CryptoHandshakeMessage& message) {
+ QUIC_DVLOG(1) << ENDPOINT << "Sending "
+ << message.DebugString(session()->perspective());
+ session()->connection()->NeuterUnencryptedPackets();
+ session()->OnCryptoHandshakeMessageSent(message);
+ const QuicData& data = message.GetSerialized(session()->perspective());
+ stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false,
+ nullptr);
+}
+
+void QuicCryptoHandshaker::OnError(CryptoFramer* framer) {
+ QUIC_DLOG(WARNING) << "Error processing crypto data: "
+ << QuicErrorCodeToString(framer->error());
+}
+
+void QuicCryptoHandshaker::OnHandshakeMessage(
+ const CryptoHandshakeMessage& message) {
+ QUIC_DVLOG(1) << ENDPOINT << "Received "
+ << message.DebugString(session()->perspective());
+ session()->OnCryptoHandshakeMessageReceived(message);
+}
+
+CryptoMessageParser* QuicCryptoHandshaker::crypto_message_parser() {
+ return &crypto_framer_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_handshaker.h b/chromium/net/quic/core/quic_crypto_handshaker.h
new file mode 100644
index 00000000000..76deb37f7c7
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_handshaker.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CORE_QUIC_CRYPTO_HANDSHAKER_H_
+#define NET_QUIC_CORE_QUIC_CRYPTO_HANDSHAKER_H_
+
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/platform/api/quic_export.h"
+
+namespace net {
+
+class QUIC_EXPORT_PRIVATE QuicCryptoHandshaker
+ : public CryptoFramerVisitorInterface {
+ public:
+ QuicCryptoHandshaker(QuicCryptoStream* stream, QuicSession* session);
+
+ ~QuicCryptoHandshaker() override;
+
+ // Sends |message| to the peer.
+ // TODO(wtc): return a success/failure status.
+ void SendHandshakeMessage(const CryptoHandshakeMessage& message);
+
+ void OnError(CryptoFramer* framer) override;
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
+
+ CryptoMessageParser* crypto_message_parser();
+
+ private:
+ QuicSession* session() { return session_; }
+
+ QuicCryptoStream* stream_;
+ QuicSession* session_;
+
+ CryptoFramer crypto_framer_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoHandshaker);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CORE_QUIC_CRYPTO_HANDSHAKER_H_
diff --git a/chromium/net/quic/core/quic_crypto_server_handshaker.cc b/chromium/net/quic/core/quic_crypto_server_handshaker.cc
new file mode 100644
index 00000000000..d5102ce9a73
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_server_handshaker.cc
@@ -0,0 +1,482 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_crypto_server_handshaker.h"
+
+#include <memory>
+
+#include "net/quic/platform/api/quic_text_utils.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
+
+using std::string;
+
+namespace net {
+
+class QuicCryptoServerHandshaker::ProcessClientHelloCallback
+ : public ProcessClientHelloResultCallback {
+ public:
+ ProcessClientHelloCallback(
+ QuicCryptoServerHandshaker* parent,
+ const QuicReferenceCountedPointer<
+ ValidateClientHelloResultCallback::Result>& result)
+ : parent_(parent), result_(result) {}
+
+ void Run(QuicErrorCode error,
+ const string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce,
+ std::unique_ptr<net::ProofSource::Details> proof_source_details)
+ override {
+ if (parent_ == nullptr) {
+ return;
+ }
+
+ parent_->FinishProcessingHandshakeMessageAfterProcessClientHello(
+ *result_, error, error_details, std::move(message),
+ std::move(diversification_nonce), std::move(proof_source_details));
+ }
+
+ void Cancel() { parent_ = nullptr; }
+
+ private:
+ QuicCryptoServerHandshaker* parent_;
+ QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+ result_;
+};
+
+QuicCryptoServerHandshaker::QuicCryptoServerHandshaker(
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCryptoServerStream* stream,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ bool use_stateless_rejects_if_peer_supported,
+ QuicSession* session,
+ QuicCryptoServerStream::Helper* helper)
+ : QuicCryptoHandshaker(stream, session),
+ stream_(stream),
+ session_(session),
+ crypto_config_(crypto_config),
+ compressed_certs_cache_(compressed_certs_cache),
+ signed_config_(new QuicSignedServerConfig),
+ helper_(helper),
+ num_handshake_messages_(0),
+ num_handshake_messages_with_server_nonces_(0),
+ send_server_config_update_cb_(nullptr),
+ num_server_config_update_messages_sent_(0),
+ use_stateless_rejects_if_peer_supported_(
+ use_stateless_rejects_if_peer_supported),
+ peer_supports_stateless_rejects_(false),
+ zero_rtt_attempted_(false),
+ chlo_packet_size_(0),
+ validate_client_hello_cb_(nullptr),
+ process_client_hello_cb_(nullptr),
+ encryption_established_(false),
+ handshake_confirmed_(false),
+ crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {}
+
+QuicCryptoServerHandshaker::~QuicCryptoServerHandshaker() {
+ CancelOutstandingCallbacks();
+}
+
+void QuicCryptoServerHandshaker::CancelOutstandingCallbacks() {
+ // Detach from the validation callback. Calling this multiple times is safe.
+ if (validate_client_hello_cb_ != nullptr) {
+ validate_client_hello_cb_->Cancel();
+ validate_client_hello_cb_ = nullptr;
+ }
+ if (send_server_config_update_cb_ != nullptr) {
+ send_server_config_update_cb_->Cancel();
+ send_server_config_update_cb_ = nullptr;
+ }
+ if (process_client_hello_cb_ != nullptr) {
+ process_client_hello_cb_->Cancel();
+ process_client_hello_cb_ = nullptr;
+ }
+}
+
+void QuicCryptoServerHandshaker::OnHandshakeMessage(
+ const CryptoHandshakeMessage& message) {
+ QuicCryptoHandshaker::OnHandshakeMessage(message);
+ ++num_handshake_messages_;
+ chlo_packet_size_ = session()->connection()->GetCurrentPacket().length();
+
+ // Do not process handshake messages after the handshake is confirmed.
+ if (handshake_confirmed_) {
+ stream_->CloseConnectionWithDetails(
+ QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
+ "Unexpected handshake message from client");
+ return;
+ }
+
+ if (message.tag() != kCHLO) {
+ stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+ "Handshake packet not CHLO");
+ return;
+ }
+
+ if (validate_client_hello_cb_ != nullptr ||
+ process_client_hello_cb_ != nullptr) {
+ // Already processing some other handshake message. The protocol
+ // does not allow for clients to send multiple handshake messages
+ // before the server has a chance to respond.
+ stream_->CloseConnectionWithDetails(
+ QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
+ "Unexpected handshake message while processing CHLO");
+ return;
+ }
+
+ CryptoUtils::HashHandshakeMessage(message, &chlo_hash_,
+ Perspective::IS_SERVER);
+
+ std::unique_ptr<ValidateCallback> cb(new ValidateCallback(this));
+ DCHECK(validate_client_hello_cb_ == nullptr);
+ DCHECK(process_client_hello_cb_ == nullptr);
+ validate_client_hello_cb_ = cb.get();
+ crypto_config_->ValidateClientHello(
+ message, GetClientAddress().host(),
+ session()->connection()->self_address(), version(),
+ session()->connection()->clock(), signed_config_, std::move(cb));
+}
+
+void QuicCryptoServerHandshaker::FinishProcessingHandshakeMessage(
+ QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+ result,
+ std::unique_ptr<ProofSource::Details> details) {
+ const CryptoHandshakeMessage& message = result->client_hello;
+
+ // Clear the callback that got us here.
+ DCHECK(validate_client_hello_cb_ != nullptr);
+ DCHECK(process_client_hello_cb_ == nullptr);
+ validate_client_hello_cb_ = nullptr;
+
+ if (use_stateless_rejects_if_peer_supported_) {
+ peer_supports_stateless_rejects_ =
+ QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects(message);
+ }
+
+ std::unique_ptr<ProcessClientHelloCallback> cb(
+ new ProcessClientHelloCallback(this, result));
+ process_client_hello_cb_ = cb.get();
+ ProcessClientHello(result, std::move(details), std::move(cb));
+}
+
+void QuicCryptoServerHandshaker::
+ FinishProcessingHandshakeMessageAfterProcessClientHello(
+ const ValidateClientHelloResultCallback::Result& result,
+ QuicErrorCode error,
+ const string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> reply,
+ std::unique_ptr<DiversificationNonce> diversification_nonce,
+ std::unique_ptr<ProofSource::Details> proof_source_details) {
+ // Clear the callback that got us here.
+ DCHECK(process_client_hello_cb_ != nullptr);
+ DCHECK(validate_client_hello_cb_ == nullptr);
+ process_client_hello_cb_ = nullptr;
+
+ const CryptoHandshakeMessage& message = result.client_hello;
+ if (error != QUIC_NO_ERROR) {
+ stream_->CloseConnectionWithDetails(error, error_details);
+ return;
+ }
+
+ if (reply->tag() != kSHLO) {
+ if (reply->tag() == kSREJ) {
+ DCHECK(use_stateless_rejects_if_peer_supported_);
+ DCHECK(peer_supports_stateless_rejects_);
+ // Before sending the SREJ, cause the connection to save crypto packets
+ // so that they can be added to the time wait list manager and
+ // retransmitted.
+ session()->connection()->EnableSavingCryptoPackets();
+ }
+ SendHandshakeMessage(*reply);
+
+ if (reply->tag() == kSREJ) {
+ DCHECK(use_stateless_rejects_if_peer_supported_);
+ DCHECK(peer_supports_stateless_rejects_);
+ DCHECK(!handshake_confirmed());
+ QUIC_DLOG(INFO) << "Closing connection "
+ << session()->connection()->connection_id()
+ << " because of a stateless reject.";
+ session()->connection()->CloseConnection(
+ QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ }
+ return;
+ }
+
+ // If we are returning a SHLO then we accepted the handshake. Now
+ // process the negotiated configuration options as part of the
+ // session config.
+ QuicConfig* config = session()->config();
+ OverrideQuicConfigDefaults(config);
+ string process_error_details;
+ const QuicErrorCode process_error =
+ config->ProcessPeerHello(message, CLIENT, &process_error_details);
+ if (process_error != QUIC_NO_ERROR) {
+ stream_->CloseConnectionWithDetails(process_error, process_error_details);
+ return;
+ }
+
+ session()->OnConfigNegotiated();
+
+ config->ToHandshakeMessage(reply.get());
+
+ // Receiving a full CHLO implies the client is prepared to decrypt with
+ // the new server write key. We can start to encrypt with the new server
+ // write key.
+ //
+ // NOTE: the SHLO will be encrypted with the new server write key.
+ session()->connection()->SetEncrypter(
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_->initial_crypters.encrypter.release());
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ // Set the decrypter immediately so that we no longer accept unencrypted
+ // packets.
+ session()->connection()->SetDecrypter(
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_->initial_crypters.decrypter.release());
+ session()->connection()->SetDiversificationNonce(*diversification_nonce);
+
+ SendHandshakeMessage(*reply);
+
+ session()->connection()->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ crypto_negotiated_params_->forward_secure_crypters.encrypter.release());
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ session()->connection()->SetAlternativeDecrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ crypto_negotiated_params_->forward_secure_crypters.decrypter.release(),
+ false /* don't latch */);
+
+ encryption_established_ = true;
+ handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
+}
+
+void QuicCryptoServerHandshaker::SendServerConfigUpdate(
+ const CachedNetworkParameters* cached_network_params) {
+ if (!handshake_confirmed_) {
+ return;
+ }
+
+ if (send_server_config_update_cb_ != nullptr) {
+ QUIC_DVLOG(1)
+ << "Skipped server config update since one is already in progress";
+ return;
+ }
+
+ std::unique_ptr<SendServerConfigUpdateCallback> cb(
+ new SendServerConfigUpdateCallback(this));
+ send_server_config_update_cb_ = cb.get();
+
+ crypto_config_->BuildServerConfigUpdateMessage(
+ session()->connection()->version(), chlo_hash_,
+ previous_source_address_tokens_, session()->connection()->self_address(),
+ GetClientAddress().host(), session()->connection()->clock(),
+ session()->connection()->random_generator(), compressed_certs_cache_,
+ *crypto_negotiated_params_, cached_network_params,
+ (session()->config()->HasReceivedConnectionOptions()
+ ? session()->config()->ReceivedConnectionOptions()
+ : QuicTagVector()),
+ std::move(cb));
+}
+
+QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::
+ SendServerConfigUpdateCallback(QuicCryptoServerHandshaker* parent)
+ : parent_(parent) {}
+
+void QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::Cancel() {
+ parent_ = nullptr;
+}
+
+// From BuildServerConfigUpdateMessageResultCallback
+void QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::Run(
+ bool ok,
+ const CryptoHandshakeMessage& message) {
+ if (parent_ == nullptr) {
+ return;
+ }
+ parent_->FinishSendServerConfigUpdate(ok, message);
+}
+
+void QuicCryptoServerHandshaker::FinishSendServerConfigUpdate(
+ bool ok,
+ const CryptoHandshakeMessage& message) {
+ // Clear the callback that got us here.
+ DCHECK(send_server_config_update_cb_ != nullptr);
+ send_server_config_update_cb_ = nullptr;
+
+ if (!ok) {
+ QUIC_DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
+ return;
+ }
+
+ QUIC_DVLOG(1) << "Server: Sending server config update: "
+ << message.DebugString(Perspective::IS_SERVER);
+ const QuicData& data = message.GetSerialized(Perspective::IS_SERVER);
+ stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false,
+ nullptr);
+
+ ++num_server_config_update_messages_sent_;
+}
+
+uint8_t QuicCryptoServerHandshaker::NumHandshakeMessages() const {
+ return num_handshake_messages_;
+}
+
+uint8_t QuicCryptoServerHandshaker::NumHandshakeMessagesWithServerNonces()
+ const {
+ return num_handshake_messages_with_server_nonces_;
+}
+
+int QuicCryptoServerHandshaker::NumServerConfigUpdateMessagesSent() const {
+ return num_server_config_update_messages_sent_;
+}
+
+const CachedNetworkParameters*
+QuicCryptoServerHandshaker::PreviousCachedNetworkParams() const {
+ return previous_cached_network_params_.get();
+}
+
+bool QuicCryptoServerHandshaker::UseStatelessRejectsIfPeerSupported() const {
+ return use_stateless_rejects_if_peer_supported_;
+}
+
+bool QuicCryptoServerHandshaker::PeerSupportsStatelessRejects() const {
+ return peer_supports_stateless_rejects_;
+}
+
+bool QuicCryptoServerHandshaker::ZeroRttAttempted() const {
+ return zero_rtt_attempted_;
+}
+
+void QuicCryptoServerHandshaker::SetPeerSupportsStatelessRejects(
+ bool peer_supports_stateless_rejects) {
+ peer_supports_stateless_rejects_ = peer_supports_stateless_rejects;
+}
+
+void QuicCryptoServerHandshaker::SetPreviousCachedNetworkParams(
+ CachedNetworkParameters cached_network_params) {
+ previous_cached_network_params_.reset(
+ new CachedNetworkParameters(cached_network_params));
+}
+
+bool QuicCryptoServerHandshaker::ShouldSendExpectCTHeader() const {
+ return signed_config_->proof.send_expect_ct_header;
+}
+
+bool QuicCryptoServerHandshaker::GetBase64SHA256ClientChannelID(
+ string* output) const {
+ if (!encryption_established() ||
+ crypto_negotiated_params_->channel_id.empty()) {
+ return false;
+ }
+
+ const string& channel_id(crypto_negotiated_params_->channel_id);
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+ SHA256(reinterpret_cast<const uint8_t*>(channel_id.data()), channel_id.size(),
+ digest);
+
+ QuicTextUtils::Base64Encode(digest, arraysize(digest), output);
+ return true;
+}
+
+bool QuicCryptoServerHandshaker::encryption_established() const {
+ return encryption_established_;
+}
+
+bool QuicCryptoServerHandshaker::handshake_confirmed() const {
+ return handshake_confirmed_;
+}
+
+const QuicCryptoNegotiatedParameters&
+QuicCryptoServerHandshaker::crypto_negotiated_params() const {
+ return *crypto_negotiated_params_;
+}
+
+CryptoMessageParser* QuicCryptoServerHandshaker::crypto_message_parser() {
+ return QuicCryptoHandshaker::crypto_message_parser();
+}
+
+void QuicCryptoServerHandshaker::ProcessClientHello(
+ QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+ result,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ std::unique_ptr<ProcessClientHelloResultCallback> done_cb) {
+ const CryptoHandshakeMessage& message = result->client_hello;
+ string error_details;
+ if (!helper_->CanAcceptClientHello(
+ message, session()->connection()->self_address(), &error_details)) {
+ done_cb->Run(QUIC_HANDSHAKE_FAILED, error_details, nullptr, nullptr,
+ nullptr);
+ return;
+ }
+ if (!result->info.server_nonce.empty()) {
+ ++num_handshake_messages_with_server_nonces_;
+ }
+
+ if (num_handshake_messages_ == 1) {
+ // Client attempts zero RTT handshake by sending a non-inchoate CHLO.
+ QuicStringPiece public_value;
+ zero_rtt_attempted_ = message.GetStringPiece(kPUBS, &public_value);
+ }
+
+ // Store the bandwidth estimate from the client.
+ if (result->cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
+ previous_cached_network_params_.reset(
+ new CachedNetworkParameters(result->cached_network_params));
+ }
+ previous_source_address_tokens_ = result->info.source_address_tokens;
+
+ const bool use_stateless_rejects_in_crypto_config =
+ use_stateless_rejects_if_peer_supported_ &&
+ peer_supports_stateless_rejects_;
+ QuicConnection* connection = session()->connection();
+ const QuicConnectionId server_designated_connection_id =
+ GenerateConnectionIdForReject(use_stateless_rejects_in_crypto_config);
+ crypto_config_->ProcessClientHello(
+ result, /*reject_only=*/false, connection->connection_id(),
+ connection->self_address(), GetClientAddress(), version(),
+ connection->supported_versions(), use_stateless_rejects_in_crypto_config,
+ server_designated_connection_id, connection->clock(),
+ connection->random_generator(), compressed_certs_cache_,
+ crypto_negotiated_params_, signed_config_,
+ QuicCryptoStream::CryptoMessageFramingOverhead(version()),
+ chlo_packet_size_, std::move(done_cb));
+}
+
+void QuicCryptoServerHandshaker::OverrideQuicConfigDefaults(
+ QuicConfig* config) {}
+
+QuicCryptoServerHandshaker::ValidateCallback::ValidateCallback(
+ QuicCryptoServerHandshaker* parent)
+ : parent_(parent) {}
+
+void QuicCryptoServerHandshaker::ValidateCallback::Cancel() {
+ parent_ = nullptr;
+}
+
+void QuicCryptoServerHandshaker::ValidateCallback::Run(
+ QuicReferenceCountedPointer<Result> result,
+ std::unique_ptr<ProofSource::Details> details) {
+ if (parent_ != nullptr) {
+ parent_->FinishProcessingHandshakeMessage(std::move(result),
+ std::move(details));
+ }
+}
+
+QuicConnectionId QuicCryptoServerHandshaker::GenerateConnectionIdForReject(
+ bool use_stateless_rejects) {
+ if (!use_stateless_rejects) {
+ return 0;
+ }
+ return helper_->GenerateConnectionIdForReject(
+ session()->connection()->connection_id());
+}
+
+const QuicSocketAddress QuicCryptoServerHandshaker::GetClientAddress() {
+ return session()->connection()->peer_address();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_server_handshaker.h b/chromium/net/quic/core/quic_crypto_server_handshaker.h
new file mode 100644
index 00000000000..6fffb98573e
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_server_handshaker.h
@@ -0,0 +1,240 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CORE_QUIC_CRYPTO_SERVER_HANDSHAKER_H_
+#define NET_QUIC_CORE_QUIC_CRYPTO_SERVER_HANDSHAKER_H_
+
+#include "net/quic/core/quic_crypto_handshaker.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/platform/api/quic_export.h"
+
+namespace net {
+
+namespace test {
+class QuicCryptoServerStreamPeer;
+} // namespace test
+
+class QUIC_EXPORT_PRIVATE QuicCryptoServerHandshaker
+ : public QuicCryptoServerStream::HandshakerDelegate,
+ public QuicCryptoHandshaker {
+ public:
+ // |crypto_config| must outlive the stream.
+ // |session| must outlive the stream.
+ // |helper| must outlive the stream.
+ QuicCryptoServerHandshaker(const QuicCryptoServerConfig* crypto_config,
+ QuicCryptoServerStream* stream,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ bool use_stateless_rejects_if_peer_supported,
+ QuicSession* session,
+ QuicCryptoServerStream::Helper* helper);
+
+ ~QuicCryptoServerHandshaker() override;
+
+ // From HandshakerDelegate
+ void CancelOutstandingCallbacks() override;
+ bool GetBase64SHA256ClientChannelID(std::string* output) const override;
+ void SendServerConfigUpdate(
+ const CachedNetworkParameters* cached_network_params) override;
+ uint8_t NumHandshakeMessages() const override;
+ uint8_t NumHandshakeMessagesWithServerNonces() const override;
+ int NumServerConfigUpdateMessagesSent() const override;
+ const CachedNetworkParameters* PreviousCachedNetworkParams() const override;
+ bool UseStatelessRejectsIfPeerSupported() const override;
+ bool PeerSupportsStatelessRejects() const override;
+ bool ZeroRttAttempted() const override;
+ void SetPeerSupportsStatelessRejects(
+ bool peer_supports_stateless_rejects) override;
+ void SetPreviousCachedNetworkParams(
+ CachedNetworkParameters cached_network_params) override;
+ bool ShouldSendExpectCTHeader() const override;
+
+ // From QuicCryptoStream
+ bool encryption_established() const override;
+ bool handshake_confirmed() const override;
+ const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
+ const override;
+ CryptoMessageParser* crypto_message_parser() override;
+
+ // From QuicCryptoHandshaker
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
+
+ protected:
+ virtual void ProcessClientHello(
+ QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+ result,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ std::unique_ptr<ProcessClientHelloResultCallback> done_cb);
+
+ // Hook that allows the server to set QuicConfig defaults just
+ // before going through the parameter negotiation step.
+ virtual void OverrideQuicConfigDefaults(QuicConfig* config);
+
+ // Returns client address used to generate and validate source address token.
+ virtual const QuicSocketAddress GetClientAddress();
+
+ private:
+ friend class test::QuicCryptoServerStreamPeer;
+
+ class ValidateCallback : public ValidateClientHelloResultCallback {
+ public:
+ explicit ValidateCallback(QuicCryptoServerHandshaker* parent);
+ // To allow the parent to detach itself from the callback before deletion.
+ void Cancel();
+
+ // From ValidateClientHelloResultCallback
+ void Run(QuicReferenceCountedPointer<Result> result,
+ std::unique_ptr<ProofSource::Details> details) override;
+
+ private:
+ QuicCryptoServerHandshaker* parent_;
+
+ DISALLOW_COPY_AND_ASSIGN(ValidateCallback);
+ };
+
+ class SendServerConfigUpdateCallback
+ : public BuildServerConfigUpdateMessageResultCallback {
+ public:
+ explicit SendServerConfigUpdateCallback(QuicCryptoServerHandshaker* parent);
+ SendServerConfigUpdateCallback(const SendServerConfigUpdateCallback&) =
+ delete;
+ void operator=(const SendServerConfigUpdateCallback&) = delete;
+
+ // To allow the parent to detach itself from the callback before deletion.
+ void Cancel();
+
+ // From BuildServerConfigUpdateMessageResultCallback
+ void Run(bool ok, const CryptoHandshakeMessage& message) override;
+
+ private:
+ QuicCryptoServerHandshaker* parent_;
+ };
+
+ // Invoked by ValidateCallback::RunImpl once initial validation of
+ // the client hello is complete. Finishes processing of the client
+ // hello message and handles handshake success/failure.
+ void FinishProcessingHandshakeMessage(
+ QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+ result,
+ std::unique_ptr<ProofSource::Details> details);
+
+ class ProcessClientHelloCallback;
+ friend class ProcessClientHelloCallback;
+
+ // Portion of FinishProcessingHandshakeMessage which executes after
+ // ProcessClientHello has been called.
+ void FinishProcessingHandshakeMessageAfterProcessClientHello(
+ const ValidateClientHelloResultCallback::Result& result,
+ QuicErrorCode error,
+ const std::string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> reply,
+ std::unique_ptr<DiversificationNonce> diversification_nonce,
+ std::unique_ptr<ProofSource::Details> proof_source_details);
+
+ // Invoked by SendServerConfigUpdateCallback::RunImpl once the proof has been
+ // received. |ok| indicates whether or not the proof was successfully
+ // acquired, and |message| holds the partially-constructed message from
+ // SendServerConfigUpdate.
+ void FinishSendServerConfigUpdate(bool ok,
+ const CryptoHandshakeMessage& message);
+
+ // Returns a new ConnectionId to be used for statelessly rejected connections
+ // if |use_stateless_rejects| is true. Returns 0 otherwise.
+ QuicConnectionId GenerateConnectionIdForReject(bool use_stateless_rejects);
+
+ // Returns the QuicSession that this stream belongs to.
+ QuicSession* session() const { return session_; }
+
+ // Returns the QuicVersion of the connection.
+ QuicVersion version() const { return session_->connection()->version(); }
+
+ QuicCryptoServerStream* stream_;
+
+ QuicSession* session_;
+
+ // crypto_config_ contains crypto parameters for the handshake.
+ const QuicCryptoServerConfig* crypto_config_;
+
+ // compressed_certs_cache_ contains a set of most recently compressed certs.
+ // Owned by QuicDispatcher.
+ QuicCompressedCertsCache* compressed_certs_cache_;
+
+ // Server's certificate chain and signature of the server config, as provided
+ // by ProofSource::GetProof.
+ QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
+
+ // Hash of the last received CHLO message which can be used for generating
+ // server config update messages.
+ std::string chlo_hash_;
+
+ // Pointer to the helper for this crypto stream. Must outlive this stream.
+ QuicCryptoServerStream::Helper* helper_;
+
+ // Number of handshake messages received by this stream.
+ uint8_t num_handshake_messages_;
+
+ // Number of handshake messages received by this stream that contain
+ // server nonces (indicating that this is a non-zero-RTT handshake
+ // attempt).
+ uint8_t num_handshake_messages_with_server_nonces_;
+
+ // Pointer to the active callback that will receive the result of
+ // BuildServerConfigUpdateMessage and forward it to
+ // FinishSendServerConfigUpdate. nullptr if no update message is currently
+ // being built.
+ SendServerConfigUpdateCallback* send_server_config_update_cb_;
+
+ // Number of server config update (SCUP) messages sent by this stream.
+ int num_server_config_update_messages_sent_;
+
+ // If the client provides CachedNetworkParameters in the STK in the CHLO, then
+ // store here, and send back in future STKs if we have no better bandwidth
+ // estimate to send.
+ std::unique_ptr<CachedNetworkParameters> previous_cached_network_params_;
+
+ // Contains any source address tokens which were present in the CHLO.
+ SourceAddressTokens previous_source_address_tokens_;
+
+ // If true, the server should use stateless rejects, so long as the
+ // client supports them, as indicated by
+ // peer_supports_stateless_rejects_.
+ bool use_stateless_rejects_if_peer_supported_;
+
+ // Set to true, once the server has received information from the
+ // client that it supports stateless reject.
+ // TODO(jokulik): Remove once client stateless reject support
+ // becomes the default.
+ bool peer_supports_stateless_rejects_;
+
+ // True if client attempts 0-rtt handshake (which can succeed or fail). If
+ // stateless rejects are used, this variable will be false for the stateless
+ // rejected connection and true for subsequent connections.
+ bool zero_rtt_attempted_;
+
+ // Size of the packet containing the most recently received CHLO.
+ QuicByteCount chlo_packet_size_;
+
+ // Pointer to the active callback that will receive the result of the client
+ // hello validation request and forward it to FinishProcessingHandshakeMessage
+ // for processing. nullptr if no handshake message is being validated. Note
+ // that this field is mutually exclusive with process_client_hello_cb_.
+ ValidateCallback* validate_client_hello_cb_;
+
+ // Pointer to the active callback which will receive the results of
+ // ProcessClientHello and forward it to
+ // FinishProcessingHandshakeMessageAfterProcessClientHello. Note that this
+ // field is mutually exclusive with validate_client_hello_cb_.
+ ProcessClientHelloCallback* process_client_hello_cb_;
+
+ bool encryption_established_;
+ bool handshake_confirmed_;
+ QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters>
+ crypto_negotiated_params_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerHandshaker);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CORE_QUIC_CRYPTO_SERVER_HANDSHAKER_H_
diff --git a/chromium/net/quic/core/quic_crypto_server_stream.cc b/chromium/net/quic/core/quic_crypto_server_stream.cc
index 7119a8e67c7..d9d2c83cb33 100644
--- a/chromium/net/quic/core/quic_crypto_server_stream.cc
+++ b/chromium/net/quic/core/quic_crypto_server_stream.cc
@@ -12,50 +12,17 @@
#include "net/quic/core/crypto/quic_random.h"
#include "net/quic/core/proto/cached_network_parameters.pb.h"
#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_crypto_server_handshaker.h"
#include "net/quic/core/quic_packets.h"
#include "net/quic/core/quic_session.h"
#include "net/quic/platform/api/quic_flags.h"
#include "net/quic/platform/api/quic_logging.h"
#include "net/quic/platform/api/quic_string_piece.h"
-#include "net/quic/platform/api/quic_text_utils.h"
-#include "third_party/boringssl/src/include/openssl/sha.h"
using std::string;
namespace net {
-class QuicCryptoServerHandshaker::ProcessClientHelloCallback
- : public ProcessClientHelloResultCallback {
- public:
- ProcessClientHelloCallback(
- QuicCryptoServerHandshaker* parent,
- const QuicReferenceCountedPointer<
- ValidateClientHelloResultCallback::Result>& result)
- : parent_(parent), result_(result) {}
-
- void Run(QuicErrorCode error,
- const string& error_details,
- std::unique_ptr<CryptoHandshakeMessage> message,
- std::unique_ptr<DiversificationNonce> diversification_nonce,
- std::unique_ptr<net::ProofSource::Details> proof_source_details)
- override {
- if (parent_ == nullptr) {
- return;
- }
-
- parent_->FinishProcessingHandshakeMessageAfterProcessClientHello(
- *result_, error, error_details, std::move(message),
- std::move(diversification_nonce), std::move(proof_source_details));
- }
-
- void Cancel() { parent_ = nullptr; }
-
- private:
- QuicCryptoServerHandshaker* parent_;
- QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
- result_;
-};
-
QuicCryptoServerStreamBase::QuicCryptoServerStreamBase(QuicSession* session)
: QuicCryptoStream(session) {}
@@ -172,438 +139,4 @@ QuicCryptoServerStream::HandshakerDelegate* QuicCryptoServerStream::handshaker()
return handshaker_.get();
}
-QuicCryptoServerHandshaker::QuicCryptoServerHandshaker(
- const QuicCryptoServerConfig* crypto_config,
- QuicCryptoServerStream* stream,
- QuicCompressedCertsCache* compressed_certs_cache,
- bool use_stateless_rejects_if_peer_supported,
- QuicSession* session,
- QuicCryptoServerStream::Helper* helper)
- : QuicCryptoHandshaker(stream, session),
- stream_(stream),
- session_(session),
- crypto_config_(crypto_config),
- compressed_certs_cache_(compressed_certs_cache),
- signed_config_(new QuicSignedServerConfig),
- helper_(helper),
- num_handshake_messages_(0),
- num_handshake_messages_with_server_nonces_(0),
- send_server_config_update_cb_(nullptr),
- num_server_config_update_messages_sent_(0),
- use_stateless_rejects_if_peer_supported_(
- use_stateless_rejects_if_peer_supported),
- peer_supports_stateless_rejects_(false),
- zero_rtt_attempted_(false),
- chlo_packet_size_(0),
- validate_client_hello_cb_(nullptr),
- process_client_hello_cb_(nullptr),
- encryption_established_(false),
- handshake_confirmed_(false),
- crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {}
-
-QuicCryptoServerHandshaker::~QuicCryptoServerHandshaker() {
- CancelOutstandingCallbacks();
-}
-
-void QuicCryptoServerHandshaker::CancelOutstandingCallbacks() {
- // Detach from the validation callback. Calling this multiple times is safe.
- if (validate_client_hello_cb_ != nullptr) {
- validate_client_hello_cb_->Cancel();
- validate_client_hello_cb_ = nullptr;
- }
- if (send_server_config_update_cb_ != nullptr) {
- send_server_config_update_cb_->Cancel();
- send_server_config_update_cb_ = nullptr;
- }
- if (process_client_hello_cb_ != nullptr) {
- process_client_hello_cb_->Cancel();
- process_client_hello_cb_ = nullptr;
- }
-}
-
-void QuicCryptoServerHandshaker::OnHandshakeMessage(
- const CryptoHandshakeMessage& message) {
- QuicCryptoHandshaker::OnHandshakeMessage(message);
- ++num_handshake_messages_;
- chlo_packet_size_ = session()->connection()->GetCurrentPacket().length();
-
- // Do not process handshake messages after the handshake is confirmed.
- if (handshake_confirmed_) {
- stream_->CloseConnectionWithDetails(
- QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
- "Unexpected handshake message from client");
- return;
- }
-
- if (message.tag() != kCHLO) {
- stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
- "Handshake packet not CHLO");
- return;
- }
-
- if (validate_client_hello_cb_ != nullptr ||
- process_client_hello_cb_ != nullptr) {
- // Already processing some other handshake message. The protocol
- // does not allow for clients to send multiple handshake messages
- // before the server has a chance to respond.
- stream_->CloseConnectionWithDetails(
- QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
- "Unexpected handshake message while processing CHLO");
- return;
- }
-
- CryptoUtils::HashHandshakeMessage(message, &chlo_hash_,
- Perspective::IS_SERVER);
-
- std::unique_ptr<ValidateCallback> cb(new ValidateCallback(this));
- DCHECK(validate_client_hello_cb_ == nullptr);
- DCHECK(process_client_hello_cb_ == nullptr);
- validate_client_hello_cb_ = cb.get();
- crypto_config_->ValidateClientHello(
- message, GetClientAddress().host(),
- session()->connection()->self_address(), version(),
- session()->connection()->clock(), signed_config_, std::move(cb));
-}
-
-void QuicCryptoServerHandshaker::FinishProcessingHandshakeMessage(
- QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
- result,
- std::unique_ptr<ProofSource::Details> details) {
- const CryptoHandshakeMessage& message = result->client_hello;
-
- // Clear the callback that got us here.
- DCHECK(validate_client_hello_cb_ != nullptr);
- DCHECK(process_client_hello_cb_ == nullptr);
- validate_client_hello_cb_ = nullptr;
-
- if (use_stateless_rejects_if_peer_supported_) {
- peer_supports_stateless_rejects_ =
- QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects(message);
- }
-
- std::unique_ptr<ProcessClientHelloCallback> cb(
- new ProcessClientHelloCallback(this, result));
- process_client_hello_cb_ = cb.get();
- ProcessClientHello(result, std::move(details), std::move(cb));
-}
-
-void QuicCryptoServerHandshaker::
- FinishProcessingHandshakeMessageAfterProcessClientHello(
- const ValidateClientHelloResultCallback::Result& result,
- QuicErrorCode error,
- const string& error_details,
- std::unique_ptr<CryptoHandshakeMessage> reply,
- std::unique_ptr<DiversificationNonce> diversification_nonce,
- std::unique_ptr<ProofSource::Details> proof_source_details) {
- // Clear the callback that got us here.
- DCHECK(process_client_hello_cb_ != nullptr);
- DCHECK(validate_client_hello_cb_ == nullptr);
- process_client_hello_cb_ = nullptr;
-
- const CryptoHandshakeMessage& message = result.client_hello;
- if (error != QUIC_NO_ERROR) {
- stream_->CloseConnectionWithDetails(error, error_details);
- return;
- }
-
- if (reply->tag() != kSHLO) {
- if (reply->tag() == kSREJ) {
- DCHECK(use_stateless_rejects_if_peer_supported_);
- DCHECK(peer_supports_stateless_rejects_);
- // Before sending the SREJ, cause the connection to save crypto packets
- // so that they can be added to the time wait list manager and
- // retransmitted.
- session()->connection()->EnableSavingCryptoPackets();
- }
- SendHandshakeMessage(*reply);
-
- if (reply->tag() == kSREJ) {
- DCHECK(use_stateless_rejects_if_peer_supported_);
- DCHECK(peer_supports_stateless_rejects_);
- DCHECK(!handshake_confirmed());
- QUIC_DLOG(INFO) << "Closing connection "
- << session()->connection()->connection_id()
- << " because of a stateless reject.";
- session()->connection()->CloseConnection(
- QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject",
- ConnectionCloseBehavior::SILENT_CLOSE);
- }
- return;
- }
-
- // If we are returning a SHLO then we accepted the handshake. Now
- // process the negotiated configuration options as part of the
- // session config.
- QuicConfig* config = session()->config();
- OverrideQuicConfigDefaults(config);
- string process_error_details;
- const QuicErrorCode process_error =
- config->ProcessPeerHello(message, CLIENT, &process_error_details);
- if (process_error != QUIC_NO_ERROR) {
- stream_->CloseConnectionWithDetails(process_error, process_error_details);
- return;
- }
-
- session()->OnConfigNegotiated();
-
- config->ToHandshakeMessage(reply.get());
-
- // Receiving a full CHLO implies the client is prepared to decrypt with
- // the new server write key. We can start to encrypt with the new server
- // write key.
- //
- // NOTE: the SHLO will be encrypted with the new server write key.
- session()->connection()->SetEncrypter(
- ENCRYPTION_INITIAL,
- crypto_negotiated_params_->initial_crypters.encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- // Set the decrypter immediately so that we no longer accept unencrypted
- // packets.
- session()->connection()->SetDecrypter(
- ENCRYPTION_INITIAL,
- crypto_negotiated_params_->initial_crypters.decrypter.release());
- session()->connection()->SetDiversificationNonce(*diversification_nonce);
-
- SendHandshakeMessage(*reply);
-
- session()->connection()->SetEncrypter(
- ENCRYPTION_FORWARD_SECURE,
- crypto_negotiated_params_->forward_secure_crypters.encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
-
- session()->connection()->SetAlternativeDecrypter(
- ENCRYPTION_FORWARD_SECURE,
- crypto_negotiated_params_->forward_secure_crypters.decrypter.release(),
- false /* don't latch */);
-
- encryption_established_ = true;
- handshake_confirmed_ = true;
- session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
-}
-
-void QuicCryptoServerHandshaker::SendServerConfigUpdate(
- const CachedNetworkParameters* cached_network_params) {
- if (!handshake_confirmed_) {
- return;
- }
-
- if (send_server_config_update_cb_ != nullptr) {
- QUIC_DVLOG(1)
- << "Skipped server config update since one is already in progress";
- return;
- }
-
- std::unique_ptr<SendServerConfigUpdateCallback> cb(
- new SendServerConfigUpdateCallback(this));
- send_server_config_update_cb_ = cb.get();
-
- crypto_config_->BuildServerConfigUpdateMessage(
- session()->connection()->version(), chlo_hash_,
- previous_source_address_tokens_, session()->connection()->self_address(),
- GetClientAddress().host(), session()->connection()->clock(),
- session()->connection()->random_generator(), compressed_certs_cache_,
- *crypto_negotiated_params_, cached_network_params,
- (session()->config()->HasReceivedConnectionOptions()
- ? session()->config()->ReceivedConnectionOptions()
- : QuicTagVector()),
- std::move(cb));
-}
-
-QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::
- SendServerConfigUpdateCallback(QuicCryptoServerHandshaker* parent)
- : parent_(parent) {}
-
-void QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::Cancel() {
- parent_ = nullptr;
-}
-
-// From BuildServerConfigUpdateMessageResultCallback
-void QuicCryptoServerHandshaker::SendServerConfigUpdateCallback::Run(
- bool ok,
- const CryptoHandshakeMessage& message) {
- if (parent_ == nullptr) {
- return;
- }
- parent_->FinishSendServerConfigUpdate(ok, message);
-}
-
-void QuicCryptoServerHandshaker::FinishSendServerConfigUpdate(
- bool ok,
- const CryptoHandshakeMessage& message) {
- // Clear the callback that got us here.
- DCHECK(send_server_config_update_cb_ != nullptr);
- send_server_config_update_cb_ = nullptr;
-
- if (!ok) {
- QUIC_DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
- return;
- }
-
- QUIC_DVLOG(1) << "Server: Sending server config update: "
- << message.DebugString(Perspective::IS_SERVER);
- const QuicData& data = message.GetSerialized(Perspective::IS_SERVER);
- stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false,
- nullptr);
-
- ++num_server_config_update_messages_sent_;
-}
-
-uint8_t QuicCryptoServerHandshaker::NumHandshakeMessages() const {
- return num_handshake_messages_;
-}
-
-uint8_t QuicCryptoServerHandshaker::NumHandshakeMessagesWithServerNonces()
- const {
- return num_handshake_messages_with_server_nonces_;
-}
-
-int QuicCryptoServerHandshaker::NumServerConfigUpdateMessagesSent() const {
- return num_server_config_update_messages_sent_;
-}
-
-const CachedNetworkParameters*
-QuicCryptoServerHandshaker::PreviousCachedNetworkParams() const {
- return previous_cached_network_params_.get();
-}
-
-bool QuicCryptoServerHandshaker::UseStatelessRejectsIfPeerSupported() const {
- return use_stateless_rejects_if_peer_supported_;
-}
-
-bool QuicCryptoServerHandshaker::PeerSupportsStatelessRejects() const {
- return peer_supports_stateless_rejects_;
-}
-
-bool QuicCryptoServerHandshaker::ZeroRttAttempted() const {
- return zero_rtt_attempted_;
-}
-
-void QuicCryptoServerHandshaker::SetPeerSupportsStatelessRejects(
- bool peer_supports_stateless_rejects) {
- peer_supports_stateless_rejects_ = peer_supports_stateless_rejects;
-}
-
-void QuicCryptoServerHandshaker::SetPreviousCachedNetworkParams(
- CachedNetworkParameters cached_network_params) {
- previous_cached_network_params_.reset(
- new CachedNetworkParameters(cached_network_params));
-}
-
-bool QuicCryptoServerHandshaker::ShouldSendExpectCTHeader() const {
- return signed_config_->proof.send_expect_ct_header;
-}
-
-bool QuicCryptoServerHandshaker::GetBase64SHA256ClientChannelID(
- string* output) const {
- if (!encryption_established() ||
- crypto_negotiated_params_->channel_id.empty()) {
- return false;
- }
-
- const string& channel_id(crypto_negotiated_params_->channel_id);
- uint8_t digest[SHA256_DIGEST_LENGTH];
- SHA256(reinterpret_cast<const uint8_t*>(channel_id.data()), channel_id.size(),
- digest);
-
- QuicTextUtils::Base64Encode(digest, arraysize(digest), output);
- return true;
-}
-
-bool QuicCryptoServerHandshaker::encryption_established() const {
- return encryption_established_;
-}
-
-bool QuicCryptoServerHandshaker::handshake_confirmed() const {
- return handshake_confirmed_;
-}
-
-const QuicCryptoNegotiatedParameters&
-QuicCryptoServerHandshaker::crypto_negotiated_params() const {
- return *crypto_negotiated_params_;
-}
-
-CryptoMessageParser* QuicCryptoServerHandshaker::crypto_message_parser() {
- return QuicCryptoHandshaker::crypto_message_parser();
-}
-
-void QuicCryptoServerHandshaker::ProcessClientHello(
- QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
- result,
- std::unique_ptr<ProofSource::Details> proof_source_details,
- std::unique_ptr<ProcessClientHelloResultCallback> done_cb) {
- const CryptoHandshakeMessage& message = result->client_hello;
- string error_details;
- if (!helper_->CanAcceptClientHello(
- message, session()->connection()->self_address(), &error_details)) {
- done_cb->Run(QUIC_HANDSHAKE_FAILED, error_details, nullptr, nullptr,
- nullptr);
- return;
- }
- if (!result->info.server_nonce.empty()) {
- ++num_handshake_messages_with_server_nonces_;
- }
-
- if (num_handshake_messages_ == 1) {
- // Client attempts zero RTT handshake by sending a non-inchoate CHLO.
- QuicStringPiece public_value;
- zero_rtt_attempted_ = message.GetStringPiece(kPUBS, &public_value);
- }
-
- // Store the bandwidth estimate from the client.
- if (result->cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
- previous_cached_network_params_.reset(
- new CachedNetworkParameters(result->cached_network_params));
- }
- previous_source_address_tokens_ = result->info.source_address_tokens;
-
- const bool use_stateless_rejects_in_crypto_config =
- use_stateless_rejects_if_peer_supported_ &&
- peer_supports_stateless_rejects_;
- QuicConnection* connection = session()->connection();
- const QuicConnectionId server_designated_connection_id =
- GenerateConnectionIdForReject(use_stateless_rejects_in_crypto_config);
- crypto_config_->ProcessClientHello(
- result, /*reject_only=*/false, connection->connection_id(),
- connection->self_address(), GetClientAddress(), version(),
- connection->supported_versions(), use_stateless_rejects_in_crypto_config,
- server_designated_connection_id, connection->clock(),
- connection->random_generator(), compressed_certs_cache_,
- crypto_negotiated_params_, signed_config_,
- QuicCryptoStream::CryptoMessageFramingOverhead(version()),
- chlo_packet_size_, std::move(done_cb));
-}
-
-void QuicCryptoServerHandshaker::OverrideQuicConfigDefaults(
- QuicConfig* config) {}
-
-QuicCryptoServerHandshaker::ValidateCallback::ValidateCallback(
- QuicCryptoServerHandshaker* parent)
- : parent_(parent) {}
-
-void QuicCryptoServerHandshaker::ValidateCallback::Cancel() {
- parent_ = nullptr;
-}
-
-void QuicCryptoServerHandshaker::ValidateCallback::Run(
- QuicReferenceCountedPointer<Result> result,
- std::unique_ptr<ProofSource::Details> details) {
- if (parent_ != nullptr) {
- parent_->FinishProcessingHandshakeMessage(std::move(result),
- std::move(details));
- }
-}
-
-QuicConnectionId QuicCryptoServerHandshaker::GenerateConnectionIdForReject(
- bool use_stateless_rejects) {
- if (!use_stateless_rejects) {
- return 0;
- }
- return helper_->GenerateConnectionIdForReject(
- session()->connection()->connection_id());
-}
-
-const QuicSocketAddress QuicCryptoServerHandshaker::GetClientAddress() {
- return session()->connection()->peer_address();
-}
-
} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_server_stream.h b/chromium/net/quic/core/quic_crypto_server_stream.h
index 29271e48993..d7772930638 100644
--- a/chromium/net/quic/core/quic_crypto_server_stream.h
+++ b/chromium/net/quic/core/quic_crypto_server_stream.h
@@ -15,6 +15,7 @@
#include "net/quic/core/crypto/quic_crypto_server_config.h"
#include "net/quic/core/proto/source_address_token.pb.h"
#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_crypto_handshaker.h"
#include "net/quic/core/quic_crypto_stream.h"
#include "net/quic/core/quic_session.h"
#include "net/quic/platform/api/quic_export.h"
@@ -26,10 +27,6 @@ class CryptoHandshakeMessage;
class QuicCryptoServerConfig;
class QuicCryptoServerStreamBase;
-namespace test {
-class QuicCryptoServerStreamPeer;
-} // namespace test
-
// TODO(alyssar) see what can be moved out of QuicCryptoServerStream with
// various code and test refactoring.
class QUIC_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream {
@@ -205,225 +202,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerStream);
};
-class QUIC_EXPORT_PRIVATE QuicCryptoServerHandshaker
- : public QuicCryptoServerStream::HandshakerDelegate,
- public QuicCryptoHandshaker {
- public:
- // |crypto_config| must outlive the stream.
- // |session| must outlive the stream.
- // |helper| must outlive the stream.
- QuicCryptoServerHandshaker(const QuicCryptoServerConfig* crypto_config,
- QuicCryptoServerStream* stream,
- QuicCompressedCertsCache* compressed_certs_cache,
- bool use_stateless_rejects_if_peer_supported,
- QuicSession* session,
- QuicCryptoServerStream::Helper* helper);
-
- ~QuicCryptoServerHandshaker() override;
-
- // From HandshakerDelegate
- void CancelOutstandingCallbacks() override;
- bool GetBase64SHA256ClientChannelID(std::string* output) const override;
- void SendServerConfigUpdate(
- const CachedNetworkParameters* cached_network_params) override;
- uint8_t NumHandshakeMessages() const override;
- uint8_t NumHandshakeMessagesWithServerNonces() const override;
- int NumServerConfigUpdateMessagesSent() const override;
- const CachedNetworkParameters* PreviousCachedNetworkParams() const override;
- bool UseStatelessRejectsIfPeerSupported() const override;
- bool PeerSupportsStatelessRejects() const override;
- bool ZeroRttAttempted() const override;
- void SetPeerSupportsStatelessRejects(
- bool peer_supports_stateless_rejects) override;
- void SetPreviousCachedNetworkParams(
- CachedNetworkParameters cached_network_params) override;
- bool ShouldSendExpectCTHeader() const override;
-
- // From QuicCryptoStream
- bool encryption_established() const override;
- bool handshake_confirmed() const override;
- const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
- const override;
- CryptoMessageParser* crypto_message_parser() override;
-
- // From QuicCryptoHandshaker
- void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
-
- protected:
- virtual void ProcessClientHello(
- QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
- result,
- std::unique_ptr<ProofSource::Details> proof_source_details,
- std::unique_ptr<ProcessClientHelloResultCallback> done_cb);
-
- // Hook that allows the server to set QuicConfig defaults just
- // before going through the parameter negotiation step.
- virtual void OverrideQuicConfigDefaults(QuicConfig* config);
-
- // Returns client address used to generate and validate source address token.
- virtual const QuicSocketAddress GetClientAddress();
-
- private:
- friend class test::QuicCryptoServerStreamPeer;
-
- class ValidateCallback : public ValidateClientHelloResultCallback {
- public:
- explicit ValidateCallback(QuicCryptoServerHandshaker* parent);
- // To allow the parent to detach itself from the callback before deletion.
- void Cancel();
-
- // From ValidateClientHelloResultCallback
- void Run(QuicReferenceCountedPointer<Result> result,
- std::unique_ptr<ProofSource::Details> details) override;
-
- private:
- QuicCryptoServerHandshaker* parent_;
-
- DISALLOW_COPY_AND_ASSIGN(ValidateCallback);
- };
-
- class SendServerConfigUpdateCallback
- : public BuildServerConfigUpdateMessageResultCallback {
- public:
- explicit SendServerConfigUpdateCallback(QuicCryptoServerHandshaker* parent);
- SendServerConfigUpdateCallback(const SendServerConfigUpdateCallback&) =
- delete;
- void operator=(const SendServerConfigUpdateCallback&) = delete;
-
- // To allow the parent to detach itself from the callback before deletion.
- void Cancel();
-
- // From BuildServerConfigUpdateMessageResultCallback
- void Run(bool ok, const CryptoHandshakeMessage& message) override;
-
- private:
- QuicCryptoServerHandshaker* parent_;
- };
-
- // Invoked by ValidateCallback::RunImpl once initial validation of
- // the client hello is complete. Finishes processing of the client
- // hello message and handles handshake success/failure.
- void FinishProcessingHandshakeMessage(
- QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
- result,
- std::unique_ptr<ProofSource::Details> details);
-
- class ProcessClientHelloCallback;
- friend class ProcessClientHelloCallback;
-
- // Portion of FinishProcessingHandshakeMessage which executes after
- // ProcessClientHello has been called.
- void FinishProcessingHandshakeMessageAfterProcessClientHello(
- const ValidateClientHelloResultCallback::Result& result,
- QuicErrorCode error,
- const std::string& error_details,
- std::unique_ptr<CryptoHandshakeMessage> reply,
- std::unique_ptr<DiversificationNonce> diversification_nonce,
- std::unique_ptr<ProofSource::Details> proof_source_details);
-
- // Invoked by SendServerConfigUpdateCallback::RunImpl once the proof has been
- // received. |ok| indicates whether or not the proof was successfully
- // acquired, and |message| holds the partially-constructed message from
- // SendServerConfigUpdate.
- void FinishSendServerConfigUpdate(bool ok,
- const CryptoHandshakeMessage& message);
-
- // Returns a new ConnectionId to be used for statelessly rejected connections
- // if |use_stateless_rejects| is true. Returns 0 otherwise.
- QuicConnectionId GenerateConnectionIdForReject(bool use_stateless_rejects);
-
- // Returns the QuicSession that this stream belongs to.
- QuicSession* session() const { return session_; }
-
- // Returns the QuicVersion of the connection.
- QuicVersion version() const { return session_->connection()->version(); }
-
- QuicCryptoServerStream* stream_;
-
- QuicSession* session_;
-
- // crypto_config_ contains crypto parameters for the handshake.
- const QuicCryptoServerConfig* crypto_config_;
-
- // compressed_certs_cache_ contains a set of most recently compressed certs.
- // Owned by QuicDispatcher.
- QuicCompressedCertsCache* compressed_certs_cache_;
-
- // Server's certificate chain and signature of the server config, as provided
- // by ProofSource::GetProof.
- QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
-
- // Hash of the last received CHLO message which can be used for generating
- // server config update messages.
- std::string chlo_hash_;
-
- // Pointer to the helper for this crypto stream. Must outlive this stream.
- QuicCryptoServerStream::Helper* helper_;
-
- // Number of handshake messages received by this stream.
- uint8_t num_handshake_messages_;
-
- // Number of handshake messages received by this stream that contain
- // server nonces (indicating that this is a non-zero-RTT handshake
- // attempt).
- uint8_t num_handshake_messages_with_server_nonces_;
-
- // Pointer to the active callback that will receive the result of
- // BuildServerConfigUpdateMessage and forward it to
- // FinishSendServerConfigUpdate. nullptr if no update message is currently
- // being built.
- SendServerConfigUpdateCallback* send_server_config_update_cb_;
-
- // Number of server config update (SCUP) messages sent by this stream.
- int num_server_config_update_messages_sent_;
-
- // If the client provides CachedNetworkParameters in the STK in the CHLO, then
- // store here, and send back in future STKs if we have no better bandwidth
- // estimate to send.
- std::unique_ptr<CachedNetworkParameters> previous_cached_network_params_;
-
- // Contains any source address tokens which were present in the CHLO.
- SourceAddressTokens previous_source_address_tokens_;
-
- // If true, the server should use stateless rejects, so long as the
- // client supports them, as indicated by
- // peer_supports_stateless_rejects_.
- bool use_stateless_rejects_if_peer_supported_;
-
- // Set to true, once the server has received information from the
- // client that it supports stateless reject.
- // TODO(jokulik): Remove once client stateless reject support
- // becomes the default.
- bool peer_supports_stateless_rejects_;
-
- // True if client attempts 0-rtt handshake (which can succeed or fail). If
- // stateless rejects are used, this variable will be false for the stateless
- // rejected connection and true for subsequent connections.
- bool zero_rtt_attempted_;
-
- // Size of the packet containing the most recently received CHLO.
- QuicByteCount chlo_packet_size_;
-
- // Pointer to the active callback that will receive the result of the client
- // hello validation request and forward it to FinishProcessingHandshakeMessage
- // for processing. nullptr if no handshake message is being validated. Note
- // that this field is mutually exclusive with process_client_hello_cb_.
- ValidateCallback* validate_client_hello_cb_;
-
- // Pointer to the active callback which will receive the results of
- // ProcessClientHello and forward it to
- // FinishProcessingHandshakeMessageAfterProcessClientHello. Note that this
- // field is mutually exclusive with validate_client_hello_cb_.
- ProcessClientHelloCallback* process_client_hello_cb_;
-
- bool encryption_established_;
- bool handshake_confirmed_;
- QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters>
- crypto_negotiated_params_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerHandshaker);
-};
-
} // namespace net
#endif // NET_QUIC_CORE_QUIC_CRYPTO_SERVER_STREAM_H_
diff --git a/chromium/net/quic/core/quic_crypto_stream.cc b/chromium/net/quic/core/quic_crypto_stream.cc
index 3af89889881..197a170bd49 100644
--- a/chromium/net/quic/core/quic_crypto_stream.cc
+++ b/chromium/net/quic/core/quic_crypto_stream.cc
@@ -57,9 +57,7 @@ void QuicCryptoStream::OnDataAvailable() {
}
sequencer()->MarkConsumed(iov.iov_len);
if (handshake_confirmed() &&
- crypto_message_parser()->InputBytesRemaining() == 0 &&
- FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer) {
- QUIC_FLAG_COUNT(quic_reloadable_flag_quic_release_crypto_stream_buffer);
+ crypto_message_parser()->InputBytesRemaining() == 0) {
// If the handshake is complete and the current message has been fully
// processed then no more handshake messages are likely to arrive soon
// so release the memory in the stream sequencer.
@@ -94,39 +92,4 @@ bool QuicCryptoStream::ExportTokenBindingKeyingMaterial(string* result) const {
/* context= */ "", 32, result);
}
-QuicCryptoHandshaker::QuicCryptoHandshaker(QuicCryptoStream* stream,
- QuicSession* session)
- : stream_(stream), session_(session) {
- crypto_framer_.set_visitor(this);
-}
-
-QuicCryptoHandshaker::~QuicCryptoHandshaker() {}
-
-void QuicCryptoHandshaker::SendHandshakeMessage(
- const CryptoHandshakeMessage& message) {
- QUIC_DVLOG(1) << ENDPOINT << "Sending "
- << message.DebugString(session()->perspective());
- session()->connection()->NeuterUnencryptedPackets();
- session()->OnCryptoHandshakeMessageSent(message);
- const QuicData& data = message.GetSerialized(session()->perspective());
- stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false,
- nullptr);
-}
-
-void QuicCryptoHandshaker::OnError(CryptoFramer* framer) {
- QUIC_DLOG(WARNING) << "Error processing crypto data: "
- << QuicErrorCodeToString(framer->error());
-}
-
-void QuicCryptoHandshaker::OnHandshakeMessage(
- const CryptoHandshakeMessage& message) {
- QUIC_DVLOG(1) << ENDPOINT << "Received "
- << message.DebugString(session()->perspective());
- session()->OnCryptoHandshakeMessageReceived(message);
-}
-
-CryptoMessageParser* QuicCryptoHandshaker::crypto_message_parser() {
- return &crypto_framer_;
-}
-
} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_stream.h b/chromium/net/quic/core/quic_crypto_stream.h
index fdbf4dc091e..8c3a548da3e 100644
--- a/chromium/net/quic/core/quic_crypto_stream.h
+++ b/chromium/net/quic/core/quic_crypto_stream.h
@@ -18,7 +18,6 @@
namespace net {
-class CryptoHandshakeMessage;
class QuicSession;
// Crypto handshake messages in QUIC take place over a reserved stream with the
@@ -80,33 +79,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream {
DISALLOW_COPY_AND_ASSIGN(QuicCryptoStream);
};
-class QUIC_EXPORT_PRIVATE QuicCryptoHandshaker
- : public CryptoFramerVisitorInterface {
- public:
- QuicCryptoHandshaker(QuicCryptoStream* stream, QuicSession* session);
-
- ~QuicCryptoHandshaker() override;
-
- // Sends |message| to the peer.
- // TODO(wtc): return a success/failure status.
- void SendHandshakeMessage(const CryptoHandshakeMessage& message);
-
- void OnError(CryptoFramer* framer) override;
- void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
-
- CryptoMessageParser* crypto_message_parser();
-
- private:
- QuicSession* session() { return session_; }
-
- QuicCryptoStream* stream_;
- QuicSession* session_;
-
- CryptoFramer crypto_framer_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoHandshaker);
-};
-
} // namespace net
#endif // NET_QUIC_CORE_QUIC_CRYPTO_STREAM_H_
diff --git a/chromium/net/quic/core/quic_data_writer.cc b/chromium/net/quic/core/quic_data_writer.cc
index e4716b30138..7e831d8b181 100644
--- a/chromium/net/quic/core/quic_data_writer.cc
+++ b/chromium/net/quic/core/quic_data_writer.cc
@@ -59,6 +59,17 @@ bool QuicDataWriter::WriteUInt64(uint64_t value) {
return WriteBytes(&value, sizeof(value));
}
+bool QuicDataWriter::WriteUInt8AtOffset(uint8_t value, size_t offset) {
+ if (offset > length_) {
+ return false;
+ }
+ size_t old_length = length_;
+ length_ = offset;
+ bool result = WriteBytes(&value, sizeof(value));
+ length_ = old_length;
+ return result;
+}
+
bool QuicDataWriter::WriteBytesToUInt64(size_t num_bytes, uint64_t value) {
if (num_bytes > sizeof(value)) {
return false;
diff --git a/chromium/net/quic/core/quic_data_writer.h b/chromium/net/quic/core/quic_data_writer.h
index 46df6862cbb..b2de22d6823 100644
--- a/chromium/net/quic/core/quic_data_writer.h
+++ b/chromium/net/quic/core/quic_data_writer.h
@@ -48,6 +48,10 @@ class QUIC_EXPORT_PRIVATE QuicDataWriter {
bool WriteUInt32(uint32_t value);
bool WriteUInt64(uint64_t value);
+ // Writes |value| to the position |offset| from the start of the data.
+ // |offset| must be less than the current length of the writer.
+ bool WriteUInt8AtOffset(uint8_t value, size_t offset);
+
// Writes least significant |num_bytes| of a 64-bit unsigned integer in the
// correct byte order.
bool WriteBytesToUInt64(size_t num_bytes, uint64_t value);
diff --git a/chromium/net/quic/core/quic_data_writer_test.cc b/chromium/net/quic/core/quic_data_writer_test.cc
index c6c2d7c31d4..0baba766126 100644
--- a/chromium/net/quic/core/quic_data_writer_test.cc
+++ b/chromium/net/quic/core/quic_data_writer_test.cc
@@ -587,6 +587,35 @@ TEST_P(QuicDataWriterTest, WriteIntegers) {
}
}
+TEST_P(QuicDataWriterTest, WriteBytes) {
+ char bytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
+ char buf[arraysize(bytes)];
+ QuicDataWriter writer(arraysize(buf), buf, GetParam().perspective,
+ GetParam().endianness);
+ EXPECT_TRUE(writer.WriteBytes(bytes, arraysize(bytes)));
+ for (unsigned int i = 0; i < arraysize(bytes); ++i) {
+ EXPECT_EQ(bytes[i], buf[i]);
+ }
+}
+
+TEST_P(QuicDataWriterTest, WriteUInt8AtOffset) {
+ char bytes[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};
+ char buf[arraysize(bytes)];
+ for (unsigned int i = 0; i < arraysize(bytes); ++i) {
+ QuicDataWriter writer(arraysize(buf), buf, GetParam().perspective,
+ GetParam().endianness);
+ EXPECT_TRUE(writer.WriteBytes(bytes, arraysize(bytes)));
+ EXPECT_TRUE(writer.WriteUInt8AtOffset('I', i));
+ for (unsigned int j = 0; j < arraysize(bytes); ++j) {
+ if (j == i) {
+ EXPECT_EQ('I', buf[j]);
+ } else {
+ EXPECT_EQ(bytes[j], buf[j]);
+ }
+ }
+ }
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/core/quic_flags_list.h b/chromium/net/quic/core/quic_flags_list.h
index a5617f399e8..e2ad9ced578 100644
--- a/chromium/net/quic/core/quic_flags_list.h
+++ b/chromium/net/quic/core/quic_flags_list.h
@@ -55,30 +55,10 @@ QUIC_FLAG(bool,
FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame,
true)
-// If true, only open limited number of quic sessions per epoll event. Leave the
-// rest to next event.
-QUIC_FLAG(bool,
- FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop,
- true)
-
-// If true, QUIC server push will enabled by default.
-QUIC_FLAG(bool,
- FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default,
- true)
-
-// If true, release QuicCryptoStream\'s read buffer when stream are less
-// frequently used.
-QUIC_FLAG(bool,
- FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer,
- true)
-
// If true, v33 QUIC client uses 1 bit to specify 8-byte connection id in
// public flag.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_remove_v33_hacks2, false)
-// Enable QUIC force HOL blocking experiment.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_force_hol_blocking, true)
-
// If true, allows packets to be buffered in anticipation of a future CHLO, and
// allow CHLO packets to be buffered until next iteration of the event loop.
QUIC_FLAG(bool, FLAGS_quic_allow_chlo_buffering, true)
@@ -96,7 +76,7 @@ QUIC_FLAG(double, FLAGS_quic_bbr_cwnd_gain, 2.0f)
// If true, do not send or process stop waiting frames in QUIC if the NSTP
// connection option is provided.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames, false)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames, true)
// Allows one self address change.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_allow_one_address_change, false)
@@ -122,21 +102,6 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_adaptive_time_loss, false)
// compressed for QUIC version >= 38.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_random_padding, true)
-// If true, update state if trailing headers with a :final-offset key are
-// received for a previously closed QUIC stream.
-QUIC_FLAG(bool,
- FLAGS_quic_reloadable_flag_quic_final_offset_from_trailers,
- true)
-
-// If enabled, use refactored stream creation methods.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_refactor_stream_creation, false)
-
-// If true, GFEs generate and validate source address token using the actual
-// client IP for proxied session.
-QUIC_FLAG(bool,
- FLAGS_quic_reloadable_flag_quic_use_client_address_for_stk_in_proxy,
- true)
-
// If true, export a varz mapping QUIC non 0-rtt handshake with corresponding
// frontend service.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_account_handshake, false)
@@ -151,9 +116,6 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_pcc, false)
// If true, enable QUIC v40.
QUIC_FLAG(bool, FLAGS_quic_enable_version_40, false)
-// If true, use the more CPU efficient bandwidth sampler datastructure.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_faster_bandwidth_sampler, true)
-
// In QUIC, QuicSession gets notified when stream frames are acked, discarded or
// retransmitted.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_stream_notifier2, false)
@@ -161,9 +123,6 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_stream_notifier2, false)
// When true, defaults to BBR congestion control instead of Cubic.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_default_to_bbr, false)
-// If true, stream sent data is saved in streams rather than stream frames.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_stream_owns_data, false)
-
// Allow a new rate based recovery in QUIC BBR to be enabled via connection
// option.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_rate_recovery, false)
@@ -174,25 +133,79 @@ QUIC_FLAG(bool,
FLAGS_quic_reloadable_flag_quic_handle_duplicate_trailers,
false)
-// Allows QUIC BBR up to twice the previously measured ack aggregation to be
-// added to the CWND as long as bytes_in_flight goes below the target recently.
-QUIC_FLAG(bool,
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes2,
- false)
-
// If true, disables support for QUIC version 36.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_36, false)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_36, true)
// If true, disables support for the packets-based QUIC congestion control
// algorithms.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_packets_based_cc, false)
-// When enabled, adds up to 1.5x the previously measured ack aggregation in
-// bytes to the CWND, but reduces that amount by 1/2 the bytes acked since the
-// queue was drained.
+// When enabled, ack frame uses a deque internally instead of a set.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_frames_deque2, false)
+
+// If true, QUIC packet creator passes a stack allocated SerializedPacket to the
+// connection.
+QUIC_FLAG(bool,
+ FLAGS_quic_reloadable_flag_quic_clear_packet_before_handed_over,
+ true)
+
+// If true, enable QUIC v41.
+QUIC_FLAG(bool, FLAGS_quic_enable_version_41, false)
+
+// Small optimization for QuicSentPacketManager::HandleAckForSentPackets.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_handle_acks, true)
+
+// When true, respect configured limits on header list size.
+QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_header_list_size, false)
+
+// When true, allows the LRTT connection option to cause QUIC BBR to exit
+// STARTUP when in recovery and there has been no bandwidth increase for 1RTT.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_exit_startup_on_loss, false)
+
+// If true, application data is saved before consumption in QUIC.
QUIC_FLAG(bool,
- FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes3,
+ FLAGS_quic_reloadable_flag_quic_save_data_before_consumption2,
false)
-// When enabled, ack frame uses a deque internally instead of a set.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_frames_deque, false)
+// If buffered data in QUIC stream is less than this threshold, buffers all
+// provided data or asks upper layer for more data.
+QUIC_FLAG(uint32_t, FLAGS_quic_buffered_data_threshold, 8192u)
+
+// Max size of data slice in bytes for QUIC stream send buffer.
+QUIC_FLAG(uint32_t, FLAGS_quic_send_buffer_max_data_slice_size, 4096u)
+
+// Enables the BBR1 and BBR2 QUIC connection options, which enable two forms of
+// ack aggregation that prevent persistent standing queues.
+QUIC_FLAG(bool,
+ FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes4,
+ false)
+
+// Add 4 new ack decimation modes to QUIC that are entirely time based at 1/4
+// or 1/8 RTT.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_ack_decimation, false)
+
+// Enables using the ConsumeDataFastPath more often for large transfers.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_consuming_data_faster, false)
+
+// If true, in QUIC, set dispatcher framer\'s version to client packet's
+// version in QuicDispatcher::OnStatelessRejectorProcessDone.
+QUIC_FLAG(
+ bool,
+ FLAGS_quic_reloadable_flag_quic_set_version_on_async_get_proof_returns,
+ false)
+
+// If true, check for packet number underflow when reading ack blocks.
+QUIC_FLAG(bool,
+ FLAGS_quic_reloadable_flag_sanitize_framer_addrange_input,
+ false)
+
+// If true, change QUIC connection to start peer migration only when peer
+// address is changed on server side. For peer address change on client side,
+// update the peer ip address only.
+QUIC_FLAG(bool,
+ FLAGS_quic_reloadable_flag_quic_disable_peer_migration_on_client,
+ true)
+
+// If true, QUIC v40 is enabled which includes changes to RST_STREAM, ACK
+// and STREAM frames match IETF format.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_40, false)
diff --git a/chromium/net/quic/core/quic_framer.cc b/chromium/net/quic/core/quic_framer.cc
index b2f29128df3..a1b05fa0871 100644
--- a/chromium/net/quic/core/quic_framer.cc
+++ b/chromium/net/quic/core/quic_framer.cc
@@ -27,6 +27,7 @@
#include "net/quic/platform/api/quic_logging.h"
#include "net/quic/platform/api/quic_map_util.h"
#include "net/quic/platform/api/quic_ptr_util.h"
+#include "net/quic/platform/api/quic_str_cat.h"
using std::string;
@@ -56,40 +57,51 @@ const uint8_t kPublicHeaderSequenceNumberShift = 4;
//
// Special Frame Types encode both a Frame Type and corresponding flags
// all in the Frame Type byte. Currently defined Special Frame Types are:
-// Stream : 0b 1xxxxxxx
-// Ack : 0b 01xxxxxx
+// Stream : 0b 11xxxxxx
+// Ack : 0b 101xxxxx
//
// Semantics of the flag bits above (the x bits) depends on the frame type.
// Masks to determine if the frame type is a special use
// and for specific special frame types.
const uint8_t kQuicFrameTypeSpecialMask = 0xE0; // 0b 11100000
-const uint8_t kQuicFrameTypeStreamMask = 0x80;
-const uint8_t kQuicFrameTypeAckMask = 0x40;
+const uint8_t kQuicFrameTypeStreamMask_Pre40 = 0x80;
+const uint8_t kQuicFrameTypeStreamMask = 0xC0;
+const uint8_t kQuicFrameTypeAckMask_Pre40 = 0x40;
+const uint8_t kQuicFrameTypeAckMask = 0xA0;
+// Stream type format is 11FSSOOD.
// Stream frame relative shifts and masks for interpreting the stream flags.
// StreamID may be 1, 2, 3, or 4 bytes.
-const uint8_t kQuicStreamIdShift = 2;
-const uint8_t kQuicStreamIDLengthMask = 0x03;
+const uint8_t kQuicStreamIdShift_Pre40 = 2;
+const uint8_t kQuicStreamIDLengthMask_Pre40 = 0x03;
+const uint8_t kQuicStreamIDLengthShift = 3;
+const uint8_t kQuicStreamIDLengthNumBits = 2;
-// Offset may be 0, 2, 3, 4, 5, 6, 7, 8 bytes.
-const uint8_t kQuicStreamOffsetShift = 3;
-const uint8_t kQuicStreamOffsetMask = 0x07;
+// Offset may be 0, 2, 4, or 8 bytes.
+const uint8_t kQuicStreamShift_Pre40 = 3;
+const uint8_t kQuicStreamOffsetMask_Pre40 = 0x07;
+const uint8_t kQuicStreamOffsetNumBits = 2;
+const uint8_t kQuicStreamOffsetShift = 1;
// Data length may be 0 or 2 bytes.
-const uint8_t kQuicStreamDataLengthShift = 1;
-const uint8_t kQuicStreamDataLengthMask = 0x01;
+const uint8_t kQuicStreamDataLengthShift_Pre40 = 1;
+const uint8_t kQuicStreamDataLengthMask_Pre40 = 0x01;
+const uint8_t kQuicStreamDataLengthShift = 0;
// Fin bit may be set or not.
-const uint8_t kQuicStreamFinShift = 1;
-const uint8_t kQuicStreamFinMask = 0x01;
+const uint8_t kQuicStreamFinShift_Pre40 = 1;
+const uint8_t kQuicStreamFinMask_Pre40 = 0x01;
+const uint8_t kQuicStreamFinShift = 5;
// packet number size shift used in AckFrames.
-const uint8_t kQuicSequenceNumberLengthShift = 2;
+const uint8_t kQuicSequenceNumberLengthNumBits = 2;
+const uint8_t kActBlockLengthOffset = 0;
+const uint8_t kLargestAckedOffset = 2;
// Acks may have only one ack block.
-const uint8_t kQuicHasMultipleAckBlocksMask = 0x01;
-const uint8_t kQuicHasMultipleAckBlocksShift = 1;
+const uint8_t kQuicHasMultipleAckBlocksOffset_Pre40 = 5;
+const uint8_t kQuicHasMultipleAckBlocksOffset = 4;
// Returns the absolute value of the difference between |a| and |b|.
QuicPacketNumber Delta(QuicPacketNumber a, QuicPacketNumber b) {
@@ -107,8 +119,8 @@ QuicPacketNumber ClosestTo(QuicPacketNumber target,
}
QuicPacketNumberLength ReadSequenceNumberLength(uint8_t flags) {
- switch (flags & PACKET_FLAGS_6BYTE_PACKET) {
- case PACKET_FLAGS_6BYTE_PACKET:
+ switch (flags & PACKET_FLAGS_8BYTE_PACKET) {
+ case PACKET_FLAGS_8BYTE_PACKET:
return PACKET_6BYTE_PACKET_NUMBER;
case PACKET_FLAGS_4BYTE_PACKET:
return PACKET_4BYTE_PACKET_NUMBER;
@@ -122,6 +134,24 @@ QuicPacketNumberLength ReadSequenceNumberLength(uint8_t flags) {
}
}
+QuicPacketNumberLength ReadAckPacketNumberLength(QuicVersion version,
+ uint8_t flags) {
+ switch (flags & PACKET_FLAGS_8BYTE_PACKET) {
+ case PACKET_FLAGS_8BYTE_PACKET:
+ return version <= QUIC_VERSION_39 ? PACKET_6BYTE_PACKET_NUMBER
+ : PACKET_8BYTE_PACKET_NUMBER;
+ case PACKET_FLAGS_4BYTE_PACKET:
+ return PACKET_4BYTE_PACKET_NUMBER;
+ case PACKET_FLAGS_2BYTE_PACKET:
+ return PACKET_2BYTE_PACKET_NUMBER;
+ case PACKET_FLAGS_1BYTE_PACKET:
+ return PACKET_1BYTE_PACKET_NUMBER;
+ default:
+ QUIC_BUG << "Unreachable case statement.";
+ return PACKET_6BYTE_PACKET_NUMBER;
+ }
+}
+
} // namespace
QuicFramer::QuicFramer(const QuicVersionVector& supported_versions,
@@ -151,11 +181,12 @@ QuicFramer::QuicFramer(const QuicVersionVector& supported_versions,
QuicFramer::~QuicFramer() {}
// static
-size_t QuicFramer::GetMinStreamFrameSize(QuicStreamId stream_id,
+size_t QuicFramer::GetMinStreamFrameSize(QuicVersion version,
+ QuicStreamId stream_id,
QuicStreamOffset offset,
bool last_frame_in_packet) {
return kQuicFrameTypeSize + GetStreamIdSize(stream_id) +
- GetStreamOffsetSize(offset) +
+ GetStreamOffsetSize(version, offset) +
(last_frame_in_packet ? 0 : kQuicStreamPayloadLengthSize);
}
@@ -217,20 +248,32 @@ size_t QuicFramer::GetStreamIdSize(QuicStreamId stream_id) {
}
// static
-size_t QuicFramer::GetStreamOffsetSize(QuicStreamOffset offset) {
- // 0 is a special case.
- if (offset == 0) {
- return 0;
- }
- // 2 through 8 are the remaining sizes.
- offset >>= 8;
- for (int i = 2; i <= 8; ++i) {
- offset >>= 8;
+size_t QuicFramer::GetStreamOffsetSize(QuicVersion version,
+ QuicStreamOffset offset) {
+ if (version < QUIC_VERSION_40) {
+ // 0 is a special case.
if (offset == 0) {
+ return 0;
+ }
+ // 2 through 8 are the remaining sizes.
+ offset >>= 8;
+ for (int i = 2; i <= 8; ++i) {
+ offset >>= 8;
+ if (offset == 0) {
+ return i;
+ }
+ }
+ QUIC_BUG << "Failed to determine StreamOffsetSize.";
+ return 8;
+ }
+ // try 0, 2 and 4.
+ for (int i = 0; i <= 4; i += 2) {
+ if ((offset >> (8 * i)) == 0) {
return i;
}
}
- QUIC_BUG << "Failed to determine StreamOffsetSize.";
+
+ // 8 is the only remaining valid value and will contain any 64bit offset.
return 8;
}
@@ -849,6 +892,7 @@ bool QuicFramer::ProcessPublicHeader(QuicDataReader* reader,
// static
QuicPacketNumberLength QuicFramer::GetMinPacketNumberLength(
+ QuicVersion version,
QuicPacketNumber packet_number) {
if (packet_number < 1 << (PACKET_1BYTE_PACKET_NUMBER * 8)) {
return PACKET_1BYTE_PACKET_NUMBER;
@@ -857,7 +901,8 @@ QuicPacketNumberLength QuicFramer::GetMinPacketNumberLength(
} else if (packet_number < UINT64_C(1) << (PACKET_4BYTE_PACKET_NUMBER * 8)) {
return PACKET_4BYTE_PACKET_NUMBER;
} else {
- return PACKET_6BYTE_PACKET_NUMBER;
+ return version <= QUIC_VERSION_39 ? PACKET_6BYTE_PACKET_NUMBER
+ : PACKET_8BYTE_PACKET_NUMBER;
}
}
@@ -872,10 +917,11 @@ uint8_t QuicFramer::GetPacketNumberFlags(
case PACKET_4BYTE_PACKET_NUMBER:
return PACKET_FLAGS_4BYTE_PACKET;
case PACKET_6BYTE_PACKET_NUMBER:
- return PACKET_FLAGS_6BYTE_PACKET;
+ case PACKET_8BYTE_PACKET_NUMBER:
+ return PACKET_FLAGS_8BYTE_PACKET;
default:
QUIC_BUG << "Unreachable case statement.";
- return PACKET_FLAGS_6BYTE_PACKET;
+ return PACKET_FLAGS_8BYTE_PACKET;
}
}
@@ -966,7 +1012,11 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader,
if (frame_type & kQuicFrameTypeSpecialMask) {
// Stream Frame
- if (frame_type & kQuicFrameTypeStreamMask) {
+ if ((quic_version_ < QUIC_VERSION_40 &&
+ (frame_type & kQuicFrameTypeStreamMask_Pre40)) ||
+ (quic_version_ >= QUIC_VERSION_40 &&
+ ((frame_type & kQuicFrameTypeStreamMask) ==
+ kQuicFrameTypeStreamMask))) {
QuicStreamFrame frame;
if (!ProcessStreamFrame(reader, frame_type, &frame)) {
return RaiseError(QUIC_INVALID_STREAM_DATA);
@@ -981,7 +1031,11 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader,
}
// Ack Frame
- if (frame_type & kQuicFrameTypeAckMask) {
+ if ((quic_version_ < QUIC_VERSION_40 &&
+ (frame_type & kQuicFrameTypeAckMask_Pre40)) ||
+ (quic_version_ >= QUIC_VERSION_40 &&
+ ((frame_type & kQuicFrameTypeSpecialMask) ==
+ kQuicFrameTypeAckMask))) {
QuicAckFrame frame;
if (!ProcessAckFrame(reader, frame_type, &frame)) {
return RaiseError(QUIC_INVALID_ACK_DATA);
@@ -1121,30 +1175,88 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader,
return true;
}
+namespace {
+// Create a mask that sets the last |num_bits| to 1 and the rest to 0.
+inline uint8_t GetMaskFromNumBits(uint8_t num_bits) {
+ return (1u << num_bits) - 1;
+}
+
+// Extract |num_bits| from |flags| offset by |offset|.
+uint8_t ExtractBits(uint8_t flags, uint8_t num_bits, uint8_t offset) {
+ return (flags >> offset) & GetMaskFromNumBits(num_bits);
+}
+
+// Extract the bit at position |offset| from |flags| as a bool.
+bool ExtractBit(uint8_t flags, uint8_t offset) {
+ return ((flags >> offset) & GetMaskFromNumBits(1)) != 0;
+}
+
+// Set |num_bits|, offset by |offset| to |val| in |flags|.
+void SetBits(uint8_t* flags, uint8_t val, uint8_t num_bits, uint8_t offset) {
+ DCHECK_LE(val, GetMaskFromNumBits(num_bits));
+ *flags |= val << offset;
+}
+
+// Set the bit at position |offset| to |val| in |flags|.
+void SetBit(uint8_t* flags, bool val, uint8_t offset) {
+ SetBits(flags, val ? 1 : 0, 1, offset);
+}
+} // namespace
+
bool QuicFramer::ProcessStreamFrame(QuicDataReader* reader,
uint8_t frame_type,
QuicStreamFrame* frame) {
uint8_t stream_flags = frame_type;
- stream_flags &= ~kQuicFrameTypeStreamMask;
+ uint8_t stream_id_length = 0;
+ uint8_t offset_length = 4;
+ bool has_data_length = true;
+ if (quic_version_ < QUIC_VERSION_40) {
+ stream_flags &= ~kQuicFrameTypeStreamMask_Pre40;
- // Read from right to left: StreamID, Offset, Data Length, Fin.
- const uint8_t stream_id_length = (stream_flags & kQuicStreamIDLengthMask) + 1;
- stream_flags >>= kQuicStreamIdShift;
+ // Read from right to left: StreamID, Offset, Data Length, Fin.
+ stream_id_length = (stream_flags & kQuicStreamIDLengthMask_Pre40) + 1;
+ stream_flags >>= kQuicStreamIdShift_Pre40;
- uint8_t offset_length = (stream_flags & kQuicStreamOffsetMask);
- // There is no encoding for 1 byte, only 0 and 2 through 8.
- if (offset_length > 0) {
- offset_length += 1;
- }
- stream_flags >>= kQuicStreamOffsetShift;
+ offset_length = (stream_flags & kQuicStreamOffsetMask_Pre40);
+ // There is no encoding for 1 byte, only 0 and 2 through 8.
+ if (offset_length > 0) {
+ offset_length += 1;
+ }
+ stream_flags >>= kQuicStreamShift_Pre40;
+
+ has_data_length = (stream_flags & kQuicStreamDataLengthMask_Pre40) ==
+ kQuicStreamDataLengthMask_Pre40;
+ stream_flags >>= kQuicStreamDataLengthShift_Pre40;
- bool has_data_length =
- (stream_flags & kQuicStreamDataLengthMask) == kQuicStreamDataLengthMask;
- stream_flags >>= kQuicStreamDataLengthShift;
+ frame->fin =
+ (stream_flags & kQuicStreamFinMask_Pre40) == kQuicStreamFinShift_Pre40;
+
+ } else {
+ stream_flags &= ~kQuicFrameTypeStreamMask;
- frame->fin = (stream_flags & kQuicStreamFinMask) == kQuicStreamFinShift;
+ stream_id_length = 1 + ExtractBits(stream_flags, kQuicStreamIDLengthNumBits,
+ kQuicStreamIDLengthShift);
+ offset_length = 1 << ExtractBits(stream_flags, kQuicStreamOffsetNumBits,
+ kQuicStreamOffsetShift);
+
+ if (offset_length == 1) {
+ offset_length = 0;
+ }
+
+ has_data_length = ExtractBit(stream_flags, kQuicStreamDataLengthShift);
+
+ frame->fin = ExtractBit(stream_flags, kQuicStreamFinShift);
+ }
+
+ uint16_t data_len = 0;
+ if (has_data_length && quic_version_ > QUIC_VERSION_39) {
+ if (!reader->ReadUInt16(&data_len)) {
+ set_detailed_error("Unable to read data length.");
+ return false;
+ }
+ }
uint64_t stream_id = 0;
if (!reader->ReadBytesToUInt64(stream_id_length, &stream_id)) {
set_detailed_error("Unable to read stream_id.");
@@ -1161,9 +1273,16 @@ bool QuicFramer::ProcessStreamFrame(QuicDataReader* reader,
// TODO(ianswett): Don't use QuicStringPiece as an intermediary.
QuicStringPiece data;
if (has_data_length) {
- if (!reader->ReadStringPiece16(&data)) {
- set_detailed_error("Unable to read frame data.");
- return false;
+ if (quic_version_ > QUIC_VERSION_39) {
+ if (!reader->ReadStringPiece(&data, data_len)) {
+ set_detailed_error("Unable to read frame data.");
+ return false;
+ }
+ } else {
+ if (!reader->ReadStringPiece16(&data)) {
+ set_detailed_error("Unable to read frame data.");
+ return false;
+ }
}
} else {
if (!reader->ReadStringPiece(&data, reader->BytesRemaining())) {
@@ -1180,16 +1299,31 @@ bool QuicFramer::ProcessStreamFrame(QuicDataReader* reader,
bool QuicFramer::ProcessAckFrame(QuicDataReader* reader,
uint8_t frame_type,
QuicAckFrame* ack_frame) {
+ bool has_ack_blocks =
+ ExtractBit(frame_type, quic_version_ < QUIC_VERSION_40
+ ? kQuicHasMultipleAckBlocksOffset_Pre40
+ : kQuicHasMultipleAckBlocksOffset);
+ uint8_t num_ack_blocks = 0;
+ uint8_t num_received_packets = 0;
+ if (quic_version_ > QUIC_VERSION_39) {
+ if (has_ack_blocks && !reader->ReadUInt8(&num_ack_blocks)) {
+ set_detailed_error("Unable to read num of ack blocks.");
+ return false;
+ }
+ if (!reader->ReadUInt8(&num_received_packets)) {
+ set_detailed_error("Unable to read num received packets.");
+ return false;
+ }
+ }
+
// Determine the two lengths from the frame type: largest acked length,
// ack block length.
- const QuicPacketNumberLength ack_block_length =
- ReadSequenceNumberLength(frame_type);
- frame_type >>= kQuicSequenceNumberLengthShift;
- const QuicPacketNumberLength largest_acked_length =
- ReadSequenceNumberLength(frame_type);
- frame_type >>= kQuicSequenceNumberLengthShift;
- frame_type >>= kQuicHasMultipleAckBlocksShift;
- bool has_ack_blocks = frame_type & kQuicHasMultipleAckBlocksMask;
+ const QuicPacketNumberLength ack_block_length = ReadAckPacketNumberLength(
+ quic_version_, ExtractBits(frame_type, kQuicSequenceNumberLengthNumBits,
+ kActBlockLengthOffset));
+ const QuicPacketNumberLength largest_acked_length = ReadAckPacketNumberLength(
+ quic_version_, ExtractBits(frame_type, kQuicSequenceNumberLengthNumBits,
+ kLargestAckedOffset));
if (!reader->ReadBytesToUInt64(largest_acked_length,
&ack_frame->largest_observed)) {
@@ -1210,9 +1344,9 @@ bool QuicFramer::ProcessAckFrame(QuicDataReader* reader,
QuicTime::Delta::FromMicroseconds(ack_delay_time_us);
}
- uint8_t num_ack_blocks = 0;
if (has_ack_blocks) {
- if (!reader->ReadUInt8(&num_ack_blocks)) {
+ if (quic_version_ <= QUIC_VERSION_39 &&
+ !reader->ReadUInt8(&num_ack_blocks)) {
set_detailed_error("Unable to read num of ack blocks.");
return false;
}
@@ -1223,9 +1357,20 @@ bool QuicFramer::ProcessAckFrame(QuicDataReader* reader,
set_detailed_error("Unable to read first ack block length.");
return false;
}
+
+ if (FLAGS_quic_reloadable_flag_sanitize_framer_addrange_input &&
+ first_block_length > ack_frame->largest_observed + 1) {
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_sanitize_framer_addrange_input, 1,
+ 2);
+ set_detailed_error(QuicStrCat("Underflow with first ack block length ",
+ first_block_length, " largest acked is ",
+ ack_frame->largest_observed + 1, ".")
+ .c_str());
+ return false;
+ }
QuicPacketNumber first_received =
ack_frame->largest_observed + 1 - first_block_length;
- ack_frame->packets.Add(first_received, ack_frame->largest_observed + 1);
+ ack_frame->packets.AddRange(first_received, ack_frame->largest_observed + 1);
if (num_ack_blocks > 0) {
for (size_t i = 0; i < num_ack_blocks; ++i) {
@@ -1239,29 +1384,41 @@ bool QuicFramer::ProcessAckFrame(QuicDataReader* reader,
set_detailed_error("Unable to ack block length.");
return false;
}
+ if (FLAGS_quic_reloadable_flag_sanitize_framer_addrange_input &&
+ first_received < gap + current_block_length) {
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_sanitize_framer_addrange_input,
+ 2, 2);
+ set_detailed_error(
+ QuicStrCat("Underflow with ack block length ", current_block_length,
+ ", end of block is ", first_received - gap, ".")
+ .c_str());
+ return false;
+ }
+
first_received -= (gap + current_block_length);
if (current_block_length > 0) {
- ack_frame->packets.Add(first_received,
- first_received + current_block_length);
+ ack_frame->packets.AddRange(first_received,
+ first_received + current_block_length);
}
}
}
- if (!ProcessTimestampsInAckFrame(reader, ack_frame)) {
+ if (quic_version_ <= QUIC_VERSION_39 &&
+ !reader->ReadUInt8(&num_received_packets)) {
+ set_detailed_error("Unable to read num received packets.");
+ return false;
+ }
+
+ if (!ProcessTimestampsInAckFrame(num_received_packets, reader, ack_frame)) {
return false;
}
return true;
}
-bool QuicFramer::ProcessTimestampsInAckFrame(QuicDataReader* reader,
+bool QuicFramer::ProcessTimestampsInAckFrame(uint8_t num_received_packets,
+ QuicDataReader* reader,
QuicAckFrame* ack_frame) {
- uint8_t num_received_packets;
- if (!reader->ReadUInt8(&num_received_packets)) {
- set_detailed_error("Unable to read num received packets.");
- return false;
- }
-
if (num_received_packets > 0) {
uint8_t delta_from_largest_observed;
if (!reader->ReadUInt8(&delta_from_largest_observed)) {
@@ -1334,9 +1491,11 @@ bool QuicFramer::ProcessRstStreamFrame(QuicDataReader* reader,
return false;
}
- if (!reader->ReadUInt64(&frame->byte_offset)) {
- set_detailed_error("Unable to read rst stream sent byte offset.");
- return false;
+ if (quic_version_ <= QUIC_VERSION_39) {
+ if (!reader->ReadUInt64(&frame->byte_offset)) {
+ set_detailed_error("Unable to read rst stream sent byte offset.");
+ return false;
+ }
}
uint32_t error_code;
@@ -1351,6 +1510,14 @@ bool QuicFramer::ProcessRstStreamFrame(QuicDataReader* reader,
}
frame->error_code = static_cast<QuicRstStreamErrorCode>(error_code);
+
+ if (quic_version_ > QUIC_VERSION_39) {
+ if (!reader->ReadUInt64(&frame->byte_offset)) {
+ set_detailed_error("Unable to read rst stream sent byte offset.");
+ return false;
+ }
+ }
+
return true;
}
@@ -1642,9 +1809,9 @@ size_t QuicFramer::GetAckFrameSize(
AckFrameInfo ack_info = GetAckFrameInfo(ack);
QuicPacketNumberLength largest_acked_length =
- GetMinPacketNumberLength(ack.largest_observed);
+ GetMinPacketNumberLength(quic_version_, ack.largest_observed);
QuicPacketNumberLength ack_block_length =
- GetMinPacketNumberLength(ack_info.max_block_length);
+ GetMinPacketNumberLength(quic_version_, ack_info.max_block_length);
ack_size = GetMinAckFrameSize(quic_version_, largest_acked_length);
// First ack block length.
@@ -1667,7 +1834,7 @@ size_t QuicFramer::ComputeFrameLength(
QuicPacketNumberLength packet_number_length) {
switch (frame.type) {
case STREAM_FRAME:
- return GetMinStreamFrameSize(frame.stream_frame->stream_id,
+ return GetMinStreamFrameSize(quic_version_, frame.stream_frame->stream_id,
frame.stream_frame->offset,
last_frame_in_packet) +
frame.stream_frame->data_length;
@@ -1714,24 +1881,62 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame,
if (frame.stream_frame == nullptr) {
QUIC_BUG << "Failed to append STREAM frame with no stream_frame.";
}
- // Fin bit.
- type_byte |= frame.stream_frame->fin ? kQuicStreamFinMask : 0;
-
- // Data Length bit.
- type_byte <<= kQuicStreamDataLengthShift;
- type_byte |= no_stream_frame_length ? 0 : kQuicStreamDataLengthMask;
-
- // Offset 3 bits.
- type_byte <<= kQuicStreamOffsetShift;
- const size_t offset_len = GetStreamOffsetSize(frame.stream_frame->offset);
- if (offset_len > 0) {
- type_byte |= offset_len - 1;
- }
+ if (quic_version_ < QUIC_VERSION_40) {
+ // Fin bit.
+ type_byte |= frame.stream_frame->fin ? kQuicStreamFinMask_Pre40 : 0;
+
+ // Data Length bit.
+ type_byte <<= kQuicStreamDataLengthShift_Pre40;
+ type_byte |=
+ no_stream_frame_length ? 0 : kQuicStreamDataLengthMask_Pre40;
+
+ // Offset 3 bits.
+ type_byte <<= kQuicStreamShift_Pre40;
+ const size_t offset_len =
+ GetStreamOffsetSize(quic_version_, frame.stream_frame->offset);
+ if (offset_len > 0) {
+ type_byte |= offset_len - 1;
+ }
+
+ // stream id 2 bits.
+ type_byte <<= kQuicStreamIdShift_Pre40;
+ type_byte |= GetStreamIdSize(frame.stream_frame->stream_id) - 1;
+ type_byte |=
+ kQuicFrameTypeStreamMask_Pre40; // Set Stream Frame Type to 1.
+ } else {
+ // Fin bit.
+ SetBit(&type_byte, frame.stream_frame->fin, kQuicStreamFinShift);
+
+ // Data Length bit.
+ SetBit(&type_byte, !no_stream_frame_length, kQuicStreamDataLengthShift);
+
+ // Offset 2 bits.
+ uint8_t offset_len_encode = 3;
+ switch (
+ GetStreamOffsetSize(quic_version_, frame.stream_frame->offset)) {
+ case 0:
+ offset_len_encode = 0;
+ break;
+ case 2:
+ offset_len_encode = 1;
+ break;
+ case 4:
+ offset_len_encode = 2;
+ break;
+ case 8:
+ offset_len_encode = 3;
+ break;
+ default:
+ QUIC_BUG << "Invalid offset_length.";
+ }
+ SetBits(&type_byte, offset_len_encode, kQuicStreamOffsetNumBits,
+ kQuicStreamOffsetShift);
- // stream id 2 bits.
- type_byte <<= kQuicStreamIdShift;
- type_byte |= GetStreamIdSize(frame.stream_frame->stream_id) - 1;
- type_byte |= kQuicFrameTypeStreamMask; // Set Stream Frame Type to 1.
+ // stream id 2 bits.
+ SetBits(&type_byte, GetStreamIdSize(frame.stream_frame->stream_id) - 1,
+ kQuicStreamIDLengthNumBits, kQuicStreamIDLengthShift);
+ type_byte |= kQuicFrameTypeStreamMask; // Set Stream Frame Type to 1.
+ }
break;
}
case ACK_FRAME:
@@ -1752,7 +1957,7 @@ bool QuicFramer::AppendPacketNumber(QuicPacketNumberLength packet_number_length,
QuicPacketNumber packet_number,
QuicDataWriter* writer) {
size_t length = packet_number_length;
- if (length != 1 && length != 2 && length != 4 && length != 6) {
+ if (length != 1 && length != 2 && length != 4 && length != 6 && length != 8) {
QUIC_BUG << "Invalid packet_number_length: " << length;
return false;
}
@@ -1794,17 +1999,24 @@ bool QuicFramer::AppendAckBlock(uint8_t gap,
bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame,
bool no_stream_frame_length,
QuicDataWriter* writer) {
+ if (!no_stream_frame_length && quic_version_ > QUIC_VERSION_39) {
+ if ((frame.data_length > std::numeric_limits<uint16_t>::max()) ||
+ !writer->WriteUInt16(static_cast<uint16_t>(frame.data_length))) {
+ QUIC_BUG << "Writing stream frame length failed";
+ return false;
+ }
+ }
if (!AppendStreamId(GetStreamIdSize(frame.stream_id), frame.stream_id,
writer)) {
QUIC_BUG << "Writing stream id size failed.";
return false;
}
- if (!AppendStreamOffset(GetStreamOffsetSize(frame.offset), frame.offset,
- writer)) {
+ if (!AppendStreamOffset(GetStreamOffsetSize(quic_version_, frame.offset),
+ frame.offset, writer)) {
QUIC_BUG << "Writing offset size failed.";
return false;
}
- if (!no_stream_frame_length) {
+ if (!no_stream_frame_length && quic_version_ <= QUIC_VERSION_39) {
if ((frame.data_length > std::numeric_limits<uint16_t>::max()) ||
!writer->WriteUInt16(static_cast<uint16_t>(frame.data_length))) {
QUIC_BUG << "Writing stream frame length failed";
@@ -1842,9 +2054,9 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame,
const AckFrameInfo new_ack_info = GetAckFrameInfo(frame);
QuicPacketNumber largest_acked = frame.largest_observed;
QuicPacketNumberLength largest_acked_length =
- GetMinPacketNumberLength(largest_acked);
+ GetMinPacketNumberLength(quic_version_, largest_acked);
QuicPacketNumberLength ack_block_length =
- GetMinPacketNumberLength(new_ack_info.max_block_length);
+ GetMinPacketNumberLength(quic_version_, new_ack_info.max_block_length);
// Calculate available bytes for timestamps and ack blocks.
int32_t available_timestamp_and_ack_block_bytes =
writer->capacity() - writer->length() - ack_block_length -
@@ -1855,24 +2067,52 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame,
// Write out the type byte by setting the low order bits and doing shifts
// to make room for the next bit flags to be set.
// Whether there are multiple ack blocks.
- uint8_t type_byte =
- new_ack_info.num_ack_blocks == 0 ? 0 : kQuicHasMultipleAckBlocksMask;
- type_byte <<= kQuicHasMultipleAckBlocksShift;
+ uint8_t type_byte = 0;
+ SetBit(&type_byte, new_ack_info.num_ack_blocks != 0,
+ quic_version_ < QUIC_VERSION_40 ? kQuicHasMultipleAckBlocksOffset_Pre40
+ : kQuicHasMultipleAckBlocksOffset);
- // Largest acked length.
- type_byte <<= kQuicSequenceNumberLengthShift;
- type_byte |= GetPacketNumberFlags(largest_acked_length);
+ SetBits(&type_byte, GetPacketNumberFlags(largest_acked_length),
+ kQuicSequenceNumberLengthNumBits, kLargestAckedOffset);
- // Ack block length.
- type_byte <<= kQuicSequenceNumberLengthShift;
- type_byte |= GetPacketNumberFlags(ack_block_length);
+ SetBits(&type_byte, GetPacketNumberFlags(ack_block_length),
+ kQuicSequenceNumberLengthNumBits, kActBlockLengthOffset);
- type_byte |= kQuicFrameTypeAckMask;
+ if (quic_version_ < QUIC_VERSION_40) {
+ type_byte |= kQuicFrameTypeAckMask_Pre40;
+ } else {
+ type_byte |= kQuicFrameTypeAckMask;
+ }
if (!writer->WriteUInt8(type_byte)) {
return false;
}
+ size_t num_timestamps_offset = 0;
+ size_t max_num_ack_blocks = available_timestamp_and_ack_block_bytes /
+ (ack_block_length + PACKET_1BYTE_PACKET_NUMBER);
+
+ // Number of ack blocks.
+ size_t num_ack_blocks =
+ std::min(new_ack_info.num_ack_blocks, max_num_ack_blocks);
+ if (num_ack_blocks > std::numeric_limits<uint8_t>::max()) {
+ num_ack_blocks = std::numeric_limits<uint8_t>::max();
+ }
+
+ if (quic_version_ > QUIC_VERSION_39) {
+ if (num_ack_blocks > 0 && !writer->WriteBytes(&num_ack_blocks, 1)) {
+ return false;
+ }
+
+ // Write a placeholder for the number of timestamps which will be
+ // overwritten after the ack blocks have been written.
+ num_timestamps_offset = writer->length();
+ uint8_t num_timestamps = 0;
+ if (!writer->WriteUInt8(num_timestamps)) {
+ return false;
+ }
+ }
+
// Largest acked.
if (!AppendPacketNumber(largest_acked_length, largest_acked, writer)) {
return false;
@@ -1888,19 +2128,11 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame,
return false;
}
- size_t max_num_ack_blocks = available_timestamp_and_ack_block_bytes /
- (ack_block_length + PACKET_1BYTE_PACKET_NUMBER);
-
- // Number of ack blocks.
- size_t num_ack_blocks =
- std::min(new_ack_info.num_ack_blocks, max_num_ack_blocks);
- if (num_ack_blocks > std::numeric_limits<uint8_t>::max()) {
- num_ack_blocks = std::numeric_limits<uint8_t>::max();
- }
-
- if (num_ack_blocks > 0) {
- if (!writer->WriteBytes(&num_ack_blocks, 1)) {
- return false;
+ if (quic_version_ <= QUIC_VERSION_39) {
+ if (num_ack_blocks > 0) {
+ if (!writer->WriteBytes(&num_ack_blocks, 1)) {
+ return false;
+ }
}
}
@@ -1971,7 +2203,7 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame,
// append any of them.
if (writer->capacity() - writer->length() >=
GetAckFrameTimeStampSize(frame)) {
- if (!AppendTimestampToAckFrame(frame, writer)) {
+ if (!AppendTimestampsToAckFrame(frame, num_timestamps_offset, writer)) {
return false;
}
} else {
@@ -1984,8 +2216,9 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame,
return true;
}
-bool QuicFramer::AppendTimestampToAckFrame(const QuicAckFrame& frame,
- QuicDataWriter* writer) {
+bool QuicFramer::AppendTimestampsToAckFrame(const QuicAckFrame& frame,
+ size_t num_timestamps_offset,
+ QuicDataWriter* writer) {
DCHECK_GE(std::numeric_limits<uint8_t>::max(),
frame.received_packet_times.size());
// num_received_packets is only 1 byte.
@@ -1995,8 +2228,15 @@ bool QuicFramer::AppendTimestampToAckFrame(const QuicAckFrame& frame,
}
uint8_t num_received_packets = frame.received_packet_times.size();
- if (!writer->WriteBytes(&num_received_packets, 1)) {
- return false;
+ if (quic_version_ <= QUIC_VERSION_39) {
+ if (!writer->WriteBytes(&num_received_packets, 1)) {
+ return false;
+ }
+ } else {
+ if (!writer->WriteUInt8AtOffset(num_received_packets,
+ num_timestamps_offset)) {
+ return false;
+ }
}
if (num_received_packets == 0) {
return true;
@@ -2081,8 +2321,10 @@ bool QuicFramer::AppendRstStreamFrame(const QuicRstStreamFrame& frame,
return false;
}
- if (!writer->WriteUInt64(frame.byte_offset)) {
- return false;
+ if (quic_version_ <= QUIC_VERSION_39) {
+ if (!writer->WriteUInt64(frame.byte_offset)) {
+ return false;
+ }
}
uint32_t error_code = static_cast<uint32_t>(frame.error_code);
@@ -2090,6 +2332,12 @@ bool QuicFramer::AppendRstStreamFrame(const QuicRstStreamFrame& frame,
return false;
}
+ if (quic_version_ > QUIC_VERSION_39) {
+ if (!writer->WriteUInt64(frame.byte_offset)) {
+ return false;
+ }
+ }
+
return true;
}
@@ -2174,15 +2422,22 @@ Endianness QuicFramer::endianness() const {
return quic_version_ > QUIC_VERSION_38 ? NETWORK_BYTE_ORDER : HOST_BYTE_ORDER;
}
-void QuicFramer::SaveStreamData(QuicStreamId id,
- QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- QuicByteCount data_length) {
- DCHECK_NE(nullptr, data_producer_);
- if (data_producer_ != nullptr) {
- data_producer_->SaveStreamData(id, iov, iov_offset, offset, data_length);
+bool QuicFramer::StartsWithChlo(QuicStreamId id,
+ QuicStreamOffset offset) const {
+ if (data_producer_ == nullptr) {
+ QUIC_BUG << "Does not have data producer.";
+ return false;
+ }
+ char buf[sizeof(kCHLO)];
+ QuicDataWriter writer(sizeof(kCHLO), buf, perspective_, endianness());
+ if (!data_producer_->WriteStreamData(id, offset, sizeof(kCHLO), &writer)) {
+ QUIC_BUG << "Failed to write data for stream " << id << " with offset "
+ << offset << " data_length = " << sizeof(kCHLO);
+ return false;
}
+
+ return strncmp(buf, reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) ==
+ 0;
}
} // namespace net
diff --git a/chromium/net/quic/core/quic_framer.h b/chromium/net/quic/core/quic_framer.h
index 652f4128125..513505e1142 100644
--- a/chromium/net/quic/core/quic_framer.h
+++ b/chromium/net/quic/core/quic_framer.h
@@ -188,7 +188,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
bool ProcessPacket(const QuicEncryptedPacket& packet);
// Largest size in bytes of all stream frame fields without the payload.
- static size_t GetMinStreamFrameSize(QuicStreamId stream_id,
+ static size_t GetMinStreamFrameSize(QuicVersion version,
+ QuicStreamId stream_id,
QuicStreamOffset offset,
bool last_frame_in_packet);
// Size in bytes of all ack frame fields without the missing packets or ack
@@ -214,7 +215,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// Size in bytes required to serialize the stream id.
static size_t GetStreamIdSize(QuicStreamId stream_id);
// Size in bytes required to serialize the stream offset.
- static size_t GetStreamOffsetSize(QuicStreamOffset offset);
+ static size_t GetStreamOffsetSize(QuicVersion version,
+ QuicStreamOffset offset);
// Size in bytes required for a serialized version negotiation packet
static size_t GetVersionNegotiationPacketSize(size_t number_versions);
@@ -324,6 +326,7 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// The minimum packet number length required to represent |packet_number|.
static QuicPacketNumberLength GetMinPacketNumberLength(
+ QuicVersion version,
QuicPacketNumber packet_number);
void SetSupportedVersions(const QuicVersionVector& versions) {
@@ -334,6 +337,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// Returns true if data_producer_ is not null.
bool HasDataProducer() const { return data_producer_ != nullptr; }
+ // Returns true if data with |offset| of stream |id| starts with 'CHLO'.
+ bool StartsWithChlo(QuicStreamId id, QuicStreamOffset offset) const;
+
// Returns byte order to read/write integers and floating numbers.
Endianness endianness() const;
@@ -400,7 +406,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
bool ProcessAckFrame(QuicDataReader* reader,
uint8_t frame_type,
QuicAckFrame* frame);
- bool ProcessTimestampsInAckFrame(QuicDataReader* reader, QuicAckFrame* frame);
+ bool ProcessTimestampsInAckFrame(uint8_t num_received_packets,
+ QuicDataReader* reader,
+ QuicAckFrame* ack_frame);
bool ProcessStopWaitingFrame(QuicDataReader* reader,
const QuicPacketHeader& public_header,
QuicStopWaitingFrame* stop_waiting);
@@ -477,8 +485,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
bool AppendAckFrameAndTypeByte(const QuicAckFrame& frame,
QuicDataWriter* builder);
- bool AppendTimestampToAckFrame(const QuicAckFrame& frame,
- QuicDataWriter* builder);
+ bool AppendTimestampsToAckFrame(const QuicAckFrame& frame,
+ size_t num_timestamps_offset,
+ QuicDataWriter* writer);
bool AppendStopWaitingFrame(const QuicPacketHeader& header,
const QuicStopWaitingFrame& frame,
QuicDataWriter* builder);
@@ -546,8 +555,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// The diversification nonce from the last received packet.
DiversificationNonce last_nonce_;
- // If not null, framer asks data_producer_ to save and write stream frame
- // data. Not owned.
+ // If not null, framer asks data_producer_ to write stream frame data. Not
+ // owned.
QuicStreamFrameDataProducer* data_producer_;
DISALLOW_COPY_AND_ASSIGN(QuicFramer);
diff --git a/chromium/net/quic/core/quic_framer_test.cc b/chromium/net/quic/core/quic_framer_test.cc
index 34337faac80..1ba37a9fe7d 100644
--- a/chromium/net/quic/core/quic_framer_test.cc
+++ b/chromium/net/quic/core/quic_framer_test.cc
@@ -23,6 +23,7 @@
#include "net/quic/platform/api/quic_test.h"
#include "net/quic/test_tools/quic_framer_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simple_data_producer.h"
using std::string;
using testing::Return;
@@ -397,13 +398,27 @@ class QuicFramerTest : public QuicTestWithParam<QuicVersion> {
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < GetMinStreamFrameSize(); ++i) {
string expected_error;
- if (i < kQuicFrameTypeSize + stream_id_size) {
- expected_error = "Unable to read stream_id.";
- } else if (i < kQuicFrameTypeSize + stream_id_size +
- kQuicMaxStreamOffsetSize) {
- expected_error = "Unable to read offset.";
+ if (framer_.version() <= QUIC_VERSION_39) {
+ if (i < kQuicFrameTypeSize + stream_id_size) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size +
+ kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read offset.";
+ } else {
+ expected_error = "Unable to read frame data.";
+ }
} else {
- expected_error = "Unable to read frame data.";
+ const size_t kQuicDataLenSize = sizeof(uint16_t);
+ if (i < kQuicFrameTypeSize + kQuicDataLenSize) {
+ expected_error = "Unable to read data length.";
+ } else if (i < kQuicFrameTypeSize + kQuicDataLenSize + stream_id_size) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + kQuicDataLenSize + stream_id_size +
+ kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read offset.";
+ } else {
+ expected_error = "Unable to read frame data.";
+ }
}
CheckProcessingFails(
packet, i + GetPacketHeaderSize(
@@ -1176,15 +1191,47 @@ TEST_P(QuicFramerTest, NewPaddingFrame) {
// paddings
0x00, 0x00,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // paddings
+ 0x00, 0x00,
+ // frame type (stream frame with fin)
+ 0xFF,
+ // data length
+ 0x00, 0x0c,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ // paddings
+ 0x00, 0x00,
+ };
// clang-format on
if (framer_.version() <= QUIC_VERSION_37) {
return;
}
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
@@ -1251,11 +1298,39 @@ TEST_P(QuicFramerTest, StreamFrame) {
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // data length
+ 0x00, 0x0c,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1331,11 +1406,39 @@ TEST_P(QuicFramerTest, MissingDiversificationNonce) {
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ 0x00, 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error());
}
@@ -1389,11 +1492,40 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
+
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (stream frame with fin)
+ 0xF7,
+ // data length
+ 0x00, 0x0c,
+ // stream id
+ 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1411,9 +1543,7 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
// Now test framing boundaries.
const size_t stream_id_size = 3;
- CheckStreamFrameBoundaries(
- framer_.version() <= QUIC_VERSION_38 ? packet : packet39, stream_id_size,
- !kIncludeVersion);
+ CheckStreamFrameBoundaries(p, stream_id_size, !kIncludeVersion);
}
TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
@@ -1442,34 +1572,62 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
'r', 'l', 'd', '!',
};
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
- 0x9A, 0xBC,
+ unsigned char packet39[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
- // frame type (stream frame with fin)
- 0xFD,
- // stream id
- 0x03, 0x04,
- // offset
- 0xBA, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54,
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
+ // frame type (stream frame with fin)
+ 0xFD,
+ // stream id
+ 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ 0x00, 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (stream frame with fin)
+ 0xEF,
+ // data length
+ 0x00, 0x0c,
+ // stream id
+ 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1487,9 +1645,7 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
// Now test framing boundaries.
const size_t stream_id_size = 2;
- CheckStreamFrameBoundaries(
- framer_.version() <= QUIC_VERSION_38 ? packet : packet39, stream_id_size,
- !kIncludeVersion);
+ CheckStreamFrameBoundaries(p, stream_id_size, !kIncludeVersion);
}
TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
@@ -1518,34 +1674,62 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
'r', 'l', 'd', '!',
};
- unsigned char packet39[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // packet number
- 0x12, 0x34, 0x56, 0x78,
- 0x9A, 0xBC,
+ unsigned char packet39[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
- // frame type (stream frame with fin)
- 0xFC,
- // stream id
- 0x04,
- // offset
- 0xBA, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54,
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
+ // frame type (stream frame with fin)
+ 0xFC,
+ // stream id
+ 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ 0x00, 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (stream frame with fin)
+ 0xE7,
+ // data length
+ 0x00, 0x0c,
+ // stream id
+ 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1563,9 +1747,7 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
// Now test framing boundaries.
const size_t stream_id_size = 1;
- CheckStreamFrameBoundaries(
- framer_.version() <= QUIC_VERSION_38 ? packet : packet39, stream_id_size,
- !kIncludeVersion);
+ CheckStreamFrameBoundaries(p, stream_id_size, !kIncludeVersion);
}
TEST_P(QuicFramerTest, StreamFrameWithVersion) {
@@ -1596,36 +1778,66 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
'r', 'l', 'd', '!',
};
- unsigned char packet39[] = {
- // public flags (version, 8 byte connection_id)
- 0x39,
- // connection_id
- 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // packet number
- 0x12, 0x34, 0x56, 0x78,
- 0x9A, 0xBC,
+ unsigned char packet39[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x39,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x01, 0x02, 0x03, 0x04,
- // offset
- 0xBA, 0x98, 0xFE, 0xDC,
- 0x32, 0x10, 0x76, 0x54,
- // data length
- 0x00, 0x0c,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ 0x00, 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ unsigned char packet40[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x39,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // data length
+ 0x00, 0x0c,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1699,11 +1911,39 @@ TEST_P(QuicFramerTest, RejectPacket) {
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ 0x00, 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1778,10 +2018,37 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) {
// num timestamps.
0x00,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (one ack block, 2 byte largest observed, 2 byte block length)
+ 0xA5,
+ // num timestamps.
+ 0x00,
+ // largest acked
+ 0x12, 0x34,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x12, 0x34,
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1807,17 +2074,267 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) {
kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
- if (i < kLargestAckedDeltaTimeOffset) {
- expected_error = "Unable to read largest acked.";
- } else if (i < kFirstAckBlockLengthOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to read first ack block length.";
+ if (framer_.version() > QUIC_VERSION_39) {
+ if (i < 2) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < 2 + PACKET_2BYTE_PACKET_NUMBER) {
+ expected_error = "Unable to read largest acked.";
+ } else if (i < 2 + PACKET_2BYTE_PACKET_NUMBER +
+ kQuicDeltaTimeLargestObservedSize) {
+ expected_error = "Unable to read ack delay time.";
+ } else {
+ expected_error = "Unable to read first ack block length.";
+ }
+ } else {
+ if (i < kLargestAckedDeltaTimeOffset) {
+ expected_error = "Unable to read largest acked.";
+ } else if (i < kFirstAckBlockLengthOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read first ack block length.";
+ } else {
+ expected_error = "Unable to read num received packets.";
+ }
+ }
+ CheckProcessingFails(
+ p,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+TEST_P(QuicFramerTest, FirstAckFrameUnderflow) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (ack frame)
+ // (one ack block, 2 byte largest observed, 2 byte block length)
+ 0x45,
+ // largest acked
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x88, 0x88,
+ // num timestamps.
+ 0x00,
+ };
+
+ unsigned char packet39[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (one ack block, 2 byte largest observed, 2 byte block length)
+ 0x45,
+ // largest acked
+ 0x12, 0x34,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x88, 0x88,
+ // num timestamps.
+ 0x00,
+ };
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (one ack block, 2 byte largest observed, 2 byte block length)
+ 0xA5,
+ // num timestamps.
+ 0x00,
+ // largest acked
+ 0x12, 0x34,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x88, 0x88,
+ };
+ // clang-format on
+
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
+ framer_.ProcessPacket(encrypted);
+
+ visitor_.header_.get();
+
+ const size_t kLargestAckedOffset = kQuicFrameTypeSize;
+ const size_t kLargestAckedDeltaTimeOffset =
+ kLargestAckedOffset + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kFirstAckBlockLengthOffset =
+ kLargestAckedDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ // Now test framing boundaries.
+ const size_t ack_frame_size =
+ kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
+ string expected_error;
+ if (framer_.version() <= QUIC_VERSION_39) {
+ if (FLAGS_quic_reloadable_flag_sanitize_framer_addrange_input) {
+ expected_error =
+ "Underflow with first ack block length 34952 largest acked is "
+ "4661.";
} else {
expected_error = "Unable to read num received packets.";
}
CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_38 ? packet : packet39,
+ p,
+ ack_frame_size +
+ GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (ack frame)
+ // (one ack block, 6 byte largest observed, 2 byte block length)
+ 0x4D,
+ // largest acked
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x34, 0x12,
+ // num timestamps.
+ 0x00,
+ };
+
+ unsigned char packet39[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (one ack block, 6 byte largest observed, 2 byte block length)
+ 0x4D,
+ // largest acked
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x12, 0x34,
+ // num timestamps.
+ 0x00,
+ };
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (one ack block, 8 byte largest observed, 2 byte block length)
+ 0xAD,
+ // num timestamps.
+ 0x00,
+ // largest acked
+ 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x12, 0x34
+ };
+ // clang-format on
+
+ unsigned char* p = packet;
+ size_t packet_size = arraysize(packet);
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ packet_size = arraysize(packet40);
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ packet_size = arraysize(packet39);
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(p), packet_size, false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(kPacketNumber, frame.largest_observed);
+ ASSERT_EQ(4660u, frame.packets.NumPacketsSlow());
+
+ const size_t kLargestAckedOffset = kQuicFrameTypeSize;
+ const size_t kLargestAckedDeltaTimeOffset =
+ kLargestAckedOffset + PACKET_6BYTE_PACKET_NUMBER;
+ const size_t kFirstAckBlockLengthOffset =
+ kLargestAckedDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kNumTimestampsOffset =
+ kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
+ // Now test framing boundaries.
+ const size_t ack_frame_size =
+ kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (framer_.version() > QUIC_VERSION_39) {
+ if (i < 2) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < 2 + PACKET_8BYTE_PACKET_NUMBER) {
+ expected_error = "Unable to read largest acked.";
+ } else if (i < 2 + PACKET_8BYTE_PACKET_NUMBER +
+ kQuicDeltaTimeLargestObservedSize) {
+ expected_error = "Unable to read ack delay time.";
+ } else {
+ expected_error = "Unable to read first ack block length.";
+ }
+ } else {
+ if (i < kLargestAckedDeltaTimeOffset) {
+ expected_error = "Unable to read largest acked.";
+ } else if (i < kFirstAckBlockLengthOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read first ack block length.";
+ } else {
+ expected_error = "Unable to read num received packets.";
+ }
+ }
+ CheckProcessingFails(
+ p,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
@@ -1920,10 +2437,61 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) {
// Delta time.
0x32, 0x10,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (more than one ack block, 2 byte largest observed, 2 byte block length)
+ 0xB5,
+ // num ack blocks ranges.
+ 0x04,
+ // Number of timestamps.
+ 0x02,
+ // largest acked
+ 0x12, 0x34,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x00, 0x01,
+ // gap to next block.
+ 0x01,
+ // ack block length.
+ 0x0e, 0xaf,
+ // gap to next block.
+ 0xff,
+ // ack block length.
+ 0x00, 0x00,
+ // gap to next block.
+ 0x91,
+ // ack block length.
+ 0x01, 0xea,
+ // gap to next block.
+ 0x05,
+ // ack block length.
+ 0x00, 0x04,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x76, 0x54, 0x32, 0x10,
+ // Delta from largest observed.
+ 0x02,
+ // Delta time.
+ 0x32, 0x10,
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1936,6 +2504,7 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) {
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(kSmallLargestObserved, frame.largest_observed);
ASSERT_EQ(4254u, frame.packets.NumPacketsSlow());
+ EXPECT_EQ(4u, frame.packets.NumIntervals());
const size_t kLargestAckedOffset = kQuicFrameTypeSize;
const size_t kLargestAckedDeltaTimeOffset =
@@ -1972,45 +2541,113 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) {
kAckBlockLengthOffset4 + PACKET_2BYTE_PACKET_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
string expected_error;
- if (i < kLargestAckedDeltaTimeOffset) {
- expected_error = "Unable to read largest acked.";
- } else if (i < kNumberOfAckBlocksOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kFirstAckBlockLengthOffset) {
- expected_error = "Unable to read num of ack blocks.";
- } else if (i < kGapToNextBlockOffset1) {
- expected_error = "Unable to read first ack block length.";
- } else if (i < kAckBlockLengthOffset1) {
- expected_error = "Unable to read gap to next ack block.";
- } else if (i < kGapToNextBlockOffset2) {
- expected_error = "Unable to ack block length.";
- } else if (i < kAckBlockLengthOffset2) {
- expected_error = "Unable to read gap to next ack block.";
- } else if (i < kGapToNextBlockOffset3) {
- expected_error = "Unable to ack block length.";
- } else if (i < kAckBlockLengthOffset3) {
- expected_error = "Unable to read gap to next ack block.";
- } else if (i < kGapToNextBlockOffset4) {
- expected_error = "Unable to ack block length.";
- } else if (i < kAckBlockLengthOffset4) {
- expected_error = "Unable to read gap to next ack block.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to ack block length.";
- } else if (i < kTimestampDeltaLargestObserved1) {
- expected_error = "Unable to read num received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved1) {
- expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < kTimestampDeltaLargestObserved2) {
- expected_error = "Unable to read time delta in received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved2) {
- expected_error = "Unable to read sequence delta in received packets.";
+ if (framer_.version() <= QUIC_VERSION_39) {
+ if (i < kLargestAckedDeltaTimeOffset) {
+ expected_error = "Unable to read largest acked.";
+ } else if (i < kNumberOfAckBlocksOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kFirstAckBlockLengthOffset) {
+ expected_error = "Unable to read num of ack blocks.";
+ } else if (i < kGapToNextBlockOffset1) {
+ expected_error = "Unable to read first ack block length.";
+ } else if (i < kAckBlockLengthOffset1) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kGapToNextBlockOffset2) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kAckBlockLengthOffset2) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kGapToNextBlockOffset3) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kAckBlockLengthOffset3) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kGapToNextBlockOffset4) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kAckBlockLengthOffset4) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kTimestampDeltaLargestObserved1) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved1) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kTimestampDeltaLargestObserved2) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved2) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else {
+ expected_error =
+ "Unable to read incremental time delta in received packets.";
+ }
} else {
- expected_error =
- "Unable to read incremental time delta in received packets.";
+ const size_t kNumberOfAckBlocksOffset = kQuicFrameTypeSize;
+ const size_t kNumTimestampsOffset = kNumberOfAckBlocksOffset + 1;
+ const size_t kLargestAckedOffset = kNumTimestampsOffset + 1;
+ const size_t kLargestAckedDeltaTimeOffset =
+ kLargestAckedOffset + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kFirstAckBlockLengthOffset =
+ kLargestAckedDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kGapToNextBlockOffset1 =
+ kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kAckBlockLengthOffset1 = kGapToNextBlockOffset1 + 1;
+ const size_t kGapToNextBlockOffset2 =
+ kAckBlockLengthOffset1 + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kAckBlockLengthOffset2 = kGapToNextBlockOffset2 + 1;
+ const size_t kGapToNextBlockOffset3 =
+ kAckBlockLengthOffset2 + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kAckBlockLengthOffset3 = kGapToNextBlockOffset3 + 1;
+ const size_t kGapToNextBlockOffset4 =
+ kAckBlockLengthOffset3 + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kAckBlockLengthOffset4 = kGapToNextBlockOffset3 + 1;
+ const size_t kTimestampDeltaLargestObserved1 =
+ kNumTimestampsOffset + kQuicNumTimestampsSize;
+ const size_t kTimestampTimeDeltaLargestObserved1 =
+ kTimestampDeltaLargestObserved1 + 1;
+ const size_t kTimestampDeltaLargestObserved2 =
+ kTimestampTimeDeltaLargestObserved1 + 4;
+ const size_t kTimestampTimeDeltaLargestObserved2 =
+ kTimestampDeltaLargestObserved2 + 1;
+ if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read num of ack blocks.";
+ } else if (i < kLargestAckedOffset) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kLargestAckedDeltaTimeOffset) {
+ expected_error = "Unable to read largest acked.";
+ } else if (i < kFirstAckBlockLengthOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kGapToNextBlockOffset1) {
+ expected_error = "Unable to read first ack block length.";
+ } else if (i < kAckBlockLengthOffset1) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kGapToNextBlockOffset2) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kAckBlockLengthOffset2) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kGapToNextBlockOffset3) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kAckBlockLengthOffset3) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kGapToNextBlockOffset4) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kAckBlockLengthOffset4) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kTimestampDeltaLargestObserved1) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved1) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kTimestampDeltaLargestObserved2) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved2) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else {
+ expected_error =
+ "Unable to read incremental time delta in received packets.";
+ }
}
CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_38 ? packet : packet39,
+ p,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
@@ -2165,11 +2802,37 @@ TEST_P(QuicFramerTest, RstStreamFrameQuic) {
// error code
0x00, 0x00, 0x00, 0x01,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (rst stream frame)
+ 0x01,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+
+ // error code
+ 0x00, 0x00, 0x00, 0x01,
+
+ // sent byte offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ };
// clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -2185,17 +2848,29 @@ TEST_P(QuicFramerTest, RstStreamFrameQuic) {
for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetRstStreamFrameSize();
++i) {
string expected_error;
- if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
- expected_error = "Unable to read stream_id.";
- } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
- kQuicMaxStreamOffsetSize) {
- expected_error = "Unable to read rst stream sent byte offset.";
- } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
- kQuicMaxStreamOffsetSize + kQuicErrorCodeSize) {
- expected_error = "Unable to read rst stream error code.";
+ if (framer_.version() <= QUIC_VERSION_39) {
+ if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read rst stream sent byte offset.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicMaxStreamOffsetSize + kQuicErrorCodeSize) {
+ expected_error = "Unable to read rst stream error code.";
+ }
+ } else {
+ if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicErrorCodeSize) {
+ expected_error = "Unable to read rst stream error code.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicMaxStreamOffsetSize + kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read rst stream sent byte offset.";
+ }
}
CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_38 ? packet : packet39,
+ p,
i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, !kIncludeDiversificationNonce,
PACKET_6BYTE_PACKET_NUMBER),
@@ -2975,15 +3650,50 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) {
// paddings
0x00, 0x00,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // paddings
+ 0x00, 0x00,
+ // frame type (stream frame with fin)
+ 0xFF,
+ // data length
+ 0x00, 0x0c,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ // paddings
+ 0x00, 0x00,
+ };
// clang-format on
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet));
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(p),
+ arraysize(packet));
}
TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
@@ -3188,15 +3898,42 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) {
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (stream frame with fin and no length)
+ 0xFE,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
// clang-format on
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet));
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(p),
+ arraysize(packet));
}
TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
@@ -3252,16 +3989,42 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
// data
'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
};
+
+ unsigned char packet40[] = {
+ // public flags (version, 8 byte connection_id)
+ static_cast<unsigned char>(
+ FLAGS_quic_reloadable_flag_quic_remove_v33_hacks2 ? 0x39 : 0x3D),
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (stream frame with fin and no length)
+ 0xFE,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
+ };
// clang-format on
QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet));
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(p),
+ arraysize(packet));
}
TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
@@ -3296,7 +4059,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) {
QuicAckFrame ack_frame;
ack_frame.largest_observed = kSmallLargestObserved;
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- ack_frame.packets.Add(1, kSmallLargestObserved + 1);
+ ack_frame.packets.AddRange(1, kSmallLargestObserved + 1);
QuicFrames frames = {QuicFrame(&ack_frame)};
@@ -3342,15 +4105,135 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) {
// num timestamps.
0x00,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (no ack blocks, 2 byte largest observed, 2 byte block length)
+ 0xA5,
+ // num timestamps.
+ 0x00,
+ // largest acked
+ 0x12, 0x34,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x12, 0x34,
+ };
// clang-format on
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(p),
+ arraysize(packet));
+}
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet));
+TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicAckFrame ack_frame;
+ FLAGS_quic_reloadable_flag_quic_frames_deque2 = true;
+ ack_frame.largest_observed = kPacketNumber;
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ ack_frame.packets.AddRange(1, kPacketNumber + 1);
+
+ QuicFrames frames = {QuicFrame(&ack_frame)};
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (ack frame)
+ // (no ack blocks, 6 byte largest observed, 6 byte block length)
+ 0x4F,
+ // largest acked
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // num timestamps.
+ 0x00,
+ };
+
+ unsigned char packet39[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (no ack blocks, 6 byte largest observed, 6 byte block length)
+ 0x4F,
+ // largest acked
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+ // num timestamps.
+ 0x00,
+ };
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (no ack blocks, 8 byte largest observed, 8 byte block length)
+ 0xAF,
+ // num timestamps.
+ 0x00,
+ // largest acked
+ 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+ };
+ // clang-format on
+ unsigned char* p = packet;
+ size_t packet_size = arraysize(packet);
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ packet_size = arraysize(packet40);
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ packet_size = arraysize(packet39);
+ }
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(p), packet_size);
}
TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) {
@@ -3364,10 +4247,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) {
QuicAckFrame ack_frame;
ack_frame.largest_observed = kSmallLargestObserved;
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- ack_frame.packets.Add(1, 5);
- ack_frame.packets.Add(10, 500);
- ack_frame.packets.Add(900, kSmallMissingPacket);
- ack_frame.packets.Add(kSmallMissingPacket + 1, kSmallLargestObserved + 1);
+ ack_frame.packets.AddRange(1, 5);
+ ack_frame.packets.AddRange(10, 500);
+ ack_frame.packets.AddRange(900, kSmallMissingPacket);
+ ack_frame.packets.AddRange(kSmallMissingPacket + 1,
+ kSmallLargestObserved + 1);
QuicFrames frames = {QuicFrame(&ack_frame)};
@@ -3449,15 +4333,59 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) {
// num timestamps.
0x00,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+
+ // frame type (ack frame)
+ // (has ack blocks, 2 byte largest observed, 2 byte block length)
+ 0xB5,
+ // num ack blocks ranges.
+ 0x04,
+ // num timestamps.
+ 0x00,
+ // largest acked
+ 0x12, 0x34,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x00, 0x01,
+ // gap to next block.
+ 0x01,
+ // ack block length.
+ 0x0e, 0xaf,
+ // gap to next block.
+ 0xff,
+ // ack block length.
+ 0x00, 0x00,
+ // gap to next block.
+ 0x91,
+ // ack block length.
+ 0x01, 0xea,
+ // gap to next block.
+ 0x05,
+ // ack block length.
+ 0x00, 0x04,
+ };
// clang-format on
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet));
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(p),
+ arraysize(packet));
}
TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) {
@@ -3475,7 +4403,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) {
for (size_t i = 2; i < 2 * 300; i += 2) {
ack_frame.packets.Add(i);
}
- ack_frame.packets.Add(600, kSmallLargestObserved + 1);
+ ack_frame.packets.AddRange(600, kSmallLargestObserved + 1);
QuicFrames frames = {QuicFrame(&ack_frame)};
@@ -3665,15 +4593,113 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) {
// num timestamps.
0x00,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
+ // frame type (ack frame)
+ // (has ack blocks, 2 byte largest observed, 2 byte block length)
+ 0xB5,
+ // num ack blocks ranges.
+ 0xff,
+ // num timestamps.
+ 0x00,
+ // largest acked
+ 0x12, 0x34,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x0f, 0xdd,
+ // 255 = 4 * 63 + 3
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+ };
// clang-format on
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet));
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(p),
+ arraysize(packet));
}
TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) {
@@ -3781,6 +4807,26 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
// error code
0x05, 0x06, 0x07, 0x08,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (rst stream frame)
+ 0x01,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // error code
+ 0x05, 0x06, 0x07, 0x08,
+ // sent byte offset
+ 0x08, 0x07, 0x06, 0x05,
+ 0x04, 0x03, 0x02, 0x01,
+ };
// clang-format on
QuicFrames frames = {QuicFrame(&rst_frame)};
@@ -3788,10 +4834,17 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != nullptr);
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet));
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(p),
+ arraysize(packet));
}
TEST_P(QuicFramerTest, BuildCloseFramePacket) {
@@ -4435,7 +5488,7 @@ TEST_P(QuicFramerTest, CleanTruncation) {
QuicAckFrame ack_frame;
ack_frame.largest_observed = 201;
- ack_frame.packets.Add(1, ack_frame.largest_observed);
+ ack_frame.packets.AddRange(1, ack_frame.largest_observed);
// Create a packet with just the ack.
QuicFrames frames = {QuicFrame(&ack_frame)};
@@ -4542,6 +5595,45 @@ TEST_P(QuicFramerTest, StopPacketProcessing) {
0x12, 0x34, 0x56, 0x78,
0x9A, 0xBE,
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // data length
+ 0x00, 0x0c,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+
+ // frame type (ack frame)
+ 0xA0,
+ // least packet number awaiting an ack
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xA0,
+ // largest observed packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBF,
+ // num missing packets
+ 0x01,
+ // missing packet
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBE,
+ };
+
// clang-format on
MockFramerVisitor visitor;
@@ -4555,9 +5647,13 @@ TEST_P(QuicFramerTest, StopPacketProcessing) {
EXPECT_CALL(visitor, OnUnauthenticatedHeader(_)).WillOnce(Return(true));
EXPECT_CALL(visitor, OnDecryptedPacket(_));
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_38 ? packet : packet39),
- arraysize(packet), false);
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
}
@@ -4725,10 +5821,61 @@ TEST_P(QuicFramerTest, FramerFuzzTest) {
'o', ' ', 'w', 'o',
'r', 'l', 'd', '!',
};
+
+ unsigned char packet40[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ // packet number
+ 0x12, 0x34, 0x56, 0x78,
+ 0x9A, 0xBC,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x01, 0x02, 0x03, 0x04,
+ // offset
+ 0xBA, 0x98, 0xFE, 0xDC,
+ 0x32, 0x10, 0x76, 0x54,
+ // data length
+ 0x00, 0x0c,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
// clang-format on
- QuicFramerFuzzFunc(framer_.version() <= QUIC_VERSION_38 ? packet : packet39,
- arraysize(packet));
+ unsigned char* p = packet;
+ if (framer_.version() > QUIC_VERSION_39) {
+ p = packet40;
+ } else if (framer_.version() > QUIC_VERSION_38) {
+ p = packet39;
+ }
+ QuicFramerFuzzFunc(p, arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, StartsWithChlo) {
+ EXPECT_FALSE(framer_.HasDataProducer());
+ SimpleDataProducer producer;
+ framer_.set_data_producer(&producer);
+ EXPECT_TRUE(framer_.HasDataProducer());
+ QuicStringPiece data("CHLOCHLO");
+ struct iovec iovec;
+ iovec.iov_base = const_cast<char*>(data.data());
+ iovec.iov_len = data.length();
+ QuicIOVector iov(&iovec, 1, iovec.iov_len);
+ producer.SaveStreamData(kCryptoStreamId, iov, 0, 0, data.length());
+ for (size_t offset = 0; offset < 5; ++offset) {
+ if (offset == 0 || offset == 4) {
+ EXPECT_TRUE(framer_.StartsWithChlo(kCryptoStreamId, offset));
+ } else {
+ EXPECT_FALSE(framer_.StartsWithChlo(kCryptoStreamId, offset));
+ }
+ }
}
} // namespace
diff --git a/chromium/net/quic/core/quic_header_list.cc b/chromium/net/quic/core/quic_header_list.cc
index 69f783adee6..3a7fe39ccbc 100644
--- a/chromium/net/quic/core/quic_header_list.cc
+++ b/chromium/net/quic/core/quic_header_list.cc
@@ -6,14 +6,17 @@
#include "net/quic/core/quic_packets.h"
#include "net/quic/platform/api/quic_flags.h"
+#include "net/spdy/core/spdy_protocol.h"
using std::string;
namespace net {
QuicHeaderList::QuicHeaderList()
- : max_uncompressed_header_bytes_(kDefaultMaxUncompressedHeaderSize),
- uncompressed_header_bytes_(0) {}
+ : max_header_list_size_(kDefaultMaxUncompressedHeaderSize),
+ current_header_list_size_(0),
+ uncompressed_header_bytes_(0),
+ compressed_header_bytes_(0) {}
QuicHeaderList::QuicHeaderList(QuicHeaderList&& other) = default;
@@ -27,15 +30,29 @@ QuicHeaderList& QuicHeaderList::operator=(QuicHeaderList&& other) = default;
QuicHeaderList::~QuicHeaderList() {}
void QuicHeaderList::OnHeaderBlockStart() {
- QUIC_BUG_IF(uncompressed_header_bytes_ != 0)
- << "OnHeaderBlockStart called more than once!";
+ if (FLAGS_quic_restart_flag_quic_header_list_size) {
+ QUIC_BUG_IF(current_header_list_size_ != 0)
+ << "OnHeaderBlockStart called more than once!";
+ } else {
+ QUIC_BUG_IF(uncompressed_header_bytes_ != 0)
+ << "OnHeaderBlockStart called more than once!";
+ }
}
void QuicHeaderList::OnHeader(QuicStringPiece name, QuicStringPiece value) {
- // Avoid infinte buffering of headers. No longer store headers
+ // Avoid infinite buffering of headers. No longer store headers
// once the current headers are over the limit.
- if (uncompressed_header_bytes_ == 0 || !header_list_.empty()) {
- header_list_.emplace_back(name.as_string(), value.as_string());
+ if (FLAGS_quic_restart_flag_quic_header_list_size) {
+ if (current_header_list_size_ < max_header_list_size_) {
+ current_header_list_size_ += name.size();
+ current_header_list_size_ += value.size();
+ current_header_list_size_ += kPerHeaderOverhead;
+ header_list_.emplace_back(string(name), string(value));
+ }
+ } else {
+ if (uncompressed_header_bytes_ == 0 || !header_list_.empty()) {
+ header_list_.emplace_back(string(name), string(value));
+ }
}
}
@@ -43,14 +60,22 @@ void QuicHeaderList::OnHeaderBlockEnd(size_t uncompressed_header_bytes,
size_t compressed_header_bytes) {
uncompressed_header_bytes_ = uncompressed_header_bytes;
compressed_header_bytes_ = compressed_header_bytes;
- if (uncompressed_header_bytes_ > max_uncompressed_header_bytes_) {
- Clear();
+ if (FLAGS_quic_restart_flag_quic_header_list_size) {
+ if (current_header_list_size_ > max_header_list_size_) {
+ Clear();
+ }
+ } else {
+ if (uncompressed_header_bytes_ > max_header_list_size_) {
+ Clear();
+ }
}
}
void QuicHeaderList::Clear() {
header_list_.clear();
+ current_header_list_size_ = 0;
uncompressed_header_bytes_ = 0;
+ compressed_header_bytes_ = 0;
}
string QuicHeaderList::DebugString() const {
diff --git a/chromium/net/quic/core/quic_header_list.h b/chromium/net/quic/core/quic_header_list.h
index 1de6ad2bf3e..983cd8ec1bb 100644
--- a/chromium/net/quic/core/quic_header_list.h
+++ b/chromium/net/quic/core/quic_header_list.h
@@ -49,15 +49,27 @@ class QUIC_EXPORT_PRIVATE QuicHeaderList : public SpdyHeadersHandlerInterface {
}
size_t compressed_header_bytes() const { return compressed_header_bytes_; }
- void set_max_uncompressed_header_bytes(size_t max_uncompressed_header_bytes) {
- max_uncompressed_header_bytes_ = max_uncompressed_header_bytes;
+ void set_max_header_list_size(size_t max_header_list_size) {
+ max_header_list_size_ = max_header_list_size;
}
+ size_t max_header_list_size() const { return max_header_list_size_; }
+
std::string DebugString() const;
private:
std::deque<std::pair<std::string, std::string>> header_list_;
- size_t max_uncompressed_header_bytes_;
+
+ // The limit on the size of the header list (defined by spec as name + value +
+ // overhead for each header field). Headers over this limit will not be
+ // buffered, and the list will be cleared upon OnHeaderBlockEnd.
+ size_t max_header_list_size_;
+
+ // Defined per the spec as the size of all header fields with an additional
+ // overhead for each field.
+ size_t current_header_list_size_;
+
+ // TODO(dahollings) Are these fields necessary?
size_t uncompressed_header_bytes_;
size_t compressed_header_bytes_;
};
diff --git a/chromium/net/quic/core/quic_header_list_test.cc b/chromium/net/quic/core/quic_header_list_test.cc
index 39666a2cd41..8e45463078e 100644
--- a/chromium/net/quic/core/quic_header_list_test.cc
+++ b/chromium/net/quic/core/quic_header_list_test.cc
@@ -28,8 +28,18 @@ TEST_F(QuicHeaderListTest, TooLarge) {
QuicHeaderList headers;
string key = "key";
string value(1 << 18, '1');
+ // Send a header that exceeds max_header_list_size.
headers.OnHeader(key, value);
- size_t total_bytes = key.size() + value.size();
+ // Send a second header exceeding max_header_list_size.
+ headers.OnHeader(key + "2", value);
+ if (FLAGS_quic_restart_flag_quic_header_list_size) {
+ // We should not allocate more memory after exceeding max_header_list_size.
+ EXPECT_LT(headers.DebugString().size(), 2 * value.size());
+ } else {
+ // Demonstrates previous behavior.
+ EXPECT_GE(headers.DebugString().size(), 2 * value.size());
+ }
+ size_t total_bytes = 2 * (key.size() + value.size()) + 1;
headers.OnHeaderBlockEnd(total_bytes, total_bytes);
EXPECT_TRUE(headers.empty());
@@ -38,7 +48,7 @@ TEST_F(QuicHeaderListTest, TooLarge) {
TEST_F(QuicHeaderListTest, NotTooLarge) {
QuicHeaderList headers;
- headers.set_max_uncompressed_header_bytes(1 << 20);
+ headers.set_max_header_list_size(1 << 20);
string key = "key";
string value(1 << 18, '1');
headers.OnHeader(key, value);
diff --git a/chromium/net/quic/core/quic_headers_stream.cc b/chromium/net/quic/core/quic_headers_stream.cc
index b6dfec1c246..97d72c90ca2 100644
--- a/chromium/net/quic/core/quic_headers_stream.cc
+++ b/chromium/net/quic/core/quic_headers_stream.cc
@@ -62,7 +62,9 @@ QuicConsumedData QuicHeadersStream::WritevDataInner(
QuicStreamOffset offset,
bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
- if (!session()->use_stream_notifier()) {
+ if (!session()->use_stream_notifier() ||
+ session()->save_data_before_consumption()) {
+ // If data is saved before consumption, unacked_headers has been populated.
return QuicStream::WritevDataInner(iov, offset, fin,
std::move(ack_listener));
}
@@ -91,31 +93,37 @@ QuicConsumedData QuicHeadersStream::WritevDataInner(
void QuicHeadersStream::OnStreamFrameAcked(const QuicStreamFrame& frame,
QuicTime::Delta ack_delay_time) {
+ QuicStreamOffset offset = frame.offset;
+ QuicByteCount length = frame.data_length;
for (CompressedHeaderInfo& header : unacked_headers_) {
- if (frame.offset < header.headers_stream_offset) {
+ if (offset < header.headers_stream_offset) {
// This header frame offset belongs to headers with smaller offset, stop
// processing.
break;
}
- if (frame.offset >= header.headers_stream_offset + header.full_length) {
+ if (offset >= header.headers_stream_offset + header.full_length) {
// This header frame belongs to headers with larger offset.
continue;
}
- if (header.unacked_length < frame.data_length) {
- // This header frame is out of range.
+ QuicByteCount header_offset = offset - header.headers_stream_offset;
+ QuicByteCount acked_length =
+ std::min(length, header.full_length - header_offset);
+
+ if (header.unacked_length < acked_length) {
+ QUIC_BUG << "Unsent stream data is acked. unacked_length: "
+ << header.unacked_length << " acked_length: " << acked_length;
CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
"Unsent stream data is acked");
return;
}
-
- header.unacked_length -= frame.data_length;
-
- if (header.ack_listener != nullptr) {
- header.ack_listener->OnPacketAcked(frame.data_length, ack_delay_time);
+ if (header.ack_listener != nullptr && acked_length > 0) {
+ header.ack_listener->OnPacketAcked(acked_length, ack_delay_time);
}
- break;
+ header.unacked_length -= acked_length;
+ offset += acked_length;
+ length -= acked_length;
}
// Remove headers which are fully acked. Please note, header frames can be
@@ -129,22 +137,47 @@ void QuicHeadersStream::OnStreamFrameAcked(const QuicStreamFrame& frame,
void QuicHeadersStream::OnStreamFrameRetransmitted(
const QuicStreamFrame& frame) {
+ QuicStreamOffset offset = frame.offset;
+ QuicByteCount length = frame.data_length;
for (CompressedHeaderInfo& header : unacked_headers_) {
- if (frame.offset < header.headers_stream_offset) {
+ if (offset < header.headers_stream_offset) {
// This header frame offset belongs to headers with smaller offset, stop
// processing.
break;
}
- if (frame.offset >= header.headers_stream_offset + header.full_length) {
+ if (offset >= header.headers_stream_offset + header.full_length) {
// This header frame belongs to headers with larger offset.
continue;
}
- if (header.ack_listener != nullptr) {
- header.ack_listener->OnPacketRetransmitted(frame.data_length);
+ QuicByteCount header_offset = offset - header.headers_stream_offset;
+ QuicByteCount retransmitted_length =
+ std::min(length, header.full_length - header_offset);
+ if (header.ack_listener != nullptr && retransmitted_length > 0) {
+ header.ack_listener->OnPacketRetransmitted(retransmitted_length);
}
- break;
+ offset += retransmitted_length;
+ length -= retransmitted_length;
+ }
+}
+
+void QuicHeadersStream::OnDataBuffered(
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) {
+ // Populate unacked_headers_.
+ if (!unacked_headers_.empty() &&
+ (offset == unacked_headers_.back().headers_stream_offset +
+ unacked_headers_.back().full_length) &&
+ ack_listener == unacked_headers_.back().ack_listener) {
+ // Try to combine with latest inserted entry if they belong to the same
+ // header (i.e., having contiguous offset and the same ack listener).
+ unacked_headers_.back().full_length += data_length;
+ unacked_headers_.back().unacked_length += data_length;
+ } else {
+ unacked_headers_.push_back(
+ CompressedHeaderInfo(offset, data_length, ack_listener));
}
}
diff --git a/chromium/net/quic/core/quic_headers_stream.h b/chromium/net/quic/core/quic_headers_stream.h
index f74b869693c..1e17b1875e2 100644
--- a/chromium/net/quic/core/quic_headers_stream.h
+++ b/chromium/net/quic/core/quic_headers_stream.h
@@ -80,6 +80,15 @@ class QUIC_EXPORT_PRIVATE QuicHeadersStream : public QuicStream {
// Returns true if the session is still connected.
bool IsConnected();
+ // Override to store mapping from offset, length to ack_listener. This
+ // ack_listener is notified once data within [offset, offset + length] is
+ // acked or retransmitted.
+ void OnDataBuffered(
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener)
+ override;
+
QuicSpdySession* spdy_session_;
// Headers that have not been fully acked.
diff --git a/chromium/net/quic/core/quic_headers_stream_test.cc b/chromium/net/quic/core/quic_headers_stream_test.cc
index 7aec2d8eafe..2f47bcc32da 100644
--- a/chromium/net/quic/core/quic_headers_stream_test.cc
+++ b/chromium/net/quic/core/quic_headers_stream_test.cc
@@ -10,6 +10,7 @@
#include <tuple>
#include <utility>
+#include "net/quic/core/quic_data_writer.h"
#include "net/quic/core/quic_utils.h"
#include "net/quic/core/spdy_utils.h"
#include "net/quic/platform/api/quic_bug_tracker.h"
@@ -23,7 +24,7 @@
#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/quic/test_tools/quic_stream_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/spdy/chromium/spdy_flags.h"
+#include "net/spdy/core/http2_frame_decoder_adapter.h"
#include "net/spdy/core/spdy_alt_svc_wire_format.h"
#include "net/spdy/core/spdy_protocol.h"
#include "net/spdy/core/spdy_test_utils.h"
@@ -59,7 +60,7 @@ const bool kFins[] = {false, true};
class MockVisitor : public SpdyFramerVisitorInterface {
public:
- MOCK_METHOD1(OnError, void(SpdyFramer* framer));
+ MOCK_METHOD1(OnError, void(Http2DecoderAdapter::SpdyFramerError error));
MOCK_METHOD3(OnDataFrameHeader,
void(SpdyStreamId stream_id, size_t length, bool fin));
MOCK_METHOD3(OnStreamFrameData,
@@ -168,7 +169,8 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> {
headers_["content-length"] = "11";
framer_ = std::unique_ptr<SpdyFramer>(
new SpdyFramer(SpdyFramer::ENABLE_COMPRESSION));
- framer_->set_visitor(&visitor_);
+ deframer_ = std::unique_ptr<Http2DecoderAdapter>(new Http2DecoderAdapter());
+ deframer_->set_visitor(&visitor_);
EXPECT_EQ(version(), session_.connection()->version());
EXPECT_TRUE(headers_stream_ != nullptr);
connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
@@ -189,9 +191,20 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> {
const iovec* iov = data.iov;
int count = data.iov_count;
int consumed = 0;
- for (int i = 0; i < count; ++i) {
- saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
- consumed += iov[i].iov_len;
+ if (iov != nullptr) {
+ for (int i = 0; i < count; ++i) {
+ saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
+ consumed += iov[i].iov_len;
+ }
+ } else {
+ consumed = data.total_length;
+ char* buf = new char[consumed];
+ QuicDataWriter writer(consumed, buf, Perspective::IS_CLIENT,
+ NETWORK_BYTE_ORDER);
+ headers_stream_->WriteStreamData(headers_stream_->stream_bytes_written(),
+ consumed, &writer);
+ saved_data_.append(buf, consumed);
+ delete[] buf;
}
return QuicConsumedData(consumed, false);
}
@@ -199,7 +212,17 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> {
QuicConsumedData SaveIovShort(const QuicIOVector& data) {
const iovec* iov = data.iov;
int consumed = 1;
- saved_data_.append(static_cast<char*>(iov[0].iov_base), consumed);
+ if (iov != nullptr) {
+ saved_data_.append(static_cast<char*>(iov[0].iov_base), consumed);
+ } else {
+ char* buf = new char[consumed];
+ QuicDataWriter writer(consumed, buf, Perspective::IS_CLIENT,
+ NETWORK_BYTE_ORDER);
+ headers_stream_->WriteStreamData(headers_stream_->stream_bytes_written(),
+ consumed, &writer);
+ saved_data_.append(buf, consumed);
+ delete[] buf;
+ }
return QuicConsumedData(consumed, false);
}
@@ -293,9 +316,10 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> {
if (fin) {
EXPECT_CALL(visitor_, OnStreamEnd(stream_id));
}
- framer_->ProcessInput(saved_data_.data(), saved_data_.length());
- EXPECT_FALSE(framer_->HasError())
- << SpdyFramer::SpdyFramerErrorToString(framer_->spdy_framer_error());
+ deframer_->ProcessInput(saved_data_.data(), saved_data_.length());
+ EXPECT_FALSE(deframer_->HasError())
+ << Http2DecoderAdapter::SpdyFramerErrorToString(
+ deframer_->spdy_framer_error());
CheckHeaders();
saved_data_.clear();
@@ -340,6 +364,7 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> {
string saved_header_data_;
string saved_payloads_;
std::unique_ptr<SpdyFramer> framer_;
+ std::unique_ptr<Http2DecoderAdapter> deframer_;
StrictMock<MockVisitor> visitor_;
QuicStreamFrame stream_frame_;
QuicStreamId next_promised_stream_id_;
@@ -396,9 +421,10 @@ TEST_P(QuicHeadersStreamTest, WritePushPromises) {
EXPECT_CALL(visitor_, OnHeaderFrameStart(stream_id))
.WillOnce(Return(headers_handler_.get()));
EXPECT_CALL(visitor_, OnHeaderFrameEnd(stream_id)).Times(1);
- framer_->ProcessInput(saved_data_.data(), saved_data_.length());
- EXPECT_FALSE(framer_->HasError())
- << SpdyFramer::SpdyFramerErrorToString(framer_->spdy_framer_error());
+ deframer_->ProcessInput(saved_data_.data(), saved_data_.length());
+ EXPECT_FALSE(deframer_->HasError())
+ << Http2DecoderAdapter::SpdyFramerErrorToString(
+ deframer_->spdy_framer_error());
CheckHeaders();
saved_data_.clear();
} else {
@@ -474,7 +500,6 @@ TEST_P(QuicHeadersStreamTest, ProcessPushPromise) {
TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) {
FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame = true;
- FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default = true;
session_.OnConfigNegotiated();
SpdySettingsIR data;
// Respect supported settings frames SETTINGS_ENABLE_PUSH.
@@ -724,8 +749,7 @@ TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameUnsupportedFields) {
QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ",
SETTINGS_INITIAL_WINDOW_SIZE),
_));
- if (!FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default ||
- session_.perspective() == Perspective::IS_CLIENT) {
+ if (session_.perspective() == Perspective::IS_CLIENT) {
EXPECT_CALL(*connection_,
CloseConnection(
QUIC_INVALID_HEADERS_STREAM_DATA,
@@ -913,7 +937,7 @@ TEST_P(QuicHeadersStreamTest, WritevStreamData) {
if (fin) {
EXPECT_CALL(visitor_, OnStreamEnd(id));
}
- framer_->ProcessInput(saved_data_.data(), saved_data_.length());
+ deframer_->ProcessInput(saved_data_.data(), saved_data_.length());
EXPECT_EQ(saved_payloads_, data);
if (use_ack_listener && !session_.use_stream_notifier()) {
@@ -991,8 +1015,7 @@ TEST_P(QuicHeadersStreamTest, AckSentData) {
}
EXPECT_CALL(session_,
WritevData(headers_stream_, kHeadersStreamId, _, _, NO_FIN, _))
- .WillRepeatedly(
- Invoke(&session_, &MockQuicSpdySession::ConsumeAndSaveAllData));
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
InSequence s;
QuicReferenceCountedPointer<MockAckListener> ack_listener1(
new MockAckListener());
@@ -1040,8 +1063,59 @@ TEST_P(QuicHeadersStreamTest, AckSentData) {
headers_stream_->OnStreamFrameAcked(frame1, QuicTime::Delta::Zero());
headers_stream_->OnStreamFrameAcked(frame2, QuicTime::Delta::Zero());
// Unsent data is acked.
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INTERNAL_ERROR, _, _));
+ if (!session_.save_data_before_consumption()) {
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_INTERNAL_ERROR, _, _));
+ EXPECT_QUIC_BUG(
+ headers_stream_->OnStreamFrameAcked(frame3, QuicTime::Delta::Zero()),
+ "Unsent stream data is acked.");
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, FrameContainsMultipleHeaders) {
+ // In this test, a stream frame can contain multiple headers.
+ if (!session_.save_data_before_consumption()) {
+ return;
+ }
+ EXPECT_CALL(session_,
+ WritevData(headers_stream_, kHeadersStreamId, _, _, NO_FIN, _))
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+ InSequence s;
+ QuicReferenceCountedPointer<MockAckListener> ack_listener1(
+ new MockAckListener());
+ QuicReferenceCountedPointer<MockAckListener> ack_listener2(
+ new MockAckListener());
+ QuicReferenceCountedPointer<MockAckListener> ack_listener3(
+ new MockAckListener());
+
+ headers_stream_->WriteOrBufferData("Header5", false, ack_listener1);
+ headers_stream_->WriteOrBufferData("Header5", false, ack_listener1);
+ headers_stream_->WriteOrBufferData("Header7", false, ack_listener2);
+ headers_stream_->WriteOrBufferData("Header9", false, ack_listener3);
+ headers_stream_->WriteOrBufferData("Header7", false, ack_listener2);
+ headers_stream_->WriteOrBufferData("Header9", false, ack_listener3);
+
+ QuicStreamFrame frame1(kHeadersStreamId, false, 0, "Header5Header5Hea");
+ QuicStreamFrame frame2(kHeadersStreamId, false, 17, "der7Header9He");
+ QuicStreamFrame frame3(kHeadersStreamId, false, 30, "ader7Header9");
+
+ // Frame 1 is retransmitted.
+ EXPECT_CALL(*ack_listener1, OnPacketRetransmitted(14));
+ EXPECT_CALL(*ack_listener2, OnPacketRetransmitted(3));
+ headers_stream_->OnStreamFrameRetransmitted(frame1);
+
+ // Frames are acked in order: 2, 3, 1.
+ EXPECT_CALL(*ack_listener2, OnPacketAcked(4, _));
+ EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _));
+ EXPECT_CALL(*ack_listener2, OnPacketAcked(2, _));
+ headers_stream_->OnStreamFrameAcked(frame2, QuicTime::Delta::Zero());
+
+ EXPECT_CALL(*ack_listener2, OnPacketAcked(5, _));
+ EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _));
headers_stream_->OnStreamFrameAcked(frame3, QuicTime::Delta::Zero());
+
+ EXPECT_CALL(*ack_listener1, OnPacketAcked(14, _));
+ EXPECT_CALL(*ack_listener2, OnPacketAcked(3, _));
+ headers_stream_->OnStreamFrameAcked(frame1, QuicTime::Delta::Zero());
}
} // namespace
diff --git a/chromium/net/quic/core/quic_packet_creator.cc b/chromium/net/quic/core/quic_packet_creator.cc
index b21e85eae60..a3ed7ee198d 100644
--- a/chromium/net/quic/core/quic_packet_creator.cc
+++ b/chromium/net/quic/core/quic_packet_creator.cc
@@ -116,7 +116,7 @@ void QuicPacketCreator::UpdatePacketNumberLength(
packet_.packet_number + 1 - least_packet_awaited_by_peer;
const uint64_t delta = std::max(current_delta, max_packets_in_flight);
packet_.packet_number_length =
- QuicFramer::GetMinPacketNumberLength(delta * 4);
+ QuicFramer::GetMinPacketNumberLength(framer_->version(), delta * 4);
}
bool QuicPacketCreator::ConsumeData(QuicStreamId id,
@@ -131,13 +131,13 @@ bool QuicPacketCreator::ConsumeData(QuicStreamId id,
}
CreateStreamFrame(id, iov, iov_offset, offset, fin, frame);
// Explicitly disallow multi-packet CHLOs.
- if (StreamFrameStartsWithChlo(iov, iov_offset, *frame->stream_frame) &&
- FLAGS_quic_enforce_single_packet_chlo &&
- frame->stream_frame->data_length < iov.iov->iov_len) {
+ if (FLAGS_quic_enforce_single_packet_chlo &&
+ StreamFrameStartsWithChlo(iov, iov_offset, *frame->stream_frame) &&
+ frame->stream_frame->data_length < iov.total_length) {
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;
+ << " CHLO length: " << iov.total_length;
delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details,
ConnectionCloseSource::FROM_SELF);
delete frame->stream_frame;
@@ -157,7 +157,8 @@ bool QuicPacketCreator::ConsumeData(QuicStreamId id,
bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id,
QuicStreamOffset offset) {
- return BytesFree() > QuicFramer::GetMinStreamFrameSize(id, offset, true);
+ return BytesFree() > QuicFramer::GetMinStreamFrameSize(framer_->version(), id,
+ offset, true);
}
// static
@@ -172,7 +173,7 @@ size_t QuicPacketCreator::StreamFramePacketOverhead(
include_diversification_nonce,
packet_number_length) +
// Assumes this is a stream with a single lone packet.
- QuicFramer::GetMinStreamFrameSize(1u, offset, true);
+ QuicFramer::GetMinStreamFrameSize(version, 1u, offset, true);
}
void QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
@@ -190,7 +191,8 @@ void QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
QUIC_BUG_IF(!HasRoomForStreamFrame(id, offset))
<< "No room for Stream frame, BytesFree: " << BytesFree()
<< " MinStreamFrameSize: "
- << QuicFramer::GetMinStreamFrameSize(id, offset, true);
+ << QuicFramer::GetMinStreamFrameSize(framer_->version(), id, offset,
+ true);
if (iov_offset == iov.total_length) {
QUIC_BUG_IF(!fin) << "Creating a stream frame with no data or fin.";
@@ -202,7 +204,7 @@ void QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
const size_t data_size = iov.total_length - iov_offset;
size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
- id, offset, /* last_frame_in_packet= */ true);
+ framer_->version(), id, offset, /* last_frame_in_packet= */ true);
size_t bytes_consumed =
std::min<size_t>(BytesFree() - min_frame_size, data_size);
@@ -210,9 +212,6 @@ void QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
if (framer_->HasDataProducer()) {
*frame =
QuicFrame(new QuicStreamFrame(id, set_fin, offset, bytes_consumed));
- if (bytes_consumed > 0) {
- framer_->SaveStreamData(id, iov, iov_offset, offset, bytes_consumed);
- }
return;
}
UniqueStreamBuffer buffer =
@@ -270,8 +269,8 @@ void QuicPacketCreator::Flush() {
return;
}
- QUIC_CACHELINE_ALIGNED char seralized_packet_buffer[kMaxPacketSize];
- SerializePacket(seralized_packet_buffer, kMaxPacketSize);
+ QUIC_CACHELINE_ALIGNED char serialized_packet_buffer[kMaxPacketSize];
+ SerializePacket(serialized_packet_buffer, kMaxPacketSize);
OnSerializedPacket();
}
@@ -285,8 +284,15 @@ void QuicPacketCreator::OnSerializedPacket() {
return;
}
- delegate_->OnSerializedPacket(&packet_);
+ if (!FLAGS_quic_reloadable_flag_quic_clear_packet_before_handed_over) {
+ delegate_->OnSerializedPacket(&packet_);
+ ClearPacket();
+ return;
+ }
+ QUIC_FLAG_COUNT(quic_reloadable_flag_quic_clear_packet_before_handed_over);
+ SerializedPacket packet(std::move(packet_));
ClearPacket();
+ delegate_->OnSerializedPacket(&packet);
}
void QuicPacketCreator::ClearPacket() {
@@ -329,7 +335,7 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
<< "Creating a stream frame with no data or fin.";
const size_t remaining_data_size = iov.total_length - iov_offset;
const size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
- id, stream_offset, /* last_frame_in_packet= */ true);
+ framer_->version(), id, stream_offset, /* last_frame_in_packet= */ true);
const size_t available_size =
max_plaintext_size_ - writer.length() - min_frame_size;
const size_t bytes_consumed =
@@ -340,10 +346,6 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame(
if (framer_->HasDataProducer()) {
frame = QuicMakeUnique<QuicStreamFrame>(id, set_fin, stream_offset,
bytes_consumed);
- if (bytes_consumed > 0) {
- framer_->SaveStreamData(id, iov, iov_offset, stream_offset,
- bytes_consumed);
- }
} else {
UniqueStreamBuffer stream_buffer =
NewStreamBuffer(buffer_allocator_, bytes_consumed);
@@ -636,18 +638,10 @@ bool QuicPacketCreator::StreamFrameStartsWithChlo(
}
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);
+ frame.stream_id != kCryptoStreamId || frame.data_length < sizeof(kCHLO)) {
return false;
}
- return strncmp(reinterpret_cast<const char*>(iov.iov[0].iov_base),
- reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) == 0;
+ return framer_->StartsWithChlo(frame.stream_id, frame.offset);
}
} // namespace net
diff --git a/chromium/net/quic/core/quic_packet_creator.h b/chromium/net/quic/core/quic_packet_creator.h
index 3911bea5385..0862c48baaa 100644
--- a/chromium/net/quic/core/quic_packet_creator.h
+++ b/chromium/net/quic/core/quic_packet_creator.h
@@ -20,7 +20,6 @@
#include "net/quic/core/quic_iovector.h"
#include "net/quic/core/quic_packets.h"
#include "net/quic/core/quic_pending_retransmission.h"
-#include "net/quic/core/quic_stream_frame_data_producer.h"
#include "net/quic/platform/api/quic_export.h"
namespace net {
diff --git a/chromium/net/quic/core/quic_packet_creator_test.cc b/chromium/net/quic/core/quic_packet_creator_test.cc
index a71e3ef2678..c5a3c6339b3 100644
--- a/chromium/net/quic/core/quic_packet_creator_test.cc
+++ b/chromium/net/quic/core/quic_packet_creator_test.cc
@@ -23,6 +23,7 @@
#include "net/quic/test_tools/quic_framer_peer.h"
#include "net/quic/test_tools/quic_packet_creator_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simple_data_producer.h"
using std::string;
using testing::DoAll;
@@ -50,7 +51,7 @@ struct TestParams {
framer_has_data_producer(framer_has_data_producer) {}
friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
- os << "{ client_version: " << QuicVersionToString(p.version)
+ os << "{ version: " << QuicVersionToString(p.version)
<< " connection id length: " << p.connection_id_length
<< " include version: " << p.version_serialization
<< " framer_has_data_producer: " << p.framer_has_data_producer << " }";
@@ -84,6 +85,37 @@ std::vector<TestParams> GetTestParams() {
return params;
}
+class TestPacketCreator : public QuicPacketCreator {
+ public:
+ TestPacketCreator(QuicConnectionId connection_id,
+ QuicFramer* framer,
+ QuicBufferAllocator* buffer_allocator,
+ DelegateInterface* delegate,
+ SimpleDataProducer* producer)
+ : QuicPacketCreator(connection_id, framer, buffer_allocator, delegate),
+ producer_(producer) {}
+
+ bool ConsumeData(QuicStreamId id,
+ QuicIOVector iov,
+ size_t iov_offset,
+ QuicStreamOffset offset,
+ bool fin,
+ bool needs_full_padding,
+ QuicFrame* frame) {
+ if (QuicPacketCreatorPeer::framer(this)->HasDataProducer()) {
+ // Save data before data is consumed.
+ QuicByteCount data_length = iov.total_length - iov_offset;
+ if (data_length > 0) {
+ producer_->SaveStreamData(id, iov, iov_offset, offset, data_length);
+ }
+ }
+ return QuicPacketCreator::ConsumeData(id, iov, iov_offset, offset, fin,
+ needs_full_padding, frame);
+ }
+
+ SimpleDataProducer* producer_;
+};
+
class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
public:
void ClearSerializedPacketForTests(SerializedPacket* serialized_packet) {
@@ -122,7 +154,8 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
creator_(connection_id_,
&client_framer_,
&buffer_allocator_,
- &delegate_),
+ &delegate_,
+ &producer_),
serialized_packet_(creator_.NoPacket()) {
creator_.set_connection_id_length(GetParam().connection_id_length);
@@ -199,9 +232,9 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
// Returns the number of bytes consumed by the non-data fields of a stream
// frame, assuming it is the last frame in the packet
- size_t GetStreamFrameOverhead() {
- return QuicFramer::GetMinStreamFrameSize(kGetNthClientInitiatedStreamId1,
- kOffset, true);
+ size_t GetStreamFrameOverhead(QuicVersion version) {
+ return QuicFramer::GetMinStreamFrameSize(
+ version, kGetNthClientInitiatedStreamId1, kOffset, true);
}
QuicIOVector MakeIOVectorFromStringPiece(QuicStringPiece s) {
@@ -219,7 +252,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
num_padding_bytes, encryption_level, packet_number_length);
}
- static const QuicStreamOffset kOffset = 1u;
+ static const QuicStreamOffset kOffset = 0u;
char buffer_[kMaxPacketSize];
QuicFrames frames_;
@@ -231,7 +264,7 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
string data_;
struct iovec iov_;
SimpleBufferAllocator buffer_allocator_;
- QuicPacketCreator creator_;
+ TestPacketCreator creator_;
SerializedPacket serialized_packet_;
SimpleDataProducer producer_;
};
@@ -354,6 +387,10 @@ TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPadding) {
QuicFrame frame;
QuicIOVector io_vector(
MakeIOVectorFromStringPiece("fake handshake message data"));
+ if (client_framer_.HasDataProducer()) {
+ producer_.SaveStreamData(kCryptoStreamId, io_vector, 0u, 0u,
+ io_vector.total_length);
+ }
QuicPacketCreatorPeer::CreateStreamFrame(&creator_, kCryptoStreamId,
io_vector, 0u, 0u, false, &frame);
QuicFrames frames;
@@ -373,6 +410,10 @@ TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPadding) {
TEST_P(QuicPacketCreatorTest, DoNotRetransmitPendingPadding) {
QuicFrame frame;
QuicIOVector io_vector(MakeIOVectorFromStringPiece("fake message data"));
+ if (client_framer_.HasDataProducer()) {
+ producer_.SaveStreamData(kCryptoStreamId, io_vector, 0u, 0u,
+ io_vector.total_length);
+ }
QuicPacketCreatorPeer::CreateStreamFrame(&creator_, kCryptoStreamId,
io_vector, 0u, 0u, false, &frame);
@@ -424,7 +465,8 @@ TEST_P(QuicPacketCreatorTest, DoNotRetransmitPendingPadding) {
TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPacketAndPadding) {
const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
- GetEncryptionOverhead() + GetStreamFrameOverhead();
+ GetEncryptionOverhead() +
+ GetStreamFrameOverhead(client_framer_.version());
size_t capacity = kDefaultMaxPacketSize - overhead;
for (int delta = -5; delta <= 0; ++delta) {
string data(capacity + delta, 'A');
@@ -432,6 +474,12 @@ TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPacketAndPadding) {
QuicFrame frame;
QuicIOVector io_vector(MakeIOVectorFromStringPiece(data));
+ SimpleDataProducer producer;
+ if (client_framer_.HasDataProducer()) {
+ producer.SaveStreamData(kCryptoStreamId, io_vector, 0u, 0u,
+ io_vector.total_length);
+ QuicPacketCreatorPeer::framer(&creator_)->set_data_producer(&producer);
+ }
QuicPacketCreatorPeer::CreateStreamFrame(
&creator_, kCryptoStreamId, io_vector, 0, kOffset, false, &frame);
QuicFrames frames;
@@ -499,12 +547,12 @@ TEST_P(QuicPacketCreatorTest, ConsumeData) {
TEST_P(QuicPacketCreatorTest, ConsumeDataFin) {
QuicFrame frame;
QuicIOVector io_vector(MakeIOVectorFromStringPiece("test"));
- ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 10u, true,
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 0u, true,
false, &frame));
ASSERT_TRUE(frame.stream_frame);
size_t consumed = frame.stream_frame->data_length;
EXPECT_EQ(4u, consumed);
- CheckStreamFrame(frame, 1u, "test", 10u, true);
+ CheckStreamFrame(frame, 1u, "test", 0u, true);
EXPECT_TRUE(creator_.HasPendingFrames());
}
@@ -526,7 +574,8 @@ TEST_P(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) {
GetEncryptionOverhead();
for (size_t i = overhead; i < overhead + 100; ++i) {
creator_.SetMaxPacketLength(i);
- const bool should_have_room = i > overhead + GetStreamFrameOverhead();
+ const bool should_have_room =
+ i > overhead + GetStreamFrameOverhead(client_framer_.version());
ASSERT_EQ(should_have_room, creator_.HasRoomForStreamFrame(
kGetNthClientInitiatedStreamId1, kOffset));
if (should_have_room) {
@@ -550,7 +599,8 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) {
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
// Compute the total overhead for a single frame in packet.
const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
- GetEncryptionOverhead() + GetStreamFrameOverhead();
+ GetEncryptionOverhead() +
+ GetStreamFrameOverhead(client_framer_.version());
size_t capacity = kDefaultMaxPacketSize - overhead;
// Now, test various sizes around this size.
for (int delta = -5; delta <= 5; ++delta) {
@@ -578,7 +628,8 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) {
TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
// Compute the total overhead for a single frame in packet.
const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
- GetEncryptionOverhead() + GetStreamFrameOverhead();
+ GetEncryptionOverhead() +
+ GetStreamFrameOverhead(client_framer_.version());
ASSERT_GT(kMaxPacketSize, overhead);
size_t capacity = kDefaultMaxPacketSize - overhead;
// Now, test various sizes around this size.
@@ -615,7 +666,8 @@ TEST_P(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) {
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
// Compute the total overhead for a single frame in packet.
const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
- GetEncryptionOverhead() + GetStreamFrameOverhead();
+ GetEncryptionOverhead() +
+ GetStreamFrameOverhead(client_framer_.version());
ASSERT_GT(kDefaultMaxPacketSize, overhead);
size_t capacity = kDefaultMaxPacketSize - overhead;
// Now, test various sizes around this size.
@@ -683,8 +735,13 @@ TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
QuicPacketCreatorPeer::SetPacketNumber(&creator_,
UINT64_C(64) * 256 * 256 * 256 * 256);
creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ if (GetParam().version <= QUIC_VERSION_39) {
+ EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ } else {
+ EXPECT_EQ(PACKET_8BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ }
}
TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthCwnd) {
@@ -706,8 +763,13 @@ TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthCwnd) {
creator_.UpdatePacketNumberLength(
1, UINT64_C(1000) * 256 * 256 * 256 * 256 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ if (GetParam().version <= QUIC_VERSION_39) {
+ EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ } else {
+ EXPECT_EQ(PACKET_8BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ }
}
TEST_P(QuicPacketCreatorTest, SerializeFrame) {
@@ -830,6 +892,9 @@ TEST_P(QuicPacketCreatorTest, SerializeAndSendStreamFrame) {
EXPECT_FALSE(creator_.HasPendingFrames());
QuicIOVector iov(MakeIOVectorFromStringPiece("test"));
+ if (client_framer_.HasDataProducer()) {
+ producer_.SaveStreamData(kHeadersStreamId, iov, 0u, 0u, iov.total_length);
+ }
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
size_t num_bytes_consumed;
@@ -953,6 +1018,10 @@ TEST_P(QuicPacketCreatorTest, SendPacketAfterFullPaddingRetransmission) {
QuicFrame frame;
QuicIOVector io_vector(
MakeIOVectorFromStringPiece("fake handshake message data"));
+ if (client_framer_.HasDataProducer()) {
+ producer_.SaveStreamData(kCryptoStreamId, io_vector, 0u, 0u,
+ io_vector.total_length);
+ }
QuicPacketCreatorPeer::CreateStreamFrame(&creator_, kCryptoStreamId,
io_vector, 0u, 0u, false, &frame);
QuicFrames frames;
@@ -1006,7 +1075,8 @@ TEST_P(QuicPacketCreatorTest, ConsumeDataAndRandomPadding) {
size_t length = GetPacketHeaderOverhead(client_framer_.version()) +
GetEncryptionOverhead() +
QuicFramer::GetMinStreamFrameSize(
- kCryptoStreamId, 0, /*last_frame_in_packet=*/false) +
+ client_framer_.version(), kCryptoStreamId, 0,
+ /*last_frame_in_packet=*/false) +
kStreamFramePayloadSize + 1;
creator_.SetMaxPacketLength(length);
creator_.AddPendingPadding(kMaxNumRandomPaddingBytes);
@@ -1029,7 +1099,7 @@ TEST_P(QuicPacketCreatorTest, ConsumeDataAndRandomPadding) {
creator_.ConsumeData(kCryptoStreamId,
MakeIOVectorFromStringPiece(
QuicStringPiece(buf, kStreamFramePayloadSize + 1)),
- 0u, 0u, false, false, &frame);
+ 0u, kStreamFramePayloadSize, false, false, &frame);
// No padding is sent.
creator_.Flush();
delete frame.stream_frame;
diff --git a/chromium/net/quic/core/quic_packet_generator.cc b/chromium/net/quic/core/quic_packet_generator.cc
index 7487cde8fa4..8f1e372621e 100644
--- a/chromium/net/quic/core/quic_packet_generator.cc
+++ b/chromium/net/quic/core/quic_packet_generator.cc
@@ -9,6 +9,8 @@
#include "net/quic/core/crypto/quic_random.h"
#include "net/quic/core/quic_utils.h"
#include "net/quic/platform/api/quic_bug_tracker.h"
+#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"
namespace net {
@@ -55,7 +57,8 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
QuicIOVector iov,
QuicStreamOffset offset,
StreamSendingState state,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener,
+ bool flag_run_fast_path) {
bool has_handshake = (id == kCryptoStreamId);
bool fin = state != NO_FIN;
QUIC_BUG_IF(has_handshake && fin)
@@ -77,9 +80,16 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
QUIC_BUG << "Attempt to consume empty data without FIN.";
return QuicConsumedData(0, false);
}
-
- while (delegate_->ShouldGeneratePacket(
- HAS_RETRANSMITTABLE_DATA, has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) {
+ // We determine if we can enter the fast path before executing
+ // the slow path loop.
+ bool run_fast_path =
+ flag_run_fast_path &&
+ (!has_handshake && state != FIN_AND_PADDING && !HasQueuedFrames() &&
+ iov.total_length - total_bytes_consumed > kMaxPacketSize);
+
+ while (!run_fast_path && delegate_->ShouldGeneratePacket(
+ HAS_RETRANSMITTABLE_DATA,
+ has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) {
QuicFrame frame;
if (!packet_creator_.ConsumeData(id, iov, total_bytes_consumed,
offset + total_bytes_consumed, fin,
@@ -115,6 +125,17 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
}
// TODO(ianswett): Move to having the creator flush itself when it's full.
packet_creator_.Flush();
+
+ run_fast_path =
+ flag_run_fast_path &&
+ (!has_handshake && state != FIN_AND_PADDING && !HasQueuedFrames() &&
+ iov.total_length - total_bytes_consumed > kMaxPacketSize);
+ }
+
+ if (run_fast_path) {
+ QUIC_FLAG_COUNT(quic_reloadable_flag_quic_consuming_data_faster);
+ return ConsumeDataFastPath(id, iov, offset, state != NO_FIN,
+ total_bytes_consumed, std::move(ack_listener));
}
// Don't allow the handshake to be bundled with other retransmittable frames.
@@ -131,9 +152,10 @@ QuicConsumedData QuicPacketGenerator::ConsumeDataFastPath(
const QuicIOVector& iov,
QuicStreamOffset offset,
bool fin,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+ size_t total_bytes_consumed,
+ const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) {
DCHECK_NE(id, kCryptoStreamId);
- size_t total_bytes_consumed = 0;
+
while (total_bytes_consumed < iov.total_length &&
delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE)) {
diff --git a/chromium/net/quic/core/quic_packet_generator.h b/chromium/net/quic/core/quic_packet_generator.h
index 43bffc1f4a4..637653c747b 100644
--- a/chromium/net/quic/core/quic_packet_generator.h
+++ b/chromium/net/quic/core/quic_packet_generator.h
@@ -101,17 +101,22 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator {
QuicIOVector iov,
QuicStreamOffset offset,
StreamSendingState state,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener,
+ bool flag_run_fast_path);
// Sends as many data only packets as allowed by the send algorithm and the
// available iov.
- // This path does not support FEC, padding, or bundling pending frames.
+ // This path does not support padding, or bundling pending frames.
+ // In case we access this method from ConsumeData, total_bytes_consumed
+ // keeps track of how many bytes have already been consumed.
QuicConsumedData ConsumeDataFastPath(
QuicStreamId id,
const QuicIOVector& iov,
QuicStreamOffset offset,
bool fin,
- QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+ size_t total_bytes_consumed,
+ const QuicReferenceCountedPointer<QuicAckListenerInterface>&
+ ack_listener);
// Generates an MTU discovery packet of specified size.
void GenerateMtuDiscoveryPacket(
diff --git a/chromium/net/quic/core/quic_packet_generator_test.cc b/chromium/net/quic/core/quic_packet_generator_test.cc
index 74a9801ad89..2e5c8fba0a0 100644
--- a/chromium/net/quic/core/quic_packet_generator_test.cc
+++ b/chromium/net/quic/core/quic_packet_generator_test.cc
@@ -102,6 +102,61 @@ struct PacketContents {
} // namespace
+class TestPacketGenerator : public QuicPacketGenerator {
+ public:
+ TestPacketGenerator(QuicConnectionId connection_id,
+ QuicFramer* framer,
+ QuicRandom* random_generator,
+ QuicBufferAllocator* buffer_allocator,
+ DelegateInterface* delegate,
+ SimpleDataProducer* producer)
+ : QuicPacketGenerator(connection_id,
+ framer,
+ random_generator,
+ buffer_allocator,
+ delegate),
+ producer_(producer) {}
+
+ QuicConsumedData ConsumeDataFastPath(
+ QuicStreamId id,
+ const QuicIOVector& iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+ if (QuicPacketCreatorPeer::framer(
+ QuicPacketGeneratorPeer::GetPacketCreator(this))
+ ->HasDataProducer()) {
+ // Save data before data is consumed.
+ if (iov.total_length > 0) {
+ producer_->SaveStreamData(id, iov, 0, offset, iov.total_length);
+ }
+ }
+ return QuicPacketGenerator::ConsumeDataFastPath(id, iov, offset, fin, 0,
+ std::move(ack_listener));
+ }
+
+ QuicConsumedData ConsumeData(
+ QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ StreamSendingState state,
+ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+ if (QuicPacketCreatorPeer::framer(
+ QuicPacketGeneratorPeer::GetPacketCreator(this))
+ ->HasDataProducer()) {
+ // Save data before data is consumed.
+ if (iov.total_length > 0) {
+ producer_->SaveStreamData(id, iov, 0, offset, iov.total_length);
+ }
+ }
+ return QuicPacketGenerator::ConsumeData(
+ id, iov, offset, state, std::move(ack_listener),
+ FLAGS_quic_reloadable_flag_quic_consuming_data_faster);
+ }
+
+ SimpleDataProducer* producer_;
+};
+
class QuicPacketGeneratorTest : public QuicTest {
public:
QuicPacketGeneratorTest()
@@ -112,12 +167,13 @@ class QuicPacketGeneratorTest : public QuicTest {
&framer_,
&random_generator_,
&buffer_allocator_,
- &delegate_),
+ &delegate_,
+ &producer_),
creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) {
creator_->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
new NullEncrypter(Perspective::IS_CLIENT));
creator_->set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- if (FLAGS_quic_reloadable_flag_quic_stream_owns_data) {
+ if (FLAGS_quic_reloadable_flag_quic_save_data_before_consumption2) {
framer_.set_data_producer(&producer_);
}
}
@@ -223,7 +279,7 @@ class QuicPacketGeneratorTest : public QuicTest {
MockRandom random_generator_;
SimpleBufferAllocator buffer_allocator_;
StrictMock<MockDelegate> delegate_;
- QuicPacketGenerator generator_;
+ TestPacketGenerator generator_;
QuicPacketCreator* creator_;
SimpleQuicFramer simple_framer_;
std::vector<SerializedPacket> packets_;
@@ -367,7 +423,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
delegate_.SetCanNotWrite();
QuicConsumedData consumed = generator_.ConsumeData(
- kHeadersStreamId, MakeIOVectorFromStringPiece("foo"), 2, FIN, nullptr);
+ kHeadersStreamId, MakeIOVectorFromStringPiece("foo"), 0, FIN, nullptr);
EXPECT_EQ(0u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
@@ -379,7 +435,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
generator_.StartBatchOperations();
QuicConsumedData consumed = generator_.ConsumeData(
- kHeadersStreamId, MakeIOVectorFromStringPiece("foo"), 2, FIN, nullptr);
+ kHeadersStreamId, MakeIOVectorFromStringPiece("foo"), 0, FIN, nullptr);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasQueuedFrames());
@@ -392,7 +448,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) {
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
QuicConsumedData consumed = generator_.ConsumeData(
- kHeadersStreamId, MakeIOVectorFromStringPiece("foo"), 2, FIN, nullptr);
+ kHeadersStreamId, MakeIOVectorFromStringPiece("foo"), 0, FIN, nullptr);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
@@ -441,9 +497,9 @@ TEST_F(QuicPacketGeneratorTest,
generator_.StartBatchOperations();
generator_.ConsumeData(kHeadersStreamId, MakeIOVectorFromStringPiece("foo"),
- 2, FIN, nullptr);
+ 0, FIN, nullptr);
QuicConsumedData consumed = generator_.ConsumeData(
- 3, MakeIOVectorFromStringPiece("quux"), 7, NO_FIN, nullptr);
+ 3, MakeIOVectorFromStringPiece("quux"), 3, NO_FIN, nullptr);
EXPECT_EQ(4u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasQueuedFrames());
@@ -455,9 +511,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) {
generator_.StartBatchOperations();
generator_.ConsumeData(kHeadersStreamId, MakeIOVectorFromStringPiece("foo"),
- 2, FIN, nullptr);
+ 0, FIN, nullptr);
QuicConsumedData consumed = generator_.ConsumeData(
- 3, MakeIOVectorFromStringPiece("quux"), 7, NO_FIN, nullptr);
+ 3, MakeIOVectorFromStringPiece("quux"), 3, NO_FIN, nullptr);
EXPECT_EQ(4u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasQueuedFrames());
@@ -486,8 +542,8 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
// Add an extra 3 bytes for the payload and 1 byte so BytesFree is larger
// than the GetMinStreamFrameSize.
- QuicFramer::GetMinStreamFrameSize(1, 0, false) + 3 +
- QuicFramer::GetMinStreamFrameSize(1, 0, true) + 1;
+ QuicFramer::GetMinStreamFrameSize(framer_.version(), 1, 0, false) + 3 +
+ QuicFramer::GetMinStreamFrameSize(framer_.version(), 1, 0, true) + 1;
generator_.SetMaxPacketLength(length);
delegate_.SetCanWriteAnything();
{
@@ -543,6 +599,113 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataFastPath) {
PacketContents contents;
contents.num_stream_frames = 1;
CheckPacketContains(contents, 0);
+ EXPECT_FALSE(packets_.empty());
+ SerializedPacket packet = packets_.back();
+ EXPECT_TRUE(!packet.retransmittable_frames.empty());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ QuicStreamFrame* stream_frame =
+ packet.retransmittable_frames.front().stream_frame;
+ EXPECT_EQ(10000u, stream_frame->data_length + stream_frame->offset);
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeDataLarge) {
+ delegate_.SetCanWriteAnything();
+
+ // Create a 10000 byte IOVector.
+ QuicIOVector iov(CreateData(10000));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, iov, 0, FIN, nullptr);
+ EXPECT_EQ(10000u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(generator_.HasRetransmittableFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+ EXPECT_FALSE(packets_.empty());
+ SerializedPacket packet = packets_.back();
+ EXPECT_TRUE(!packet.retransmittable_frames.empty());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ QuicStreamFrame* stream_frame =
+ packet.retransmittable_frames.front().stream_frame;
+ EXPECT_EQ(10000u, stream_frame->data_length + stream_frame->offset);
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeDataLargeSendAckFalse) {
+ delegate_.SetCanNotWrite();
+
+ generator_.SetShouldSendAck(false);
+ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+ EXPECT_TRUE(generator_.HasRetransmittableFrames());
+
+ delegate_.SetCanWriteAnything();
+
+ generator_.StartBatchOperations();
+
+ EXPECT_CALL(delegate_, GetUpdatedAckFrame())
+ .WillOnce(Return(QuicFrame(&ack_frame_)));
+
+ // Create a 10000 byte IOVector.
+ QuicIOVector iov(CreateData(10000));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, iov, 0, FIN, nullptr);
+ generator_.FinishBatchOperations();
+
+ EXPECT_EQ(10000u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(generator_.HasRetransmittableFrames());
+
+ EXPECT_FALSE(packets_.empty());
+ SerializedPacket packet = packets_.back();
+ EXPECT_TRUE(!packet.retransmittable_frames.empty());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ QuicStreamFrame* stream_frame =
+ packet.retransmittable_frames.front().stream_frame;
+ EXPECT_EQ(10000u, stream_frame->data_length + stream_frame->offset);
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeDataLargeSendAckTrue) {
+ delegate_.SetCanNotWrite();
+ generator_.SetShouldSendAck(true);
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ // Set up frames to write into the creator when control frames are written.
+ EXPECT_CALL(delegate_, GetUpdatedAckFrame())
+ .WillOnce(Return(QuicFrame(&ack_frame_)));
+ EXPECT_CALL(delegate_, PopulateStopWaitingFrame(_));
+ // Generator should have queued control frames, and creator should be empty.
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(generator_.HasRetransmittableFrames());
+ EXPECT_FALSE(creator_->HasPendingFrames());
+
+ // Create a 10000 byte IOVector.
+ QuicIOVector iov(CreateData(10000));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, iov, 0, FIN, nullptr);
+ generator_.FinishBatchOperations();
+
+ EXPECT_EQ(10000u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(generator_.HasRetransmittableFrames());
+
+ EXPECT_FALSE(packets_.empty());
+ SerializedPacket packet = packets_.back();
+ EXPECT_TRUE(!packet.retransmittable_frames.empty());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ QuicStreamFrame* stream_frame =
+ packet.retransmittable_frames.front().stream_frame;
+ EXPECT_EQ(10000u, stream_frame->data_length + stream_frame->offset);
}
TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
@@ -562,7 +725,7 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
.WillOnce(Return(QuicFrame(&ack_frame_)));
// Send some data and a control frame
- generator_.ConsumeData(3, MakeIOVectorFromStringPiece("quux"), 7, NO_FIN,
+ generator_.ConsumeData(3, MakeIOVectorFromStringPiece("quux"), 0, NO_FIN,
nullptr);
generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame()));
@@ -659,7 +822,7 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Initial) {
.WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
QuicConsumedData consumed =
generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- /*offset=*/2, FIN, nullptr);
+ /*offset=*/0, FIN, nullptr);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
@@ -694,7 +857,7 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) {
// Send two packets before packet size change.
QuicConsumedData consumed =
generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- /*offset=*/2, NO_FIN, nullptr);
+ /*offset=*/0, NO_FIN, nullptr);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
@@ -709,7 +872,7 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) {
// Send a packet after packet size change.
consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- 2 + data_len, FIN, nullptr);
+ data_len, FIN, nullptr);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
@@ -738,7 +901,7 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) {
// should not cause packet serialization.
QuicConsumedData consumed =
generator_.ConsumeData(kHeadersStreamId, CreateData(first_write_len),
- /*offset=*/2, NO_FIN, nullptr);
+ /*offset=*/0, NO_FIN, nullptr);
EXPECT_EQ(first_write_len, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasQueuedFrames());
@@ -769,7 +932,7 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) {
// trigger serialization of one packet, and queue another one.
consumed =
generator_.ConsumeData(kHeadersStreamId, CreateData(second_write_len),
- /*offset=*/2 + first_write_len, FIN, nullptr);
+ /*offset=*/first_write_len, FIN, nullptr);
EXPECT_EQ(second_write_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_TRUE(generator_.HasQueuedFrames());
@@ -829,7 +992,7 @@ TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) {
// Send data before the MTU probe.
QuicConsumedData consumed =
generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- /*offset=*/2, NO_FIN, nullptr);
+ /*offset=*/0, NO_FIN, nullptr);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
@@ -842,7 +1005,7 @@ TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) {
// Send data after the MTU probe.
consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- /*offset=*/2 + data_len, FIN, nullptr);
+ /*offset=*/data_len, FIN, nullptr);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
@@ -916,14 +1079,15 @@ TEST_F(QuicPacketGeneratorTest, RandomPaddingAfterFinSingleStreamSinglePacket) {
const QuicStreamId kDataStreamId = 5;
// Set the packet size be enough for one stream frame with 0 stream offset and
// max size of random padding.
- size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
- GetPacketHeaderSize(
- framer_.version(), creator_->connection_id_length(),
- kIncludeVersion, !kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
- QuicFramer::GetMinStreamFrameSize(
- kDataStreamId, 0, /*last_frame_in_packet=*/false) +
- kStreamFramePayloadSize + kMaxNumRandomPaddingBytes;
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.version(), creator_->connection_id_length(), kIncludeVersion,
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
+ QuicFramer::GetMinStreamFrameSize(framer_.version(), kDataStreamId, 0,
+ /*last_frame_in_packet=*/false) +
+ kStreamFramePayloadSize + kMaxNumRandomPaddingBytes;
generator_.SetMaxPacketLength(length);
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
@@ -954,14 +1118,15 @@ TEST_F(QuicPacketGeneratorTest,
const QuicStreamId kDataStreamId = 5;
// Set the packet size be enough for one stream frame with 0 stream offset +
// 1. One or more packets will accommodate.
- size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
- GetPacketHeaderSize(
- framer_.version(), creator_->connection_id_length(),
- kIncludeVersion, !kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
- QuicFramer::GetMinStreamFrameSize(
- kDataStreamId, 0, /*last_frame_in_packet=*/false) +
- kStreamFramePayloadSize + 1;
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.version(), creator_->connection_id_length(), kIncludeVersion,
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
+ QuicFramer::GetMinStreamFrameSize(framer_.version(), kDataStreamId, 0,
+ /*last_frame_in_packet=*/false) +
+ kStreamFramePayloadSize + 1;
generator_.SetMaxPacketLength(length);
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
@@ -1000,17 +1165,18 @@ TEST_F(QuicPacketGeneratorTest,
const QuicStreamId kDataStreamId2 = 6;
// Set the packet size be enough for first frame with 0 stream offset + second
// frame + 1 byte payload. two or more packets will accommodate.
- size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
- GetPacketHeaderSize(
- framer_.version(), creator_->connection_id_length(),
- kIncludeVersion, !kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
- QuicFramer::GetMinStreamFrameSize(
- kDataStreamId1, 0, /*last_frame_in_packet=*/false) +
- kStreamFramePayloadSize +
- QuicFramer::GetMinStreamFrameSize(
- kDataStreamId1, 0, /*last_frame_in_packet=*/false) +
- 1;
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.version(), creator_->connection_id_length(), kIncludeVersion,
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
+ QuicFramer::GetMinStreamFrameSize(framer_.version(), kDataStreamId1, 0,
+ /*last_frame_in_packet=*/false) +
+ kStreamFramePayloadSize +
+ QuicFramer::GetMinStreamFrameSize(framer_.version(), kDataStreamId1, 0,
+ /*last_frame_in_packet=*/false) +
+ 1;
generator_.SetMaxPacketLength(length);
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
diff --git a/chromium/net/quic/core/quic_packets.cc b/chromium/net/quic/core/quic_packets.cc
index 579aa8cad5f..16720b7b984 100644
--- a/chromium/net/quic/core/quic_packets.cc
+++ b/chromium/net/quic/core/quic_packets.cc
@@ -216,6 +216,26 @@ SerializedPacket::SerializedPacket(QuicPacketNumber packet_number,
SerializedPacket::SerializedPacket(const SerializedPacket& other) = default;
+SerializedPacket& SerializedPacket::operator=(const SerializedPacket& other) =
+ default;
+
+SerializedPacket::SerializedPacket(SerializedPacket&& other)
+ : encrypted_buffer(other.encrypted_buffer),
+ encrypted_length(other.encrypted_length),
+ has_crypto_handshake(other.has_crypto_handshake),
+ num_padding_bytes(other.num_padding_bytes),
+ packet_number(other.packet_number),
+ packet_number_length(other.packet_number_length),
+ encryption_level(other.encryption_level),
+ has_ack(other.has_ack),
+ has_stop_waiting(other.has_stop_waiting),
+ transmission_type(other.transmission_type),
+ original_packet_number(other.original_packet_number),
+ largest_acked(other.largest_acked) {
+ retransmittable_frames.swap(other.retransmittable_frames);
+ listeners.swap(other.listeners);
+}
+
SerializedPacket::~SerializedPacket() {}
void ClearSerializedPacket(SerializedPacket* serialized_packet) {
diff --git a/chromium/net/quic/core/quic_packets.h b/chromium/net/quic/core/quic_packets.h
index d097a0cbbaa..f552f0d666a 100644
--- a/chromium/net/quic/core/quic_packets.h
+++ b/chromium/net/quic/core/quic_packets.h
@@ -214,6 +214,8 @@ struct QUIC_EXPORT_PRIVATE SerializedPacket {
bool has_ack,
bool has_stop_waiting);
SerializedPacket(const SerializedPacket& other);
+ SerializedPacket& operator=(const SerializedPacket& other);
+ SerializedPacket(SerializedPacket&& other);
~SerializedPacket();
// Not owned.
diff --git a/chromium/net/quic/core/quic_sent_packet_manager.cc b/chromium/net/quic/core/quic_sent_packet_manager.cc
index 90eaad05966..1491f3add53 100644
--- a/chromium/net/quic/core/quic_sent_packet_manager.cc
+++ b/chromium/net/quic/core/quic_sent_packet_manager.cc
@@ -15,6 +15,7 @@
#include "net/quic/core/quic_connection_stats.h"
#include "net/quic/core/quic_pending_retransmission.h"
#include "net/quic/platform/api/quic_bug_tracker.h"
+#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_map_util.h"
@@ -79,7 +80,6 @@ QuicSentPacketManager::QuicSentPacketManager(
enable_half_rtt_tail_loss_probe_(false),
using_pacing_(false),
use_new_rto_(false),
- undo_pending_retransmits_(false),
conservative_handshake_retransmits_(false),
largest_newly_acked_(0),
largest_mtu_acked_(0),
@@ -151,9 +151,6 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
if (config.HasClientRequestedIndependentOption(kLFAK, perspective_)) {
general_loss_algorithm_.SetLossDetectionType(kLazyFack);
}
- if (config.HasClientSentConnectionOption(kUNDO, perspective_)) {
- undo_pending_retransmits_ = true;
- }
if (config.HasClientSentConnectionOption(kCONH, perspective_)) {
conservative_handshake_retransmits_ = true;
}
@@ -174,8 +171,14 @@ void QuicSentPacketManager::ResumeConnectionState(
std::max(kMinInitialRoundTripTimeUs,
std::min(kMaxInitialRoundTripTimeUs, initial_rtt_us)));
}
- send_algorithm_->ResumeConnectionState(cached_network_params,
- max_bandwidth_resumption);
+
+ QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(
+ max_bandwidth_resumption
+ ? cached_network_params.max_bandwidth_estimate_bytes_per_second()
+ : cached_network_params.bandwidth_estimate_bytes_per_second());
+ QuicTime::Delta rtt =
+ QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms());
+ send_algorithm_->AdjustNetworkParameters(bandwidth, rtt);
}
void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) {
@@ -238,17 +241,6 @@ void QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame,
consecutive_tlp_count_ = 0;
consecutive_crypto_retransmission_count_ = 0;
}
- // TODO(ianswett): Consider replacing the pending_retransmissions_ with a
- // fast way to retrieve the next pending retransmission, if there are any.
- // A single packet number indicating all packets below that are lost should
- // be all the state that is necessary.
- while (undo_pending_retransmits_ && !pending_retransmissions_.empty() &&
- pending_retransmissions_.front().first > largest_newly_acked_ &&
- pending_retransmissions_.front().second == LOSS_RETRANSMISSION) {
- // Cancel any pending retransmissions larger than largest_newly_acked_.
- unacked_packets_.RestoreToInFlight(pending_retransmissions_.front().first);
- pending_retransmissions_.pop_front();
- }
if (debug_delegate_ != nullptr) {
debug_delegate_->OnIncomingAck(ack_frame, ack_receive_time,
@@ -289,6 +281,8 @@ void QuicSentPacketManager::MaybeInvokeCongestionEvent(
void QuicSentPacketManager::HandleAckForSentPackets(
const QuicAckFrame& ack_frame) {
+ const bool skip_unackable_packets_early =
+ FLAGS_quic_reloadable_flag_quic_handle_acks;
// Go through the packets we have not received an ack for and see if this
// incoming_ack shows they've been seen by the peer.
QuicTime::Delta ack_delay_time = ack_frame.ack_delay_time;
@@ -299,7 +293,10 @@ void QuicSentPacketManager::HandleAckForSentPackets(
// These packets are still in flight.
break;
}
-
+ if (skip_unackable_packets_early && it->is_unackable) {
+ QUIC_FLAG_COUNT(quic_reloadable_flag_quic_handle_acks);
+ continue;
+ }
if (!ack_frame.packets.Contains(packet_number)) {
// Packet is still missing.
continue;
@@ -313,8 +310,9 @@ void QuicSentPacketManager::HandleAckForSentPackets(
// If data is associated with the most recent transmission of this
// packet, then inform the caller.
if (it->in_flight) {
- packets_acked_.push_back(std::make_pair(packet_number, it->bytes_sent));
- } else if (!it->is_unackable) {
+ packets_acked_.push_back(SendAlgorithmInterface::AckedPacket(
+ packet_number, it->bytes_sent, QuicTime::Zero()));
+ } else if (skip_unackable_packets_early || !it->is_unackable) {
// Packets are marked unackable after they've been acked once.
largest_newly_acked_ = packet_number;
}
@@ -670,8 +668,9 @@ QuicSentPacketManager::GetRetransmissionMode() const {
void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
if (!packets_acked_.empty()) {
- DCHECK_LE(packets_acked_.front().first, packets_acked_.back().first);
- largest_newly_acked_ = packets_acked_.back().first;
+ DCHECK_LE(packets_acked_.front().packet_number,
+ packets_acked_.back().packet_number);
+ largest_newly_acked_ = packets_acked_.back().packet_number;
}
loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
largest_newly_acked_, &packets_lost_);
@@ -929,11 +928,6 @@ QuicPacketNumber QuicSentPacketManager::GetLargestSentPacket() const {
return unacked_packets_.largest_sent_packet();
}
-// Remove this method when deprecating QUIC_VERSION_33.
-QuicPacketNumber QuicSentPacketManager::GetLeastPacketAwaitedByPeer() const {
- return least_packet_awaited_by_peer_;
-}
-
void QuicSentPacketManager::SetNetworkChangeVisitor(
NetworkChangeVisitor* visitor) {
DCHECK(!network_change_visitor_);
diff --git a/chromium/net/quic/core/quic_sent_packet_manager.h b/chromium/net/quic/core/quic_sent_packet_manager.h
index 268a54c43c9..14d264707c2 100644
--- a/chromium/net/quic/core/quic_sent_packet_manager.h
+++ b/chromium/net/quic/core/quic_sent_packet_manager.h
@@ -210,8 +210,6 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
QuicPacketNumber GetLargestSentPacket() const;
- QuicPacketNumber GetLeastPacketAwaitedByPeer() const;
-
void SetNetworkChangeVisitor(NetworkChangeVisitor* visitor);
bool InSlowStart() const;
@@ -382,14 +380,11 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager {
// If true, use the new RTO with loss based CWND reduction instead of the send
// algorithms's OnRetransmissionTimeout to reduce the congestion window.
bool use_new_rto_;
- // If true, cancel pending retransmissions if they're larger than
- // largest_newly_acked.
- bool undo_pending_retransmits_;
// If true, use a more conservative handshake retransmission policy.
bool conservative_handshake_retransmits_;
// Vectors packets acked and lost as a result of the last congestion event.
- SendAlgorithmInterface::CongestionVector packets_acked_;
+ SendAlgorithmInterface::AckedPacketVector packets_acked_;
SendAlgorithmInterface::CongestionVector packets_lost_;
// Largest newly acknowledged packet.
QuicPacketNumber largest_newly_acked_;
diff --git a/chromium/net/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/quic/core/quic_sent_packet_manager_test.cc
index 4a2beb31f44..eb25463bb6e 100644
--- a/chromium/net/quic/core/quic_sent_packet_manager_test.cc
+++ b/chromium/net/quic/core/quic_sent_packet_manager_test.cc
@@ -43,6 +43,10 @@ const size_t kMinTimeoutsBeforePathDegrading = 2;
MATCHER(KeyEq, "") {
return std::tr1::get<0>(arg).first == std::tr1::get<1>(arg);
}
+// Matcher to check that the packet number matches the second argument.
+MATCHER(PacketNumberEq, "") {
+ return std::tr1::get<0>(arg).packet_number == std::tr1::get<1>(arg);
+}
class MockDebugDelegate : public QuicSentPacketManager::DebugDelegate {
public:
@@ -115,7 +119,9 @@ class QuicSentPacketManagerTest : public QuicTest {
void ExpectAck(QuicPacketNumber largest_observed) {
EXPECT_CALL(
*send_algorithm_,
- OnCongestionEvent(true, _, _, ElementsAre(Pair(largest_observed, _)),
+ // Ensure the AckedPacketVector argument contains largest_observed.
+ OnCongestionEvent(true, _, _,
+ Pointwise(PacketNumberEq(), {largest_observed}),
IsEmpty()));
EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
}
@@ -129,10 +135,11 @@ class QuicSentPacketManagerTest : public QuicTest {
void ExpectAckAndLoss(bool rtt_updated,
QuicPacketNumber largest_observed,
QuicPacketNumber lost_packet) {
- EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(rtt_updated, _, _,
- ElementsAre(Pair(largest_observed, _)),
- ElementsAre(Pair(lost_packet, _))));
+ EXPECT_CALL(
+ *send_algorithm_,
+ OnCongestionEvent(rtt_updated, _, _,
+ Pointwise(PacketNumberEq(), {largest_observed}),
+ ElementsAre(Pair(lost_packet, _))));
EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
}
@@ -150,10 +157,10 @@ class QuicSentPacketManagerTest : public QuicTest {
for (size_t i = 0; i < num_packets_lost; ++i) {
lost_vector.push_back(packets_lost[i]);
}
- EXPECT_CALL(
- *send_algorithm_,
- OnCongestionEvent(rtt_updated, _, _, Pointwise(KeyEq(), ack_vector),
- Pointwise(KeyEq(), lost_vector)));
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(rtt_updated, _, _,
+ Pointwise(PacketNumberEq(), ack_vector),
+ Pointwise(KeyEq(), lost_vector)));
EXPECT_CALL(*network_change_visitor_, OnCongestionChange())
.Times(AnyNumber());
}
@@ -257,7 +264,7 @@ class QuicSentPacketManagerTest : public QuicTest {
const QuicAckFrame InitAckFrame(QuicPacketNumber largest_observed) {
QuicAckFrame frame(MakeAckFrame(largest_observed));
if (largest_observed > 0) {
- frame.packets.Add(1, largest_observed + 1);
+ frame.packets.AddRange(1, largest_observed + 1);
}
return frame;
}
@@ -269,10 +276,10 @@ class QuicSentPacketManagerTest : public QuicTest {
QuicPacketNumber range2_end) {
QuicAckFrame ack_frame;
if (range1_start < range1_end) {
- ack_frame.packets.Add(range1_start, range1_end);
+ ack_frame.packets.AddRange(range1_start, range1_end);
}
if (range2_start <= range2_end) {
- ack_frame.packets.Add(range2_start, range2_end + 1);
+ ack_frame.packets.AddRange(range2_start, range2_end + 1);
}
ack_frame.largest_observed = range2_end;
return ack_frame;
@@ -724,9 +731,11 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeThenRTO) {
RetransmitNextPacket(103);
QuicAckFrame ack_frame = ConstructAckFrame(1, 0, 103, 103);
+ QuicPacketNumber largest_acked = 103;
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(true, _, _, ElementsAre(Pair(103, _)), _));
+ OnCongestionEvent(
+ true, _, _, Pointwise(PacketNumberEq(), {largest_acked}), _));
EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
// All packets before 103 should be lost.
@@ -766,8 +775,8 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) {
QuicPacketNumber acked[] = {3, 4, 5, 8, 9};
ExpectAcksAndLosses(true, acked, arraysize(acked), nullptr, 0);
QuicAckFrame ack_frame;
- ack_frame.packets.Add(3, 6);
- ack_frame.packets.Add(8, 10);
+ ack_frame.packets.AddRange(3, 6);
+ ack_frame.packets.AddRange(8, 10);
ack_frame.largest_observed = 9;
manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
@@ -940,8 +949,10 @@ TEST_F(QuicSentPacketManagerTest, RetransmissionTimeout) {
QuicAckFrame ack_frame = ConstructAckFrame(1, 0, 102, 102);
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
// Ensure no packets are lost.
+ QuicPacketNumber largest_acked = 102;
EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(true, _, _, ElementsAre(Pair(102, _)),
+ OnCongestionEvent(true, _, _,
+ Pointwise(PacketNumberEq(), {largest_acked}),
/*lost_packets=*/IsEmpty()));
EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
@@ -987,8 +998,10 @@ TEST_F(QuicSentPacketManagerTest, NewRetransmissionTimeout) {
QuicAckFrame ack_frame = ConstructAckFrame(1, 0, 102, 102);
ack_frame.ack_delay_time = QuicTime::Delta::Zero();
// This will include packets in the lost packet map.
+ QuicPacketNumber largest_acked = 102;
EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(true, _, _, ElementsAre(Pair(102, _)),
+ OnCongestionEvent(true, _, _,
+ Pointwise(PacketNumberEq(), {largest_acked}),
/*lost_packets=*/Not(IsEmpty())));
EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
manager_.OnIncomingAck(ack_frame, clock_.Now());
@@ -1574,70 +1587,6 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtClient) {
EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
}
-TEST_F(QuicSentPacketManagerTest, NegotiateUndoFromOptionsAtServer) {
- EXPECT_FALSE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
- QuicConfig config;
- QuicTagVector options;
-
- options.push_back(kUNDO);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- manager_.SetFromConfig(config);
- EXPECT_TRUE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
-
- // Ensure undo works as intended.
- // Send 5 packets, mark the first 4 for retransmission, and then cancel
- // them when 1 is acked.
- EXPECT_CALL(*send_algorithm_, PacingRate(_))
- .WillRepeatedly(Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(10 * kDefaultTCPMSS));
- const size_t kNumSentPackets = 5;
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- auto loss_algorithm = QuicMakeUnique<MockLossAlgorithm>();
- QuicSentPacketManagerPeer::SetLossAlgorithm(&manager_, loss_algorithm.get());
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- SendAlgorithmInterface::CongestionVector lost_packets;
- for (size_t i = 1; i < kNumSentPackets; ++i) {
- lost_packets.push_back(std::make_pair(i, kMaxPacketSize));
- }
- EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- QuicAckFrame ack_frame =
- ConstructAckFrame(1, 1, kNumSentPackets, kNumSentPackets);
- // Congestion block the sending right before losing the packets.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(Return(QuicTime::Delta::Infinite()));
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(0u, BytesInFlight());
-
- // Ack 1 and ensure the retransmissions are cancelled and put back in flight.
- EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
- ack_frame = ConstructAckFrame(1, 2, kNumSentPackets, 5);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(3u * kDefaultLength, BytesInFlight());
-}
-
-TEST_F(QuicSentPacketManagerTest, NegotiateUndoFromOptionsAtClient) {
- EXPECT_FALSE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
- QuicConfig client_config;
- QuicTagVector options;
-
- options.push_back(kUNDO);
- QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
- client_config.SetConnectionOptionsToSend(options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- manager_.SetFromConfig(client_config);
- EXPECT_TRUE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
-}
-
TEST_F(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
uint32_t initial_rtt_us = 325000;
EXPECT_NE(initial_rtt_us,
@@ -1660,7 +1609,9 @@ TEST_F(QuicSentPacketManagerTest, ResumeConnectionState) {
CachedNetworkParameters cached_network_params;
cached_network_params.set_min_rtt_ms(kRttMs);
- EXPECT_CALL(*send_algorithm_, ResumeConnectionState(_, false));
+ EXPECT_CALL(*send_algorithm_, AdjustNetworkParameters(
+ QuicBandwidth::Zero(),
+ QuicTime::Delta::FromMilliseconds(kRttMs)));
manager_.ResumeConnectionState(cached_network_params, false);
EXPECT_EQ(kRttMs * kNumMicrosPerMilli,
static_cast<uint64_t>(manager_.GetRttStats()->initial_rtt_us()));
diff --git a/chromium/net/quic/core/quic_server_session_base.cc b/chromium/net/quic/core/quic_server_session_base.cc
index 2524e5c1963..2a352ca844e 100644
--- a/chromium/net/quic/core/quic_server_session_base.cc
+++ b/chromium/net/quic/core/quic_server_session_base.cc
@@ -55,8 +55,7 @@ void QuicServerSessionBase::OnConfigNegotiated() {
bandwidth_resumption_enabled_ =
last_bandwidth_resumption || max_bandwidth_resumption;
- if (!FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default ||
- connection()->version() < QUIC_VERSION_35) {
+ if (connection()->version() < QUIC_VERSION_35) {
set_server_push_enabled(
ContainsQuicTag(config()->ReceivedConnectionOptions(), kSPSH));
}
@@ -195,7 +194,6 @@ void QuicServerSessionBase::OnCongestionWindowChange(QuicTime now) {
}
bool QuicServerSessionBase::ShouldCreateIncomingDynamicStream(QuicStreamId id) {
- DCHECK(!FLAGS_quic_reloadable_flag_quic_refactor_stream_creation);
if (!connection()->connected()) {
QUIC_BUG << "ShouldCreateIncomingDynamicStream called when disconnected";
return false;
@@ -212,7 +210,6 @@ bool QuicServerSessionBase::ShouldCreateIncomingDynamicStream(QuicStreamId id) {
}
bool QuicServerSessionBase::ShouldCreateOutgoingDynamicStream() {
- DCHECK(!FLAGS_quic_reloadable_flag_quic_refactor_stream_creation);
if (!connection()->connected()) {
QUIC_BUG << "ShouldCreateOutgoingDynamicStream called when disconnected";
return false;
diff --git a/chromium/net/quic/core/quic_server_session_base_test.cc b/chromium/net/quic/core/quic_server_session_base_test.cc
index 8c1eb8794f2..8182bd6f0b7 100644
--- a/chromium/net/quic/core/quic_server_session_base_test.cc
+++ b/chromium/net/quic/core/quic_server_session_base_test.cc
@@ -80,8 +80,6 @@ class TestServerSession : public QuicServerSessionBase {
~TestServerSession() override { delete connection(); };
protected:
- // TODO(ckrasic) - for two below, remove when
- // quic_reloadable_flag_quic_refactor_stream_creation is deprecated.
QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override {
if (!ShouldCreateIncomingDynamicStream(id)) {
return nullptr;
@@ -104,10 +102,6 @@ class TestServerSession : public QuicServerSessionBase {
return stream;
}
- std::unique_ptr<QuicStream> CreateStream(QuicStreamId id) override {
- return QuicMakeUnique<QuicSimpleServerStream>(id, this, response_cache_);
- }
-
QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache) override {
@@ -198,17 +192,6 @@ MATCHER_P(EqualsProto, network_params, "") {
INSTANTIATE_TEST_CASE_P(Tests,
QuicServerSessionBaseTest,
::testing::ValuesIn(AllSupportedVersions()));
-TEST_P(QuicServerSessionBaseTest, ServerPushDisabledByDefault) {
- FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default = true;
- // Without the client explicitly sending kSPSH, server push will be disabled
- // at the server, until version 35 when it is enabled by default.
- EXPECT_FALSE(
- session_->config()->HasReceivedConnectionOptions() &&
- ContainsQuicTag(session_->config()->ReceivedConnectionOptions(), kSPSH));
- session_->OnConfigNegotiated();
- EXPECT_TRUE(session_->server_push_enabled());
-}
-
TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) {
// Open a stream, then reset it.
// Send two bytes of payload to open it.
@@ -358,19 +341,6 @@ TEST_P(QuicServerSessionBaseTest, MaxAvailableStreams) {
session_.get(), kLimitingStreamId + 2 * next_id));
}
-// TODO(ckrasic): remove this when
-// FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default is
-// deprecated.
-TEST_P(QuicServerSessionBaseTest, EnableServerPushThroughConnectionOption) {
- FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default = false;
- // Assume server received server push connection option.
- QuicTagVector copt;
- copt.push_back(kSPSH);
- QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
- session_->OnConfigNegotiated();
- EXPECT_TRUE(session_->server_push_enabled());
-}
-
TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) {
// Incoming streams on the server session must be odd.
EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _));
@@ -381,15 +351,9 @@ TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) {
TEST_P(QuicServerSessionBaseTest, GetStreamDisconnected) {
// Don't create new streams if the connection is disconnected.
QuicConnectionPeer::TearDownLocalConnectionState(connection_);
- if (FLAGS_quic_reloadable_flag_quic_refactor_stream_creation) {
- EXPECT_EQ(nullptr, QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), GetNthClientInitiatedId(0)));
- } else {
- EXPECT_QUIC_BUG(
- QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), GetNthClientInitiatedId(0)),
- "ShouldCreateIncomingDynamicStream called when disconnected");
- }
+ EXPECT_QUIC_BUG(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ session_.get(), GetNthClientInitiatedId(0)),
+ "ShouldCreateIncomingDynamicStream called when disconnected");
}
class MockQuicCryptoServerStream : public QuicCryptoServerStream {
diff --git a/chromium/net/quic/core/quic_session.cc b/chromium/net/quic/core/quic_session.cc
index 4f7a0ab45b6..f2da8007c26 100644
--- a/chromium/net/quic/core/quic_session.cc
+++ b/chromium/net/quic/core/quic_session.cc
@@ -10,6 +10,7 @@
#include "net/quic/core/quic_connection.h"
#include "net/quic/core/quic_flow_controller.h"
#include "net/quic/platform/api/quic_bug_tracker.h"
+#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_map_util.h"
@@ -45,18 +46,18 @@ QuicSession::QuicSession(QuicConnection* connection,
perspective() == Perspective::IS_SERVER,
nullptr),
currently_writing_stream_id_(0),
- respect_goaway_(true),
use_stream_notifier_(
FLAGS_quic_reloadable_flag_quic_use_stream_notifier2),
- streams_own_data_(use_stream_notifier_ &&
- FLAGS_quic_reloadable_flag_quic_stream_owns_data) {}
+ save_data_before_consumption_(
+ use_stream_notifier_ &&
+ FLAGS_quic_reloadable_flag_quic_save_data_before_consumption2) {}
void QuicSession::Initialize() {
connection_->set_visitor(this);
if (use_stream_notifier_) {
connection_->SetStreamNotifier(this);
}
- if (streams_own_data_) {
+ if (save_data_before_consumption_) {
connection_->SetDataProducer(this);
}
connection_->SetFromConfig(config_);
@@ -743,11 +744,6 @@ QuicStream* QuicSession::GetOrCreateDynamicStream(
if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
return nullptr;
}
-
- if (FLAGS_quic_reloadable_flag_quic_refactor_stream_creation) {
- return MaybeCreateIncomingDynamicStream(stream_id);
- }
-
// Check if the new number of open streams would cause the number of
// open streams to exceed the limit.
if (GetNumOpenIncomingStreams() >= max_open_incoming_streams()) {
@@ -894,78 +890,6 @@ bool QuicSession::IsIncomingStream(QuicStreamId id) const {
return id % 2 != next_outgoing_stream_id_ % 2;
}
-bool QuicSession::ShouldCreateIncomingDynamicStream2(QuicStreamId id) {
- DCHECK(FLAGS_quic_reloadable_flag_quic_refactor_stream_creation);
- if (goaway_received() && respect_goaway_) {
- QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
- << "Already received goaway.";
- return false;
- }
- if (!IsIncomingStream(id)) {
- QUIC_DLOG(INFO) << "invalid incoming stream id: " << id;
- return false;
- }
- if (!connection()->connected()) {
- QUIC_DLOG(INFO)
- << "ShouldCreateIncomingDynamicStream called when disconnected";
- return false;
- }
- if (GetNumOpenIncomingStreams() >= max_open_incoming_streams()) {
- DVLOG(1) << "Reset stream (refused) " << id;
- SendRstStream(id, QUIC_REFUSED_STREAM, 0);
- return false;
- }
-
- return true;
-}
-
-bool QuicSession::ShouldCreateOutgoingDynamicStream2() {
- DCHECK(FLAGS_quic_reloadable_flag_quic_refactor_stream_creation);
- if (!connection()->connected()) {
- QUIC_DLOG(INFO)
- << "ShouldCreateOutgoingDynamicStream called when disconnected";
- return false;
- }
- if (!IsEncryptionEstablished()) {
- QUIC_DLOG(INFO) << "Encryption not established so no outgoing stream "
- << "created.";
- return false;
- }
- if (goaway_received() && respect_goaway_) {
- QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
- << "Already received goaway.";
- return false;
- }
- if (GetNumOpenOutgoingStreams() >= max_open_outgoing_streams()) {
- QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
- << "Already " << GetNumOpenOutgoingStreams() << " open.";
- return false;
- }
- return true;
-}
-
-QuicStream* QuicSession::MaybeCreateIncomingDynamicStream(QuicStreamId id) {
- if (!ShouldCreateIncomingDynamicStream2(id)) {
- return nullptr;
- }
- return CreateAndActivateStream(id);
-}
-
-QuicStream* QuicSession::MaybeCreateOutgoingDynamicStream(
- SpdyPriority priority) {
- if (!ShouldCreateOutgoingDynamicStream2()) {
- return nullptr;
- }
- return CreateAndActivateStream(GetNextOutgoingStreamId());
-}
-
-QuicStream* QuicSession::CreateAndActivateStream(QuicStreamId id) {
- std::unique_ptr<QuicStream> stream = CreateStream(id);
- QuicStream* stream_ptr = stream.get();
- ActivateStream(std::move(stream));
- return stream_ptr;
-}
-
void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) {
auto it = zombie_streams_.find(id);
if (it == zombie_streams_.end()) {
@@ -1024,25 +948,10 @@ void QuicSession::OnStreamFrameDiscarded(const QuicStreamFrame& frame) {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_stream_notifier2, 3, 3);
stream->OnStreamFrameDiscarded(frame);
}
-void QuicSession::SaveStreamData(QuicStreamId id,
- QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- QuicByteCount data_length) {
- QuicStream* stream = GetStream(id);
- if (stream == nullptr) {
- QUIC_BUG << "Stream " << id << " does not exist when trying to save data.";
- connection()->CloseConnection(
- QUIC_INTERNAL_ERROR, "Attempt to save data of a closed stream",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- stream->SaveStreamData(iov, iov_offset, offset, data_length);
-}
-
bool QuicSession::WriteStreamData(QuicStreamId id,
QuicStreamOffset offset,
QuicByteCount data_length,
diff --git a/chromium/net/quic/core/quic_session.h b/chromium/net/quic/core/quic_session.h
index e52b21275c2..b95ea3635c8 100644
--- a/chromium/net/quic/core/quic_session.h
+++ b/chromium/net/quic/core/quic_session.h
@@ -110,12 +110,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
bool HasOpenDynamicStreams() const override;
void OnPathDegrading() override;
- // QuicStreamFrameDataProducer methods:
- void SaveStreamData(QuicStreamId id,
- QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- QuicByteCount data_length) override;
+ // QuicStreamFrameDataProducer
bool WriteStreamData(QuicStreamId id,
QuicStreamOffset offset,
QuicByteCount data_length,
@@ -202,6 +197,9 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
const QuicSocketAddress& peer_address() const {
return connection_->peer_address();
}
+ const QuicSocketAddress& self_address() const {
+ return connection_->self_address();
+ }
QuicConnectionId connection_id() const {
return connection_->connection_id();
}
@@ -275,13 +273,11 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// Returns true if this stream should yield writes to another blocked stream.
bool ShouldYield(QuicStreamId stream_id);
- void set_respect_goaway(bool respect_goaway) {
- respect_goaway_ = respect_goaway;
- }
-
bool use_stream_notifier() const { return use_stream_notifier_; }
- bool streams_own_data() const { return streams_own_data_; }
+ bool save_data_before_consumption() const {
+ return save_data_before_consumption_;
+ }
protected:
using StaticStreamMap = QuicSmallMap<QuicStreamId, QuicStream*, 2>;
@@ -294,28 +290,6 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
using ZombieStreamMap =
QuicSmallMap<QuicStreamId, std::unique_ptr<QuicStream>, 10>;
- // TODO(ckrasic) - For all *DynamicStream2 below, rename after
- // quic_reloadable_flag_quic_refactor_stream_creation is deprecated.
-
- // Returns true if an incoming stream can be created.
- virtual bool ShouldCreateIncomingDynamicStream2(QuicStreamId id);
-
- // Returns true if an outgoing stream can be created.
- virtual bool ShouldCreateOutgoingDynamicStream2();
-
- // Creates a new stream to handle a peer-initiated stream.
- // Caller does not own the returned stream.
- // Returns nullptr and does error handling if the stream can not be created.
- virtual QuicStream* MaybeCreateIncomingDynamicStream(QuicStreamId id);
-
- // Create a new stream to handle a locally-initiated stream.
- // Caller does not own the returned stream.
- // Returns nullptr if max streams have already been opened.
- virtual QuicStream* MaybeCreateOutgoingDynamicStream(SpdyPriority priority);
-
- // TODO(ckrasic) - For all Create*DynamicStream below, remove when
- // quic_reloadable_flag_quic_refactor_stream_creation is deprecated.
-
// Creates a new stream to handle a peer-initiated stream.
// Caller does not own the returned stream.
// Returns nullptr and does error handling if the stream can not be created.
@@ -361,14 +335,6 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// Return true if given stream is peer initiated.
bool IsIncomingStream(QuicStreamId id) const;
- // Unconditionally creates a stream. Subclasses should use this to
- // provide streams appropriately subclassed from |QuicStream|,
- // e.g. |QuicSpdySession::CreateStream()| creates a |QuicSpdyStream|.
- virtual std::unique_ptr<QuicStream> CreateStream(QuicStreamId id) = 0;
-
- // Creates a stream and activates it, owned by the session.
- QuicStream* CreateAndActivateStream(QuicStreamId id);
-
StaticStreamMap& static_streams() { return static_stream_map_; }
const StaticStreamMap& static_streams() const { return static_stream_map_; }
@@ -427,8 +393,6 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
virtual void HandleRstOnValidNonexistentStream(
const QuicRstStreamFrame& frame);
- bool respect_goaway() const { return respect_goaway_; }
-
private:
friend class test::QuicSessionPeer;
@@ -522,17 +486,11 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// call stack of OnCanWrite.
QuicStreamId currently_writing_stream_id_;
- // If this is set to false, the session will ignore peer GOAWAYs and
- // allow the creation of outgoing streams regardless of the high
- // chance they will fail.
- bool respect_goaway_;
-
// This session is notified on every ack or loss.
const bool use_stream_notifier_;
- // Streams of this session own their outstanding data. Outstanding data here
- // means sent data waiting to be acked.
- const bool streams_own_data_;
+ // Application data is saved before it is actually consumed.
+ const bool save_data_before_consumption_;
DISALLOW_COPY_AND_ASSIGN(QuicSession);
};
diff --git a/chromium/net/quic/core/quic_session_test.cc b/chromium/net/quic/core/quic_session_test.cc
index fd1c15ee44a..82b7b9629ee 100644
--- a/chromium/net/quic/core/quic_session_test.cc
+++ b/chromium/net/quic/core/quic_session_test.cc
@@ -77,10 +77,6 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker {
session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
}
- void set_encryption_established(bool value) {
- encryption_established_ = value;
- }
-
// QuicCryptoStream implementation
bool encryption_established() const override {
return encryption_established_;
@@ -188,15 +184,6 @@ class TestSession : public QuicSpdySession {
bool ShouldCreateOutgoingDynamicStream() override { return true; }
- TestStream* MaybeCreateOutgoingDynamicStream(SpdyPriority priority) override {
- return static_cast<TestStream*>(
- QuicSpdySession::MaybeCreateOutgoingDynamicStream(priority));
- }
-
- std::unique_ptr<QuicStream> CreateStream(QuicStreamId id) override {
- return QuicMakeUnique<TestStream>(id, this);
- }
-
bool IsClosedStream(QuicStreamId id) {
return QuicSession::IsClosedStream(id);
}
@@ -219,8 +206,6 @@ class TestSession : public QuicSpdySession {
consumed = QuicSession::WritevData(stream, id, data, offset, state,
std::move(ack_listener));
}
- stream->set_stream_bytes_written(stream->stream_bytes_written() +
- consumed.bytes_consumed);
if (fin && consumed.fin_consumed) {
stream->set_fin_sent(true);
}
@@ -238,6 +223,10 @@ class TestSession : public QuicSpdySession {
if (stream->id() != kCryptoStreamId) {
this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
}
+ if (save_data_before_consumption()) {
+ QuicStreamPeer::SendBuffer(stream).SaveStreamData(
+ MakeIOVector("not empty", &iov), 0, 9);
+ }
QuicConsumedData consumed = WritevData(
stream, stream->id(), MakeIOVector("not empty", &iov), 0, FIN, nullptr);
return consumed;
@@ -303,9 +292,6 @@ class QuicSessionTestBase : public QuicTestWithParam<QuicVersion> {
"EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
"JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
- if (FLAGS_quic_reloadable_flag_quic_refactor_stream_creation) {
- session_.GetMutableCryptoStream()->set_encryption_established(true);
- }
}
void CheckClosedStreams() {
@@ -358,6 +344,10 @@ TEST_P(QuicSessionTestServer, PeerAddress) {
session_.peer_address());
}
+TEST_P(QuicSessionTestServer, SelfAddress) {
+ EXPECT_EQ(QuicSocketAddress(), session_.self_address());
+}
+
TEST_P(QuicSessionTestServer, IsCryptoHandshakeConfirmed) {
EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
CryptoHandshakeMessage message;
diff --git a/chromium/net/quic/core/quic_client_session_base.cc b/chromium/net/quic/core/quic_spdy_client_session_base.cc
index b13496d73d7..a1fd538cec4 100644
--- a/chromium/net/quic/core/quic_client_session_base.cc
+++ b/chromium/net/quic/core/quic_spdy_client_session_base.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_spdy_client_session_base.h"
#include "net/quic/core/quic_client_promised_info.h"
#include "net/quic/core/spdy_utils.h"
@@ -13,7 +13,7 @@ using std::string;
namespace net {
-QuicClientSessionBase::QuicClientSessionBase(
+QuicSpdyClientSessionBase::QuicSpdyClientSessionBase(
QuicConnection* connection,
QuicClientPushPromiseIndex* push_promise_index,
const QuicConfig& config)
@@ -21,7 +21,7 @@ QuicClientSessionBase::QuicClientSessionBase(
push_promise_index_(push_promise_index),
largest_promised_stream_id_(kInvalidStreamId) {}
-QuicClientSessionBase::~QuicClientSessionBase() {
+QuicSpdyClientSessionBase::~QuicSpdyClientSessionBase() {
// all promised streams for this session
for (auto& it : promised_by_id_) {
QUIC_DVLOG(1) << "erase stream " << it.first << " url " << it.second->url();
@@ -30,15 +30,16 @@ QuicClientSessionBase::~QuicClientSessionBase() {
delete connection();
}
-void QuicClientSessionBase::OnConfigNegotiated() {
+void QuicSpdyClientSessionBase::OnConfigNegotiated() {
QuicSpdySession::OnConfigNegotiated();
}
-void QuicClientSessionBase::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
+void QuicSpdyClientSessionBase::OnCryptoHandshakeEvent(
+ CryptoHandshakeEvent event) {
QuicSpdySession::OnCryptoHandshakeEvent(event);
}
-void QuicClientSessionBase::OnInitialHeadersComplete(
+void QuicSpdyClientSessionBase::OnInitialHeadersComplete(
QuicStreamId stream_id,
const SpdyHeaderBlock& response_headers) {
// Note that the strong ordering of the headers stream means that
@@ -53,7 +54,7 @@ void QuicClientSessionBase::OnInitialHeadersComplete(
promised->OnResponseHeaders(response_headers);
}
-void QuicClientSessionBase::OnPromiseHeaderList(
+void QuicSpdyClientSessionBase::OnPromiseHeaderList(
QuicStreamId stream_id,
QuicStreamId promised_stream_id,
size_t frame_len,
@@ -77,9 +78,9 @@ void QuicClientSessionBase::OnPromiseHeaderList(
stream->OnPromiseHeaderList(promised_stream_id, frame_len, header_list);
}
-bool QuicClientSessionBase::HandlePromised(QuicStreamId /* associated_id */,
- QuicStreamId promised_id,
- const SpdyHeaderBlock& headers) {
+bool QuicSpdyClientSessionBase::HandlePromised(QuicStreamId /* associated_id */,
+ QuicStreamId promised_id,
+ const SpdyHeaderBlock& headers) {
// Due to pathalogical packet re-ordering, it is possible that
// frames for the promised stream have already arrived, and the
// promised stream could be active or closed.
@@ -126,7 +127,7 @@ bool QuicClientSessionBase::HandlePromised(QuicStreamId /* associated_id */,
return true;
}
-QuicClientPromisedInfo* QuicClientSessionBase::GetPromisedByUrl(
+QuicClientPromisedInfo* QuicSpdyClientSessionBase::GetPromisedByUrl(
const string& url) {
QuicPromisedByUrlMap::iterator it =
push_promise_index_->promised_by_url()->find(url);
@@ -136,7 +137,7 @@ QuicClientPromisedInfo* QuicClientSessionBase::GetPromisedByUrl(
return nullptr;
}
-QuicClientPromisedInfo* QuicClientSessionBase::GetPromisedById(
+QuicClientPromisedInfo* QuicSpdyClientSessionBase::GetPromisedById(
const QuicStreamId id) {
QuicPromisedByIdMap::iterator it = promised_by_id_.find(id);
if (it != promised_by_id_.end()) {
@@ -145,7 +146,7 @@ QuicClientPromisedInfo* QuicClientSessionBase::GetPromisedById(
return nullptr;
}
-QuicSpdyStream* QuicClientSessionBase::GetPromisedStream(
+QuicSpdyStream* QuicSpdyClientSessionBase::GetPromisedStream(
const QuicStreamId id) {
DynamicStreamMap::iterator it = dynamic_streams().find(id);
if (it != dynamic_streams().end()) {
@@ -154,7 +155,8 @@ QuicSpdyStream* QuicClientSessionBase::GetPromisedStream(
return nullptr;
}
-void QuicClientSessionBase::DeletePromised(QuicClientPromisedInfo* promised) {
+void QuicSpdyClientSessionBase::DeletePromised(
+ QuicClientPromisedInfo* promised) {
push_promise_index_->promised_by_url()->erase(promised->url());
// Since promised_by_id_ contains the unique_ptr, this will destroy
// promised.
@@ -162,23 +164,24 @@ void QuicClientSessionBase::DeletePromised(QuicClientPromisedInfo* promised) {
headers_stream()->MaybeReleaseSequencerBuffer();
}
-void QuicClientSessionBase::OnPushStreamTimedOut(QuicStreamId stream_id) {}
+void QuicSpdyClientSessionBase::OnPushStreamTimedOut(QuicStreamId stream_id) {}
-void QuicClientSessionBase::ResetPromised(QuicStreamId id,
- QuicRstStreamErrorCode error_code) {
+void QuicSpdyClientSessionBase::ResetPromised(
+ QuicStreamId id,
+ QuicRstStreamErrorCode error_code) {
SendRstStream(id, error_code, 0);
if (!IsOpenStream(id)) {
MaybeIncreaseLargestPeerStreamId(id);
}
}
-void QuicClientSessionBase::CloseStreamInner(QuicStreamId stream_id,
- bool locally_reset) {
+void QuicSpdyClientSessionBase::CloseStreamInner(QuicStreamId stream_id,
+ bool locally_reset) {
QuicSpdySession::CloseStreamInner(stream_id, locally_reset);
headers_stream()->MaybeReleaseSequencerBuffer();
}
-bool QuicClientSessionBase::ShouldReleaseHeadersStreamSequencerBuffer() {
+bool QuicSpdyClientSessionBase::ShouldReleaseHeadersStreamSequencerBuffer() {
return num_active_requests() == 0 && promised_by_id_.empty();
}
diff --git a/chromium/net/quic/core/quic_client_session_base.h b/chromium/net/quic/core/quic_spdy_client_session_base.h
index 8e6c1a6d670..696be5edf68 100644
--- a/chromium/net/quic/core/quic_client_session_base.h
+++ b/chromium/net/quic/core/quic_spdy_client_session_base.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_QUIC_CORE_QUIC_CLIENT_SESSION_BASE_H_
-#define NET_QUIC_CORE_QUIC_CLIENT_SESSION_BASE_H_
+#ifndef NET_QUIC_CORE_QUIC_SPDY_CLIENT_SESSION_BASE_H_
+#define NET_QUIC_CORE_QUIC_SPDY_CLIENT_SESSION_BASE_H_
#include <string>
@@ -33,17 +33,17 @@ using QuicPromisedByUrlMap =
const int64_t kPushPromiseTimeoutSecs = 60;
// Base class for all client-specific QuicSession subclasses.
-class QUIC_EXPORT_PRIVATE QuicClientSessionBase
+class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase
: public QuicSpdySession,
public QuicCryptoClientStream::ProofHandler {
public:
// Takes ownership of |connection|. Caller retains ownership of
// |promised_by_url|.
- QuicClientSessionBase(QuicConnection* connection,
- QuicClientPushPromiseIndex* push_promise_index,
- const QuicConfig& config);
+ QuicSpdyClientSessionBase(QuicConnection* connection,
+ QuicClientPushPromiseIndex* push_promise_index,
+ const QuicConfig& config);
- ~QuicClientSessionBase() override;
+ ~QuicSpdyClientSessionBase() override;
void OnConfigNegotiated() override;
@@ -131,9 +131,9 @@ class QUIC_EXPORT_PRIVATE QuicClientSessionBase
QuicPromisedByIdMap promised_by_id_;
QuicStreamId largest_promised_stream_id_;
- DISALLOW_COPY_AND_ASSIGN(QuicClientSessionBase);
+ DISALLOW_COPY_AND_ASSIGN(QuicSpdyClientSessionBase);
};
} // namespace net
-#endif // NET_QUIC_CORE_QUIC_CLIENT_SESSION_BASE_H_
+#endif // NET_QUIC_CORE_QUIC_SPDY_CLIENT_SESSION_BASE_H_
diff --git a/chromium/net/quic/core/quic_spdy_session.cc b/chromium/net/quic/core/quic_spdy_session.cc
index 95369471f29..57e5d0de38f 100644
--- a/chromium/net/quic/core/quic_spdy_session.cc
+++ b/chromium/net/quic/core/quic_spdy_session.cc
@@ -16,6 +16,7 @@
#include "net/quic/platform/api/quic_logging.h"
#include "net/quic/platform/api/quic_str_cat.h"
#include "net/quic/platform/api/quic_text_utils.h"
+#include "net/spdy/core/http2_frame_decoder_adapter.h"
using std::string;
@@ -137,19 +138,19 @@ class QuicSpdySession::SpdyFramerVisitor
QUIC_INVALID_HEADERS_STREAM_DATA);
}
- void OnError(SpdyFramer* framer) override {
+ void OnError(Http2DecoderAdapter::SpdyFramerError error) override {
QuicErrorCode code = QUIC_INVALID_HEADERS_STREAM_DATA;
- SpdyFramer::SpdyFramerError error = framer->spdy_framer_error();
switch (error) {
- case SpdyFramer::SpdyFramerError::SPDY_DECOMPRESS_FAILURE:
+ case Http2DecoderAdapter::SpdyFramerError::SPDY_DECOMPRESS_FAILURE:
code = QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE;
break;
default:
break;
}
- CloseConnection(QuicStrCat("SPDY framing error: ",
- SpdyFramer::SpdyFramerErrorToString(error)),
- code);
+ CloseConnection(
+ QuicStrCat("SPDY framing error: ",
+ Http2DecoderAdapter::SpdyFramerErrorToString(error)),
+ code);
}
void OnDataFrameHeader(SpdyStreamId stream_id,
@@ -178,8 +179,7 @@ class QuicSpdySession::SpdyFramerVisitor
session_->UpdateHeaderEncoderTableSize(value);
break;
case SETTINGS_ENABLE_PUSH:
- if (FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default &&
- session_->perspective() == Perspective::IS_SERVER) {
+ if (session_->perspective() == Perspective::IS_SERVER) {
// See rfc7540, Section 6.5.2.
if (value > 1) {
CloseConnection(
@@ -309,8 +309,7 @@ class QuicSpdySession::SpdyFramerVisitor
void set_max_uncompressed_header_bytes(
size_t set_max_uncompressed_header_bytes) {
- header_list_.set_max_uncompressed_header_bytes(
- set_max_uncompressed_header_bytes);
+ header_list_.set_max_header_list_size(set_max_uncompressed_header_bytes);
}
private:
@@ -335,8 +334,9 @@ QuicSpdySession::QuicSpdySession(QuicConnection* connection,
QuicSession::Visitor* visitor,
const QuicConfig& config)
: QuicSession(connection, visitor, config),
+ max_inbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
force_hol_blocking_(false),
- server_push_enabled_(false),
+ server_push_enabled_(true),
stream_id_(kInvalidStreamId),
promised_stream_id_(kInvalidStreamId),
fin_(false),
@@ -347,8 +347,8 @@ QuicSpdySession::QuicSpdySession(QuicConnection* connection,
prev_max_timestamp_(QuicTime::Zero()),
spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
- spdy_framer_.set_visitor(spdy_framer_visitor_.get());
- spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
+ h2_deframer_.set_visitor(spdy_framer_visitor_.get());
+ h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
}
QuicSpdySession::~QuicSpdySession() {
@@ -378,6 +378,14 @@ void QuicSpdySession::Initialize() {
headers_stream_.reset(new QuicHeadersStream(this));
DCHECK_EQ(kHeadersStreamId, headers_stream_->id());
static_streams()[kHeadersStreamId] = headers_stream_.get();
+
+ if (FLAGS_quic_restart_flag_quic_header_list_size) {
+ QUIC_FLAG_COUNT_N(quic_restart_flag_quic_header_list_size, 1, 2);
+ set_max_uncompressed_header_bytes(max_inbound_header_list_size_);
+
+ // Limit HPACK buffering to 2x header list size limit.
+ set_max_decode_buffer_size_bytes(2 * max_inbound_header_list_size_);
+ }
}
void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
@@ -396,31 +404,23 @@ void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
const QuicHeaderList& header_list) {
QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
if (stream == nullptr) {
- QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_final_offset_from_trailers, 1,
- 3);
- if (FLAGS_quic_reloadable_flag_quic_final_offset_from_trailers) {
- QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_final_offset_from_trailers, 2,
- 3);
- // The stream no longer exists, but trailing headers may contain the final
- // byte offset necessary for flow control and open stream accounting.
- size_t final_byte_offset = 0;
- for (const auto& header : header_list) {
- const string& header_key = header.first;
- const string& header_value = header.second;
- if (header_key == kFinalOffsetHeaderKey) {
- if (!QuicTextUtils::StringToSizeT(header_value, &final_byte_offset)) {
- connection()->CloseConnection(
- QUIC_INVALID_HEADERS_STREAM_DATA,
- "Trailers are malformed (no final offset)",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- DVLOG(1) << "Received final byte offset in trailers for stream "
- << stream_id << ", which no longer exists.";
- OnFinalByteOffsetReceived(stream_id, final_byte_offset);
- QUIC_FLAG_COUNT_N(
- quic_reloadable_flag_quic_final_offset_from_trailers, 3, 3);
+ // The stream no longer exists, but trailing headers may contain the final
+ // byte offset necessary for flow control and open stream accounting.
+ size_t final_byte_offset = 0;
+ for (const auto& header : header_list) {
+ const string& header_key = header.first;
+ const string& header_value = header.second;
+ if (header_key == kFinalOffsetHeaderKey) {
+ if (!QuicTextUtils::StringToSizeT(header_value, &final_byte_offset)) {
+ connection()->CloseConnection(
+ QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Trailers are malformed (no final offset)",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
}
+ DVLOG(1) << "Received final byte offset in trailers for stream "
+ << stream_id << ", which no longer exists.";
+ OnFinalByteOffsetReceived(stream_id, final_byte_offset);
}
}
@@ -434,7 +434,7 @@ size_t QuicSpdySession::ProcessHeaderData(const struct iovec& iov,
QuicTime timestamp) {
DCHECK(timestamp.IsInitialized());
UpdateCurMaxTimeStamp(timestamp);
- return spdy_framer_.ProcessInput(static_cast<char*>(iov.iov_base),
+ return h2_deframer_.ProcessInput(static_cast<char*>(iov.iov_base),
iov.iov_len);
}
@@ -605,7 +605,11 @@ void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
QuicSession::OnCryptoHandshakeEvent(event);
if (FLAGS_quic_reloadable_flag_quic_send_max_header_list_size &&
event == HANDSHAKE_CONFIRMED && config()->SupportMaxHeaderListSize()) {
- SendMaxHeaderListSize(kDefaultMaxUncompressedHeaderSize);
+ if (FLAGS_quic_restart_flag_quic_header_list_size) {
+ SendMaxHeaderListSize(max_inbound_header_list_size_);
+ } else {
+ SendMaxHeaderListSize(kDefaultMaxUncompressedHeaderSize);
+ }
}
}
@@ -613,7 +617,7 @@ void QuicSpdySession::OnPromiseHeaderList(QuicStreamId stream_id,
QuicStreamId promised_stream_id,
size_t frame_len,
const QuicHeaderList& header_list) {
- string error = "OnPromiseHeaderList should be overriden in client code.";
+ string error = "OnPromiseHeaderList should be overridden in client code.";
QUIC_BUG << error;
connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
ConnectionCloseBehavior::SILENT_CLOSE);
@@ -626,7 +630,6 @@ void QuicSpdySession::OnConfigNegotiated() {
}
const QuicVersion version = connection()->version();
if (!use_stream_notifier() &&
- FLAGS_quic_reloadable_flag_quic_enable_force_hol_blocking &&
version == QUIC_VERSION_36 && config()->ForceHolBlocking(perspective())) {
force_hol_blocking_ = true;
// Since all streams are tunneled through the headers stream, it
@@ -639,9 +642,6 @@ void QuicSpdySession::OnConfigNegotiated() {
headers_stream_->flow_controller()->UpdateSendWindowOffset(
kStreamReceiveWindowLimit);
}
-
- server_push_enabled_ =
- FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default;
}
void QuicSpdySession::OnStreamFrameData(QuicStreamId stream_id,
@@ -745,7 +745,7 @@ void QuicSpdySession::SetHpackEncoderDebugVisitor(
void QuicSpdySession::SetHpackDecoderDebugVisitor(
std::unique_ptr<QuicHpackDebugVisitor> visitor) {
- spdy_framer_.SetDecoderHeaderTableDebugVisitor(
+ h2_deframer_.SetDecoderHeaderTableDebugVisitor(
std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
connection()->helper()->GetClock(), std::move(visitor))));
}
@@ -804,20 +804,4 @@ void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
-QuicSpdyStream* QuicSpdySession::MaybeCreateIncomingDynamicStream(
- QuicStreamId id) {
- return static_cast<QuicSpdyStream*>(
- QuicSession::MaybeCreateIncomingDynamicStream(id));
-}
-
-QuicSpdyStream* QuicSpdySession::MaybeCreateOutgoingDynamicStream(
- SpdyPriority priority) {
- auto* stream = static_cast<QuicSpdyStream*>(
- QuicSession::MaybeCreateOutgoingDynamicStream(priority));
- if (stream) {
- stream->SetPriority(priority);
- }
- return stream;
-}
-
} // namespace net
diff --git a/chromium/net/quic/core/quic_spdy_session.h b/chromium/net/quic/core/quic_spdy_session.h
index 17115a76139..1855d4a99c9 100644
--- a/chromium/net/quic/core/quic_spdy_session.h
+++ b/chromium/net/quic/core/quic_spdy_session.h
@@ -15,6 +15,7 @@
#include "net/quic/core/quic_spdy_stream.h"
#include "net/quic/platform/api/quic_export.h"
#include "net/quic/platform/api/quic_string_piece.h"
+#include "net/spdy/core/http2_frame_decoder_adapter.h"
namespace net {
@@ -76,7 +77,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
size_t frame_len,
const QuicHeaderList& header_list);
- // Sends contents of |iov| to spdy_framer_, returns number of bytes processd.
+ // Sends contents of |iov| to h2_deframer_, returns number of bytes processed.
size_t ProcessHeaderData(const struct iovec& iov, QuicTime timestamp);
// Writes |headers| for the stream |id| to the dedicated headers stream.
@@ -148,24 +149,26 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
// aggressively.
virtual bool ShouldReleaseHeadersStreamSequencerBuffer();
- SpdyFramer* spdy_framer() { return &spdy_framer_; }
-
void CloseConnectionWithDetails(QuicErrorCode error,
const std::string& details);
// Sets how much encoded data the hpack decoder of spdy_framer_ is willing to
// buffer.
void set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes) {
- spdy_framer_.set_max_decode_buffer_size_bytes(max_decode_buffer_size_bytes);
+ h2_deframer_.GetHpackDecoder()->set_max_decode_buffer_size_bytes(
+ max_decode_buffer_size_bytes);
}
+ // TODO(dahollings): Move to private upon deprecation of
+ // --quic_restart_flag_quic_header_list_size.
void set_max_uncompressed_header_bytes(
size_t set_max_uncompressed_header_bytes);
+ void set_max_inbound_header_list_size(size_t max_inbound_header_list_size) {
+ max_inbound_header_list_size_ = max_inbound_header_list_size;
+ }
+
protected:
- // TODO(ckrasic) - remove these two when
- // FLAGS_quic_reloadable_flag_quic_refactor_stream_creation is
- // deprecated.
// Override CreateIncomingDynamicStream() and CreateOutgoingDynamicStream()
// with QuicSpdyStream return type to make sure that all data streams are
// QuicSpdyStreams.
@@ -173,16 +176,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
QuicSpdyStream* CreateOutgoingDynamicStream(SpdyPriority priority) override =
0;
- QuicSpdyStream* MaybeCreateIncomingDynamicStream(QuicStreamId id) override;
- QuicSpdyStream* MaybeCreateOutgoingDynamicStream(
- SpdyPriority priority) override;
-
QuicSpdyStream* GetSpdyDataStream(const QuicStreamId stream_id);
- // TODO(ckrasic) - remove these two when
- // FLAGS_quic_reloadable_flag_quic_refactor_stream_creation is
- // depreacted.
-
// If an incoming stream can be created, return true.
virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id) = 0;
@@ -205,7 +200,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
std::unique_ptr<QuicHpackDebugVisitor> visitor);
// Sets the maximum size of the header compression table spdy_framer_ is
- // willing to use to decode header blocks.
+ // willing to use to encode header blocks.
void UpdateHeaderEncoderTableSize(uint32_t value);
// Called when SETTINGS_ENABLE_PUSH is received, only supported on
@@ -263,6 +258,10 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
std::unique_ptr<QuicHeadersStream> headers_stream_;
+ // The maximum size of a header block that will be accepted from the peer,
+ // defined per spec as key + value + overhead per field (uncompressed).
+ size_t max_inbound_header_list_size_;
+
// If set, redirect all data through the headers stream in order to
// simulate forced HOL blocking between streams as happens in
// HTTP/2 over TCP.
@@ -291,6 +290,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
QuicTime prev_max_timestamp_;
SpdyFramer spdy_framer_;
+ Http2DecoderAdapter h2_deframer_;
std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
DISALLOW_COPY_AND_ASSIGN(QuicSpdySession);
diff --git a/chromium/net/quic/core/quic_spdy_stream.cc b/chromium/net/quic/core/quic_spdy_stream.cc
index a1034f0664c..1c44653eccf 100644
--- a/chromium/net/quic/core/quic_spdy_stream.cc
+++ b/chromium/net/quic/core/quic_spdy_stream.cc
@@ -14,6 +14,7 @@
#include "net/quic/platform/api/quic_logging.h"
#include "net/quic/platform/api/quic_string_piece.h"
#include "net/quic/platform/api/quic_text_utils.h"
+#include "net/spdy/core/spdy_protocol.h"
using base::IntToString;
using std::string;
@@ -271,7 +272,7 @@ bool QuicSpdyStream::FinishedReadingHeaders() const {
bool QuicSpdyStream::ParseHeaderStatusCode(const SpdyHeaderBlock& header,
int* status_code) const {
- SpdyHeaderBlock::const_iterator it = header.find(":status");
+ SpdyHeaderBlock::const_iterator it = header.find(kHttp2StatusHeader);
if (it == header.end()) {
return false;
}
diff --git a/chromium/net/quic/core/quic_spdy_stream_test.cc b/chromium/net/quic/core/quic_spdy_stream_test.cc
index eb295251a9d..6eb3423be55 100644
--- a/chromium/net/quic/core/quic_spdy_stream_test.cc
+++ b/chromium/net/quic/core/quic_spdy_stream_test.cc
@@ -924,7 +924,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersWithQueuedBytes) {
stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
// Write non-zero body data, but only consume partially, ensuring queueing.
- const int kBodySize = 1 * 1024; // 1 MB
+ const int kBodySize = 1 * 1024; // 1 KB
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(kBodySize - 1, false)));
stream_->WriteOrBufferData(string(kBodySize, 'x'), false, nullptr);
@@ -973,8 +973,7 @@ TEST_P(QuicSpdyStreamTest, HeaderStreamNotiferCorrespondingSpdyStream) {
}
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.Times(AnyNumber())
- .WillRepeatedly(
- Invoke(session_.get(), &MockQuicSpdySession::ConsumeAndSaveAllData));
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
testing::InSequence s;
QuicReferenceCountedPointer<MockAckListener> ack_listener1(
new MockAckListener());
diff --git a/chromium/net/quic/core/quic_stream.cc b/chromium/net/quic/core/quic_stream.cc
index e8583b62c04..4afb5c24531 100644
--- a/chromium/net/quic/core/quic_stream.cc
+++ b/chromium/net/quic/core/quic_stream.cc
@@ -7,6 +7,8 @@
#include "net/quic/core/quic_flow_controller.h"
#include "net/quic/core/quic_session.h"
#include "net/quic/platform/api/quic_bug_tracker.h"
+#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"
using std::string;
@@ -78,7 +80,10 @@ QuicStream::QuicStream(QuicStreamId id, QuicSession* session)
busy_counter_(0),
add_random_padding_after_fin_(false),
ack_listener_(nullptr),
- send_buffer_(session->connection()->helper()->GetBufferAllocator()) {
+ send_buffer_(
+ session->connection()->helper()->GetStreamSendBufferAllocator()),
+ buffered_data_threshold_(
+ GetQuicFlag(FLAGS_quic_buffered_data_threshold)) {
SetFromConfig();
}
@@ -214,6 +219,26 @@ void QuicStream::WriteOrBufferData(
QuicConsumedData consumed_data(0, false);
fin_buffered_ = fin;
+ if (session_->save_data_before_consumption()) {
+ bool had_buffered_data = HasBufferedData();
+ // Do not respect buffered data upper limit as WriteOrBufferData guarantees
+ // all data to be consumed.
+ if (data.length() > 0) {
+ struct iovec iov(MakeIovec(data));
+ QuicIOVector quic_iov(&iov, 1, data.length());
+ QuicStreamOffset offset = send_buffer_.stream_offset();
+ send_buffer_.SaveStreamData(quic_iov, 0, data.length());
+ OnDataBuffered(offset, data.length(), ack_listener);
+ }
+ if (!had_buffered_data && (HasBufferedData() || fin_buffered_)) {
+ // Write data if there is no buffered data before.
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_save_data_before_consumption2,
+ 2, 4);
+ WriteBufferedData();
+ }
+ return;
+ }
+
if (queued_data_.empty()) {
struct iovec iov(MakeIovec(data));
consumed_data = WritevData(&iov, 1, fin, ack_listener);
@@ -230,6 +255,26 @@ void QuicStream::WriteOrBufferData(
}
void QuicStream::OnCanWrite() {
+ if (session_->save_data_before_consumption()) {
+ DCHECK(queued_data_.empty());
+ if (write_side_closed_) {
+ QUIC_DLOG(ERROR) << ENDPOINT << "Stream " << id()
+ << "attempting to write when the write side is closed";
+ return;
+ }
+ if (HasBufferedData() || (fin_buffered_ && !fin_sent_)) {
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_save_data_before_consumption2,
+ 3, 4);
+ WriteBufferedData();
+ }
+ if (!fin_buffered_ && !fin_sent_ && CanWriteNewData()) {
+ // Notify upper layer to write new data when buffered data size is below
+ // low water mark.
+ OnCanWriteNewData();
+ }
+ return;
+ }
+
bool fin = false;
while (!queued_data_.empty()) {
PendingData* pending_data = &queued_data_.front();
@@ -299,6 +344,38 @@ QuicConsumedData QuicStream::WritevData(
}
}
+ if (session_->save_data_before_consumption()) {
+ QuicConsumedData consumed_data(0, false);
+ if (fin_buffered_) {
+ QUIC_BUG << "Fin already buffered";
+ return consumed_data;
+ }
+
+ bool had_buffered_data = HasBufferedData();
+ if (CanWriteNewData()) {
+ // Save all data if buffered data size is below low water mark.
+ QuicIOVector quic_iovec(iov, iov_count, write_length);
+ consumed_data.bytes_consumed = write_length;
+ if (consumed_data.bytes_consumed > 0) {
+ QuicStreamOffset offset = send_buffer_.stream_offset();
+ send_buffer_.SaveStreamData(quic_iovec, 0, write_length);
+ OnDataBuffered(offset, write_length, ack_listener);
+ }
+ }
+ consumed_data.fin_consumed =
+ consumed_data.bytes_consumed == write_length && fin;
+ fin_buffered_ = consumed_data.fin_consumed;
+
+ if (!had_buffered_data && (HasBufferedData() || fin_buffered_)) {
+ // Write data if there is no buffered data before.
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_save_data_before_consumption2,
+ 1, 4);
+ WriteBufferedData();
+ }
+
+ return consumed_data;
+ }
+
// A FIN with zero data payload should not be flow control blocked.
bool fin_with_zero_data = (fin && write_length == 0);
@@ -409,6 +486,11 @@ void QuicStream::CloseWriteSide() {
}
bool QuicStream::HasBufferedData() const {
+ if (session_->save_data_before_consumption()) {
+ DCHECK(queued_data_.empty());
+ DCHECK_GE(send_buffer_.stream_offset(), stream_bytes_written_);
+ return send_buffer_.stream_offset() > stream_bytes_written_;
+ }
return !queued_data_.empty();
}
@@ -511,12 +593,14 @@ void QuicStream::OnStreamFrameAcked(const QuicStreamFrame& frame,
QuicTime::Delta ack_delay_time) {
OnStreamFrameDiscarded(frame);
if (ack_listener_ != nullptr) {
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_stream_notifier2, 1, 3);
ack_listener_->OnPacketAcked(frame.data_length, ack_delay_time);
}
}
void QuicStream::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) {
if (ack_listener_ != nullptr) {
+ QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_stream_notifier2, 2, 3);
ack_listener_->OnPacketRetransmitted(frame.data_length);
}
}
@@ -533,7 +617,7 @@ void QuicStream::OnStreamFrameDiscarded(const QuicStreamFrame& frame) {
if (frame.fin) {
fin_outstanding_ = false;
}
- if (session_->streams_own_data() && frame.data_length > 0) {
+ if (session_->save_data_before_consumption() && frame.data_length > 0) {
send_buffer_.RemoveStreamFrame(frame.offset, frame.data_length);
}
if (!IsWaitingForAcks()) {
@@ -545,14 +629,6 @@ bool QuicStream::IsWaitingForAcks() const {
return stream_bytes_outstanding_ || fin_outstanding_;
}
-void QuicStream::SaveStreamData(QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- QuicByteCount data_length) {
- DCHECK_LT(0u, data_length);
- send_buffer_.SaveStreamData(iov, iov_offset, offset, data_length);
-}
-
bool QuicStream::WriteStreamData(QuicStreamOffset offset,
QuicByteCount data_length,
QuicDataWriter* writer) {
@@ -560,4 +636,99 @@ bool QuicStream::WriteStreamData(QuicStreamOffset offset,
return send_buffer_.WriteStreamData(offset, data_length, writer);
}
+void QuicStream::WriteBufferedData() {
+ DCHECK(!write_side_closed_ && queued_data_.empty() &&
+ (HasBufferedData() || fin_buffered_));
+
+ if (session_->ShouldYield(id())) {
+ session_->MarkConnectionLevelWriteBlocked(id());
+ return;
+ }
+
+ // Size of buffered data.
+ size_t write_length = queued_data_bytes();
+
+ // A FIN with zero data payload should not be flow control blocked.
+ bool fin_with_zero_data = (fin_buffered_ && write_length == 0);
+
+ bool fin = fin_buffered_;
+
+ // How much data flow control permits to be written.
+ QuicByteCount send_window = flow_controller_.SendWindowSize();
+ if (stream_contributes_to_connection_flow_control_) {
+ send_window =
+ std::min(send_window, connection_flow_controller_->SendWindowSize());
+ }
+
+ if (send_window == 0 && !fin_with_zero_data) {
+ // Quick return if nothing can be sent.
+ MaybeSendBlocked();
+ return;
+ }
+
+ if (write_length > send_window) {
+ // Don't send the FIN unless all the data will be sent.
+ fin = false;
+
+ // Writing more data would be a violation of flow control.
+ write_length = static_cast<size_t>(send_window);
+ QUIC_DVLOG(1) << "stream " << id() << " shortens write length to "
+ << write_length << " due to flow control";
+ }
+
+ QuicConsumedData consumed_data = WritevDataInner(
+ QuicIOVector(/*iov=*/nullptr, /*iov_count=*/0, write_length),
+ stream_bytes_written_, fin, nullptr);
+
+ stream_bytes_written_ += consumed_data.bytes_consumed;
+ stream_bytes_outstanding_ += consumed_data.bytes_consumed;
+
+ AddBytesSent(consumed_data.bytes_consumed);
+ QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ << " sends "
+ << stream_bytes_written_ << " bytes "
+ << " and has buffered data " << queued_data_bytes() << " bytes."
+ << " fin is sent: " << consumed_data.fin_consumed
+ << " fin is buffered: " << fin_buffered_;
+
+ // The write may have generated a write error causing this stream to be
+ // closed. If so, simply return without marking the stream write blocked.
+ if (write_side_closed_) {
+ return;
+ }
+
+ if (consumed_data.bytes_consumed == write_length) {
+ if (!fin_with_zero_data) {
+ MaybeSendBlocked();
+ }
+ if (fin && consumed_data.fin_consumed) {
+ fin_sent_ = true;
+ fin_outstanding_ = true;
+ if (fin_received_) {
+ session_->StreamDraining(id_);
+ }
+ CloseWriteSide();
+ } else if (fin && !consumed_data.fin_consumed) {
+ session_->MarkConnectionLevelWriteBlocked(id());
+ }
+ } else {
+ session_->MarkConnectionLevelWriteBlocked(id());
+ }
+ if (consumed_data.bytes_consumed > 0 || consumed_data.fin_consumed) {
+ busy_counter_ = 0;
+ }
+}
+
+uint64_t QuicStream::queued_data_bytes() const {
+ if (session_->save_data_before_consumption()) {
+ DCHECK_EQ(0u, queued_data_bytes_);
+ DCHECK_GE(send_buffer_.stream_offset(), stream_bytes_written_);
+ return send_buffer_.stream_offset() - stream_bytes_written_;
+ }
+ return queued_data_bytes_;
+}
+
+bool QuicStream::CanWriteNewData() const {
+ return queued_data_bytes() < buffered_data_threshold_;
+}
+
} // namespace net
diff --git a/chromium/net/quic/core/quic_stream.h b/chromium/net/quic/core/quic_stream.h
index a8bff46d130..be60503def0 100644
--- a/chromium/net/quic/core/quic_stream.h
+++ b/chromium/net/quic/core/quic_stream.h
@@ -114,14 +114,12 @@ class QUIC_EXPORT_PRIVATE QuicStream : public StreamNotifierInterface {
bool fin_received() { return fin_received_; }
bool fin_sent() { return fin_sent_; }
- uint64_t queued_data_bytes() const { return queued_data_bytes_; }
+ // TODO(fayang): Rename this function to BufferedDataBytes() when
+ // deprecating quic_reloadable_flag_quic_save_data_before_consumption2.
+ uint64_t queued_data_bytes() const;
uint64_t stream_bytes_read() const { return stream_bytes_read_; }
uint64_t stream_bytes_written() const { return stream_bytes_written_; }
- // For tests that override WritevData.
- void set_stream_bytes_written(uint64_t bytes_written) {
- stream_bytes_written_ = bytes_written;
- }
size_t busy_counter() const { return busy_counter_; }
void set_busy_counter(size_t busy_counter) { busy_counter_ = busy_counter; }
@@ -197,12 +195,6 @@ class QUIC_EXPORT_PRIVATE QuicStream : public StreamNotifierInterface {
// Adds random padding after the fin is consumed for this stream.
void AddRandomPaddingAfterFin();
- // Save |data_length| of data starts at |iov_offset| in |iov| to send buffer.
- void SaveStreamData(QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- QuicByteCount data_length);
-
// Write |data_length| of data starts at |offset| from send buffer.
bool WriteStreamData(QuicStreamOffset offset,
QuicByteCount data_length,
@@ -216,10 +208,17 @@ class QUIC_EXPORT_PRIVATE QuicStream : public StreamNotifierInterface {
protected:
// Sends as many bytes in the first |count| buffers of |iov| to the connection
- // as the connection will consume.
+ // as the connection will consume. If FIN is consumed, the write side is
+ // immediately closed.
// If |ack_listener| is provided, then it will be notified once all
// the ACKs for this write have been received.
// Returns the number of bytes consumed by the connection.
+ // Please note: when quic_reloadable_flag_quic_save_data_before_consumption2
+ // is true, returned consumed data is the amount of data saved in send buffer.
+ // The data is not necessarily consumed by the connection. So write side is
+ // closed when FIN is sent.
+ // TODO(fayang): Let WritevData return boolean when deprecating
+ // quic_reloadable_flag_quic_save_data_before_consumption2.
QuicConsumedData WritevData(
const struct iovec* iov,
int iov_count,
@@ -239,6 +238,26 @@ class QUIC_EXPORT_PRIVATE QuicStream : public StreamNotifierInterface {
// Does not send a FIN. May cause the stream to be closed.
virtual void CloseWriteSide();
+ // Close the read side of the socket. May cause the stream to be closed.
+ // Subclasses and consumers should use StopReading to terminate reading early
+ // if expecting a FIN. Can be used directly by subclasses if not expecting a
+ // FIN.
+ void CloseReadSide();
+
+ // Called when data of [offset, offset + data_length] is buffered in send
+ // buffer.
+ virtual void OnDataBuffered(
+ QuicStreamOffset offset,
+ QuicByteCount data_length,
+ const QuicReferenceCountedPointer<QuicAckListenerInterface>&
+ ack_listener) {}
+
+ // True if buffered data in send buffer is below buffered_data_threshold_.
+ bool CanWriteNewData() const;
+
+ // Called when upper layer can write new data.
+ virtual void OnCanWriteNewData() {}
+
bool fin_buffered() const { return fin_buffered_; }
const QuicSession* session() const { return session_; }
@@ -260,10 +279,6 @@ class QUIC_EXPORT_PRIVATE QuicStream : public StreamNotifierInterface {
friend class test::QuicStreamPeer;
friend class QuicStreamUtils;
- // Close the read side of the socket. May cause the stream to be closed.
- // Subclasses and consumers should use StopReading to terminate reading early.
- void CloseReadSide();
-
// Subclasses and consumers should use reading_stopped.
bool read_side_closed() const { return read_side_closed_; }
@@ -288,8 +303,15 @@ class QUIC_EXPORT_PRIVATE QuicStream : public StreamNotifierInterface {
// controller, marks this stream as connection-level write blocked.
void MaybeSendBlocked();
+ // Write buffered data in send buffer. TODO(fayang): Consider combine
+ // WriteOrBufferData, Writev and WriteBufferedData when deprecating
+ // quic_reloadable_flag_quic_save_data_before_consumption2.
+ void WriteBufferedData();
+
std::list<PendingData> queued_data_;
// How many bytes are queued?
+ // TODO(fayang): Remove this variable when deprecating
+ // quic_reloadable_flag_quic_save_data_before_consumption2.
uint64_t queued_data_bytes_;
QuicStreamSequencer sequencer_;
@@ -366,6 +388,9 @@ class QUIC_EXPORT_PRIVATE QuicStream : public StreamNotifierInterface {
// or discarded.
QuicStreamSendBuffer send_buffer_;
+ // Latched value of FLAGS_quic_buffered_data_threshold.
+ const QuicByteCount buffered_data_threshold_;
+
DISALLOW_COPY_AND_ASSIGN(QuicStream);
};
diff --git a/chromium/net/quic/core/quic_stream_frame_data_producer.h b/chromium/net/quic/core/quic_stream_frame_data_producer.h
index abe8af1fb67..9786da6efce 100644
--- a/chromium/net/quic/core/quic_stream_frame_data_producer.h
+++ b/chromium/net/quic/core/quic_stream_frame_data_producer.h
@@ -12,18 +12,11 @@ namespace net {
class QuicDataWriter;
-// Pure virtual class to save and retrieve stream data.
+// Pure virtual class to retrieve stream data.
class QUIC_EXPORT_PRIVATE QuicStreamFrameDataProducer {
public:
virtual ~QuicStreamFrameDataProducer() {}
- // Save |data_length| data starts at |iov_offset| in |iov|.
- virtual void SaveStreamData(QuicStreamId id,
- QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- QuicByteCount data_length) = 0;
-
// Let |writer| write |data_length| data with |offset| of stream |id|. Returns
// false when the writing fails either because stream is closed or
// corresponding data is failed to be retrieved. This method allows writing a
diff --git a/chromium/net/quic/core/quic_stream_send_buffer.cc b/chromium/net/quic/core/quic_stream_send_buffer.cc
index e38d1008dd7..c091ca6574a 100644
--- a/chromium/net/quic/core/quic_stream_send_buffer.cc
+++ b/chromium/net/quic/core/quic_stream_send_buffer.cc
@@ -9,6 +9,8 @@
#include "net/quic/core/quic_stream_send_buffer.h"
#include "net/quic/core/quic_utils.h"
#include "net/quic/platform/api/quic_bug_tracker.h"
+#include "net/quic/platform/api/quic_flags.h"
+#include "net/quic/platform/api/quic_logging.h"
namespace net {
@@ -18,23 +20,28 @@ QuicStreamDataSlice::QuicStreamDataSlice(UniqueStreamBuffer data,
: data(std::move(data)),
offset(offset),
data_length(data_length),
- data_length_waiting_for_acks(data_length) {}
+ outstanding_data_length(data_length) {}
QuicStreamDataSlice::~QuicStreamDataSlice() {}
QuicStreamSendBuffer::QuicStreamSendBuffer(QuicBufferAllocator* allocator)
- : allocator_(allocator) {}
+ : stream_offset_(0), allocator_(allocator) {}
QuicStreamSendBuffer::~QuicStreamSendBuffer() {}
void QuicStreamSendBuffer::SaveStreamData(QuicIOVector iov,
size_t iov_offset,
- QuicStreamOffset offset,
QuicByteCount data_length) {
- DCHECK_LE(iov_offset + data_length, iov.total_length);
- UniqueStreamBuffer buffer = NewStreamBuffer(allocator_, data_length);
- QuicUtils::CopyToBuffer(iov, iov_offset, data_length, buffer.get());
- send_buffer_.emplace_back(std::move(buffer), offset, data_length);
+ DCHECK_LT(0u, data_length);
+ // Latch the maximum data slice size.
+ const QuicByteCount max_data_slice_size =
+ GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size);
+ while (data_length > 0) {
+ size_t slice_len = std::min(data_length, max_data_slice_size);
+ SaveStreamDataOneSlice(iov, iov_offset, slice_len);
+ data_length -= slice_len;
+ iov_offset += slice_len;
+ }
}
bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset,
@@ -62,7 +69,6 @@ bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset,
void QuicStreamSendBuffer::RemoveStreamFrame(QuicStreamOffset offset,
QuicByteCount data_length) {
- DCHECK_LT(0u, data_length);
for (QuicStreamDataSlice& slice : send_buffer_) {
if (offset < slice.offset) {
break;
@@ -73,7 +79,7 @@ void QuicStreamSendBuffer::RemoveStreamFrame(QuicStreamOffset offset,
QuicByteCount slice_offset = offset - slice.offset;
QuicByteCount removing_length =
std::min(data_length, slice.data_length - slice_offset);
- slice.data_length_waiting_for_acks -= removing_length;
+ slice.outstanding_data_length -= removing_length;
offset += removing_length;
data_length -= removing_length;
}
@@ -82,11 +88,21 @@ void QuicStreamSendBuffer::RemoveStreamFrame(QuicStreamOffset offset,
// Remove data which stops waiting for acks. Please note, data can be
// acked out of order, but send buffer is cleaned up in order.
while (!send_buffer_.empty() &&
- send_buffer_.front().data_length_waiting_for_acks == 0) {
+ send_buffer_.front().outstanding_data_length == 0) {
send_buffer_.pop_front();
}
}
+void QuicStreamSendBuffer::SaveStreamDataOneSlice(QuicIOVector iov,
+ size_t iov_offset,
+ QuicByteCount data_length) {
+ DCHECK_LE(iov_offset + data_length, iov.total_length);
+ UniqueStreamBuffer buffer = NewStreamBuffer(allocator_, data_length);
+ QuicUtils::CopyToBuffer(iov, iov_offset, data_length, buffer.get());
+ send_buffer_.emplace_back(std::move(buffer), stream_offset_, data_length);
+ stream_offset_ += data_length;
+}
+
size_t QuicStreamSendBuffer::size() const {
return send_buffer_.size();
}
diff --git a/chromium/net/quic/core/quic_stream_send_buffer.h b/chromium/net/quic/core/quic_stream_send_buffer.h
index 15345213b31..14e50f76af3 100644
--- a/chromium/net/quic/core/quic_stream_send_buffer.h
+++ b/chromium/net/quic/core/quic_stream_send_buffer.h
@@ -12,6 +12,10 @@
namespace net {
+namespace test {
+class QuicStreamSendBufferPeer;
+} // namespace test
+
class QuicDataWriter;
// QuicStreamDataSlice comprises information of a piece of stream data.
@@ -29,8 +33,8 @@ struct QuicStreamDataSlice {
QuicStreamOffset offset;
// Length of this data slice in bytes.
QuicByteCount data_length;
- // Length of payload which is waiting for acks.
- QuicByteCount data_length_waiting_for_acks;
+ // Length of payload which is outstanding and waiting for acks.
+ QuicByteCount outstanding_data_length;
};
// QuicStreamSendBuffer contains a list of QuicStreamDataSlices. New data slices
@@ -47,7 +51,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer {
// Save |data_length| of data starts at |iov_offset| in |iov| to send buffer.
void SaveStreamData(QuicIOVector iov,
size_t iov_offset,
- QuicStreamOffset offset,
QuicByteCount data_length);
// Write |data_length| of data starts at |offset|.
@@ -62,9 +65,21 @@ class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer {
// Number of data slices in send buffer.
size_t size() const;
+ QuicStreamOffset stream_offset() const { return stream_offset_; }
+
private:
+ friend class test::QuicStreamSendBufferPeer;
+ // Save |data_length| of data starts at |iov_offset| in |iov| to one data
+ // slice which contains data in a contiguous memory space.
+ void SaveStreamDataOneSlice(QuicIOVector iov,
+ size_t iov_offset,
+ QuicByteCount data_length);
+
std::deque<QuicStreamDataSlice> send_buffer_;
+ // Offset of next inserted byte.
+ QuicStreamOffset stream_offset_;
+
QuicBufferAllocator* allocator_;
};
diff --git a/chromium/net/quic/core/quic_stream_send_buffer_test.cc b/chromium/net/quic/core/quic_stream_send_buffer_test.cc
index d3520a8f09a..95d2bc0f9a1 100644
--- a/chromium/net/quic/core/quic_stream_send_buffer_test.cc
+++ b/chromium/net/quic/core/quic_stream_send_buffer_test.cc
@@ -7,6 +7,7 @@
#include "net/quic/core/quic_data_writer.h"
#include "net/quic/core/quic_simple_buffer_allocator.h"
#include "net/quic/core/quic_utils.h"
+#include "net/quic/platform/api/quic_flags.h"
#include "net/quic/platform/api/quic_test.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -35,14 +36,9 @@ class QuicStreamSendBufferTest : public QuicTest {
iov[2] = MakeIovec(QuicStringPiece(data3));
QuicIOVector quic_iov(iov, 3, 3840);
- // Add all data.
- send_buffer_.SaveStreamData(quic_iov, /*iov_offset=*/0, /*offset=*/0, 1024);
- send_buffer_.SaveStreamData(quic_iov, /*iov_offset=*/1024,
- /*offset=*/1024, 1024);
- send_buffer_.SaveStreamData(quic_iov, /*iov_offset=*/2048,
- /*offset=*/2048, 1024);
- send_buffer_.SaveStreamData(quic_iov, /*iov_offset=*/3072,
- /*offset=*/3072, 768);
+ // Save all data.
+ SetQuicFlag(&FLAGS_quic_send_buffer_max_data_slice_size, 1024);
+ send_buffer_.SaveStreamData(quic_iov, 0, 3840);
EXPECT_EQ(4u, send_buffer_.size());
}
diff --git a/chromium/net/quic/core/quic_stream_sequencer_test.cc b/chromium/net/quic/core/quic_stream_sequencer_test.cc
index f65394dc730..8ca75ff1656 100644
--- a/chromium/net/quic/core/quic_stream_sequencer_test.cc
+++ b/chromium/net/quic/core/quic_stream_sequencer_test.cc
@@ -27,8 +27,6 @@ using testing::_;
using testing::AnyNumber;
using testing::CreateFunctor;
using testing::InSequence;
-using testing::Return;
-using testing::StrEq;
namespace net {
namespace test {
@@ -43,7 +41,6 @@ class MockStream : public QuicStream {
void(QuicErrorCode error, const string& details));
MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error));
MOCK_METHOD0(OnCanWrite, void());
- virtual bool IsFlowControlEnabled() const { return true; }
const QuicSocketAddress& PeerAddressOfLatestPacket() const override {
return peer_address_;
diff --git a/chromium/net/quic/core/quic_stream_test.cc b/chromium/net/quic/core/quic_stream_test.cc
index e9e04a92261..77164b0bb29 100644
--- a/chromium/net/quic/core/quic_stream_test.cc
+++ b/chromium/net/quic/core/quic_stream_test.cc
@@ -48,23 +48,19 @@ const bool kShouldNotProcessData = false;
class TestStream : public QuicStream {
public:
TestStream(QuicStreamId id, QuicSession* session, bool should_process_data)
- : QuicStream(id, session), should_process_data_(should_process_data) {}
+ : QuicStream(id, session) {}
void OnDataAvailable() override {}
- uint32_t ProcessRawData(const char* data, uint32_t data_len) {
- EXPECT_NE(0u, data_len);
- QUIC_DVLOG(1) << "ProcessData data_len: " << data_len;
- data_ += string(data, data_len);
- return should_process_data_ ? data_len : 0;
- }
+ MOCK_METHOD0(OnCanWriteNewData, void());
+ using QuicStream::CanWriteNewData;
using QuicStream::WriteOrBufferData;
+ using QuicStream::WritevData;
using QuicStream::CloseWriteSide;
using QuicStream::OnClose;
private:
- bool should_process_data_;
string data_;
};
@@ -249,17 +245,23 @@ TEST_F(QuicStreamTest, WriteOrBufferData) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(kDataLen - 1, false)));
stream_->WriteOrBufferData(kData1, false, nullptr);
+ EXPECT_EQ(1u, stream_->queued_data_bytes());
EXPECT_TRUE(HasWriteBlockedStreams());
// Queue a bytes_consumed write.
stream_->WriteOrBufferData(kData2, false, nullptr);
-
+ EXPECT_EQ(10u, stream_->queued_data_bytes());
// Make sure we get the tail of the first write followed by the bytes_consumed
InSequence s;
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(1, false)));
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(kDataLen - 2, false)));
+ if (session_->save_data_before_consumption()) {
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kDataLen - 1, false)));
+ } else {
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(1, false)));
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kDataLen - 2, false)));
+ }
stream_->OnCanWrite();
// And finally the end of the bytes_consumed.
@@ -717,15 +719,14 @@ TEST_F(QuicStreamTest, EarlyResponseFinHandling) {
TEST_F(QuicStreamTest, StreamWaitsForAcks) {
Initialize(kShouldProcessData);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillRepeatedly(
- Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
// Stream is not waiting for acks initially.
EXPECT_FALSE(stream_->IsWaitingForAcks());
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
// Send kData1.
stream_->WriteOrBufferData(kData1, false, nullptr);
- if (session_->streams_own_data()) {
+ if (session_->save_data_before_consumption()) {
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
} else {
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
@@ -740,14 +741,14 @@ TEST_F(QuicStreamTest, StreamWaitsForAcks) {
// Send kData2.
stream_->WriteOrBufferData(kData2, false, nullptr);
EXPECT_TRUE(stream_->IsWaitingForAcks());
- if (session_->streams_own_data()) {
+ if (session_->save_data_before_consumption()) {
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
} else {
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
}
// Send FIN.
stream_->WriteOrBufferData("", true, nullptr);
- if (session_->streams_own_data()) {
+ if (session_->save_data_before_consumption()) {
// Fin only frame is not stored in send buffer.
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
} else {
@@ -771,14 +772,13 @@ TEST_F(QuicStreamTest, StreamWaitsForAcks) {
TEST_F(QuicStreamTest, StreamDataGetAckedOutOfOrder) {
Initialize(kShouldProcessData);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillRepeatedly(
- Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
// Send data.
stream_->WriteOrBufferData(kData1, false, nullptr);
stream_->WriteOrBufferData(kData1, false, nullptr);
stream_->WriteOrBufferData(kData1, false, nullptr);
stream_->WriteOrBufferData("", true, nullptr);
- if (session_->streams_own_data()) {
+ if (session_->save_data_before_consumption()) {
EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size());
} else {
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
@@ -790,11 +790,11 @@ TEST_F(QuicStreamTest, StreamDataGetAckedOutOfOrder) {
QuicStreamFrame frame3(stream_->id(), false, 18, kData1);
QuicStreamFrame frame4(stream_->id(), true, 27, "");
stream_->OnStreamFrameAcked(frame2, QuicTime::Delta::Zero());
- if (session_->streams_own_data()) {
+ if (session_->save_data_before_consumption()) {
EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size());
}
stream_->OnStreamFrameAcked(frame3, QuicTime::Delta::Zero());
- if (session_->streams_own_data()) {
+ if (session_->save_data_before_consumption()) {
EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size());
}
stream_->OnStreamFrameDiscarded(frame1);
@@ -808,15 +808,14 @@ TEST_F(QuicStreamTest, StreamDataGetAckedOutOfOrder) {
TEST_F(QuicStreamTest, CancelStream) {
Initialize(kShouldProcessData);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillRepeatedly(
- Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
EXPECT_FALSE(stream_->IsWaitingForAcks());
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
stream_->WriteOrBufferData(kData1, false, nullptr);
QuicStreamFrame frame(stream_->id(), 0, false, kData1);
EXPECT_TRUE(stream_->IsWaitingForAcks());
- if (session_->streams_own_data()) {
+ if (session_->save_data_before_consumption()) {
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
} else {
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
@@ -840,15 +839,14 @@ TEST_F(QuicStreamTest, CancelStream) {
TEST_F(QuicStreamTest, RstFrameReceivedStreamNotFinishSending) {
Initialize(kShouldProcessData);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillRepeatedly(
- Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
EXPECT_FALSE(stream_->IsWaitingForAcks());
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
stream_->WriteOrBufferData(kData1, false, nullptr);
QuicStreamFrame frame(stream_->id(), 0, false, kData1);
EXPECT_TRUE(stream_->IsWaitingForAcks());
- if (session_->streams_own_data()) {
+ if (session_->save_data_before_consumption()) {
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
} else {
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
@@ -871,8 +869,7 @@ TEST_F(QuicStreamTest, RstFrameReceivedStreamNotFinishSending) {
TEST_F(QuicStreamTest, RstFrameReceivedStreamFinishSending) {
Initialize(kShouldProcessData);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillRepeatedly(
- Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
EXPECT_FALSE(stream_->IsWaitingForAcks());
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
@@ -885,7 +882,7 @@ TEST_F(QuicStreamTest, RstFrameReceivedStreamFinishSending) {
stream_->OnStreamReset(rst_frame);
// Stream stops waiting for acks as it has unacked data.
EXPECT_TRUE(stream_->IsWaitingForAcks());
- if (session_->streams_own_data()) {
+ if (session_->save_data_before_consumption()) {
EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
} else {
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
@@ -895,8 +892,7 @@ TEST_F(QuicStreamTest, RstFrameReceivedStreamFinishSending) {
TEST_F(QuicStreamTest, ConnectionClosed) {
Initialize(kShouldProcessData);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillRepeatedly(
- Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
EXPECT_FALSE(stream_->IsWaitingForAcks());
EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
@@ -916,6 +912,96 @@ TEST_F(QuicStreamTest, ConnectionClosed) {
}
}
+TEST_F(QuicStreamTest, WriteBufferedData) {
+ // Set buffered data low water mark to be 100.
+ SetQuicFlag(&FLAGS_quic_buffered_data_threshold, 100);
+ // Do not stream level flow control block this stream.
+ set_initial_flow_control_window_bytes(500000);
+
+ Initialize(kShouldProcessData);
+ if (!session_->save_data_before_consumption()) {
+ return;
+ }
+ string data(1024, 'a');
+ EXPECT_TRUE(stream_->CanWriteNewData());
+
+ // Testing WriteOrBufferData.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(100, false)));
+ stream_->WriteOrBufferData(data, false, nullptr);
+ stream_->WriteOrBufferData(data, false, nullptr);
+ stream_->WriteOrBufferData(data, false, nullptr);
+ // Verify all data is saved.
+ EXPECT_EQ(3 * data.length() - 100, stream_->queued_data_bytes());
+
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(100, false)));
+ // Buffered data size > threshold, do not ask upper layer for more data.
+ EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(0);
+ stream_->OnCanWrite();
+ EXPECT_EQ(3 * data.length() - 200, stream_->queued_data_bytes());
+ EXPECT_FALSE(stream_->CanWriteNewData());
+
+ // Send buffered data to make buffered data size < threshold.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(
+ 3 * data.length() - 200 -
+ GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1,
+ false)));
+ // Buffered data size < threshold, ask upper layer for more data.
+ EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
+ stream_->OnCanWrite();
+ EXPECT_EQ(GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1u,
+ stream_->queued_data_bytes());
+ EXPECT_TRUE(stream_->CanWriteNewData());
+
+ // Flush all buffered data.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Invoke(MockQuicSession::ConsumeAllData));
+ EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
+ stream_->OnCanWrite();
+ EXPECT_EQ(0u, stream_->queued_data_bytes());
+ EXPECT_FALSE(stream_->HasBufferedData());
+ EXPECT_TRUE(stream_->CanWriteNewData());
+
+ // Testing Writev.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(0, false)));
+ struct iovec iov = {const_cast<char*>(data.data()), data.length()};
+ QuicConsumedData consumed = stream_->WritevData(&iov, 1, false, nullptr);
+ // There is no buffered data before, all data should be consumed without
+ // respecting buffered data upper limit.
+ EXPECT_EQ(data.length(), consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_EQ(data.length(), stream_->queued_data_bytes());
+ EXPECT_FALSE(stream_->CanWriteNewData());
+
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(0);
+ consumed = stream_->WritevData(&iov, 1, false, nullptr);
+ // No Data can be consumed as buffered data is beyond upper limit.
+ EXPECT_EQ(0u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_EQ(data.length(), stream_->queued_data_bytes());
+
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(
+ data.length() - FLAGS_quic_buffered_data_threshold + 1, false)));
+ EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1);
+ stream_->OnCanWrite();
+ EXPECT_EQ(GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1,
+ stream_->queued_data_bytes());
+ EXPECT_TRUE(stream_->CanWriteNewData());
+
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(0);
+ // All data can be consumed as buffered data is below upper limit.
+ consumed = stream_->WritevData(&iov, 1, false, nullptr);
+ EXPECT_EQ(data.length(), consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_EQ(data.length() + GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1,
+ stream_->queued_data_bytes());
+ EXPECT_FALSE(stream_->CanWriteNewData());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/core/quic_time.h b/chromium/net/quic/core/quic_time.h
index 18ef46f1170..2bbdc18003f 100644
--- a/chromium/net/quic/core/quic_time.h
+++ b/chromium/net/quic/core/quic_time.h
@@ -206,9 +206,6 @@ inline bool operator<=(QuicTime::Delta lhs, QuicTime::Delta rhs) {
inline bool operator>=(QuicTime::Delta lhs, QuicTime::Delta rhs) {
return !(lhs < rhs);
}
-inline QuicTime::Delta operator<<(QuicTime::Delta lhs, size_t rhs) {
- return QuicTime::Delta(lhs.time_offset_ << rhs);
-}
inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs) {
return QuicTime::Delta(lhs.time_offset_ >> rhs);
}
diff --git a/chromium/net/quic/core/quic_types.h b/chromium/net/quic/core/quic_types.h
index eab0bc8398a..f7e9f9a5180 100644
--- a/chromium/net/quic/core/quic_types.h
+++ b/chromium/net/quic/core/quic_types.h
@@ -140,7 +140,9 @@ enum QuicPacketNumberLength : int8_t {
PACKET_1BYTE_PACKET_NUMBER = 1,
PACKET_2BYTE_PACKET_NUMBER = 2,
PACKET_4BYTE_PACKET_NUMBER = 4,
- PACKET_6BYTE_PACKET_NUMBER = 6
+ // TODO(rch): Remove this when we remove QUIC_VERSION_39.
+ PACKET_6BYTE_PACKET_NUMBER = 6,
+ PACKET_8BYTE_PACKET_NUMBER = 8
};
// Used to indicate a QuicSequenceNumberLength using two flag bits.
@@ -148,7 +150,7 @@ enum QuicPacketNumberLengthFlags {
PACKET_FLAGS_1BYTE_PACKET = 0, // 00
PACKET_FLAGS_2BYTE_PACKET = 1, // 01
PACKET_FLAGS_4BYTE_PACKET = 1 << 1, // 10
- PACKET_FLAGS_6BYTE_PACKET = 1 << 1 | 1, // 11
+ PACKET_FLAGS_8BYTE_PACKET = 1 << 1 | 1, // 11
};
// The public flags are specified in one byte.
@@ -180,7 +182,7 @@ enum QuicPacketPublicFlags {
PACKET_PUBLIC_FLAGS_1BYTE_PACKET = PACKET_FLAGS_1BYTE_PACKET << 4,
PACKET_PUBLIC_FLAGS_2BYTE_PACKET = PACKET_FLAGS_2BYTE_PACKET << 4,
PACKET_PUBLIC_FLAGS_4BYTE_PACKET = PACKET_FLAGS_4BYTE_PACKET << 4,
- PACKET_PUBLIC_FLAGS_6BYTE_PACKET = PACKET_FLAGS_6BYTE_PACKET << 4,
+ PACKET_PUBLIC_FLAGS_6BYTE_PACKET = PACKET_FLAGS_8BYTE_PACKET << 4,
// Reserved, unimplemented flags:
diff --git a/chromium/net/quic/core/quic_utils.cc b/chromium/net/quic/core/quic_utils.cc
index 078a26ca1bd..62bd144f11d 100644
--- a/chromium/net/quic/core/quic_utils.cc
+++ b/chromium/net/quic/core/quic_utils.cc
@@ -244,7 +244,7 @@ void QuicUtils::CopyToBuffer(QuicIOVector iov,
// prefetch(next_base, PREFETCH_HINT_T0);
if (iov.iov[iovnum + 1].iov_len >= 64) {
// TODO(ckrasic) - investigate what to do about prefetch directives.
- // prefetch(next_base + CACHELINE_SIZE, PREFETCH_HINT_T0);
+ // prefetch(next_base + ABSL_CACHELINE_SIZE, PREFETCH_HINT_T0);
}
}
diff --git a/chromium/net/quic/core/quic_version_manager.cc b/chromium/net/quic/core/quic_version_manager.cc
index 201d8ae6ba6..2136890fed0 100644
--- a/chromium/net/quic/core/quic_version_manager.cc
+++ b/chromium/net/quic/core/quic_version_manager.cc
@@ -10,7 +10,8 @@
namespace net {
QuicVersionManager::QuicVersionManager(QuicVersionVector supported_versions)
- : enable_version_40_(GetQuicFlag(FLAGS_quic_enable_version_40)),
+ : enable_version_41_(GetQuicFlag(FLAGS_quic_enable_version_41)),
+ enable_version_40_(FLAGS_quic_reloadable_flag_quic_enable_version_40),
enable_version_39_(FLAGS_quic_reloadable_flag_quic_enable_version_39),
enable_version_38_(FLAGS_quic_reloadable_flag_quic_enable_version_38),
disable_version_36_(FLAGS_quic_reloadable_flag_quic_disable_version_36),
@@ -26,12 +27,14 @@ const QuicVersionVector& QuicVersionManager::GetSupportedVersions() {
}
void QuicVersionManager::MaybeRefilterSupportedVersions() {
- if (enable_version_40_ != GetQuicFlag(FLAGS_quic_enable_version_40) ||
+ if (enable_version_41_ != GetQuicFlag(FLAGS_quic_enable_version_41) ||
+ enable_version_40_ != FLAGS_quic_reloadable_flag_quic_enable_version_40 ||
enable_version_39_ != FLAGS_quic_reloadable_flag_quic_enable_version_39 ||
enable_version_38_ != FLAGS_quic_reloadable_flag_quic_enable_version_38 ||
disable_version_36_ !=
FLAGS_quic_reloadable_flag_quic_disable_version_36) {
- enable_version_40_ = GetQuicFlag(FLAGS_quic_enable_version_40);
+ enable_version_41_ = GetQuicFlag(FLAGS_quic_enable_version_41);
+ enable_version_40_ = FLAGS_quic_reloadable_flag_quic_enable_version_40;
enable_version_39_ = FLAGS_quic_reloadable_flag_quic_enable_version_39;
enable_version_38_ = FLAGS_quic_reloadable_flag_quic_enable_version_38;
disable_version_36_ = FLAGS_quic_reloadable_flag_quic_disable_version_36;
diff --git a/chromium/net/quic/core/quic_version_manager.h b/chromium/net/quic/core/quic_version_manager.h
index a9201dadace..c6fa10d7f93 100644
--- a/chromium/net/quic/core/quic_version_manager.h
+++ b/chromium/net/quic/core/quic_version_manager.h
@@ -31,7 +31,9 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager {
}
private:
- // FLAGS_quic_enable_version_40
+ // FLAGS_quic_enable_version_41
+ bool enable_version_41_;
+ // FLAGS_quic_reloadable_flag_quic_enable_version_40
bool enable_version_40_;
// FLAGS_quic_reloadable_flag_quic_enable_version_39
bool enable_version_39_;
diff --git a/chromium/net/quic/core/quic_version_manager_test.cc b/chromium/net/quic/core/quic_version_manager_test.cc
index 232e5cc82b7..0fdd0982ce2 100644
--- a/chromium/net/quic/core/quic_version_manager_test.cc
+++ b/chromium/net/quic/core/quic_version_manager_test.cc
@@ -16,7 +16,8 @@ namespace {
class QuicVersionManagerTest : public QuicTest {};
TEST_F(QuicVersionManagerTest, QuicVersionManager) {
- SetQuicFlag(&FLAGS_quic_enable_version_40, false);
+ SetQuicFlag(&FLAGS_quic_enable_version_41, false);
+ FLAGS_quic_reloadable_flag_quic_enable_version_40 = false;
FLAGS_quic_reloadable_flag_quic_enable_version_39 = false;
FLAGS_quic_reloadable_flag_quic_enable_version_38 = false;
FLAGS_quic_reloadable_flag_quic_disable_version_36 = false;
@@ -48,7 +49,7 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
EXPECT_EQ(QUIC_VERSION_37, manager.GetSupportedVersions()[2]);
EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[3]);
- SetQuicFlag(&FLAGS_quic_enable_version_40, true);
+ FLAGS_quic_reloadable_flag_quic_enable_version_40 = true;
ASSERT_EQ(5u, manager.GetSupportedVersions().size());
EXPECT_EQ(QUIC_VERSION_40, manager.GetSupportedVersions()[0]);
EXPECT_EQ(QUIC_VERSION_39, manager.GetSupportedVersions()[1]);
@@ -56,14 +57,24 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) {
EXPECT_EQ(QUIC_VERSION_37, manager.GetSupportedVersions()[3]);
EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[4]);
+ SetQuicFlag(&FLAGS_quic_enable_version_41, true);
+ ASSERT_EQ(6u, manager.GetSupportedVersions().size());
+ EXPECT_EQ(QUIC_VERSION_41, manager.GetSupportedVersions()[0]);
+ EXPECT_EQ(QUIC_VERSION_40, manager.GetSupportedVersions()[1]);
+ EXPECT_EQ(QUIC_VERSION_39, manager.GetSupportedVersions()[2]);
+ EXPECT_EQ(QUIC_VERSION_38, manager.GetSupportedVersions()[3]);
+ EXPECT_EQ(QUIC_VERSION_37, manager.GetSupportedVersions()[4]);
+ EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[5]);
+
EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
manager.GetSupportedVersions());
- ASSERT_EQ(5u, manager.GetSupportedVersions().size());
- EXPECT_EQ(QUIC_VERSION_40, manager.GetSupportedVersions()[0]);
- EXPECT_EQ(QUIC_VERSION_39, manager.GetSupportedVersions()[1]);
- EXPECT_EQ(QUIC_VERSION_38, manager.GetSupportedVersions()[2]);
- EXPECT_EQ(QUIC_VERSION_37, manager.GetSupportedVersions()[3]);
- EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[4]);
+ ASSERT_EQ(6u, manager.GetSupportedVersions().size());
+ EXPECT_EQ(QUIC_VERSION_41, manager.GetSupportedVersions()[0]);
+ EXPECT_EQ(QUIC_VERSION_40, manager.GetSupportedVersions()[1]);
+ EXPECT_EQ(QUIC_VERSION_39, manager.GetSupportedVersions()[2]);
+ EXPECT_EQ(QUIC_VERSION_38, manager.GetSupportedVersions()[3]);
+ EXPECT_EQ(QUIC_VERSION_37, manager.GetSupportedVersions()[4]);
+ EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[5]);
}
} // namespace
diff --git a/chromium/net/quic/core/quic_versions.cc b/chromium/net/quic/core/quic_versions.cc
index ff4d7fe3bb5..9936bb4de60 100644
--- a/chromium/net/quic/core/quic_versions.cc
+++ b/chromium/net/quic/core/quic_versions.cc
@@ -30,8 +30,15 @@ QuicVersionVector FilterSupportedVersions(QuicVersionVector versions) {
QuicVersionVector filtered_versions(versions.size());
filtered_versions.clear(); // Guaranteed by spec not to change capacity.
for (QuicVersion version : versions) {
- if (version == QUIC_VERSION_40) {
- if (GetQuicFlag(FLAGS_quic_enable_version_40) &&
+ if (version == QUIC_VERSION_41) {
+ if (GetQuicFlag(FLAGS_quic_enable_version_41) &&
+ FLAGS_quic_reloadable_flag_quic_enable_version_40 &&
+ FLAGS_quic_reloadable_flag_quic_enable_version_39 &&
+ FLAGS_quic_reloadable_flag_quic_enable_version_38) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version == QUIC_VERSION_40) {
+ if (FLAGS_quic_reloadable_flag_quic_enable_version_40 &&
FLAGS_quic_reloadable_flag_quic_enable_version_39 &&
FLAGS_quic_reloadable_flag_quic_enable_version_38) {
filtered_versions.push_back(version);
@@ -81,6 +88,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) {
return MakeQuicTag('Q', '0', '3', '9');
case QUIC_VERSION_40:
return MakeQuicTag('Q', '0', '4', '0');
+ case QUIC_VERSION_41:
+ return MakeQuicTag('Q', '0', '4', '1');
default:
// This shold be an ERROR because we should never attempt to convert an
// invalid QuicVersion to be written to the wire.
@@ -113,6 +122,7 @@ string QuicVersionToString(const QuicVersion version) {
RETURN_STRING_LITERAL(QUIC_VERSION_38);
RETURN_STRING_LITERAL(QUIC_VERSION_39);
RETURN_STRING_LITERAL(QUIC_VERSION_40);
+ RETURN_STRING_LITERAL(QUIC_VERSION_41);
default:
return "QUIC_VERSION_UNSUPPORTED";
}
diff --git a/chromium/net/quic/core/quic_versions.h b/chromium/net/quic/core/quic_versions.h
index 1ddffe1ce55..3f9e1129ae3 100644
--- a/chromium/net/quic/core/quic_versions.h
+++ b/chromium/net/quic/core/quic_versions.h
@@ -33,11 +33,8 @@ enum QuicVersion {
// endian. Dot not ack acks. Send a connection level
// WINDOW_UPDATE every 20 sent packets which do not
// contain retransmittable frames.
- QUIC_VERSION_40 = 40, // Initial packet number is randomly chosen from
- // [0:2^31], WINDOW_UPDATE for connection flow control
- // advertises value in 1024-byte units, WINDOW_UPDATE
- // splits into MAX_DATA and MAX_STREAM_DATA, BLOCKED
- // frame split into BLOCKED and STREAM_BLOCKED frames
+ QUIC_VERSION_40 = 40, // RST_STREAM, ACK and STREAM frames match IETF format.
+ QUIC_VERSION_41 = 41, // Use IETF packet header format.
// IMPORTANT: if you are adding to this list, follow the instructions at
// http://sites/quic/adding-and-removing-versions
@@ -51,7 +48,7 @@ enum QuicVersion {
// IMPORTANT: if you are adding to this list, follow the instructions at
// http://sites/quic/adding-and-removing-versions
static const QuicVersion kSupportedQuicVersions[] = {
- QUIC_VERSION_40, QUIC_VERSION_39, QUIC_VERSION_38,
+ QUIC_VERSION_41, QUIC_VERSION_40, QUIC_VERSION_39, QUIC_VERSION_38,
QUIC_VERSION_37, QUIC_VERSION_36, QUIC_VERSION_35};
typedef std::vector<QuicVersion> QuicVersionVector;
diff --git a/chromium/net/quic/core/spdy_utils.cc b/chromium/net/quic/core/spdy_utils.cc
index 24f226442f1..e6285134a92 100644
--- a/chromium/net/quic/core/spdy_utils.cc
+++ b/chromium/net/quic/core/spdy_utils.cc
@@ -14,7 +14,6 @@
#include "net/quic/platform/api/quic_string_piece.h"
#include "net/quic/platform/api/quic_text_utils.h"
#include "net/quic/platform/api/quic_url_utils.h"
-#include "net/spdy/chromium/spdy_flags.h"
#include "net/spdy/core/spdy_frame_builder.h"
#include "net/spdy/core/spdy_framer.h"
#include "net/spdy/core/spdy_protocol.h"
diff --git a/chromium/net/quic/core/spdy_utils.h b/chromium/net/quic/core/spdy_utils.h
index cb11c93a629..724136af20e 100644
--- a/chromium/net/quic/core/spdy_utils.h
+++ b/chromium/net/quic/core/spdy_utils.h
@@ -54,8 +54,6 @@ class QUIC_EXPORT_PRIVATE SpdyUtils {
static bool PopulateHeaderBlockFromUrl(const std::string url,
SpdyHeaderBlock* headers);
- static bool IsServerPushStream(QuicStreamId id) { return id % 2 == 0; }
-
private:
DISALLOW_COPY_AND_ASSIGN(SpdyUtils);
};