summaryrefslogtreecommitdiff
path: root/chromium/net/quic
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-08-14 11:38:45 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-08-14 17:16:47 +0000
commit3a97ca8dd9b96b599ae2d33e40df0dd2f7ea5859 (patch)
tree43cc572ba067417c7341db81f71ae7cc6e0fcc3e /chromium/net/quic
parentf61ab1ac7f855cd281809255c0aedbb1895e1823 (diff)
downloadqtwebengine-chromium-3a97ca8dd9b96b599ae2d33e40df0dd2f7ea5859.tar.gz
BASELINE: Update chromium to 45.0.2454.40
Change-Id: Id2121d9f11a8fc633677236c65a3e41feef589e4 Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Diffstat (limited to 'chromium/net/quic')
-rw-r--r--chromium/net/quic/congestion_control/cubic.cc3
-rw-r--r--chromium/net/quic/congestion_control/cubic_bytes.cc3
-rw-r--r--chromium/net/quic/congestion_control/hybrid_slow_start.cc5
-rw-r--r--chromium/net/quic/congestion_control/hybrid_slow_start.h4
-rw-r--r--chromium/net/quic/congestion_control/hybrid_slow_start_test.cc4
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_bytes_sender.cc5
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc6
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender.cc22
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender_test.cc27
-rw-r--r--chromium/net/quic/congestion_control/tcp_loss_algorithm_test.cc8
-rw-r--r--chromium/net/quic/congestion_control/time_loss_algorithm_test.cc8
-rw-r--r--chromium/net/quic/crypto/aead_base_decrypter.h7
-rw-r--r--chromium/net/quic/crypto/aead_base_decrypter_nss.cc50
-rw-r--r--chromium/net/quic/crypto/aead_base_decrypter_openssl.cc43
-rw-r--r--chromium/net/quic/crypto/aead_base_encrypter.h11
-rw-r--r--chromium/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc186
-rw-r--r--chromium/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc181
-rw-r--r--chromium/net/quic/crypto/channel_id_chromium.cc39
-rw-r--r--chromium/net/quic/crypto/channel_id_chromium.h3
-rw-r--r--chromium/net/quic/crypto/common_cert_set_1.c2
-rw-r--r--chromium/net/quic/crypto/common_cert_set_test.cc6
-rw-r--r--chromium/net/quic/crypto/crypto_protocol.h12
-rw-r--r--chromium/net/quic/crypto/crypto_secret_boxer.cc6
-rw-r--r--chromium/net/quic/crypto/null_decrypter.cc4
-rw-r--r--chromium/net/quic/crypto/null_encrypter.cc21
-rw-r--r--chromium/net/quic/crypto/null_encrypter.h4
-rw-r--r--chromium/net/quic/crypto/proof_verifier_chromium.cc2
-rw-r--r--chromium/net/quic/crypto/proof_verifier_chromium.h2
-rw-r--r--chromium/net/quic/crypto/quic_crypto_client_config.cc27
-rw-r--r--chromium/net/quic/crypto/quic_crypto_client_config.h16
-rw-r--r--chromium/net/quic/crypto/quic_crypto_client_config_test.cc46
-rw-r--r--chromium/net/quic/crypto/quic_crypto_server_config.h4
-rw-r--r--chromium/net/quic/crypto/quic_encrypter.h10
-rw-r--r--chromium/net/quic/crypto/quic_server_info.cc6
-rw-r--r--chromium/net/quic/iovector.h41
-rw-r--r--chromium/net/quic/iovector_test.cc108
-rw-r--r--chromium/net/quic/quic_ack_notifier_manager.cc21
-rw-r--r--chromium/net/quic/quic_ack_notifier_manager.h10
-rw-r--r--chromium/net/quic/quic_ack_notifier_manager_test.cc172
-rw-r--r--chromium/net/quic/quic_bandwidth.cc4
-rw-r--r--chromium/net/quic/quic_client_session.cc122
-rw-r--r--chromium/net/quic/quic_client_session.h31
-rw-r--r--chromium/net/quic/quic_client_session_base.cc10
-rw-r--r--chromium/net/quic/quic_client_session_base.h4
-rw-r--r--chromium/net/quic/quic_client_session_test.cc27
-rw-r--r--chromium/net/quic/quic_config.cc15
-rw-r--r--chromium/net/quic/quic_config.h5
-rw-r--r--chromium/net/quic/quic_config_test.cc28
-rw-r--r--chromium/net/quic/quic_connection.cc296
-rw-r--r--chromium/net/quic/quic_connection.h100
-rw-r--r--chromium/net/quic/quic_connection_logger.cc128
-rw-r--r--chromium/net/quic/quic_connection_logger.h6
-rw-r--r--chromium/net/quic/quic_connection_logger_unittest.cc2
-rw-r--r--chromium/net/quic/quic_connection_stats.cc1
-rw-r--r--chromium/net/quic/quic_connection_stats.h1
-rw-r--r--chromium/net/quic/quic_connection_test.cc481
-rw-r--r--chromium/net/quic/quic_crypto_client_stream.cc16
-rw-r--r--chromium/net/quic/quic_crypto_client_stream_test.cc124
-rw-r--r--chromium/net/quic/quic_crypto_server_stream.cc11
-rw-r--r--chromium/net/quic/quic_crypto_server_stream.h9
-rw-r--r--chromium/net/quic/quic_crypto_server_stream_test.cc201
-rw-r--r--chromium/net/quic/quic_crypto_stream_test.cc2
-rw-r--r--chromium/net/quic/quic_data_stream.cc76
-rw-r--r--chromium/net/quic/quic_data_stream.h29
-rw-r--r--chromium/net/quic/quic_data_stream_test.cc116
-rw-r--r--chromium/net/quic/quic_data_writer.cc21
-rw-r--r--chromium/net/quic/quic_data_writer.h2
-rw-r--r--chromium/net/quic/quic_data_writer_test.cc6
-rw-r--r--chromium/net/quic/quic_default_packet_writer.cc2
-rw-r--r--chromium/net/quic/quic_flags.cc24
-rw-r--r--chromium/net/quic/quic_flags.h7
-rw-r--r--chromium/net/quic/quic_flow_controller.cc127
-rw-r--r--chromium/net/quic/quic_flow_controller.h65
-rw-r--r--chromium/net/quic/quic_flow_controller_test.cc233
-rw-r--r--chromium/net/quic/quic_framer.cc86
-rw-r--r--chromium/net/quic/quic_framer.h19
-rw-r--r--chromium/net/quic/quic_framer_test.cc446
-rw-r--r--chromium/net/quic/quic_headers_stream.cc24
-rw-r--r--chromium/net/quic/quic_headers_stream.h8
-rw-r--r--chromium/net/quic/quic_headers_stream_test.cc53
-rw-r--r--chromium/net/quic/quic_http_stream.cc49
-rw-r--r--chromium/net/quic/quic_http_stream.h6
-rw-r--r--chromium/net/quic/quic_http_stream_test.cc29
-rw-r--r--chromium/net/quic/quic_http_utils.cc15
-rw-r--r--chromium/net/quic/quic_http_utils.h5
-rw-r--r--chromium/net/quic/quic_network_transaction_unittest.cc159
-rw-r--r--chromium/net/quic/quic_packet_creator.cc162
-rw-r--r--chromium/net/quic/quic_packet_creator.h43
-rw-r--r--chromium/net/quic/quic_packet_creator_test.cc225
-rw-r--r--chromium/net/quic/quic_packet_generator.cc174
-rw-r--r--chromium/net/quic/quic_packet_generator.h57
-rw-r--r--chromium/net/quic/quic_packet_generator_test.cc702
-rw-r--r--chromium/net/quic/quic_packet_reader.cc7
-rw-r--r--chromium/net/quic/quic_protocol.cc76
-rw-r--r--chromium/net/quic/quic_protocol.h77
-rw-r--r--chromium/net/quic/quic_reliable_client_stream.cc22
-rw-r--r--chromium/net/quic/quic_reliable_client_stream.h8
-rw-r--r--chromium/net/quic/quic_reliable_client_stream_test.cc32
-rw-r--r--chromium/net/quic/quic_sent_packet_manager.cc24
-rw-r--r--chromium/net/quic/quic_sent_packet_manager.h5
-rw-r--r--chromium/net/quic/quic_sent_packet_manager_test.cc8
-rw-r--r--chromium/net/quic/quic_session.cc216
-rw-r--r--chromium/net/quic/quic_session.h97
-rw-r--r--chromium/net/quic/quic_session_test.cc310
-rw-r--r--chromium/net/quic/quic_socket_address_coder.cc2
-rw-r--r--chromium/net/quic/quic_socket_address_coder_test.cc2
-rw-r--r--chromium/net/quic/quic_spdy_session.cc80
-rw-r--r--chromium/net/quic/quic_spdy_session.h76
-rw-r--r--chromium/net/quic/quic_stream_factory.cc342
-rw-r--r--chromium/net/quic/quic_stream_factory.h66
-rw-r--r--chromium/net/quic/quic_stream_factory_test.cc1364
-rw-r--r--chromium/net/quic/quic_stream_sequencer.cc71
-rw-r--r--chromium/net/quic/quic_stream_sequencer.h22
-rw-r--r--chromium/net/quic/quic_stream_sequencer_test.cc194
-rw-r--r--chromium/net/quic/quic_time.cc4
-rw-r--r--chromium/net/quic/quic_unacked_packet_map.cc34
-rw-r--r--chromium/net/quic/quic_unacked_packet_map.h14
-rw-r--r--chromium/net/quic/quic_unacked_packet_map_test.cc12
-rw-r--r--chromium/net/quic/quic_utils.cc19
-rw-r--r--chromium/net/quic/quic_utils.h13
-rw-r--r--chromium/net/quic/reliable_quic_stream.cc83
-rw-r--r--chromium/net/quic/reliable_quic_stream.h105
-rw-r--r--chromium/net/quic/reliable_quic_stream_test.cc158
-rw-r--r--chromium/net/quic/spdy_utils.cc4
-rw-r--r--chromium/net/quic/test_tools/crypto_test_utils.cc66
-rw-r--r--chromium/net/quic/test_tools/crypto_test_utils_nss.cc6
-rw-r--r--chromium/net/quic/test_tools/mock_crypto_client_stream.cc8
-rw-r--r--chromium/net/quic/test_tools/quic_ack_notifier_manager_peer.cc18
-rw-r--r--chromium/net/quic/test_tools/quic_ack_notifier_manager_peer.h29
-rw-r--r--chromium/net/quic/test_tools/quic_connection_peer.cc6
-rw-r--r--chromium/net/quic/test_tools/quic_connection_peer.h1
-rw-r--r--chromium/net/quic/test_tools/quic_flow_controller_peer.cc8
-rw-r--r--chromium/net/quic/test_tools/quic_flow_controller_peer.h3
-rw-r--r--chromium/net/quic/test_tools/quic_framer_peer.cc5
-rw-r--r--chromium/net/quic/test_tools/quic_framer_peer.h3
-rw-r--r--chromium/net/quic/test_tools/quic_session_peer.cc53
-rw-r--r--chromium/net/quic/test_tools/quic_session_peer.h18
-rw-r--r--chromium/net/quic/test_tools/quic_spdy_session_peer.cc26
-rw-r--r--chromium/net/quic/test_tools/quic_spdy_session_peer.h32
-rw-r--r--chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc11
-rw-r--r--chromium/net/quic/test_tools/quic_stream_sequencer_peer.h6
-rw-r--r--chromium/net/quic/test_tools/quic_test_packet_maker.cc30
-rw-r--r--chromium/net/quic/test_tools/quic_test_utils.cc132
-rw-r--r--chromium/net/quic/test_tools/quic_test_utils.h121
-rw-r--r--chromium/net/quic/test_tools/simple_quic_framer.cc8
145 files changed, 6816 insertions, 3050 deletions
diff --git a/chromium/net/quic/congestion_control/cubic.cc b/chromium/net/quic/congestion_control/cubic.cc
index 499eafbf691..23ed2dd2f3b 100644
--- a/chromium/net/quic/congestion_control/cubic.cc
+++ b/chromium/net/quic/congestion_control/cubic.cc
@@ -4,6 +4,7 @@
#include "net/quic/congestion_control/cubic.h"
+#include <stdint.h>
#include <algorithm>
#include <cmath>
@@ -26,7 +27,7 @@ const int kCubeScale = 40; // 1024*1024^3 (first 1024 is from 0.100^3)
// where 0.100 is 100 ms which is the scaling
// round trip time.
const int kCubeCongestionWindowScale = 410;
-const uint64 kCubeFactor = (GG_UINT64_C(1) << kCubeScale) /
+const uint64 kCubeFactor = (UINT64_C(1) << kCubeScale) /
kCubeCongestionWindowScale;
const uint32 kDefaultNumConnections = 2;
diff --git a/chromium/net/quic/congestion_control/cubic_bytes.cc b/chromium/net/quic/congestion_control/cubic_bytes.cc
index b5af3d1219c..40259ceae61 100644
--- a/chromium/net/quic/congestion_control/cubic_bytes.cc
+++ b/chromium/net/quic/congestion_control/cubic_bytes.cc
@@ -4,6 +4,7 @@
#include "net/quic/congestion_control/cubic_bytes.h"
+#include <stdint.h>
#include <algorithm>
#include <cmath>
@@ -26,7 +27,7 @@ const int kCubeScale = 40; // 1024*1024^3 (first 1024 is from 0.100^3)
// round trip time.
const int kCubeCongestionWindowScale = 410;
// The cube factor for packets in bytes.
-const uint64 kCubeFactor = (GG_UINT64_C(1) << kCubeScale) /
+const uint64 kCubeFactor = (UINT64_C(1) << kCubeScale) /
kCubeCongestionWindowScale / kDefaultTCPMSS;
const uint32 kDefaultNumConnections = 2;
diff --git a/chromium/net/quic/congestion_control/hybrid_slow_start.cc b/chromium/net/quic/congestion_control/hybrid_slow_start.cc
index f2ac90877ad..d6a47e4ed6d 100644
--- a/chromium/net/quic/congestion_control/hybrid_slow_start.cc
+++ b/chromium/net/quic/congestion_control/hybrid_slow_start.cc
@@ -22,9 +22,8 @@ const int kHybridStartDelayFactorExp = 3; // 2^3 = 8
const int64 kHybridStartDelayMinThresholdUs = 4000;
const int64 kHybridStartDelayMaxThresholdUs = 16000;
-HybridSlowStart::HybridSlowStart(const QuicClock* clock)
- : clock_(clock),
- started_(false),
+HybridSlowStart::HybridSlowStart()
+ : started_(false),
hystart_found_(NOT_FOUND),
last_sent_sequence_number_(0),
end_sequence_number_(0),
diff --git a/chromium/net/quic/congestion_control/hybrid_slow_start.h b/chromium/net/quic/congestion_control/hybrid_slow_start.h
index 2077211806c..9f0a9aef359 100644
--- a/chromium/net/quic/congestion_control/hybrid_slow_start.h
+++ b/chromium/net/quic/congestion_control/hybrid_slow_start.h
@@ -18,7 +18,6 @@
#include "base/basictypes.h"
#include "net/base/net_export.h"
-#include "net/quic/quic_clock.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_time.h"
@@ -26,7 +25,7 @@ namespace net {
class NET_EXPORT_PRIVATE HybridSlowStart {
public:
- explicit HybridSlowStart(const QuicClock* clock);
+ HybridSlowStart();
void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number,
bool in_slow_start);
@@ -67,7 +66,6 @@ class NET_EXPORT_PRIVATE HybridSlowStart {
DELAY, // Too much increase in the round's min_rtt was observed.
};
- const QuicClock* clock_;
// Whether the hybrid slow start has been started.
bool started_;
HystartState hystart_found_;
diff --git a/chromium/net/quic/congestion_control/hybrid_slow_start_test.cc b/chromium/net/quic/congestion_control/hybrid_slow_start_test.cc
index 1b34ad5bed9..a839a3160d3 100644
--- a/chromium/net/quic/congestion_control/hybrid_slow_start_test.cc
+++ b/chromium/net/quic/congestion_control/hybrid_slow_start_test.cc
@@ -5,7 +5,6 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "net/quic/congestion_control/hybrid_slow_start.h"
-#include "net/quic/test_tools/mock_clock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -17,10 +16,9 @@ class HybridSlowStartTest : public ::testing::Test {
: one_ms_(QuicTime::Delta::FromMilliseconds(1)),
rtt_(QuicTime::Delta::FromMilliseconds(60)) {
}
- void SetUp() override { slow_start_.reset(new HybridSlowStart(&clock_)); }
+ void SetUp() override { slow_start_.reset(new HybridSlowStart); }
const QuicTime::Delta one_ms_;
const QuicTime::Delta rtt_;
- MockClock clock_;
scoped_ptr<HybridSlowStart> slow_start_;
};
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_bytes_sender.cc b/chromium/net/quic/congestion_control/tcp_cubic_bytes_sender.cc
index 987cfc42ee5..b3ceaca57fb 100644
--- a/chromium/net/quic/congestion_control/tcp_cubic_bytes_sender.cc
+++ b/chromium/net/quic/congestion_control/tcp_cubic_bytes_sender.cc
@@ -34,8 +34,7 @@ TcpCubicBytesSender::TcpCubicBytesSender(
QuicPacketCount initial_tcp_congestion_window,
QuicPacketCount max_congestion_window,
QuicConnectionStats* stats)
- : hybrid_slow_start_(clock),
- cubic_(clock),
+ : cubic_(clock),
rtt_stats_(rtt_stats),
stats_(stats),
reno_(reno),
@@ -99,7 +98,7 @@ bool TcpCubicBytesSender::ResumeConnectionState(
// Make sure CWND is in appropriate range (in case of bad data).
QuicByteCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt_ms);
congestion_window_ =
- max(min(new_congestion_window, kMaxTcpCongestionWindow * kMaxSegmentSize),
+ max(min(new_congestion_window, kMaxResumptionCwnd * kMaxSegmentSize),
kMinCongestionWindowForBandwidthResumption * kMaxSegmentSize);
// TODO(rjshade): Set appropriate CWND when previous connection was in slow
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc b/chromium/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc
index c00b76c1c3d..5bff6c0527a 100644
--- a/chromium/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc
+++ b/chromium/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc
@@ -35,7 +35,7 @@ class TcpCubicBytesSenderPeer : public TcpCubicBytesSender {
&rtt_stats_,
reno,
kInitialCongestionWindowPackets,
- kMaxTcpCongestionWindow,
+ kMaxResumptionCwnd,
&stats_) {}
const HybridSlowStart& hybrid_slow_start() const {
@@ -573,9 +573,9 @@ TEST_F(TcpCubicBytesSenderTest, BandwidthResumption) {
// Resumed CWND is limited to be in a sensible range.
cached_network_params.set_bandwidth_estimate_bytes_per_second(
- (kMaxTcpCongestionWindow + 1) * kDefaultTCPMSS);
+ (kMaxResumptionCwnd + 1) * kDefaultTCPMSS);
EXPECT_TRUE(sender_->ResumeConnectionState(cached_network_params, false));
- EXPECT_EQ(kMaxTcpCongestionWindow * kDefaultTCPMSS,
+ EXPECT_EQ(kMaxResumptionCwnd * kDefaultTCPMSS,
sender_->GetCongestionWindow());
cached_network_params.set_bandwidth_estimate_bytes_per_second(
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender.cc b/chromium/net/quic/congestion_control/tcp_cubic_sender.cc
index 30c0be6bc5d..e6607b46891 100644
--- a/chromium/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/chromium/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "net/quic/congestion_control/prr_sender.h"
#include "net/quic/congestion_control/rtt_stats.h"
#include "net/quic/crypto/crypto_protocol.h"
@@ -34,8 +34,7 @@ TcpCubicSender::TcpCubicSender(const QuicClock* clock,
QuicPacketCount initial_tcp_congestion_window,
QuicPacketCount max_tcp_congestion_window,
QuicConnectionStats* stats)
- : hybrid_slow_start_(clock),
- cubic_(clock),
+ : cubic_(clock),
rtt_stats_(rtt_stats),
stats_(stats),
reno_(reno),
@@ -61,11 +60,26 @@ void TcpCubicSender::SetFromConfig(const QuicConfig& config,
Perspective perspective) {
if (perspective == Perspective::IS_SERVER) {
if (config.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config.ReceivedConnectionOptions(), kIW03)) {
+ // Initial window experiment.
+ congestion_window_ = 3;
+ }
+ if (config.HasReceivedConnectionOptions() &&
ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) {
// Initial window experiment.
congestion_window_ = 10;
}
if (config.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config.ReceivedConnectionOptions(), kIW20)) {
+ // Initial window experiment.
+ congestion_window_ = 20;
+ }
+ if (config.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config.ReceivedConnectionOptions(), kIW50)) {
+ // Initial window experiment.
+ congestion_window_ = 50;
+ }
+ if (config.HasReceivedConnectionOptions() &&
ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) {
// Min CWND experiment.
min_congestion_window_ = 1;
@@ -100,7 +114,7 @@ bool TcpCubicSender::ResumeConnectionState(
// Make sure CWND is in appropriate range (in case of bad data).
QuicPacketCount new_congestion_window =
bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize;
- congestion_window_ = max(min(new_congestion_window, kMaxTcpCongestionWindow),
+ congestion_window_ = max(min(new_congestion_window, kMaxResumptionCwnd),
kMinCongestionWindowForBandwidthResumption);
// TODO(rjshade): Set appropriate CWND when previous connection was in slow
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender_test.cc b/chromium/net/quic/congestion_control/tcp_cubic_sender_test.cc
index cbcad0f8d52..36eb8b7aa6c 100644
--- a/chromium/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/chromium/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -65,7 +65,7 @@ class TcpCubicSenderTest : public ::testing::Test {
protected:
TcpCubicSenderTest()
: one_ms_(QuicTime::Delta::FromMilliseconds(1)),
- sender_(new TcpCubicSenderPeer(&clock_, true, kMaxTcpCongestionWindow)),
+ sender_(new TcpCubicSenderPeer(&clock_, true, kMaxResumptionCwnd)),
sequence_number_(1),
acked_sequence_number_(0),
bytes_in_flight_(0) {
@@ -374,7 +374,7 @@ TEST_F(TcpCubicSenderTest, SlowStartBurstPacketLossPRR) {
TEST_F(TcpCubicSenderTest, RTOCongestionWindow) {
EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- EXPECT_EQ(kMaxTcpCongestionWindow, sender_->slowstart_threshold());
+ EXPECT_EQ(kMaxResumptionCwnd, sender_->slowstart_threshold());
// Expect the window to decrease to the minimum once the RTO fires
// and slow start threshold to be set to 1/2 of the CWND.
@@ -517,12 +517,29 @@ TEST_F(TcpCubicSenderTest, DontTrackAckPackets) {
TEST_F(TcpCubicSenderTest, ConfigureInitialWindow) {
QuicConfig config;
- // Verify that kCOPT: kIW10 forces the congestion window to the default of 10.
QuicTagVector options;
+ options.push_back(kIW03);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(3u, sender_->congestion_window());
+
+ options.clear();
options.push_back(kIW10);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
sender_->SetFromConfig(config, Perspective::IS_SERVER);
EXPECT_EQ(10u, sender_->congestion_window());
+
+ options.clear();
+ options.push_back(kIW20);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(20u, sender_->congestion_window());
+
+ options.clear();
+ options.push_back(kIW50);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(50u, sender_->congestion_window());
}
TEST_F(TcpCubicSenderTest, ConfigureMinimumWindow) {
@@ -667,9 +684,9 @@ TEST_F(TcpCubicSenderTest, BandwidthResumption) {
// Resumed CWND is limited to be in a sensible range.
cached_network_params.set_bandwidth_estimate_bytes_per_second(
- (kMaxTcpCongestionWindow + 1) * kMaxPacketSize);
+ (kMaxResumptionCwnd + 1) * kMaxPacketSize);
EXPECT_TRUE(sender_->ResumeConnectionState(cached_network_params, false));
- EXPECT_EQ(kMaxTcpCongestionWindow, sender_->congestion_window());
+ EXPECT_EQ(kMaxResumptionCwnd, sender_->congestion_window());
cached_network_params.set_bandwidth_estimate_bytes_per_second(
(kMinCongestionWindowForBandwidthResumption - 1) * kMaxPacketSize);
diff --git a/chromium/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/chromium/net/quic/congestion_control/tcp_loss_algorithm_test.cc
index 69fb04bf931..a58ba7f87b0 100644
--- a/chromium/net/quic/congestion_control/tcp_loss_algorithm_test.cc
+++ b/chromium/net/quic/congestion_control/tcp_loss_algorithm_test.cc
@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "net/quic/congestion_control/tcp_loss_algorithm.h"
+
#include <algorithm>
#include "base/logging.h"
#include "base/stl_util.h"
#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/congestion_control/tcp_loss_algorithm.h"
+#include "net/quic/quic_ack_notifier_manager.h"
#include "net/quic/quic_unacked_packet_map.h"
#include "net/quic/test_tools/mock_clock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,8 +25,7 @@ const uint32 kDefaultLength = 1000;
class TcpLossAlgorithmTest : public ::testing::Test {
protected:
- TcpLossAlgorithmTest()
- : unacked_packets_() {
+ TcpLossAlgorithmTest() : unacked_packets_(&ack_notifier_manager_) {
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
QuicTime::Delta::Zero(),
clock_.Now());
@@ -56,6 +57,7 @@ class TcpLossAlgorithmTest : public ::testing::Test {
}
vector<QuicEncryptedPacket*> packets_;
+ AckNotifierManager ack_notifier_manager_;
QuicUnackedPacketMap unacked_packets_;
TCPLossAlgorithm loss_algorithm_;
RttStats rtt_stats_;
diff --git a/chromium/net/quic/congestion_control/time_loss_algorithm_test.cc b/chromium/net/quic/congestion_control/time_loss_algorithm_test.cc
index 24f63509101..2505c6bd9bd 100644
--- a/chromium/net/quic/congestion_control/time_loss_algorithm_test.cc
+++ b/chromium/net/quic/congestion_control/time_loss_algorithm_test.cc
@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "net/quic/congestion_control/time_loss_algorithm.h"
+
#include <algorithm>
#include "base/logging.h"
#include "base/stl_util.h"
#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/congestion_control/time_loss_algorithm.h"
+#include "net/quic/quic_ack_notifier_manager.h"
#include "net/quic/quic_unacked_packet_map.h"
#include "net/quic/test_tools/mock_clock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,8 +25,7 @@ const uint32 kDefaultLength = 1000;
class TimeLossAlgorithmTest : public ::testing::Test {
protected:
- TimeLossAlgorithmTest()
- : unacked_packets_() {
+ TimeLossAlgorithmTest() : unacked_packets_(&ack_notifier_manager_) {
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
QuicTime::Delta::Zero(),
clock_.Now());
@@ -56,6 +57,7 @@ class TimeLossAlgorithmTest : public ::testing::Test {
}
vector<QuicEncryptedPacket*> packets_;
+ AckNotifierManager ack_notifier_manager_;
QuicUnackedPacketMap unacked_packets_;
TimeLossAlgorithm loss_algorithm_;
RttStats rtt_stats_;
diff --git a/chromium/net/quic/crypto/aead_base_decrypter.h b/chromium/net/quic/crypto/aead_base_decrypter.h
index de9e9969b99..f8d6f1b861a 100644
--- a/chromium/net/quic/crypto/aead_base_decrypter.h
+++ b/chromium/net/quic/crypto/aead_base_decrypter.h
@@ -78,13 +78,6 @@ class NET_EXPORT_PRIVATE AeadBaseDecrypter : public QuicDecrypter {
#endif // !defined(USE_OPENSSL)
private:
- bool Decrypt(base::StringPiece nonce,
- const base::StringPiece& associated_data,
- const base::StringPiece& ciphertext,
- uint8* output,
- size_t* output_length,
- size_t max_output_length);
-
#if defined(USE_OPENSSL)
const EVP_AEAD* const aead_alg_;
#else
diff --git a/chromium/net/quic/crypto/aead_base_decrypter_nss.cc b/chromium/net/quic/crypto/aead_base_decrypter_nss.cc
index 1ed4f3ab6e2..255e88da3f8 100644
--- a/chromium/net/quic/crypto/aead_base_decrypter_nss.cc
+++ b/chromium/net/quic/crypto/aead_base_decrypter_nss.cc
@@ -47,16 +47,22 @@ bool AeadBaseDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
return true;
}
-bool AeadBaseDecrypter::Decrypt(StringPiece nonce,
- const StringPiece& associated_data,
- const StringPiece& ciphertext,
- uint8* output,
- size_t* output_length,
- size_t max_output_length) {
- if (ciphertext.length() < auth_tag_size_ ||
- nonce.size() != nonce_prefix_size_ + sizeof(QuicPacketSequenceNumber)) {
+bool AeadBaseDecrypter::DecryptPacket(QuicPacketSequenceNumber sequence_number,
+ const StringPiece& associated_data,
+ const StringPiece& ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) {
+ if (ciphertext.length() < auth_tag_size_) {
return false;
}
+
+ uint8 nonce[sizeof(nonce_prefix_) + sizeof(sequence_number)];
+ const size_t nonce_size = nonce_prefix_size_ + sizeof(sequence_number);
+ DCHECK_LE(nonce_size, sizeof(nonce));
+ memcpy(nonce, nonce_prefix_, nonce_prefix_size_);
+ memcpy(nonce + nonce_prefix_size_, &sequence_number, sizeof(sequence_number));
+
// NSS 3.14.x incorrectly requires an output buffer at least as long as
// the ciphertext (NSS bug
// https://bugzilla.mozilla.org/show_bug.cgi?id= 853674). Fortunately
@@ -93,7 +99,8 @@ bool AeadBaseDecrypter::Decrypt(StringPiece nonce,
}
AeadParams aead_params = {0};
- FillAeadParams(nonce, associated_data, auth_tag_size_, &aead_params);
+ FillAeadParams(StringPiece(reinterpret_cast<char*>(nonce), nonce_size),
+ associated_data, auth_tag_size_, &aead_params);
SECItem param;
param.type = siBuffer;
@@ -101,8 +108,9 @@ bool AeadBaseDecrypter::Decrypt(StringPiece nonce,
param.len = aead_params.len;
unsigned int output_len;
- if (pk11_decrypt_(aead_key.get(), aead_mechanism_, &param, output,
- &output_len, max_output_length,
+ if (pk11_decrypt_(aead_key.get(), aead_mechanism_, &param,
+ reinterpret_cast<uint8*>(output), &output_len,
+ max_output_length,
reinterpret_cast<const unsigned char*>(ciphertext.data()),
ciphertext.length()) != SECSuccess) {
return false;
@@ -116,26 +124,6 @@ bool AeadBaseDecrypter::Decrypt(StringPiece nonce,
return true;
}
-bool AeadBaseDecrypter::DecryptPacket(QuicPacketSequenceNumber sequence_number,
- const StringPiece& associated_data,
- const StringPiece& ciphertext,
- char* output,
- size_t* output_length,
- size_t max_output_length) {
- if (ciphertext.length() < auth_tag_size_) {
- return false;
- }
-
- uint8 nonce[sizeof(nonce_prefix_) + sizeof(sequence_number)];
- const size_t nonce_size = nonce_prefix_size_ + sizeof(sequence_number);
- DCHECK_LE(nonce_size, sizeof(nonce));
- memcpy(nonce, nonce_prefix_, nonce_prefix_size_);
- memcpy(nonce + nonce_prefix_size_, &sequence_number, sizeof(sequence_number));
- return Decrypt(StringPiece(reinterpret_cast<char*>(nonce), nonce_size),
- associated_data, ciphertext, reinterpret_cast<uint8*>(output),
- output_length, max_output_length);
-}
-
StringPiece AeadBaseDecrypter::GetKey() const {
return StringPiece(reinterpret_cast<const char*>(key_), key_size_);
}
diff --git a/chromium/net/quic/crypto/aead_base_decrypter_openssl.cc b/chromium/net/quic/crypto/aead_base_decrypter_openssl.cc
index 7929388114b..95991200a37 100644
--- a/chromium/net/quic/crypto/aead_base_decrypter_openssl.cc
+++ b/chromium/net/quic/crypto/aead_base_decrypter_openssl.cc
@@ -76,32 +76,6 @@ bool AeadBaseDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
return true;
}
-bool AeadBaseDecrypter::Decrypt(StringPiece nonce,
- const StringPiece& associated_data,
- const StringPiece& ciphertext,
- uint8* output,
- size_t* output_length,
- size_t max_output_length) {
- if (ciphertext.length() < auth_tag_size_ ||
- nonce.size() != nonce_prefix_size_ + sizeof(QuicPacketSequenceNumber)) {
- return false;
- }
-
- if (!EVP_AEAD_CTX_open(
- ctx_.get(), output, output_length, max_output_length,
- reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(),
- reinterpret_cast<const uint8_t*>(ciphertext.data()),
- ciphertext.size(),
- reinterpret_cast<const uint8_t*>(associated_data.data()),
- associated_data.size())) {
- // Because QuicFramer does trial decryption, decryption errors are expected
- // when encryption level changes. So we don't log decryption errors.
- ClearOpenSslErrors();
- return false;
- }
- return true;
-}
-
bool AeadBaseDecrypter::DecryptPacket(QuicPacketSequenceNumber sequence_number,
const StringPiece& associated_data,
const StringPiece& ciphertext,
@@ -114,12 +88,21 @@ bool AeadBaseDecrypter::DecryptPacket(QuicPacketSequenceNumber sequence_number,
uint8 nonce[sizeof(nonce_prefix_) + sizeof(sequence_number)];
const size_t nonce_size = nonce_prefix_size_ + sizeof(sequence_number);
- DCHECK_LE(nonce_size, sizeof(nonce));
memcpy(nonce, nonce_prefix_, nonce_prefix_size_);
memcpy(nonce + nonce_prefix_size_, &sequence_number, sizeof(sequence_number));
- return Decrypt(StringPiece(reinterpret_cast<char*>(nonce), nonce_size),
- associated_data, ciphertext, reinterpret_cast<uint8*>(output),
- output_length, max_output_length);
+ if (!EVP_AEAD_CTX_open(
+ ctx_.get(), reinterpret_cast<uint8_t*>(output), output_length,
+ max_output_length, reinterpret_cast<const uint8_t*>(nonce),
+ nonce_size, reinterpret_cast<const uint8_t*>(ciphertext.data()),
+ ciphertext.size(),
+ reinterpret_cast<const uint8_t*>(associated_data.data()),
+ associated_data.size())) {
+ // Because QuicFramer does trial decryption, decryption errors are expected
+ // when encryption level changes. So we don't log decryption errors.
+ ClearOpenSslErrors();
+ return false;
+ }
+ return true;
}
StringPiece AeadBaseDecrypter::GetKey() const {
diff --git a/chromium/net/quic/crypto/aead_base_encrypter.h b/chromium/net/quic/crypto/aead_base_encrypter.h
index 86db32c0253..dd8f775caeb 100644
--- a/chromium/net/quic/crypto/aead_base_encrypter.h
+++ b/chromium/net/quic/crypto/aead_base_encrypter.h
@@ -42,10 +42,6 @@ class NET_EXPORT_PRIVATE AeadBaseEncrypter : public QuicEncrypter {
// QuicEncrypter implementation
bool SetKey(base::StringPiece key) override;
bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
- bool Encrypt(base::StringPiece nonce,
- base::StringPiece associated_data,
- base::StringPiece plaintext,
- unsigned char* output) override;
bool EncryptPacket(QuicPacketSequenceNumber sequence_number,
base::StringPiece associated_data,
base::StringPiece plaintext,
@@ -59,6 +55,13 @@ class NET_EXPORT_PRIVATE AeadBaseEncrypter : public QuicEncrypter {
base::StringPiece GetKey() const override;
base::StringPiece GetNoncePrefix() const override;
+ // Necessary so unit tests can explicitly specify a nonce, instead of a
+ // nonce prefix and sequence number.
+ bool Encrypt(base::StringPiece nonce,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext,
+ unsigned char* output);
+
protected:
// Make these constants available to the subclasses so that the subclasses
// can assert at compile time their key_size_ and nonce_prefix_size_ do not
diff --git a/chromium/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc b/chromium/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc
index f6c3d6d47b9..aba387ae333 100644
--- a/chromium/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc
+++ b/chromium/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc
@@ -7,13 +7,7 @@
#include <pk11pub.h>
#include <secerr.h>
-#include "base/lazy_instance.h"
-#include "crypto/ghash.h"
-#include "crypto/scoped_nss_types.h"
-
-#if defined(USE_NSS_CERTS)
-#include <dlfcn.h>
-#endif
+#include "crypto/aes_128_gcm_helpers_nss.h"
using base::StringPiece;
@@ -24,185 +18,16 @@ namespace {
const size_t kKeySize = 16;
const size_t kNoncePrefixSize = 4;
-// On Linux, dynamically link against the system version of libnss3.so. In
-// order to continue working on systems without up-to-date versions of NSS,
-// lookup PK11_Decrypt with dlsym.
-
-// GcmSupportChecker is a singleton which caches the results of runtime symbol
-// resolution of PK11_Decrypt.
-class GcmSupportChecker {
- public:
- static PK11_DecryptFunction pk11_decrypt_func() {
- return pk11_decrypt_func_;
- }
-
- private:
- friend struct base::DefaultLazyInstanceTraits<GcmSupportChecker>;
-
- GcmSupportChecker() {
-#if !defined(USE_NSS_CERTS)
- // Using a bundled version of NSS that is guaranteed to have this symbol.
- pk11_decrypt_func_ = PK11_Decrypt;
-#else
- // Using system NSS libraries and PCKS #11 modules, which may not have the
- // necessary function (PK11_Decrypt) or mechanism support (CKM_AES_GCM).
-
- // If PK11_Decrypt() was successfully resolved, then NSS will support
- // AES-GCM directly. This was introduced in NSS 3.15.
- pk11_decrypt_func_ = (PK11_DecryptFunction)dlsym(RTLD_DEFAULT,
- "PK11_Decrypt");
-#endif
- }
-
- // |pk11_decrypt_func_| stores the runtime symbol resolution of PK11_Decrypt.
- static PK11_DecryptFunction pk11_decrypt_func_;
-};
-
-// static
-PK11_DecryptFunction GcmSupportChecker::pk11_decrypt_func_ = nullptr;
-
-base::LazyInstance<GcmSupportChecker>::Leaky g_gcm_support_checker =
- LAZY_INSTANCE_INITIALIZER;
-
-// Calls PK11_Decrypt if it's available. Otherwise, emulates CKM_AES_GCM using
-// CKM_AES_CTR and the GaloisHash class.
SECStatus My_Decrypt(PK11SymKey* key,
CK_MECHANISM_TYPE mechanism,
SECItem* param,
unsigned char* out,
unsigned int* out_len,
unsigned int max_len,
- const unsigned char* enc,
- unsigned int enc_len) {
- // If PK11_Decrypt() was successfully resolved or if bundled version of NSS is
- // being used, then NSS will support AES-GCM directly.
- PK11_DecryptFunction pk11_decrypt_func =
- GcmSupportChecker::pk11_decrypt_func();
- if (pk11_decrypt_func != nullptr) {
- return pk11_decrypt_func(key, mechanism, param, out, out_len, max_len, enc,
- enc_len);
- }
-
- // Otherwise, the user has an older version of NSS. Regrettably, NSS 3.14.x
- // has a bug in the AES GCM code
- // (https://bugzilla.mozilla.org/show_bug.cgi?id=853285), as well as missing
- // the PK11_Decrypt function
- // (https://bugzilla.mozilla.org/show_bug.cgi?id=854063), both of which are
- // resolved in NSS 3.15.
-
- DCHECK_EQ(mechanism, static_cast<CK_MECHANISM_TYPE>(CKM_AES_GCM));
- DCHECK_EQ(param->len, sizeof(CK_GCM_PARAMS));
-
- const CK_GCM_PARAMS* gcm_params =
- reinterpret_cast<CK_GCM_PARAMS*>(param->data);
-
- DCHECK_EQ(gcm_params->ulTagBits,
- static_cast<CK_ULONG>(Aes128Gcm12Decrypter::kAuthTagSize * 8));
- if (gcm_params->ulIvLen != 12u) {
- DVLOG(1) << "ulIvLen is not equal to 12";
- PORT_SetError(SEC_ERROR_INPUT_LEN);
- return SECFailure;
- }
-
- SECItem my_param = { siBuffer, nullptr, 0 };
-
- // Step 2. Let H = CIPH_K(128 '0' bits).
- unsigned char ghash_key[16] = {0};
- crypto::ScopedPK11Context ctx(PK11_CreateContextBySymKey(
- CKM_AES_ECB, CKA_ENCRYPT, key, &my_param));
- if (!ctx) {
- DVLOG(1) << "PK11_CreateContextBySymKey failed";
- return SECFailure;
- }
- int output_len;
- if (PK11_CipherOp(ctx.get(), ghash_key, &output_len, sizeof(ghash_key),
- ghash_key, sizeof(ghash_key)) != SECSuccess) {
- DVLOG(1) << "PK11_CipherOp failed";
- return SECFailure;
- }
-
- PK11_Finalize(ctx.get());
-
- if (output_len != sizeof(ghash_key)) {
- DVLOG(1) << "Wrong output length";
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- // Step 3. If len(IV)=96, then let J0 = IV || 31 '0' bits || 1.
- CK_AES_CTR_PARAMS ctr_params = {0};
- ctr_params.ulCounterBits = 32;
- memcpy(ctr_params.cb, gcm_params->pIv, gcm_params->ulIvLen);
- ctr_params.cb[12] = 0;
- ctr_params.cb[13] = 0;
- ctr_params.cb[14] = 0;
- ctr_params.cb[15] = 1;
-
- my_param.type = siBuffer;
- my_param.data = reinterpret_cast<unsigned char*>(&ctr_params);
- my_param.len = sizeof(ctr_params);
-
- ctx.reset(PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, key,
- &my_param));
- if (!ctx) {
- DVLOG(1) << "PK11_CreateContextBySymKey failed";
- return SECFailure;
- }
-
- // Step 6. Calculate the encryption mask of GCTR_K(J0, ...).
- unsigned char tag_mask[16] = {0};
- if (PK11_CipherOp(ctx.get(), tag_mask, &output_len, sizeof(tag_mask),
- tag_mask, sizeof(tag_mask)) != SECSuccess) {
- DVLOG(1) << "PK11_CipherOp failed";
- return SECFailure;
- }
- if (output_len != sizeof(tag_mask)) {
- DVLOG(1) << "Wrong output length";
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- if (enc_len < Aes128Gcm12Decrypter::kAuthTagSize) {
- PORT_SetError(SEC_ERROR_INPUT_LEN);
- return SECFailure;
- }
-
- // The const_cast for |enc| can be removed if system NSS libraries are
- // NSS 3.14.1 or later (NSS bug
- // https://bugzilla.mozilla.org/show_bug.cgi?id=808218).
- if (PK11_CipherOp(ctx.get(), out, &output_len, max_len,
- const_cast<unsigned char*>(enc),
- enc_len - Aes128Gcm12Decrypter::kAuthTagSize) != SECSuccess) {
- DVLOG(1) << "PK11_CipherOp failed";
- return SECFailure;
- }
-
- PK11_Finalize(ctx.get());
-
- if (static_cast<unsigned int>(output_len) !=
- enc_len - Aes128Gcm12Decrypter::kAuthTagSize) {
- DVLOG(1) << "Wrong output length";
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- crypto::GaloisHash ghash(ghash_key);
- ghash.UpdateAdditional(gcm_params->pAAD, gcm_params->ulAADLen);
- ghash.UpdateCiphertext(enc, output_len);
- unsigned char auth_tag[Aes128Gcm12Decrypter::kAuthTagSize];
- ghash.Finish(auth_tag, Aes128Gcm12Decrypter::kAuthTagSize);
- for (unsigned int i = 0; i < Aes128Gcm12Decrypter::kAuthTagSize; i++) {
- auth_tag[i] ^= tag_mask[i];
- }
-
- if (NSS_SecureMemcmp(auth_tag, enc + output_len,
- Aes128Gcm12Decrypter::kAuthTagSize) != 0) {
- PORT_SetError(SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
-
- *out_len = output_len;
- return SECSuccess;
+ const unsigned char* data,
+ unsigned int data_len) {
+ return crypto::PK11DecryptHelper(key, mechanism, param, out, out_len, max_len,
+ data, data_len);
}
} // namespace
@@ -213,7 +38,6 @@ Aes128Gcm12Decrypter::Aes128Gcm12Decrypter()
static_assert(kKeySize <= kMaxKeySize, "key size too big");
static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
"nonce prefix size too big");
- ignore_result(g_gcm_support_checker.Get());
}
Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {}
diff --git a/chromium/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc b/chromium/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
index 6ad96f4f34d..bc9b519eab8 100644
--- a/chromium/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
+++ b/chromium/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
@@ -7,13 +7,7 @@
#include <pk11pub.h>
#include <secerr.h>
-#include "base/lazy_instance.h"
-#include "crypto/ghash.h"
-#include "crypto/scoped_nss_types.h"
-
-#if defined(USE_NSS_CERTS)
-#include <dlfcn.h>
-#endif
+#include "crypto/aes_128_gcm_helpers_nss.h"
using base::StringPiece;
@@ -24,48 +18,6 @@ namespace {
const size_t kKeySize = 16;
const size_t kNoncePrefixSize = 4;
-// On Linux, dynamically link against the system version of libnss3.so. In
-// order to continue working on systems without up-to-date versions of NSS,
-// lookup PK11_Encrypt with dlsym.
-
-// GcmSupportChecker is a singleton which caches the results of runtime symbol
-// resolution of PK11_Encrypt.
-class GcmSupportChecker {
- public:
- static PK11_EncryptFunction pk11_encrypt_func() {
- return pk11_encrypt_func_;
- }
-
- private:
- friend struct base::DefaultLazyInstanceTraits<GcmSupportChecker>;
-
- GcmSupportChecker() {
-#if !defined(USE_NSS_CERTS)
- // Using a bundled version of NSS that is guaranteed to have this symbol.
- pk11_encrypt_func_ = PK11_Encrypt;
-#else
- // Using system NSS libraries and PCKS #11 modules, which may not have the
- // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM).
-
- // If PK11_Encrypt() was successfully resolved, then NSS will support
- // AES-GCM directly. This was introduced in NSS 3.15.
- pk11_encrypt_func_ = (PK11_EncryptFunction)dlsym(RTLD_DEFAULT,
- "PK11_Encrypt");
-#endif
- }
-
- // |pk11_encrypt_func_| stores the runtime symbol resolution of PK11_Encrypt.
- static PK11_EncryptFunction pk11_encrypt_func_;
-};
-
-// static
-PK11_EncryptFunction GcmSupportChecker::pk11_encrypt_func_ = nullptr;
-
-base::LazyInstance<GcmSupportChecker>::Leaky g_gcm_support_checker =
- LAZY_INSTANCE_INITIALIZER;
-
-// Calls PK11_Encrypt if it's available. Otherwise, emulates CKM_AES_GCM using
-// CKM_AES_CTR and the GaloisHash class.
SECStatus My_Encrypt(PK11SymKey* key,
CK_MECHANISM_TYPE mechanism,
SECItem* param,
@@ -74,134 +26,8 @@ SECStatus My_Encrypt(PK11SymKey* key,
unsigned int max_len,
const unsigned char* data,
unsigned int data_len) {
- // If PK11_Encrypt() was successfully resolved or if bundled version of NSS is
- // being used, then NSS will support AES-GCM directly.
- PK11_EncryptFunction pk11_encrypt_func =
- GcmSupportChecker::pk11_encrypt_func();
- if (pk11_encrypt_func != nullptr) {
- return pk11_encrypt_func(key, mechanism, param, out, out_len, max_len, data,
- data_len);
- }
-
- // Otherwise, the user has an older version of NSS. Regrettably, NSS 3.14.x
- // has a bug in the AES GCM code
- // (https://bugzilla.mozilla.org/show_bug.cgi?id=853285), as well as missing
- // the PK11_Encrypt function
- // (https://bugzilla.mozilla.org/show_bug.cgi?id=854063), both of which are
- // resolved in NSS 3.15.
-
- DCHECK_EQ(mechanism, static_cast<CK_MECHANISM_TYPE>(CKM_AES_GCM));
- DCHECK_EQ(param->len, sizeof(CK_GCM_PARAMS));
-
- if (max_len < static_cast<unsigned int>(Aes128Gcm12Encrypter::kAuthTagSize)) {
- DVLOG(1) << "max_len is less than kAuthTagSize";
- PORT_SetError(SEC_ERROR_OUTPUT_LEN);
- return SECFailure;
- }
-
- const CK_GCM_PARAMS* gcm_params =
- reinterpret_cast<CK_GCM_PARAMS*>(param->data);
-
- DCHECK_EQ(gcm_params->ulTagBits,
- static_cast<CK_ULONG>(Aes128Gcm12Encrypter::kAuthTagSize * 8));
- if (gcm_params->ulIvLen != 12u) {
- DVLOG(1) << "ulIvLen is not equal to 12";
- PORT_SetError(SEC_ERROR_INPUT_LEN);
- return SECFailure;
- }
-
- SECItem my_param = { siBuffer, nullptr, 0 };
-
- // Step 1. Let H = CIPH_K(128 '0' bits).
- unsigned char ghash_key[16] = {0};
- crypto::ScopedPK11Context ctx(PK11_CreateContextBySymKey(
- CKM_AES_ECB, CKA_ENCRYPT, key, &my_param));
- if (!ctx) {
- DVLOG(1) << "PK11_CreateContextBySymKey failed";
- return SECFailure;
- }
- int output_len;
- if (PK11_CipherOp(ctx.get(), ghash_key, &output_len, sizeof(ghash_key),
- ghash_key, sizeof(ghash_key)) != SECSuccess) {
- DVLOG(1) << "PK11_CipherOp failed";
- return SECFailure;
- }
-
- PK11_Finalize(ctx.get());
-
- if (output_len != sizeof(ghash_key)) {
- DVLOG(1) << "Wrong output length";
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- // Step 2. If len(IV)=96, then let J0 = IV || 31 '0' bits || 1.
- CK_AES_CTR_PARAMS ctr_params = {0};
- ctr_params.ulCounterBits = 32;
- memcpy(ctr_params.cb, gcm_params->pIv, gcm_params->ulIvLen);
- ctr_params.cb[12] = 0;
- ctr_params.cb[13] = 0;
- ctr_params.cb[14] = 0;
- ctr_params.cb[15] = 1;
-
- my_param.type = siBuffer;
- my_param.data = reinterpret_cast<unsigned char*>(&ctr_params);
- my_param.len = sizeof(ctr_params);
-
- ctx.reset(PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, key,
- &my_param));
- if (!ctx) {
- DVLOG(1) << "PK11_CreateContextBySymKey failed";
- return SECFailure;
- }
-
- // Step 6. Calculate the encryption mask of GCTR_K(J0, ...).
- unsigned char tag_mask[16] = {0};
- if (PK11_CipherOp(ctx.get(), tag_mask, &output_len, sizeof(tag_mask),
- tag_mask, sizeof(tag_mask)) != SECSuccess) {
- DVLOG(1) << "PK11_CipherOp failed";
- return SECFailure;
- }
- if (output_len != sizeof(tag_mask)) {
- DVLOG(1) << "Wrong output length";
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- // The const_cast for |data| can be removed if system NSS libraries are
- // NSS 3.14.1 or later (NSS bug
- // https://bugzilla.mozilla.org/show_bug.cgi?id=808218).
- if (PK11_CipherOp(ctx.get(), out, &output_len, max_len,
- const_cast<unsigned char*>(data), data_len) != SECSuccess) {
- DVLOG(1) << "PK11_CipherOp failed";
- return SECFailure;
- }
-
- PK11_Finalize(ctx.get());
-
- if (static_cast<unsigned int>(output_len) != data_len) {
- DVLOG(1) << "Wrong output length";
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- if ((max_len - Aes128Gcm12Encrypter::kAuthTagSize) <
- static_cast<unsigned int>(output_len)) {
- DVLOG(1) << "(max_len - kAuthTagSize) is less than output_len";
- PORT_SetError(SEC_ERROR_OUTPUT_LEN);
- return SECFailure;
- }
-
- crypto::GaloisHash ghash(ghash_key);
- ghash.UpdateAdditional(gcm_params->pAAD, gcm_params->ulAADLen);
- ghash.UpdateCiphertext(out, output_len);
- ghash.Finish(out + output_len, Aes128Gcm12Encrypter::kAuthTagSize);
- for (unsigned int i = 0; i < Aes128Gcm12Encrypter::kAuthTagSize; i++) {
- out[output_len + i] ^= tag_mask[i];
- }
-
- *out_len = output_len + Aes128Gcm12Encrypter::kAuthTagSize;
- return SECSuccess;
+ return crypto::PK11EncryptHelper(key, mechanism, param, out, out_len, max_len,
+ data, data_len);
}
} // namespace
@@ -212,7 +38,6 @@ Aes128Gcm12Encrypter::Aes128Gcm12Encrypter()
static_assert(kKeySize <= kMaxKeySize, "key size too big");
static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
"nonce prefix size too big");
- ignore_result(g_gcm_support_checker.Get());
}
Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {}
diff --git a/chromium/net/quic/crypto/channel_id_chromium.cc b/chromium/net/quic/crypto/channel_id_chromium.cc
index 53feed30630..a4d6d919c55 100644
--- a/chromium/net/quic/crypto/channel_id_chromium.cc
+++ b/chromium/net/quic/crypto/channel_id_chromium.cc
@@ -17,8 +17,9 @@
namespace net {
ChannelIDKeyChromium::ChannelIDKeyChromium(
- crypto::ECPrivateKey* ec_private_key)
- : ec_private_key_(ec_private_key) {}
+ scoped_ptr<crypto::ECPrivateKey> ec_private_key)
+ : ec_private_key_(ec_private_key.Pass()) {
+}
ChannelIDKeyChromium::~ChannelIDKeyChromium() {}
@@ -43,7 +44,7 @@ bool ChannelIDKeyChromium::Sign(base::StringPiece signed_data,
if (!sig_creator->DecodeSignature(der_signature, &raw_signature)) {
return false;
}
- memcpy(WriteInto(out_signature, raw_signature.size() + 1),
+ memcpy(base::WriteInto(out_signature, raw_signature.size() + 1),
&raw_signature[0], raw_signature.size());
return true;
}
@@ -87,9 +88,8 @@ class ChannelIDSourceChromium::Job {
ChannelIDService* const channel_id_service_;
- std::string channel_id_private_key_;
- std::string channel_id_cert_;
- ChannelIDService::RequestHandle channel_id_request_handle_;
+ scoped_ptr<crypto::ECPrivateKey> channel_id_crypto_key_;
+ ChannelIDService::Request channel_id_request_;
// |hostname| specifies the hostname for which we need a channel ID.
std::string hostname_;
@@ -178,12 +178,10 @@ int ChannelIDSourceChromium::Job::DoGetChannelIDKey(int result) {
next_state_ = STATE_GET_CHANNEL_ID_KEY_COMPLETE;
return channel_id_service_->GetOrCreateChannelID(
- hostname_,
- &channel_id_private_key_,
- &channel_id_cert_,
+ hostname_, &channel_id_crypto_key_,
base::Bind(&ChannelIDSourceChromium::Job::OnIOComplete,
base::Unretained(this)),
- &channel_id_request_handle_);
+ &channel_id_request_);
}
int ChannelIDSourceChromium::Job::DoGetChannelIDKeyComplete(int result) {
@@ -193,28 +191,13 @@ int ChannelIDSourceChromium::Job::DoGetChannelIDKeyComplete(int result) {
return result;
}
- std::vector<uint8> encrypted_private_key_info(
- channel_id_private_key_.size());
- memcpy(&encrypted_private_key_info[0], channel_id_private_key_.data(),
- channel_id_private_key_.size());
-
- base::StringPiece spki_piece;
- if (!asn1::ExtractSPKIFromDERCert(channel_id_cert_, &spki_piece)) {
- return ERR_UNEXPECTED;
- }
- std::vector<uint8> subject_public_key_info(spki_piece.size());
- memcpy(&subject_public_key_info[0], spki_piece.data(), spki_piece.size());
-
- crypto::ECPrivateKey* ec_private_key =
- crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
- ChannelIDService::kEPKIPassword, encrypted_private_key_info,
- subject_public_key_info);
- if (!ec_private_key) {
+ if (!channel_id_crypto_key_) {
// TODO(wtc): use the new error code ERR_CHANNEL_ID_IMPORT_FAILED to be
// added in https://codereview.chromium.org/338093012/.
return ERR_UNEXPECTED;
}
- channel_id_key_.reset(new ChannelIDKeyChromium(ec_private_key));
+ channel_id_key_.reset(
+ new ChannelIDKeyChromium(channel_id_crypto_key_.Pass()));
return result;
}
diff --git a/chromium/net/quic/crypto/channel_id_chromium.h b/chromium/net/quic/crypto/channel_id_chromium.h
index 20a1d8d7aa8..43a1ed390b6 100644
--- a/chromium/net/quic/crypto/channel_id_chromium.h
+++ b/chromium/net/quic/crypto/channel_id_chromium.h
@@ -19,7 +19,8 @@ class ChannelIDService;
class NET_EXPORT_PRIVATE ChannelIDKeyChromium: public ChannelIDKey {
public:
- explicit ChannelIDKeyChromium(crypto::ECPrivateKey* ec_private_key);
+ explicit ChannelIDKeyChromium(
+ scoped_ptr<crypto::ECPrivateKey> ec_private_key);
~ChannelIDKeyChromium() override;
// ChannelIDKey interface
diff --git a/chromium/net/quic/crypto/common_cert_set_1.c b/chromium/net/quic/crypto/common_cert_set_1.c
index ba182332b5a..aa436e2e926 100644
--- a/chromium/net/quic/crypto/common_cert_set_1.c
+++ b/chromium/net/quic/crypto/common_cert_set_1.c
@@ -140,4 +140,4 @@ static const size_t kLens[] = {
1770,
};
-static const uint64 kHash = GG_UINT64_C(0xff715ce4e7e9267b);
+static const uint64 kHash = UINT64_C(0xff715ce4e7e9267b);
diff --git a/chromium/net/quic/crypto/common_cert_set_test.cc b/chromium/net/quic/crypto/common_cert_set_test.cc
index ad81ec4955e..09b06d18eb5 100644
--- a/chromium/net/quic/crypto/common_cert_set_test.cc
+++ b/chromium/net/quic/crypto/common_cert_set_test.cc
@@ -4,6 +4,8 @@
#include "net/quic/crypto/common_cert_set.h"
+#include <stdint.h>
+
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece;
@@ -104,7 +106,7 @@ TEST(CommonCertSets, FindGIA_1) {
sizeof(kGIACertificate1));
const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
- const uint64 in_hash = GG_UINT64_C(0xff715ce4e7e9267b);
+ const uint64 in_hash = UINT64_C(0xff715ce4e7e9267b);
uint64 hash;
uint32 index;
ASSERT_TRUE(sets->MatchCert(
@@ -122,7 +124,7 @@ TEST(CommonCertSets, FindGIA_1) {
TEST(CommonCertSets, NonMatch) {
const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
StringPiece not_a_cert("hello");
- const uint64 in_hash = GG_UINT64_C(0xc9fef74053f99f39);
+ const uint64 in_hash = UINT64_C(0xc9fef74053f99f39);
uint64 hash;
uint32 index;
EXPECT_FALSE(sets->MatchCert(
diff --git a/chromium/net/quic/crypto/crypto_protocol.h b/chromium/net/quic/crypto/crypto_protocol.h
index 1f881ea2ea6..2d16b9ce595 100644
--- a/chromium/net/quic/crypto/crypto_protocol.h
+++ b/chromium/net/quic/crypto/crypto_protocol.h
@@ -53,10 +53,15 @@ const QuicTag kSRBF = TAG('S', 'R', 'B', 'F'); // Socket receive buffer
const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic
// Connection options (COPT) values
+const QuicTag kAFCW = TAG('A', 'F', 'C', 'W'); // Auto-tune flow control
+ // receive windows.
const QuicTag kTBBR = TAG('T', 'B', 'B', 'R'); // Reduced Buffer Bloat TCP
const QuicTag kRENO = TAG('R', 'E', 'N', 'O'); // Reno Congestion Control
const QuicTag kBYTE = TAG('B', 'Y', 'T', 'E'); // TCP cubic or reno in bytes
+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
+const QuicTag kIW50 = TAG('I', 'W', '5', '0'); // Force ICWND to 50
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
@@ -73,11 +78,18 @@ const QuicTag kTCID = TAG('T', 'C', 'I', 'D'); // Connection ID truncation.
// FEC options
const QuicTag kFHDR = TAG('F', 'H', 'D', 'R'); // FEC protect headers
+const QuicTag kFSTR = TAG('F', 'S', 'T', 'R'); // FEC protect all streams
+// Set FecSendPolicy for sending FEC packet only when FEC alarm goes off.
+const QuicTag kFSPA = TAG('F', 'S', 'P', 'A');
// Enable bandwidth resumption experiment.
const QuicTag kBWRE = TAG('B', 'W', 'R', 'E'); // Bandwidth resumption.
const QuicTag kBWMX = TAG('B', 'W', 'M', 'X'); // Max bandwidth resumption.
+// Enable path MTU discovery experiment.
+const QuicTag kMTUH = TAG('M', 'T', 'U', 'H'); // High-target MTU discovery.
+const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery.
+
// Proof types (i.e. certificate types)
// NOTE: although it would be silly to do so, specifying both kX509 and kX59R
// is allowed and is equivalent to specifying only kX509.
diff --git a/chromium/net/quic/crypto/crypto_secret_boxer.cc b/chromium/net/quic/crypto/crypto_secret_boxer.cc
index b139a6a50fb..a7898d995a4 100644
--- a/chromium/net/quic/crypto/crypto_secret_boxer.cc
+++ b/chromium/net/quic/crypto/crypto_secret_boxer.cc
@@ -6,6 +6,8 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "net/quic/crypto/aes_128_gcm_12_decrypter.h"
+#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
@@ -41,7 +43,7 @@ void CryptoSecretBoxer::SetKey(StringPiece key) {
}
string CryptoSecretBoxer::Box(QuicRandom* rand, StringPiece plaintext) const {
- scoped_ptr<QuicEncrypter> encrypter(QuicEncrypter::Create(kAESG));
+ scoped_ptr<Aes128Gcm12Encrypter> encrypter(new Aes128Gcm12Encrypter());
if (!encrypter->SetKey(key_)) {
DLOG(DFATAL) << "CryptoSecretBoxer's encrypter->SetKey failed.";
return string();
@@ -82,7 +84,7 @@ bool CryptoSecretBoxer::Unbox(StringPiece ciphertext,
memcpy(&sequence_number, nonce.data() + nonce_prefix.size(),
sizeof(sequence_number));
- scoped_ptr<QuicDecrypter> decrypter(QuicDecrypter::Create(kAESG));
+ scoped_ptr<Aes128Gcm12Decrypter> decrypter(new Aes128Gcm12Decrypter());
if (!decrypter->SetKey(key_)) {
DLOG(DFATAL) << "CryptoSecretBoxer's decrypter->SetKey failed.";
return false;
diff --git a/chromium/net/quic/crypto/null_decrypter.cc b/chromium/net/quic/crypto/null_decrypter.cc
index 8a18172a5c2..19f9ad10102 100644
--- a/chromium/net/quic/crypto/null_decrypter.cc
+++ b/chromium/net/quic/crypto/null_decrypter.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stdint.h>
+
#include "net/quic/crypto/null_decrypter.h"
#include "net/quic/quic_utils.h"
#include "net/quic/quic_data_reader.h"
@@ -67,7 +69,7 @@ uint128 NullDecrypter::ComputeHash(const StringPiece& data1,
const StringPiece& data2) const {
uint128 correct_hash = QuicUtils::FNV1a_128_Hash_Two(
data1.data(), data1.length(), data2.data(), data2.length());
- uint128 mask(GG_UINT64_C(0x0), GG_UINT64_C(0xffffffff));
+ uint128 mask(UINT64_C(0x0), UINT64_C(0xffffffff));
mask <<= 96;
correct_hash &= ~mask;
return correct_hash;
diff --git a/chromium/net/quic/crypto/null_encrypter.cc b/chromium/net/quic/crypto/null_encrypter.cc
index 286694ad7b2..c1e823e78cc 100644
--- a/chromium/net/quic/crypto/null_encrypter.cc
+++ b/chromium/net/quic/crypto/null_encrypter.cc
@@ -21,19 +21,6 @@ bool NullEncrypter::SetNoncePrefix(StringPiece nonce_prefix) {
return nonce_prefix.empty();
}
-bool NullEncrypter::Encrypt(
- StringPiece /*nonce*/,
- StringPiece associated_data,
- StringPiece plaintext,
- unsigned char* output) {
- string buffer = associated_data.as_string();
- plaintext.AppendToString(&buffer);
- uint128 hash = QuicUtils::FNV1a_128_Hash(buffer.data(), buffer.length());
- QuicUtils::SerializeUint128Short(hash, output);
- memcpy(output + GetHashLength(), plaintext.data(), plaintext.size());
- return true;
-}
-
bool NullEncrypter::EncryptPacket(QuicPacketSequenceNumber /*sequence_number*/,
StringPiece associated_data,
StringPiece plaintext,
@@ -44,8 +31,12 @@ bool NullEncrypter::EncryptPacket(QuicPacketSequenceNumber /*sequence_number*/,
if (max_output_length < len) {
return false;
}
- Encrypt(StringPiece(), associated_data, plaintext,
- reinterpret_cast<unsigned char*>(output));
+ uint128 hash = QuicUtils::FNV1a_128_Hash_Two(
+ associated_data.data(), associated_data.size(), plaintext.data(),
+ plaintext.size());
+ QuicUtils::SerializeUint128Short(hash,
+ reinterpret_cast<unsigned char*>(output));
+ memcpy(output + GetHashLength(), plaintext.data(), plaintext.length());
*output_length = len;
return true;
}
diff --git a/chromium/net/quic/crypto/null_encrypter.h b/chromium/net/quic/crypto/null_encrypter.h
index 40bcacc703e..66618fb9530 100644
--- a/chromium/net/quic/crypto/null_encrypter.h
+++ b/chromium/net/quic/crypto/null_encrypter.h
@@ -22,10 +22,6 @@ class NET_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter {
// QuicEncrypter implementation
bool SetKey(base::StringPiece key) override;
bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
- bool Encrypt(base::StringPiece nonce,
- base::StringPiece associated_data,
- base::StringPiece plaintext,
- unsigned char* output) override;
bool EncryptPacket(QuicPacketSequenceNumber sequence_number,
base::StringPiece associated_data,
base::StringPiece plaintext,
diff --git a/chromium/net/quic/crypto/proof_verifier_chromium.cc b/chromium/net/quic/crypto/proof_verifier_chromium.cc
index 280ca5ade8d..90543cbbbcc 100644
--- a/chromium/net/quic/crypto/proof_verifier_chromium.cc
+++ b/chromium/net/quic/crypto/proof_verifier_chromium.cc
@@ -9,7 +9,7 @@
#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/profiler/scoped_tracker.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/net/quic/crypto/proof_verifier_chromium.h b/chromium/net/quic/crypto/proof_verifier_chromium.h
index 7c0b069f8e2..ca7358a9604 100644
--- a/chromium/net/quic/crypto/proof_verifier_chromium.h
+++ b/chromium/net/quic/crypto/proof_verifier_chromium.h
@@ -35,7 +35,7 @@ class NET_EXPORT_PRIVATE ProofVerifyDetailsChromium
CertVerifyResult cert_verify_result;
// pinning_failure_log contains a message produced by
- // TransportSecurityState::DomainState::CheckPublicKeyPins in the event of a
+ // TransportSecurityState::PKPState::CheckPublicKeyPins in the event of a
// pinning failure. It is a (somewhat) human-readable string.
std::string pinning_failure_log;
};
diff --git a/chromium/net/quic/crypto/quic_crypto_client_config.cc b/chromium/net/quic/crypto/quic_crypto_client_config.cc
index a95c0f08e2b..a041f4c292f 100644
--- a/chromium/net/quic/crypto/quic_crypto_client_config.cc
+++ b/chromium/net/quic/crypto/quic_crypto_client_config.cc
@@ -4,7 +4,7 @@
#include "net/quic/crypto/quic_crypto_client_config.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -128,6 +128,15 @@ bool QuicCryptoClientConfig::CachedState::has_server_designated_connection_id()
return !server_designated_connection_ids_.empty();
}
+void QuicCryptoClientConfig::CachedState::add_server_nonce(
+ const string& server_nonce) {
+ server_nonces_.push(server_nonce);
+}
+
+bool QuicCryptoClientConfig::CachedState::has_server_nonce() const {
+ return !server_nonces_.empty();
+}
+
QuicCryptoClientConfig::CachedState::ServerConfigState
QuicCryptoClientConfig::CachedState::SetServerConfig(
StringPiece server_config, QuicWallTime now, string* error_details) {
@@ -325,6 +334,17 @@ QuicCryptoClientConfig::CachedState::GetNextServerDesignatedConnectionId() {
return next_id;
}
+string QuicCryptoClientConfig::CachedState::GetNextServerNonce() {
+ if (server_nonces_.empty()) {
+ LOG(DFATAL)
+ << "Attempting to consume a server nonce that was never designated.";
+ return "";
+ }
+ const string server_nonce = server_nonces_.front();
+ server_nonces_.pop();
+ return server_nonce;
+}
+
void QuicCryptoClientConfig::SetDefaults() {
// Key exchange methods.
kexs.resize(2);
@@ -727,6 +747,9 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
}
cached->add_server_designated_connection_id(connection_id);
+ if (!nonce.empty()) {
+ cached->add_server_nonce(nonce.as_string());
+ }
return QUIC_NO_ERROR;
}
@@ -881,7 +904,7 @@ bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
DCHECK(server_state->IsEmpty());
size_t i = 0;
for (; i < canonical_suffixes_.size(); ++i) {
- if (EndsWith(server_id.host(), canonical_suffixes_[i], false)) {
+ if (base::EndsWith(server_id.host(), canonical_suffixes_[i], false)) {
break;
}
}
diff --git a/chromium/net/quic/crypto/quic_crypto_client_config.h b/chromium/net/quic/crypto/quic_crypto_client_config.h
index a65f007e9b1..4eb4caf0938 100644
--- a/chromium/net/quic/crypto/quic_crypto_client_config.h
+++ b/chromium/net/quic/crypto/quic_crypto_client_config.h
@@ -124,6 +124,18 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
// queue of ids.
QuicConnectionId GetNextServerDesignatedConnectionId();
+ // Adds the servernonce to the queue of server nonces.
+ void add_server_nonce(const std::string& server_nonce);
+
+ // If true, the crypto config contains at least one server nonce, and the
+ // client should use one of these nonces.
+ bool has_server_nonce() const;
+
+ // This function should only be called when has_server_nonce is true.
+ // Returns the next connection_id specified by the server and removes it
+ // from the queue of ids.
+ std::string GetNextServerNonce();
+
// SetProofVerifyDetails takes ownership of |details|.
void SetProofVerifyDetails(ProofVerifyDetails* details);
@@ -161,8 +173,10 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
mutable scoped_ptr<CryptoHandshakeMessage> scfg_;
// TODO(jokulik): Consider using a hash-set as extra book-keeping to ensure
- // that no connection-id is added twice.
+ // that no connection-id is added twice. Also, consider keeping the server
+ // nonces and connection_ids together in one queue.
std::queue<QuicConnectionId> server_designated_connection_ids_;
+ std::queue<std::string> server_nonces_;
DISALLOW_COPY_AND_ASSIGN(CachedState);
};
diff --git a/chromium/net/quic/crypto/quic_crypto_client_config_test.cc b/chromium/net/quic/crypto/quic_crypto_client_config_test.cc
index 348f8f90e4d..0e1ea792f86 100644
--- a/chromium/net/quic/crypto/quic_crypto_client_config_test.cc
+++ b/chromium/net/quic/crypto/quic_crypto_client_config_test.cc
@@ -94,6 +94,47 @@ TEST(QuicCryptoClientConfigTest, CachedState_ServerIdConsumedBeforeSet) {
#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
}
+TEST(QuicCryptoClientConfigTest, CachedState_ServerNonce) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_FALSE(state.has_server_nonce());
+
+ string server_nonce = "nonce_1";
+ state.add_server_nonce(server_nonce);
+ EXPECT_TRUE(state.has_server_nonce());
+ EXPECT_EQ(server_nonce, state.GetNextServerNonce());
+ EXPECT_FALSE(state.has_server_nonce());
+
+ // Allow the ID to be set multiple times. It's unusual that this would
+ // happen, but not impossible.
+ server_nonce = "nonce_2";
+ state.add_server_nonce(server_nonce);
+ EXPECT_TRUE(state.has_server_nonce());
+ EXPECT_EQ(server_nonce, state.GetNextServerNonce());
+ server_nonce = "nonce_3";
+ state.add_server_nonce(server_nonce);
+ EXPECT_EQ(server_nonce, state.GetNextServerNonce());
+ EXPECT_FALSE(state.has_server_nonce());
+
+ // Test FIFO behavior.
+ const string first_nonce = "first_nonce";
+ const string second_nonce = "second_nonce";
+ state.add_server_nonce(first_nonce);
+ state.add_server_nonce(second_nonce);
+ EXPECT_TRUE(state.has_server_nonce());
+ EXPECT_EQ(first_nonce, state.GetNextServerNonce());
+ EXPECT_EQ(second_nonce, state.GetNextServerNonce());
+}
+
+TEST(QuicCryptoClientConfigTest, CachedState_ServerNonceConsumedBeforeSet) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_FALSE(state.has_server_nonce());
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+ EXPECT_DEBUG_DEATH(state.GetNextServerNonce(),
+ "Attempting to consume a server nonce "
+ "that was never designated.");
+#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+}
+
TEST(QuicCryptoClientConfigTest, CachedState_InitializeFrom) {
QuicCryptoClientConfig::CachedState state;
QuicCryptoClientConfig::CachedState other;
@@ -105,6 +146,7 @@ TEST(QuicCryptoClientConfigTest, CachedState_InitializeFrom) {
EXPECT_EQ(state.certs(), other.certs());
EXPECT_EQ(1u, other.generation_counter());
EXPECT_FALSE(state.has_server_designated_connection_id());
+ EXPECT_FALSE(state.has_server_nonce());
}
TEST(QuicCryptoClientConfigTest, InchoateChlo) {
@@ -356,6 +398,7 @@ TEST(QuicCryptoClientConfigTest, ProcessReject) {
true, // is_https
&out_params, &error));
EXPECT_FALSE(cached.has_server_designated_connection_id());
+ EXPECT_FALSE(cached.has_server_nonce());
}
TEST(QuicCryptoClientConfigTest, ProcessStatelessReject) {
@@ -363,7 +406,9 @@ TEST(QuicCryptoClientConfigTest, ProcessStatelessReject) {
CryptoHandshakeMessage rej;
FillInDummyReject(&rej, /* stateless */ true);
const QuicConnectionId kConnectionId = 0xdeadbeef;
+ const string server_nonce = "SERVER_NONCE";
rej.SetValue(kRCID, kConnectionId);
+ rej.SetStringPiece(kServerNonceTag, server_nonce);
// Now process the rejection.
QuicCryptoClientConfig::CachedState cached;
@@ -376,6 +421,7 @@ TEST(QuicCryptoClientConfigTest, ProcessStatelessReject) {
&out_params, &error));
EXPECT_TRUE(cached.has_server_designated_connection_id());
EXPECT_EQ(kConnectionId, cached.GetNextServerDesignatedConnectionId());
+ EXPECT_EQ(server_nonce, cached.GetNextServerNonce());
}
TEST(QuicCryptoClientConfigTest, BadlyFormattedStatelessReject) {
diff --git a/chromium/net/quic/crypto/quic_crypto_server_config.h b/chromium/net/quic/crypto/quic_crypto_server_config.h
index ab7442f0629..f7716e25f2b 100644
--- a/chromium/net/quic/crypto/quic_crypto_server_config.h
+++ b/chromium/net/quic/crypto/quic_crypto_server_config.h
@@ -215,8 +215,8 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// ProcessClientHello processes |client_hello| and decides whether to accept
// or reject the connection. If the connection is to be accepted, |out| is
// set to the contents of the ServerHello, |out_params| is completed and
- // QUIC_NO_ERROR is returned. Otherwise |out| is set to be a REJ message and
- // an error code is returned.
+ // QUIC_NO_ERROR is returned. Otherwise |out| is set to be a REJ or SREJ
+ // message and QUIC_NO_ERROR is returned.
//
// validate_chlo_result: Output from the asynchronous call to
// ValidateClientHello. Contains the client hello message and
diff --git a/chromium/net/quic/crypto/quic_encrypter.h b/chromium/net/quic/crypto/quic_encrypter.h
index 2e565c543bc..a44ef207096 100644
--- a/chromium/net/quic/crypto/quic_encrypter.h
+++ b/chromium/net/quic/crypto/quic_encrypter.h
@@ -39,16 +39,6 @@ class NET_EXPORT_PRIVATE QuicEncrypter {
// packet sequence number, even when retransmitting a lost packet.
virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0;
- // Encrypt encrypts |plaintext| and writes the ciphertext, plus a MAC over
- // both |associated_data| and |plaintext| to |output|, using |nonce| as the
- // nonce. |nonce| must be |8+GetNoncePrefixSize()| bytes long and |output|
- // must point to a buffer that is at least
- // |GetCiphertextSize(plaintext.size()| bytes long.
- virtual bool Encrypt(base::StringPiece nonce,
- base::StringPiece associated_data,
- base::StringPiece plaintext,
- unsigned char* output) = 0;
-
// Returns a newly created QuicData object containing the encrypted
// |plaintext| as well as a MAC over both |plaintext| and |associated_data|,
// or nullptr if there is an error. |sequence_number| is appended to the
diff --git a/chromium/net/quic/crypto/quic_server_info.cc b/chromium/net/quic/crypto/quic_server_info.cc
index c86d1f63c10..40111519fc2 100644
--- a/chromium/net/quic/crypto/quic_server_info.cc
+++ b/chromium/net/quic/crypto/quic_server_info.cc
@@ -63,8 +63,8 @@ bool QuicServerInfo::ParseInner(const string& data) {
return false;
}
- Pickle p(data.data(), data.size());
- PickleIterator iter(p);
+ base::Pickle p(data.data(), data.size());
+ base::PickleIterator iter(p);
int version = -1;
if (!iter.ReadInt(&version)) {
@@ -116,7 +116,7 @@ string QuicServerInfo::Serialize() {
}
string QuicServerInfo::SerializeInner() const {
- Pickle p(sizeof(Pickle::Header));
+ base::Pickle p(sizeof(base::Pickle::Header));
if (!p.WriteInt(kQuicCryptoConfigVersion) ||
!p.WriteString(state_.server_config) ||
diff --git a/chromium/net/quic/iovector.h b/chromium/net/quic/iovector.h
index 22d2cc9a8cd..fcf50e87d57 100644
--- a/chromium/net/quic/iovector.h
+++ b/chromium/net/quic/iovector.h
@@ -89,7 +89,7 @@ class NET_EXPORT_PRIVATE IOVector {
// and write, it always takes char*. Clients that writes will need to cast
// away the constant of the pointer before appending a block.
void Append(char* buffer, size_t length) {
- if (buffer != NULL && length > 0) {
+ if (buffer != nullptr && length > 0) {
if (iovec_.size() > 0) {
struct iovec& last = iovec_.back();
// If the new block is contiguous with the last block, just extend.
@@ -106,7 +106,7 @@ class NET_EXPORT_PRIVATE IOVector {
// Same as Append, but doesn't do the tail merge optimization.
// Intended for testing.
void AppendNoCoalesce(char* buffer, size_t length) {
- if (buffer != NULL && length > 0) {
+ if (buffer != nullptr && length > 0) {
struct iovec tmp = {buffer, length};
iovec_.push_back(tmp);
}
@@ -127,7 +127,7 @@ class NET_EXPORT_PRIVATE IOVector {
bytes_to_consume -= iter->iov_len;
}
iovec_.erase(iovec_.begin(), iter);
- if (iovec_.size() > 0 && bytes_to_consume != 0) {
+ if (!iovec_.empty() && bytes_to_consume != 0) {
iovec_[0].iov_base =
static_cast<char*>(iovec_[0].iov_base) + bytes_to_consume;
iovec_[0].iov_len -= bytes_to_consume;
@@ -142,6 +142,41 @@ class NET_EXPORT_PRIVATE IOVector {
return length - bytes_to_consume;
}
+ // Identical to Consume, but also copies the portion of the buffer being
+ // consumed into |buffer|. |buffer| must be at least size |length|. If
+ // the IOVector is less than |length|, the method consumes the entire
+ // IOVector, logs an error and returns the length consumed.
+ size_t ConsumeAndCopy(size_t length, char* buffer) {
+ if (length == 0)
+ return 0;
+
+ size_t bytes_to_consume = length;
+ // First consume all the iovecs which can be consumed completely.
+ std::vector<struct iovec>::iterator iter = iovec_.begin();
+ std::vector<struct iovec>::iterator end = iovec_.end();
+ for (; iter < end && bytes_to_consume >= iter->iov_len; ++iter) {
+ memcpy(buffer, iter->iov_base, iter->iov_len);
+ bytes_to_consume -= iter->iov_len;
+ buffer += iter->iov_len;
+ }
+ iovec_.erase(iovec_.begin(), iter);
+ if (bytes_to_consume == 0) {
+ return length;
+ }
+ if (iovec_.empty()) {
+ LOG_IF(DFATAL, bytes_to_consume > 0) << "Attempting to consume "
+ << bytes_to_consume
+ << " non-existent bytes.";
+ return length - bytes_to_consume;
+ }
+ // Partially consume the next iovec.
+ memcpy(buffer, iovec_[0].iov_base, bytes_to_consume);
+ iovec_[0].iov_base =
+ static_cast<char*>(iovec_[0].iov_base) + bytes_to_consume;
+ iovec_[0].iov_len -= bytes_to_consume;
+ return length;
+ }
+
// TODO(joechan): If capacity is large, swap out for a blank one.
// Clears the IOVector object to contain no blocks.
void Clear() { iovec_.clear(); }
diff --git a/chromium/net/quic/iovector_test.cc b/chromium/net/quic/iovector_test.cc
index 37a1523e5ce..f25ae1b5f51 100644
--- a/chromium/net/quic/iovector_test.cc
+++ b/chromium/net/quic/iovector_test.cc
@@ -7,6 +7,8 @@
#include <string.h>
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using std::string;
@@ -63,7 +65,7 @@ TEST(IOVectorTest, Append) {
for (size_t i = 0; i < arraysize(test_data); ++i) {
const int str_len = strlen(test_data[i]);
const int append_len = str_len / 2;
- // This should append a new block
+ // This should append a new block.
iov.Append(const_cast<char*>(test_data[i]), append_len);
length += append_len;
ASSERT_EQ(i + 1, static_cast<size_t>(iov.Size()));
@@ -140,7 +142,7 @@ TEST(IOVectorTest, ConsumeHalfBlocks) {
ASSERT_TRUE(iov2[0].iov_base == test_data[i] + tmp);
ASSERT_EQ(iov2[0].iov_len, str_len - tmp);
- // Consume the rest of the first block
+ // Consume the rest of the first block.
consumed = iov.Consume(str_len - tmp);
ASSERT_EQ(str_len - tmp, consumed);
ASSERT_EQ(arraysize(test_data) - i - 1, static_cast<size_t>(iov.Size()));
@@ -197,13 +199,107 @@ TEST(IOVectorTest, ConsumeTooMuch) {
}
int consumed = 0;
- consumed = iov.Consume(length);
- // TODO(rtenneti): enable when chromium supports EXPECT_DFATAL.
- /*
EXPECT_DFATAL(
{consumed = iov.Consume(length + 1);},
"Attempting to consume 1 non-existent bytes.");
- */
+ ASSERT_EQ(length, consumed);
+ const struct iovec* iov2 = iov.iovec();
+ ASSERT_EQ(0u, iov.Size());
+ ASSERT_TRUE(iov2 == nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
+}
+
+TEST(IOVectorTest, ConsumeAndCopyHalfBlocks) {
+ IOVector iov;
+ int length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+ const char* endp = iov.LastBlockEnd();
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const struct iovec* iov2 = iov.iovec();
+ const size_t str_len = strlen(test_data[i]);
+ size_t tmp = str_len / 2;
+
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_TRUE(iov2[0].iov_base == test_data[i]);
+ ASSERT_EQ(str_len, iov2[0].iov_len);
+
+ // Consume half of the first block.
+ scoped_ptr<char[]> buffer(new char[str_len]);
+ size_t consumed = iov.ConsumeAndCopy(tmp, buffer.get());
+ EXPECT_EQ(0, memcmp(test_data[i], buffer.get(), tmp));
+ ASSERT_EQ(tmp, consumed);
+ ASSERT_EQ(arraysize(test_data) - i, static_cast<size_t>(iov.Size()));
+ iov2 = iov.iovec();
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_TRUE(iov2[0].iov_base == test_data[i] + tmp);
+ ASSERT_EQ(iov2[0].iov_len, str_len - tmp);
+
+ // Consume the rest of the first block.
+ consumed = iov.ConsumeAndCopy(str_len - tmp, buffer.get());
+ ASSERT_EQ(str_len - tmp, consumed);
+ ASSERT_EQ(arraysize(test_data) - i - 1, static_cast<size_t>(iov.Size()));
+ iov2 = iov.iovec();
+ if (iov.Size() > 0) {
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == endp);
+ } else {
+ ASSERT_TRUE(iov2 == nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
+ }
+ }
+}
+
+TEST(IOVectorTest, ConsumeAndCopyTwoAndHalfBlocks) {
+ IOVector iov;
+ size_t length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+ const size_t last_len = strlen(test_data[arraysize(test_data) - 1]);
+ const size_t half_len = last_len / 2;
+
+ const char* endp = iov.LastBlockEnd();
+ scoped_ptr<char[]> buffer(new char[length]);
+ size_t consumed = iov.ConsumeAndCopy(length - half_len, buffer.get());
+ ASSERT_EQ(length - half_len, consumed);
+ const struct iovec* iov2 = iov.iovec();
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_EQ(1u, iov.Size());
+ ASSERT_TRUE(iov2[0].iov_base ==
+ test_data[arraysize(test_data) - 1] + last_len - half_len);
+ ASSERT_EQ(half_len, iov2[0].iov_len);
+ ASSERT_TRUE(iov.LastBlockEnd() == endp);
+
+ consumed = iov.Consume(half_len);
+ ASSERT_EQ(half_len, consumed);
+ iov2 = iov.iovec();
+ ASSERT_EQ(0u, iov.Size());
+ ASSERT_TRUE(iov2 == nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
+}
+
+TEST(IOVectorTest, ConsumeAndCopyTooMuch) {
+ IOVector iov;
+ int length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+
+ int consumed = 0;
+ scoped_ptr<char[]> buffer(new char[length + 1]);
+ EXPECT_DFATAL({ consumed = iov.ConsumeAndCopy(length + 1, buffer.get()); },
+ "Attempting to consume 1 non-existent bytes.");
ASSERT_EQ(length, consumed);
const struct iovec* iov2 = iov.iovec();
ASSERT_EQ(0u, iov.Size());
diff --git a/chromium/net/quic/quic_ack_notifier_manager.cc b/chromium/net/quic/quic_ack_notifier_manager.cc
index cfdf8f90ffc..599e7d74c92 100644
--- a/chromium/net/quic/quic_ack_notifier_manager.cc
+++ b/chromium/net/quic/quic_ack_notifier_manager.cc
@@ -89,4 +89,25 @@ void AckNotifierManager::OnSerializedPacket(
}
}
+void AckNotifierManager::OnPacketRemoved(
+ QuicPacketSequenceNumber sequence_number) {
+ // Determine if there are any notifiers interested in this packet.
+ auto map_it = ack_notifier_map_.find(sequence_number);
+ if (map_it == ack_notifier_map_.end()) {
+ return;
+ }
+
+ // Notify all of the interested notifiers that the packet is abandoned.
+ for (QuicAckNotifier* ack_notifier : map_it->second) {
+ DCHECK(ack_notifier);
+ if (ack_notifier->OnPacketAbandoned()) {
+ // If this has resulted in an empty AckNotifer, erase it.
+ delete ack_notifier;
+ }
+ }
+
+ // Remove the packet with given sequence number from the map.
+ ack_notifier_map_.erase(map_it);
+}
+
} // namespace net
diff --git a/chromium/net/quic/quic_ack_notifier_manager.h b/chromium/net/quic/quic_ack_notifier_manager.h
index d4d97ad7cd7..aa9d9d1670c 100644
--- a/chromium/net/quic/quic_ack_notifier_manager.h
+++ b/chromium/net/quic/quic_ack_notifier_manager.h
@@ -15,6 +15,10 @@ namespace net {
class QuicAckNotifier;
+namespace test {
+class AckNotifierManagerPeer;
+}
+
// The AckNotifierManager is used by the QuicSentPacketManager to keep track of
// all the AckNotifiers currently active. It owns the AckNotifiers which it gets
// from the serialized packets passed into OnSerializedPacket. It maintains both
@@ -46,7 +50,13 @@ class NET_EXPORT_PRIVATE AckNotifierManager {
// inform the AckNotifier of the sequence number which it should track.
void OnSerializedPacket(const SerializedPacket& serialized_packet);
+ // This method is invoked when a packet is removed from the list of unacked
+ // packets, and it is no longer necessary to keep track of the notifier.
+ void OnPacketRemoved(QuicPacketSequenceNumber sequence_number);
+
private:
+ friend class test::AckNotifierManagerPeer;
+
typedef std::list<QuicAckNotifier*> AckNotifierList;
// TODO(ianswett): Further improvement may come from changing this to a deque.
typedef base::hash_map<QuicPacketSequenceNumber, AckNotifierList>
diff --git a/chromium/net/quic/quic_ack_notifier_manager_test.cc b/chromium/net/quic/quic_ack_notifier_manager_test.cc
new file mode 100644
index 00000000000..e791b91b9e1
--- /dev/null
+++ b/chromium/net/quic/quic_ack_notifier_manager_test.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2015 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/quic_ack_notifier_manager.h"
+
+#include "net/quic/quic_ack_notifier.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/test_tools/quic_ack_notifier_manager_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+// Test fixture for testing AckNotifierManager. Instantiates a manager and
+// provides shared code for adding notifiers and verifying the contents of the
+// manager.
+class QuicAckNotifierManagerTest : public ::testing::Test {
+ protected:
+ AckNotifierManager manager_;
+ scoped_refptr<MockAckNotifierDelegate> delegate_;
+ QuicTime::Delta zero_;
+
+ QuicAckNotifierManagerTest() : zero_(QuicTime::Delta::Zero()) {
+ delegate_ = new MockAckNotifierDelegate;
+ }
+
+ ~QuicAckNotifierManagerTest() override {}
+
+ size_t CountPackets() const {
+ return AckNotifierManagerPeer::GetNumberOfRegisteredPackets(&manager_);
+ }
+
+ // Add a mock packet with specified parameters. The packet with given
+ // sequence number must not exist in the map before.
+ void AddPacket(QuicPacketSequenceNumber sequence_number,
+ bool retransmittable) {
+ // Create a mock packet.
+ RetransmittableFrames frames(ENCRYPTION_NONE);
+ SerializedPacket packet(sequence_number, PACKET_4BYTE_SEQUENCE_NUMBER,
+ /*packet=*/nullptr,
+ /*entropy_hash=*/0,
+ retransmittable ? &frames : nullptr);
+
+ // Create and register a notifier. Normally, this would be created by
+ // QuicPacketGenerator.
+ QuicAckNotifier* notifier = new QuicAckNotifier(delegate_.get());
+ packet.notifiers.push_back(notifier);
+
+ // Ensure that exactly one packet is added.
+ const size_t old_packet_count = CountPackets();
+
+ // Actually add the packet.
+ manager_.OnSerializedPacket(packet);
+
+ // Ensure the change in the number of packets.
+ EXPECT_EQ(old_packet_count + 1, CountPackets());
+ }
+};
+
+// This test verifies that QuicAckNotifierManager can handle the trivial case of
+// received packet notification.
+TEST_F(QuicAckNotifierManagerTest, SimpleAck) {
+ AddPacket(1, false);
+ AddPacket(2, true);
+
+ EXPECT_CALL(*delegate_, OnAckNotification(0, 0, zero_)).Times(2);
+ manager_.OnPacketAcked(1, zero_);
+ EXPECT_EQ(1u, CountPackets());
+ manager_.OnPacketAcked(2, zero_);
+ EXPECT_EQ(0u, CountPackets());
+
+ manager_.OnPacketRemoved(1);
+ manager_.OnPacketRemoved(2);
+ EXPECT_EQ(0u, CountPackets());
+}
+
+// This test verifies that QuicAckNotifierManager can correctly handle the case
+// when some of the packets are lost, which causes retransmission and removal
+// from the unacked packet map.
+TEST_F(QuicAckNotifierManagerTest, AckWithLosses) {
+ const size_t retransmitted_packet_size = kDefaultMaxPacketSize;
+
+ // Here, we simulate the following scenario:
+ // 1. We send packets 1 to 5, where only odd-numbered packets are
+ // retransmittable.
+ // 2. The peer acks 1, 2 and 5, but not 3 and 4.
+ // 3. We retransmit 3 as 6.
+ // 4. We remove 1 and 2, since we no longer care about them.
+ // 4. The peer acks 6.
+ // 5. We remove packets 3 to 6.
+
+ // Step 1: send five packets.
+ AddPacket(1, true);
+ AddPacket(2, false);
+ AddPacket(3, true);
+ AddPacket(4, false);
+ AddPacket(5, true);
+
+ // Step 2: handle acks from peer.
+ EXPECT_CALL(*delegate_, OnAckNotification(0, 0, zero_)).Times(3);
+ manager_.OnPacketAcked(1, zero_);
+ EXPECT_EQ(4u, CountPackets());
+ manager_.OnPacketAcked(2, zero_);
+ EXPECT_EQ(3u, CountPackets());
+ manager_.OnPacketAcked(5, zero_);
+ EXPECT_EQ(2u, CountPackets());
+
+ // Step 3: retransmit 3 as 6.
+ manager_.OnPacketRetransmitted(3, 6, retransmitted_packet_size);
+ EXPECT_EQ(2u, CountPackets());
+
+ // Step 4: remove 1 and 2.
+ manager_.OnPacketRemoved(1);
+ manager_.OnPacketRemoved(2);
+ EXPECT_EQ(2u, CountPackets());
+
+ // Step 4: ack packet 6.
+ EXPECT_CALL(*delegate_,
+ OnAckNotification(1, retransmitted_packet_size, zero_)).Times(1);
+ manager_.OnPacketAcked(6, zero_);
+ EXPECT_EQ(1u, CountPackets());
+
+ // Step 5: remove all packets. This causes packet 4 to be dropped from the
+ // map.
+ manager_.OnPacketRemoved(3);
+ manager_.OnPacketRemoved(4);
+ manager_.OnPacketRemoved(5);
+ manager_.OnPacketRemoved(6);
+ EXPECT_EQ(0u, CountPackets());
+}
+
+// This test verifies that the QuicAckNotifierManager behaves correctly when
+// there are many retransmissions.
+TEST_F(QuicAckNotifierManagerTest, RepeatedRetransmission) {
+ AddPacket(1, true);
+
+ const size_t packet_size = kDefaultMaxPacketSize;
+ const size_t times_lost = 100;
+ const size_t total_size_lost = packet_size * times_lost;
+ const QuicPacketSequenceNumber last_packet = times_lost + 1;
+
+ // Retransmit the packet many times.
+ for (size_t sequence_number = 1; sequence_number < last_packet;
+ sequence_number++) {
+ manager_.OnPacketRetransmitted(sequence_number, sequence_number + 1,
+ packet_size);
+ EXPECT_EQ(1u, CountPackets());
+ }
+
+ // Remove all lost packets.
+ for (QuicPacketSequenceNumber packet = 1; packet < last_packet; packet++) {
+ manager_.OnPacketRemoved(packet);
+ }
+ EXPECT_EQ(1u, CountPackets());
+
+ // Finally get the packet acknowledged.
+ EXPECT_CALL(*delegate_, OnAckNotification(times_lost, total_size_lost, zero_))
+ .Times(1);
+ manager_.OnPacketAcked(last_packet, zero_);
+ EXPECT_EQ(0u, CountPackets());
+
+ // Remove the last packet.
+ manager_.OnPacketRemoved(last_packet);
+ EXPECT_EQ(0u, CountPackets());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/quic_bandwidth.cc b/chromium/net/quic/quic_bandwidth.cc
index b42a1f37e2e..911eb6c83cf 100644
--- a/chromium/net/quic/quic_bandwidth.cc
+++ b/chromium/net/quic/quic_bandwidth.cc
@@ -4,6 +4,8 @@
#include "net/quic/quic_bandwidth.h"
+#include <stdint.h>
+
#include "base/logging.h"
#include "net/quic/quic_time.h"
#include "net/quic/quic_types.h"
@@ -11,7 +13,7 @@
namespace net {
// Highest number that QuicBandwidth can hold.
-const int64 kQuicInfiniteBandwidth = GG_INT64_C(0x7fffffffffffffff);
+const int64 kQuicInfiniteBandwidth = INT64_C(0x7fffffffffffffff);
// static
QuicBandwidth QuicBandwidth::Zero() {
diff --git a/chromium/net/quic/quic_client_session.cc b/chromium/net/quic/quic_client_session.cc
index 9721e719961..e45a4b8d3a9 100644
--- a/chromium/net/quic/quic_client_session.cc
+++ b/chromium/net/quic/quic_client_session.cc
@@ -5,11 +5,13 @@
#include "net/quic/quic_client_session.h"
#include "base/callback_helpers.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram.h"
+#include "base/location.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "base/values.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -96,12 +98,12 @@ void RecordHandshakeState(HandshakeState state) {
NUM_HANDSHAKE_STATES);
}
-base::Value* NetLogQuicClientSessionCallback(
+scoped_ptr<base::Value> NetLogQuicClientSessionCallback(
const QuicServerId* server_id,
int cert_verify_flags,
bool require_confirmation,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("host", server_id->host());
dict->SetInteger("port", server_id->port());
dict->SetBoolean("is_https", server_id->is_https());
@@ -109,7 +111,7 @@ base::Value* NetLogQuicClientSessionCallback(
server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
dict->SetBoolean("require_confirmation", require_confirmation);
dict->SetInteger("cert_verify_flags", cert_verify_flags);
- return dict;
+ return dict.Pass();
}
} // namespace
@@ -157,21 +159,24 @@ QuicClientSession::QuicClientSession(
QuicConnection* connection,
scoped_ptr<DatagramClientSocket> socket,
QuicStreamFactory* stream_factory,
+ QuicCryptoClientStreamFactory* crypto_client_stream_factory,
TransportSecurityState* transport_security_state,
scoped_ptr<QuicServerInfo> server_info,
+ const QuicServerId& server_id,
int cert_verify_flags,
const QuicConfig& config,
+ QuicCryptoClientConfig* crypto_config,
const char* const connection_description,
base::TimeTicks dns_resolution_end_time,
base::TaskRunner* task_runner,
NetLog* net_log)
: QuicClientSessionBase(connection, config),
+ server_id_(server_id),
require_confirmation_(false),
stream_factory_(stream_factory),
socket_(socket.Pass()),
transport_security_state_(transport_security_state),
server_info_(server_info.Pass()),
- cert_verify_flags_(cert_verify_flags),
num_total_streams_(0),
task_runner_(task_runner),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
@@ -179,49 +184,40 @@ QuicClientSession::QuicClientSession(
dns_resolution_end_time_(dns_resolution_end_time),
logger_(new QuicConnectionLogger(this, connection_description, net_log_)),
going_away_(false),
+ disabled_reason_(QUIC_DISABLED_NOT),
weak_factory_(this) {
- connection->set_debug_visitor(logger_.get());
- IPEndPoint address;
- if (socket && socket->GetLocalAddress(&address) == OK &&
- address.GetFamily() == ADDRESS_FAMILY_IPV6) {
- connection->set_max_packet_length(
- connection->max_packet_length() - kAdditionalOverheadForIPv6);
- }
-}
-
-void QuicClientSession::InitializeSession(
- const QuicServerId& server_id,
- QuicCryptoClientConfig* crypto_config,
- QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
- server_id_ = server_id;
crypto_stream_.reset(
crypto_client_stream_factory
? crypto_client_stream_factory->CreateQuicCryptoClientStream(
server_id, this, crypto_config)
: new QuicCryptoClientStream(
server_id, this,
- new ProofVerifyContextChromium(cert_verify_flags_, net_log_),
+ new ProofVerifyContextChromium(cert_verify_flags, net_log_),
crypto_config));
- QuicClientSessionBase::InitializeSession();
- // TODO(rch): pass in full host port proxy pair
+ connection->set_debug_visitor(logger_.get());
net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
base::Bind(NetLogQuicClientSessionCallback, &server_id,
- cert_verify_flags_, require_confirmation_));
+ cert_verify_flags, require_confirmation_));
+ IPEndPoint address;
+ if (socket && socket->GetLocalAddress(&address) == OK &&
+ address.GetFamily() == ADDRESS_FAMILY_IPV6) {
+ connection->set_max_packet_length(connection->max_packet_length() -
+ kAdditionalOverheadForIPv6);
+ }
}
QuicClientSession::~QuicClientSession() {
- if (!streams()->empty())
+ if (!dynamic_streams().empty())
RecordUnexpectedOpenStreams(DESTRUCTOR);
if (!observers_.empty())
RecordUnexpectedObservers(DESTRUCTOR);
if (!going_away_)
RecordUnexpectedNotGoingAway(DESTRUCTOR);
- while (!streams()->empty() ||
- !observers_.empty() ||
+ while (!dynamic_streams().empty() || !observers_.empty() ||
!stream_requests_.empty()) {
// The session must be closed before it is destroyed.
- DCHECK(streams()->empty());
+ DCHECK(dynamic_streams().empty());
CloseAllStreams(ERR_UNEXPECTED);
DCHECK(observers_.empty());
CloseAllObservers(ERR_UNEXPECTED);
@@ -311,6 +307,17 @@ QuicClientSession::~QuicClientSession() {
}
}
+ // The MTU used by QUIC is limited to a fairly small set of predefined values
+ // (initial values and MTU discovery values), but does not fare well when
+ // bucketed. Because of that, a sparse histogram is used here.
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ClientSideMtu",
+ connection()->max_packet_length());
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ServerSideMtu",
+ stats.max_received_packet_size);
+
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.MtuProbesSent",
+ connection()->mtu_probe_count());
+
if (stats.max_sequence_reordering == 0)
return;
const base::HistogramBase::Sample kMaxReordering = 100;
@@ -347,7 +354,7 @@ void QuicClientSession::OnStreamFrames(
it->second);
}
- return QuicSession::OnStreamFrames(frames);
+ return QuicSpdySession::OnStreamFrames(frames);
}
void QuicClientSession::AddObserver(Observer* observer) {
@@ -407,7 +414,7 @@ void QuicClientSession::CancelRequest(StreamRequest* request) {
}
}
-QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
+QuicReliableClientStream* QuicClientSession::CreateOutgoingDynamicStream() {
if (!crypto_stream_->encryption_established()) {
DVLOG(1) << "Encryption not active so no outgoing stream created.";
return nullptr;
@@ -559,7 +566,7 @@ bool QuicClientSession::CanPool(const std::string& hostname,
server_id_.host(), hostname);
}
-QuicDataStream* QuicClientSession::CreateIncomingDataStream(
+QuicDataStream* QuicClientSession::CreateIncomingDynamicStream(
QuicStreamId id) {
DLOG(ERROR) << "Server push not supported";
return nullptr;
@@ -572,14 +579,14 @@ void QuicClientSession::CloseStream(QuicStreamId stream_id) {
stream_id, stream->num_frames_received(),
stream->num_duplicate_frames_received());
}
- QuicSession::CloseStream(stream_id);
+ QuicSpdySession::CloseStream(stream_id);
OnClosedStream();
}
void QuicClientSession::SendRstStream(QuicStreamId id,
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written) {
- QuicSession::SendRstStream(id, error, bytes_written);
+ QuicSpdySession::SendRstStream(id, error, bytes_written);
OnClosedStream();
}
@@ -650,7 +657,7 @@ void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
if (server_info_)
server_info_->OnExternalCacheHit();
}
- QuicSession::OnCryptoHandshakeEvent(event);
+ QuicSpdySession::OnCryptoHandshakeEvent(event);
}
void QuicClientSession::OnCryptoHandshakeMessageSent(
@@ -681,6 +688,7 @@ void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
GetNumOpenStreams());
if (IsCryptoHandshakeConfirmed()) {
if (GetNumOpenStreams() > 0) {
+ disabled_reason_ = QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS;
UMA_HISTOGRAM_BOOLEAN(
"Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
connection()->sent_packet_manager().HasUnackedPackets());
@@ -727,6 +735,8 @@ void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
"Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
error);
}
+ } else if (error == QUIC_PUBLIC_RESET) {
+ disabled_reason_ = QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE;
}
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
@@ -737,7 +747,7 @@ void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
}
socket_->Close();
QuicSession::OnConnectionClosed(error, from_peer);
- DCHECK(streams()->empty());
+ DCHECK(dynamic_streams().empty());
CloseAllStreams(ERR_UNEXPECTED);
CloseAllObservers(ERR_UNEXPECTED);
NotifyFactoryOfSessionClosedLater();
@@ -746,7 +756,7 @@ void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
void QuicClientSession::OnSuccessfulVersionNegotiation(
const QuicVersion& version) {
logger_->OnSuccessfulVersionNegotiation(version);
- QuicSession::OnSuccessfulVersionNegotiation(version);
+ QuicSpdySession::OnSuccessfulVersionNegotiation(version);
}
void QuicClientSession::OnProofValid(
@@ -818,8 +828,8 @@ void QuicClientSession::CloseSessionOnErrorInner(int net_error,
}
void QuicClientSession::CloseAllStreams(int net_error) {
- while (!streams()->empty()) {
- ReliableQuicStream* stream = streams()->begin()->second;
+ while (!dynamic_streams().empty()) {
+ ReliableQuicStream* stream = dynamic_streams().begin()->second;
QuicStreamId id = stream->id();
static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
CloseStream(id);
@@ -834,20 +844,19 @@ void QuicClientSession::CloseAllObservers(int net_error) {
}
}
-base::Value* QuicClientSession::GetInfoAsValue(
+scoped_ptr<base::Value> QuicClientSession::GetInfoAsValue(
const std::set<HostPortPair>& aliases) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("version", QuicVersionToString(connection()->version()));
dict->SetInteger("open_streams", GetNumOpenStreams());
- base::ListValue* stream_list = new base::ListValue();
- for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
- = streams()->begin();
- it != streams()->end();
- ++it) {
- stream_list->Append(new base::StringValue(
- base::Uint64ToString(it->second->id())));
+ scoped_ptr<base::ListValue> stream_list(new base::ListValue());
+ for (base::hash_map<QuicStreamId, ReliableQuicStream*>::const_iterator it =
+ dynamic_streams().begin();
+ it != dynamic_streams().end(); ++it) {
+ stream_list->Append(
+ new base::StringValue(base::UintToString(it->second->id())));
}
- dict->Set("active_streams", stream_list);
+ dict->Set("active_streams", stream_list.Pass());
dict->SetInteger("total_streams", num_total_streams_);
dict->SetString("peer_address", peer_address().ToString());
@@ -860,14 +869,14 @@ base::Value* QuicClientSession::GetInfoAsValue(
SSLInfo ssl_info;
dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
- base::ListValue* alias_list = new base::ListValue();
+ scoped_ptr<base::ListValue> alias_list(new base::ListValue());
for (std::set<HostPortPair>::const_iterator it = aliases.begin();
it != aliases.end(); it++) {
alias_list->Append(new base::StringValue(it->ToString()));
}
- dict->Set("aliases", alias_list);
+ dict->Set("aliases", alias_list.Pass());
- return dict;
+ return dict.Pass();
}
base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
@@ -900,7 +909,7 @@ void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
}
void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
- if (!streams()->empty())
+ if (!dynamic_streams().empty())
RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
if (!going_away_)
@@ -909,14 +918,13 @@ void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
going_away_ = true;
DCHECK_EQ(0u, GetNumOpenStreams());
DCHECK(!connection()->connected());
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
- weak_factory_.GetWeakPtr()));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
+ weak_factory_.GetWeakPtr()));
}
void QuicClientSession::NotifyFactoryOfSessionClosed() {
- if (!streams()->empty())
+ if (!dynamic_streams().empty())
RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
if (!going_away_)
diff --git a/chromium/net/quic/quic_client_session.h b/chromium/net/quic/quic_client_session.h
index db13de99830..ae55a18ede4 100644
--- a/chromium/net/quic/quic_client_session.h
+++ b/chromium/net/quic/quic_client_session.h
@@ -44,6 +44,18 @@ class QuicClientSessionPeer;
class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase,
public QuicPacketReader::Visitor {
public:
+ // Reasons to disable QUIC, that is under certain pathological
+ // connection errors. Note: these values must be kept in sync with
+ // the corresponding values of QuicDisabledReason in:
+ // tools/metrics/histograms/histograms.xml
+ enum QuicDisabledReason {
+ QUIC_DISABLED_NOT = 0, // default, not disabled
+ QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE = 1,
+ QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS = 2,
+ QUIC_DISABLED_BAD_PACKET_LOSS_RATE = 3,
+ QUIC_DISABLED_MAX = 4,
+ };
+
// An interface for observing events on a session.
class NET_EXPORT_PRIVATE Observer {
public:
@@ -95,22 +107,19 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase,
QuicClientSession(QuicConnection* connection,
scoped_ptr<DatagramClientSocket> socket,
QuicStreamFactory* stream_factory,
+ QuicCryptoClientStreamFactory* crypto_client_stream_factory,
TransportSecurityState* transport_security_state,
scoped_ptr<QuicServerInfo> server_info,
+ const QuicServerId& server_id,
int cert_verify_flags,
const QuicConfig& config,
+ QuicCryptoClientConfig* crypto_config,
const char* const connection_description,
base::TimeTicks dns_resolution_end_time,
base::TaskRunner* task_runner,
NetLog* net_log);
~QuicClientSession() override;
- // Initialize session's connection to |server_id|.
- void InitializeSession(
- const QuicServerId& server_id,
- QuicCryptoClientConfig* config,
- QuicCryptoClientStreamFactory* crypto_client_stream_factory);
-
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
@@ -129,7 +138,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase,
// QuicSession methods:
void OnStreamFrames(const std::vector<QuicStreamFrame>& frames) override;
- QuicReliableClientStream* CreateOutgoingDataStream() override;
+ QuicReliableClientStream* CreateOutgoingDynamicStream() override;
QuicCryptoClientStream* GetCryptoStream() override;
void CloseStream(QuicStreamId stream_id) override;
void SendRstStream(QuicStreamId id,
@@ -179,7 +188,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase,
void CloseSessionOnErrorAndNotifyFactoryLater(int error,
QuicErrorCode quic_error);
- base::Value* GetInfoAsValue(const std::set<HostPortPair>& aliases);
+ scoped_ptr<base::Value> GetInfoAsValue(const std::set<HostPortPair>& aliases);
const BoundNetLog& net_log() const { return net_log_; }
@@ -197,9 +206,11 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase,
const QuicServerId& server_id() const { return server_id_; }
+ QuicDisabledReason disabled_reason() const { return disabled_reason_; }
+
protected:
// QuicSession methods:
- QuicDataStream* CreateIncomingDataStream(QuicStreamId id) override;
+ QuicDataStream* CreateIncomingDynamicStream(QuicStreamId id) override;
private:
friend class test::QuicClientSessionPeer;
@@ -250,7 +261,6 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase,
TransportSecurityState* transport_security_state_;
scoped_ptr<QuicServerInfo> server_info_;
scoped_ptr<CertVerifyResult> cert_verify_result_;
- int cert_verify_flags_;
std::string pinning_failure_log_;
ObserverSet observers_;
StreamRequestQueue stream_requests_;
@@ -265,6 +275,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase,
// True when the session is going away, and streams may no longer be created
// on this session. Existing stream will continue to be processed.
bool going_away_;
+ QuicDisabledReason disabled_reason_;
base::WeakPtrFactory<QuicClientSession> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(QuicClientSession);
diff --git a/chromium/net/quic/quic_client_session_base.cc b/chromium/net/quic/quic_client_session_base.cc
index 40d4b86dc2c..12173e51019 100644
--- a/chromium/net/quic/quic_client_session_base.cc
+++ b/chromium/net/quic/quic_client_session_base.cc
@@ -8,10 +8,10 @@
namespace net {
-QuicClientSessionBase::QuicClientSessionBase(
- QuicConnection* connection,
- const QuicConfig& config)
- : QuicSession(connection, config) {}
+QuicClientSessionBase::QuicClientSessionBase(QuicConnection* connection,
+ const QuicConfig& config)
+ : QuicSpdySession(connection, config) {
+}
QuicClientSessionBase::~QuicClientSessionBase() {}
@@ -27,7 +27,7 @@ void QuicClientSessionBase::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
}
// kFHDR config maps to FEC protection always for headers stream.
// TODO(jri): Add crypto stream in addition to headers for kHDR.
- headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
+ headers_stream()->set_fec_policy(FEC_PROTECT_ALWAYS);
}
} // namespace net
diff --git a/chromium/net/quic/quic_client_session_base.h b/chromium/net/quic/quic_client_session_base.h
index d72996c4118..0e3c0fa3ff3 100644
--- a/chromium/net/quic/quic_client_session_base.h
+++ b/chromium/net/quic/quic_client_session_base.h
@@ -6,12 +6,12 @@
#define NET_QUIC_QUIC_CLIENT_SESSION_BASE_H_
#include "net/quic/quic_crypto_client_stream.h"
-#include "net/quic/quic_session.h"
+#include "net/quic/quic_spdy_session.h"
namespace net {
// Base class for all client-specific QuicSession subclasses.
-class NET_EXPORT_PRIVATE QuicClientSessionBase : public QuicSession {
+class NET_EXPORT_PRIVATE QuicClientSessionBase : public QuicSpdySession {
public:
QuicClientSessionBase(QuicConnection* connection,
const QuicConfig& config);
diff --git a/chromium/net/quic/quic_client_session_test.cc b/chromium/net/quic/quic_client_session_test.cc
index 1d9f0218a77..921e7a6dbcc 100644
--- a/chromium/net/quic/quic_client_session_test.cc
+++ b/chromium/net/quic/quic_client_session_test.cc
@@ -9,6 +9,7 @@
#include "base/base64.h"
#include "base/files/file_path.h"
#include "base/rand_util.h"
+#include "base/thread_task_runner_handle.h"
#include "net/base/test_completion_callback.h"
#include "net/base/test_data_directory.h"
#include "net/cert/cert_verify_result.h"
@@ -22,6 +23,7 @@
#include "net/quic/crypto/quic_server_info.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_client_session_peer.h"
+#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/simple_quic_framer.h"
#include "net/socket/socket_test_util.h"
@@ -45,19 +47,22 @@ class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> {
SupportedVersions(GetParam()))),
session_(connection_,
GetSocket().Pass(),
- nullptr,
+ /*stream_factory=*/nullptr,
+ /*crypto_client_stream_factory=*/nullptr,
&transport_security_state_,
make_scoped_ptr((QuicServerInfo*)nullptr),
+ QuicServerId(kServerHostname,
+ kServerPort,
+ /*is_secure=*/false,
+ PRIVACY_MODE_DISABLED),
/*cert_verify_flags=*/0,
DefaultQuicConfig(),
+ &crypto_config_,
"CONNECTION_UNKNOWN",
base::TimeTicks::Now(),
- base::MessageLoop::current()->message_loop_proxy().get(),
+ base::ThreadTaskRunnerHandle::Get().get(),
&net_log_) {
- session_.InitializeSession(QuicServerId(kServerHostname, kServerPort,
- /*is_secure=*/false,
- PRIVACY_MODE_DISABLED),
- &crypto_config_, nullptr);
+ session_.Initialize();
// Advance the time, because timers do not like uninitialized times.
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
}
@@ -106,15 +111,15 @@ TEST_P(QuicClientSessionTest, MaxNumStreams) {
std::vector<QuicReliableClientStream*> streams;
for (size_t i = 0; i < kDefaultMaxStreamsPerConnection; i++) {
- QuicReliableClientStream* stream = session_.CreateOutgoingDataStream();
+ QuicReliableClientStream* stream = session_.CreateOutgoingDynamicStream();
EXPECT_TRUE(stream);
streams.push_back(stream);
}
- EXPECT_FALSE(session_.CreateOutgoingDataStream());
+ EXPECT_FALSE(session_.CreateOutgoingDynamicStream());
// Close a stream and ensure I can now open a new one.
session_.CloseStream(streams[0]->id());
- EXPECT_TRUE(session_.CreateOutgoingDataStream());
+ EXPECT_TRUE(session_.CreateOutgoingDynamicStream());
}
TEST_P(QuicClientSessionTest, MaxNumStreamsViaRequest) {
@@ -122,7 +127,7 @@ TEST_P(QuicClientSessionTest, MaxNumStreamsViaRequest) {
std::vector<QuicReliableClientStream*> streams;
for (size_t i = 0; i < kDefaultMaxStreamsPerConnection; i++) {
- QuicReliableClientStream* stream = session_.CreateOutgoingDataStream();
+ QuicReliableClientStream* stream = session_.CreateOutgoingDynamicStream();
EXPECT_TRUE(stream);
streams.push_back(stream);
}
@@ -147,7 +152,7 @@ TEST_P(QuicClientSessionTest, GoAwayReceived) {
// After receiving a GoAway, I should no longer be able to create outgoing
// streams.
session_.OnGoAway(QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away."));
- EXPECT_EQ(nullptr, session_.CreateOutgoingDataStream());
+ EXPECT_EQ(nullptr, session_.CreateOutgoingDynamicStream());
}
TEST_P(QuicClientSessionTest, CanPool) {
diff --git a/chromium/net/quic/quic_config.cc b/chromium/net/quic/quic_config.cc
index 30db003ba4d..675716c2ca5 100644
--- a/chromium/net/quic/quic_config.cc
+++ b/chromium/net/quic/quic_config.cc
@@ -45,7 +45,6 @@ QuicErrorCode ReadUint32(const CryptoHandshakeMessage& msg,
return error;
}
-
QuicConfigValue::QuicConfigValue(QuicTag tag,
QuicConfigPresence presence)
: tag_(tag),
@@ -388,6 +387,20 @@ QuicTagVector QuicConfig::SendConnectionOptions() const {
return connection_options_.GetSendValues();
}
+bool QuicConfig::HasClientSentConnectionOption(QuicTag tag,
+ Perspective perspective) const {
+ if (perspective == Perspective::IS_SERVER) {
+ if (HasReceivedConnectionOptions() &&
+ ContainsQuicTag(ReceivedConnectionOptions(), tag)) {
+ return true;
+ }
+ } else if (HasSendConnectionOptions() &&
+ ContainsQuicTag(SendConnectionOptions(), tag)) {
+ return true;
+ }
+ return false;
+}
+
void QuicConfig::SetIdleConnectionStateLifetime(
QuicTime::Delta max_idle_connection_state_lifetime,
QuicTime::Delta default_idle_conection_state_lifetime) {
diff --git a/chromium/net/quic/quic_config.h b/chromium/net/quic/quic_config.h
index 34ea5930c8b..20d71c60a26 100644
--- a/chromium/net/quic/quic_config.h
+++ b/chromium/net/quic/quic_config.h
@@ -229,6 +229,11 @@ class NET_EXPORT_PRIVATE QuicConfig {
QuicTagVector SendConnectionOptions() const;
+ // Returns true if the client is sending or the server has received a
+ // connection option.
+ bool HasClientSentConnectionOption(QuicTag tag,
+ Perspective perspective) const;
+
void SetIdleConnectionStateLifetime(
QuicTime::Delta max_idle_connection_state_lifetime,
QuicTime::Delta default_idle_conection_state_lifetime);
diff --git a/chromium/net/quic/quic_config_test.cc b/chromium/net/quic/quic_config_test.cc
index 4cd3820a7db..dcf19a58057 100644
--- a/chromium/net/quic/quic_config_test.cc
+++ b/chromium/net/quic/quic_config_test.cc
@@ -217,6 +217,34 @@ TEST_F(QuicConfigTest, InvalidFlowControlWindow) {
config.GetInitialStreamFlowControlWindowToSend());
}
+TEST_F(QuicConfigTest, HasClientSentConnectionOption) {
+ QuicConfig client_config;
+ QuicTagVector copt;
+ copt.push_back(kTBBR);
+ copt.push_back(kFHDR);
+ client_config.SetConnectionOptionsToSend(copt);
+ EXPECT_TRUE(client_config.HasClientSentConnectionOption(
+ kTBBR, Perspective::IS_CLIENT));
+ EXPECT_TRUE(client_config.HasClientSentConnectionOption(
+ kFHDR, Perspective::IS_CLIENT));
+
+ CryptoHandshakeMessage msg;
+ client_config.ToHandshakeMessage(&msg);
+
+ string error_details;
+ const QuicErrorCode error =
+ config_.ProcessPeerHello(msg, CLIENT, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_TRUE(config_.negotiated());
+
+ EXPECT_TRUE(config_.HasReceivedConnectionOptions());
+ EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size());
+ EXPECT_TRUE(
+ config_.HasClientSentConnectionOption(kTBBR, Perspective::IS_SERVER));
+ EXPECT_TRUE(
+ config_.HasClientSentConnectionOption(kFHDR, Perspective::IS_SERVER));
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/quic_connection.cc b/chromium/net/quic/quic_connection.cc
index 73f43127873..3db39c3aef8 100644
--- a/chromium/net/quic/quic_connection.cc
+++ b/chromium/net/quic/quic_connection.cc
@@ -17,13 +17,14 @@
#include "base/debug/stack_trace.h"
#include "base/format_macros.h"
#include "base/logging.h"
+#include "base/memory/ref_counted.h"
#include "base/profiler/scoped_tracker.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "net/base/net_errors.h"
+#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/iovector.h"
#include "net/quic/proto/cached_network_parameters.pb.h"
#include "net/quic/quic_bandwidth.h"
#include "net/quic/quic_config.h"
@@ -63,9 +64,6 @@ const size_t kMaxFecGroups = 2;
// Maximum number of acks received before sending an ack in response.
const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20;
-// Maximum number of tracked packets.
-const QuicPacketCount kMaxTrackedPackets = 15 * kMaxTcpCongestionWindow;
-
bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) {
QuicPacketSequenceNumber delta = (a > b) ? a - b : b - a;
return delta <= kMaxPacketGap;
@@ -164,6 +162,23 @@ class PingAlarm : public QuicAlarm::Delegate {
DISALLOW_COPY_AND_ASSIGN(PingAlarm);
};
+class MtuDiscoveryAlarm : public QuicAlarm::Delegate {
+ public:
+ explicit MtuDiscoveryAlarm(QuicConnection* connection)
+ : connection_(connection) {}
+
+ QuicTime OnAlarm() override {
+ connection_->DiscoverMtu();
+ // DiscoverMtu() handles rescheduling the alarm by itself.
+ return QuicTime::Zero();
+ }
+
+ private:
+ QuicConnection* connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(MtuDiscoveryAlarm);
+};
+
// This alarm may be scheduled when an FEC protected packet is sent out.
class FecAlarm : public QuicAlarm::Delegate {
public:
@@ -181,6 +196,33 @@ class FecAlarm : public QuicAlarm::Delegate {
DISALLOW_COPY_AND_ASSIGN(FecAlarm);
};
+// Listens for acks of MTU discovery packets and raises the maximum packet size
+// of the connection if the probe succeeds.
+class MtuDiscoveryAckListener : public QuicAckNotifier::DelegateInterface {
+ public:
+ MtuDiscoveryAckListener(QuicConnection* connection, QuicByteCount probe_size)
+ : connection_(connection), probe_size_(probe_size) {}
+
+ void OnAckNotification(int /*num_retransmittable_packets*/,
+ int /*num_retransmittable_bytes*/,
+ QuicTime::Delta /*delta_largest_observed*/) override {
+ // Since the probe was successful, increase the maximum packet size to that.
+ if (probe_size_ > connection_->max_packet_length()) {
+ connection_->set_max_packet_length(probe_size_);
+ }
+ }
+
+ protected:
+ // MtuDiscoveryAckListener is ref counted.
+ ~MtuDiscoveryAckListener() override {}
+
+ private:
+ QuicConnection* connection_;
+ QuicByteCount probe_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(MtuDiscoveryAckListener);
+};
+
} // namespace
QuicConnection::QueuedPacket::QueuedPacket(SerializedPacket packet,
@@ -240,12 +282,15 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
ack_queued_(false),
num_packets_received_since_last_ack_sent_(0),
stop_waiting_count_(0),
+ delay_setting_retransmission_alarm_(false),
+ pending_retransmission_alarm_(false),
ack_alarm_(helper->CreateAlarm(new AckAlarm(this))),
retransmission_alarm_(helper->CreateAlarm(new RetransmissionAlarm(this))),
send_alarm_(helper->CreateAlarm(new SendAlarm(this))),
resume_writes_alarm_(helper->CreateAlarm(new SendAlarm(this))),
timeout_alarm_(helper->CreateAlarm(new TimeoutAlarm(this))),
ping_alarm_(helper->CreateAlarm(new PingAlarm(this))),
+ mtu_discovery_alarm_(helper->CreateAlarm(new MtuDiscoveryAlarm(this))),
visitor_(nullptr),
debug_visitor_(nullptr),
packet_generator_(connection_id_, &framer_, random_generator_, this),
@@ -270,7 +315,12 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
self_ip_changed_(false),
self_port_changed_(false),
can_truncate_connection_ids_(true),
- is_secure_(is_secure) {
+ is_secure_(is_secure),
+ mtu_discovery_target_(0),
+ mtu_probe_count_(0),
+ packets_between_mtu_probes_(kPacketsBetweenMtuProbesBase),
+ next_mtu_probe_at_(kPacketsBetweenMtuProbesBase),
+ largest_received_packet_size_(0) {
DVLOG(1) << ENDPOINT << "Created connection with connection_id: "
<< connection_id;
framer_.set_visitor(this);
@@ -314,6 +364,18 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
config.ReceivedBytesForConnectionId());
}
max_undecryptable_packets_ = config.max_undecryptable_packets();
+
+ if (FLAGS_quic_send_fec_packet_only_on_fec_alarm &&
+ config.HasClientSentConnectionOption(kFSPA, perspective_)) {
+ packet_generator_.set_fec_send_policy(FecSendPolicy::FEC_ALARM_TRIGGER);
+ }
+
+ if (config.HasClientSentConnectionOption(kMTUH, perspective_)) {
+ mtu_discovery_target_ = kMtuDiscoveryTargetPacketSizeHigh;
+ }
+ if (config.HasClientSentConnectionOption(kMTUL, perspective_)) {
+ mtu_discovery_target_ = kMtuDiscoveryTargetPacketSizeLow;
+ }
}
void QuicConnection::OnSendConnectionState(
@@ -671,15 +733,10 @@ void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) {
time_of_last_received_packet_);
sent_entropy_manager_.ClearEntropyBefore(
sent_packet_manager_.least_packet_awaited_by_peer() - 1);
- if (sent_packet_manager_.HasPendingRetransmissions()) {
- WriteIfNotBlocked();
- }
// Always reset the retransmission alarm when an ack comes in, since we now
// have a better estimate of the current rtt than when it was set.
- QuicTime retransmission_time = sent_packet_manager_.GetRetransmissionTime();
- retransmission_alarm_->Update(retransmission_time,
- QuicTime::Delta::FromMilliseconds(1));
+ SetRetransmissionAlarm();
}
void QuicConnection::ProcessStopWaitingFrame(
@@ -876,16 +933,16 @@ void QuicConnection::OnPacketComplete() {
}
DVLOG(1) << ENDPOINT << (last_packet_revived_ ? "Revived" : "Got")
- << " packet " << last_header_.packet_sequence_number
- << " with " << last_stream_frames_.size()<< " stream frames "
- << last_ack_frames_.size() << " acks, "
- << last_stop_waiting_frames_.size() << " stop_waiting, "
- << last_rst_frames_.size() << " rsts, "
- << last_goaway_frames_.size() << " goaways, "
- << last_window_update_frames_.size() << " window updates, "
- << last_blocked_frames_.size() << " blocked, "
- << last_ping_frames_.size() << " pings, "
- << last_close_frames_.size() << " closes, "
+ << " packet " << last_header_.packet_sequence_number << " with " //
+ << last_stream_frames_.size() << " stream frames, " //
+ << last_ack_frames_.size() << " acks, " //
+ << last_stop_waiting_frames_.size() << " stop_waiting, " //
+ << last_rst_frames_.size() << " rsts, " //
+ << last_goaway_frames_.size() << " goaways, " //
+ << last_window_update_frames_.size() << " window updates, " //
+ << last_blocked_frames_.size() << " blocked, " //
+ << last_ping_frames_.size() << " pings, " //
+ << last_close_frames_.size() << " closes " //
<< "for " << last_header_.public_header.connection_id;
++num_packets_received_since_last_ack_sent_;
@@ -907,63 +964,61 @@ void QuicConnection::OnPacketComplete() {
if (!last_stream_frames_.empty()) {
visitor_->OnStreamFrames(last_stream_frames_);
- if (!connected_ && !FLAGS_quic_stop_early) {
+ if (!connected_) {
return;
}
}
- for (size_t i = 0; i < last_stream_frames_.size(); ++i) {
- stats_.stream_bytes_received +=
- last_stream_frames_[i].data.TotalBufferSize();
+ for (const QuicStreamFrame& stream_frame : last_stream_frames_) {
+ stats_.stream_bytes_received += stream_frame.data.size();
}
// Process window updates, blocked, stream resets, acks, then congestion
// feedback.
if (!last_window_update_frames_.empty()) {
visitor_->OnWindowUpdateFrames(last_window_update_frames_);
- if (!connected_ && !FLAGS_quic_stop_early) {
+ if (!connected_) {
return;
}
}
if (!last_blocked_frames_.empty()) {
visitor_->OnBlockedFrames(last_blocked_frames_);
- if (!connected_ && !FLAGS_quic_stop_early) {
+ if (!connected_) {
return;
}
}
for (size_t i = 0; i < last_goaway_frames_.size(); ++i) {
visitor_->OnGoAway(last_goaway_frames_[i]);
- if (!connected_ && !FLAGS_quic_stop_early) {
+ if (!connected_) {
return;
}
}
for (size_t i = 0; i < last_rst_frames_.size(); ++i) {
visitor_->OnRstStream(last_rst_frames_[i]);
- if (!connected_ && !FLAGS_quic_stop_early) {
+ if (!connected_) {
return;
}
}
for (size_t i = 0; i < last_ack_frames_.size(); ++i) {
ProcessAckFrame(last_ack_frames_[i]);
- if (!connected_ && !FLAGS_quic_stop_early) {
+ if (!connected_) {
return;
}
}
for (size_t i = 0; i < last_stop_waiting_frames_.size(); ++i) {
ProcessStopWaitingFrame(last_stop_waiting_frames_[i]);
- if (!connected_ && !FLAGS_quic_stop_early) {
+ if (!connected_) {
return;
}
}
if (!last_close_frames_.empty()) {
CloseConnection(last_close_frames_[0].error_code, true);
DCHECK(!connected_);
- if (!FLAGS_quic_stop_early) {
- return;
- }
+ return;
}
// If there are new missing packets to report, send an ack immediately.
- if (received_packet_manager_.HasNewMissingPackets()) {
+ if ((!FLAGS_quic_dont_ack_acks || ShouldLastPacketInstigateAck()) &&
+ received_packet_manager_.HasNewMissingPackets()) {
ack_queued_ = true;
ack_alarm_->Cancel();
}
@@ -974,11 +1029,15 @@ void QuicConnection::OnPacketComplete() {
}
void QuicConnection::MaybeQueueAck() {
+ // If the last packet is an ack, don't ack it.
+ if (!ShouldLastPacketInstigateAck()) {
+ return;
+ }
// If the incoming packet was missing, send an ack immediately.
ack_queued_ = received_packet_manager_.IsMissing(
last_header_.packet_sequence_number);
- if (!ack_queued_ && ShouldLastPacketInstigateAck()) {
+ if (!ack_queued_) {
if (ack_alarm_->IsSet()) {
ack_queued_ = true;
} else {
@@ -1084,9 +1143,7 @@ void QuicConnection::MaybeSendInResponseToPacket() {
// Now that we have received an ack, we might be able to send packets which
// are queued locally, or drain streams which are blocked.
- if (CanWrite(HAS_RETRANSMITTABLE_DATA)) {
- OnCanWrite();
- }
+ WriteIfNotBlocked();
}
void QuicConnection::SendVersionNegotiationPacket() {
@@ -1123,12 +1180,12 @@ void QuicConnection::SendVersionNegotiationPacket() {
QuicConsumedData QuicConnection::SendStreamData(
QuicStreamId id,
- const IOVector& data,
+ const QuicIOVector& iov,
QuicStreamOffset offset,
bool fin,
FecProtection fec_protection,
QuicAckNotifier::DelegateInterface* delegate) {
- if (!fin && data.Empty()) {
+ if (!fin && iov.total_length == 0) {
LOG(DFATAL) << "Attempt to send empty stream frame";
return QuicConsumedData(0, false);
}
@@ -1146,8 +1203,9 @@ QuicConsumedData QuicConnection::SendStreamData(
// right thing: check ack_queued_, and then check undecryptable packets and
// also if there is possibility of revival. Only bundle an ack if there's no
// processing left that may cause received_info_ to change.
+ ScopedRetransmissionScheduler alarm_delayer(this);
ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
- return packet_generator_.ConsumeData(id, data, offset, fin, fec_protection,
+ return packet_generator_.ConsumeData(id, iov, offset, fin, fec_protection,
delegate);
}
@@ -1215,7 +1273,8 @@ const QuicConnectionStats& QuicConnection::GetStats() {
stats_.srtt_us = srtt.ToMicroseconds();
stats_.estimated_bandwidth = sent_packet_manager_.BandwidthEstimate();
- stats_.max_packet_size = packet_generator_.max_packet_length();
+ stats_.max_packet_size = packet_generator_.GetMaxPacketLength();
+ stats_.max_received_packet_size = largest_received_packet_size_;
return stats_;
}
@@ -1239,6 +1298,7 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
stats_.bytes_received += packet.length();
++stats_.packets_received;
+ ScopedRetransmissionScheduler alarm_delayer(this);
if (!framer_.ProcessPacket(packet)) {
// If we are unable to decrypt this packet, it might be
// because the CHLO or SHLO packet was lost.
@@ -1347,9 +1407,13 @@ bool QuicConnection::ProcessValidatedPacket() {
DVLOG(1) << ENDPOINT << "time of last received packet: "
<< time_of_last_received_packet_.ToDebuggingValue();
+ if (last_size_ > largest_received_packet_size_) {
+ largest_received_packet_size_ = last_size_;
+ }
+
if (perspective_ == Perspective::IS_SERVER &&
encryption_level_ == ENCRYPTION_NONE &&
- last_size_ > packet_generator_.max_packet_length()) {
+ last_size_ > packet_generator_.GetMaxPacketLength()) {
set_max_packet_length(last_size_);
}
return true;
@@ -1418,9 +1482,7 @@ void QuicConnection::RetransmitUnackedPackets(
void QuicConnection::NeuterUnencryptedPackets() {
sent_packet_manager_.NeuterUnencryptedPackets();
// This may have changed the retransmission timer, so re-arm it.
- QuicTime retransmission_time = sent_packet_manager_.GetRetransmissionTime();
- retransmission_alarm_->Update(retransmission_time,
- QuicTime::Delta::FromMilliseconds(1));
+ SetRetransmissionAlarm();
}
bool QuicConnection::ShouldGeneratePacket(
@@ -1509,7 +1571,7 @@ bool QuicConnection::WritePacketInner(QueuedPacket* packet) {
if (!FLAGS_quic_allow_oversized_packets_for_test) {
DCHECK_LE(encrypted->length(), kMaxPacketSize);
}
- DCHECK_LE(encrypted->length(), packet_generator_.max_packet_length());
+ DCHECK_LE(encrypted->length(), packet_generator_.GetMaxPacketLength());
DVLOG(1) << ENDPOINT << "Sending packet " << sequence_number << " : "
<< (packet->serialized_packet.is_fec_packet
? "FEC "
@@ -1557,6 +1619,7 @@ bool QuicConnection::WritePacketInner(QueuedPacket* packet) {
}
SetPingAlarm();
MaybeSetFecAlarm(sequence_number);
+ MaybeSetMtuAlarm();
DVLOG(1) << ENDPOINT << "time we began writing last sent packet: "
<< packet_send_time.ToDebuggingValue();
@@ -1576,8 +1639,7 @@ bool QuicConnection::WritePacketInner(QueuedPacket* packet) {
IsRetransmittable(*packet));
if (reset_retransmission_alarm || !retransmission_alarm_->IsSet()) {
- retransmission_alarm_->Update(sent_packet_manager_.GetRetransmissionTime(),
- QuicTime::Delta::FromMilliseconds(1));
+ SetRetransmissionAlarm();
}
stats_.bytes_sent += result.bytes_written;
@@ -1646,9 +1708,7 @@ void QuicConnection::OnSerializedPacket(
CloseConnection(QUIC_ENCRYPTION_FAILURE, false);
return;
}
- if (serialized_packet.retransmittable_frames) {
- sent_packet_manager_.OnSerializedPacket(serialized_packet);
- }
+ sent_packet_manager_.OnSerializedPacket(serialized_packet);
if (serialized_packet.is_fec_packet && fec_alarm_->IsSet()) {
// If an FEC packet is serialized with the FEC alarm set, cancel the alarm.
fec_alarm_->Cancel();
@@ -1656,6 +1716,14 @@ void QuicConnection::OnSerializedPacket(
SendOrQueuePacket(QueuedPacket(serialized_packet, encryption_level_));
}
+void QuicConnection::OnResetFecGroup() {
+ if (!fec_alarm_->IsSet()) {
+ return;
+ }
+ // If an FEC Group is closed with the FEC alarm set, cancel the alarm.
+ fec_alarm_->Cancel();
+}
+
void QuicConnection::OnCongestionWindowChange() {
packet_generator_.OnCongestionWindowChange(
sent_packet_manager_.EstimateMaxPacketsInFlight(max_packet_length()));
@@ -1724,6 +1792,7 @@ void QuicConnection::SendPing() {
void QuicConnection::SendAck() {
ack_alarm_->Cancel();
+ ack_queued_ = false;
stop_waiting_count_ = 0;
num_packets_received_since_last_ack_sent_ = 0;
@@ -1753,11 +1822,10 @@ void QuicConnection::OnRetransmissionTimeout() {
// Ensure the retransmission alarm is always set if there are unacked packets
// and nothing waiting to be sent.
+ // This happens if the loss algorithm invokes a timer based loss, but the
+ // packet doesn't need to be retransmitted.
if (!HasQueuedData() && !retransmission_alarm_->IsSet()) {
- QuicTime rto_timeout = sent_packet_manager_.GetRetransmissionTime();
- if (rto_timeout.IsInitialized()) {
- retransmission_alarm_->Set(rto_timeout);
- }
+ SetRetransmissionAlarm();
}
}
@@ -1781,15 +1849,15 @@ void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) {
packet_generator_.set_encryption_level(level);
}
-void QuicConnection::SetDecrypter(QuicDecrypter* decrypter,
- EncryptionLevel level) {
- framer_.SetDecrypter(decrypter, level);
+void QuicConnection::SetDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter) {
+ framer_.SetDecrypter(level, decrypter);
}
-void QuicConnection::SetAlternativeDecrypter(QuicDecrypter* decrypter,
- EncryptionLevel level,
+void QuicConnection::SetAlternativeDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter,
bool latch_once_used) {
- framer_.SetAlternativeDecrypter(decrypter, level, latch_once_used);
+ framer_.SetAlternativeDecrypter(level, decrypter, latch_once_used);
}
const QuicDecrypter* QuicConnection::decrypter() const {
@@ -1947,6 +2015,7 @@ void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) {
retransmission_alarm_->Cancel();
send_alarm_->Cancel();
timeout_alarm_->Cancel();
+ mtu_discovery_alarm_->Cancel();
}
void QuicConnection::SendGoAway(QuicErrorCode error,
@@ -1984,11 +2053,11 @@ void QuicConnection::CloseFecGroupsBefore(
}
QuicByteCount QuicConnection::max_packet_length() const {
- return packet_generator_.max_packet_length();
+ return packet_generator_.GetMaxPacketLength();
}
void QuicConnection::set_max_packet_length(QuicByteCount length) {
- return packet_generator_.set_max_packet_length(length);
+ return packet_generator_.SetMaxPacketLength(length, /*force=*/false);
}
bool QuicConnection::HasQueuedData() const {
@@ -2088,7 +2157,7 @@ void QuicConnection::SetPingAlarm() {
// Only clients send pings.
return;
}
- if (!visitor_->HasOpenDataStreams()) {
+ if (!visitor_->HasOpenDynamicStreams()) {
ping_alarm_->Cancel();
// Don't send a ping unless there are open streams.
return;
@@ -2098,6 +2167,43 @@ void QuicConnection::SetPingAlarm() {
QuicTime::Delta::FromSeconds(1));
}
+void QuicConnection::SetRetransmissionAlarm() {
+ if (delay_setting_retransmission_alarm_) {
+ pending_retransmission_alarm_ = true;
+ return;
+ }
+ QuicTime retransmission_time = sent_packet_manager_.GetRetransmissionTime();
+ retransmission_alarm_->Update(retransmission_time,
+ QuicTime::Delta::FromMilliseconds(1));
+}
+
+void QuicConnection::MaybeSetMtuAlarm() {
+ if (!FLAGS_quic_do_path_mtu_discovery) {
+ return;
+ }
+
+ // Do not set the alarm if the target size is less than the current size.
+ // This covers the case when |mtu_discovery_target_| is at its default value,
+ // zero.
+ if (mtu_discovery_target_ <= max_packet_length()) {
+ return;
+ }
+
+ if (mtu_probe_count_ >= kMtuDiscoveryAttempts) {
+ return;
+ }
+
+ if (mtu_discovery_alarm_->IsSet()) {
+ return;
+ }
+
+ if (sequence_number_of_last_sent_packet_ >= next_mtu_probe_at_) {
+ // Use an alarm to send the MTU probe to ensure that no ScopedPacketBundlers
+ // are active.
+ mtu_discovery_alarm_->Set(clock_->ApproximateNow());
+ }
+}
+
QuicConnection::ScopedPacketBundler::ScopedPacketBundler(
QuicConnection* connection,
AckBundling send_ack)
@@ -2136,6 +2242,28 @@ QuicConnection::ScopedPacketBundler::~ScopedPacketBundler() {
connection_->packet_generator_.InBatchMode());
}
+QuicConnection::ScopedRetransmissionScheduler::ScopedRetransmissionScheduler(
+ QuicConnection* connection)
+ : connection_(connection),
+ already_delayed_(connection_->delay_setting_retransmission_alarm_) {
+ if (FLAGS_quic_delay_retransmission_alarm) {
+ return;
+ }
+ connection_->delay_setting_retransmission_alarm_ = true;
+}
+
+QuicConnection::ScopedRetransmissionScheduler::
+ ~ScopedRetransmissionScheduler() {
+ if (FLAGS_quic_delay_retransmission_alarm || already_delayed_) {
+ return;
+ }
+ connection_->delay_setting_retransmission_alarm_ = false;
+ if (connection_->pending_retransmission_alarm_) {
+ connection_->SetRetransmissionAlarm();
+ connection_->pending_retransmission_alarm_ = false;
+ }
+}
+
HasRetransmittableData QuicConnection::IsRetransmittable(
const QueuedPacket& packet) {
// Retransmitted packets retransmittable frames are owned by the unacked
@@ -2162,4 +2290,40 @@ bool QuicConnection::IsConnectionClose(const QueuedPacket& packet) {
return false;
}
+void QuicConnection::SendMtuDiscoveryPacket(QuicByteCount target_mtu) {
+ // Create a listener for the new probe. The ownership of the listener is
+ // transferred to the AckNotifierManager. The notifier will get destroyed
+ // before the connection (because it's stored in one of the connection's
+ // subfields), hence |this| pointer is guaranteed to stay valid at all times.
+ scoped_refptr<MtuDiscoveryAckListener> last_mtu_discovery_ack_listener(
+ new MtuDiscoveryAckListener(this, target_mtu));
+
+ // Send the probe.
+ packet_generator_.GenerateMtuDiscoveryPacket(
+ target_mtu, last_mtu_discovery_ack_listener.get());
+}
+
+void QuicConnection::DiscoverMtu() {
+ DCHECK(!mtu_discovery_alarm_->IsSet());
+
+ // Chcek if the MTU has been already increased.
+ if (mtu_discovery_target_ <= max_packet_length()) {
+ return;
+ }
+
+ // Schedule the next probe *before* sending the current one. This is
+ // important, otherwise, when SendMtuDiscoveryPacket() is called,
+ // MaybeSetMtuAlarm() will not realize that the probe has been just sent, and
+ // will reschedule this probe again.
+ packets_between_mtu_probes_ *= 2;
+ next_mtu_probe_at_ =
+ sequence_number_of_last_sent_packet_ + packets_between_mtu_probes_ + 1;
+ ++mtu_probe_count_;
+
+ DVLOG(2) << "Sending a path MTU discovery packet #" << mtu_probe_count_;
+ SendMtuDiscoveryPacket(mtu_discovery_target_);
+
+ DCHECK(!mtu_discovery_alarm_->IsSet());
+}
+
} // namespace net
diff --git a/chromium/net/quic/quic_connection.h b/chromium/net/quic/quic_connection.h
index d47b8dc9a72..b38504322d9 100644
--- a/chromium/net/quic/quic_connection.h
+++ b/chromium/net/quic/quic_connection.h
@@ -29,7 +29,6 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_piece.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/iovector.h"
#include "net/quic/quic_ack_notifier.h"
#include "net/quic/quic_ack_notifier_manager.h"
#include "net/quic/quic_alarm.h"
@@ -60,6 +59,35 @@ class PacketSavingConnection;
class QuicConnectionPeer;
} // namespace test
+// The initial number of packets between MTU probes. After each attempt the
+// number is doubled.
+const QuicPacketCount kPacketsBetweenMtuProbesBase = 100;
+
+// The number of MTU probes that get sent before giving up.
+const size_t kMtuDiscoveryAttempts = 3;
+
+// Ensure that exponential back-off does not result in an integer overflow.
+// The number of packets can be potentially capped, but that is not useful at
+// current kMtuDiscoveryAttempts value, and hence is not implemented at present.
+static_assert(kMtuDiscoveryAttempts + 8 < 8 * sizeof(QuicPacketSequenceNumber),
+ "The number of MTU discovery attempts is too high");
+static_assert(kPacketsBetweenMtuProbesBase < (1 << 8),
+ "The initial number of packets between MTU probes is too high");
+
+// The incresed packet size targeted when doing path MTU discovery.
+const QuicByteCount kMtuDiscoveryTargetPacketSizeHigh = 1450;
+const QuicByteCount kMtuDiscoveryTargetPacketSizeLow = 1430;
+
+static_assert(kMtuDiscoveryTargetPacketSizeLow <= kMaxPacketSize,
+ "MTU discovery target is too large");
+static_assert(kMtuDiscoveryTargetPacketSizeHigh <= kMaxPacketSize,
+ "MTU discovery target is too large");
+
+static_assert(kMtuDiscoveryTargetPacketSizeLow > kDefaultMaxPacketSize,
+ "MTU discovery target does not exceed the default packet size");
+static_assert(kMtuDiscoveryTargetPacketSizeHigh > kDefaultMaxPacketSize,
+ "MTU discovery target does not exceed the default packet size");
+
// Class that receives callbacks from the connection when frames are received
// and when other interesting events happen.
class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface {
@@ -113,7 +141,7 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// Called to ask if any streams are open in this visitor, excluding the
// reserved crypto and headers stream.
- virtual bool HasOpenDataStreams() const = 0;
+ virtual bool HasOpenDynamicStreams() const = 0;
};
// Interface which gets callbacks from the QuicConnection at interesting
@@ -289,7 +317,7 @@ class NET_EXPORT_PRIVATE QuicConnection
// received for all the packets written in this call.
// The |delegate| is not owned by the QuicConnection and must outlive it.
QuicConsumedData SendStreamData(QuicStreamId id,
- const IOVector& data,
+ const QuicIOVector& iov,
QuicStreamOffset offset,
bool fin,
FecProtection fec_protection,
@@ -388,6 +416,7 @@ class NET_EXPORT_PRIVATE QuicConnection
void PopulateAckFrame(QuicAckFrame* ack) override;
void PopulateStopWaitingFrame(QuicStopWaitingFrame* stop_waiting) override;
void OnSerializedPacket(const SerializedPacket& packet) override;
+ void OnResetFecGroup() override;
// QuicSentPacketManager::NetworkChangeVisitor
void OnCongestionWindowChange() override;
@@ -414,6 +443,7 @@ class NET_EXPORT_PRIVATE QuicConnection
QuicRandom* random_generator() const { return random_generator_; }
QuicByteCount max_packet_length() const;
void set_max_packet_length(QuicByteCount length);
+ size_t mtu_probe_count() const { return mtu_probe_count_; }
bool connected() const { return connected_; }
@@ -486,7 +516,7 @@ class NET_EXPORT_PRIVATE QuicConnection
// function DCHECKs. This is intended for cases where one knows that future
// packets will be using the new decrypter and the previous decrypter is now
// obsolete. |level| indicates the encryption level of the new decrypter.
- void SetDecrypter(QuicDecrypter* decrypter, EncryptionLevel level);
+ void SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter);
// SetAlternativeDecrypter sets a decrypter that may be used to decrypt
// future packets and takes ownership of it. |level| indicates the encryption
@@ -494,8 +524,8 @@ class NET_EXPORT_PRIVATE QuicConnection
// that the decrypter is successful it will replace the primary decrypter.
// Otherwise both decrypters will remain active and the primary decrypter
// will be the one last used.
- void SetAlternativeDecrypter(QuicDecrypter* decrypter,
- EncryptionLevel level,
+ void SetAlternativeDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter,
bool latch_once_used);
const QuicDecrypter* decrypter() const;
@@ -535,13 +565,39 @@ class NET_EXPORT_PRIVATE QuicConnection
bool already_in_batch_mode_;
};
+ // Delays setting the retransmission alarm until the scope is exited.
+ // When nested, only the outermost scheduler will set the alarm, and inner
+ // ones have no effect.
+ class NET_EXPORT_PRIVATE ScopedRetransmissionScheduler {
+ public:
+ explicit ScopedRetransmissionScheduler(QuicConnection* connection);
+ ~ScopedRetransmissionScheduler();
+
+ private:
+ QuicConnection* connection_;
+ // Set to the connection's delay_setting_retransmission_alarm_ value in the
+ // constructor and when true, causes this class to do nothing.
+ const bool already_delayed_;
+ };
+
QuicPacketSequenceNumber sequence_number_of_last_sent_packet() const {
return sequence_number_of_last_sent_packet_;
}
+
+ QuicPacketWriter* writer() { return writer_; }
const QuicPacketWriter* writer() const { return writer_; }
bool is_secure() const { return is_secure_; }
+ // Sends an MTU discovery packet of size |target_mtu|. If the packet is
+ // acknowledged by the peer, the maximum packet size will be increased to
+ // |target_mtu|.
+ void SendMtuDiscoveryPacket(QuicByteCount target_mtu);
+
+ // Sends an MTU discovery packet of size |mtu_discovery_target_| and updates
+ // the MTU discovery alarm.
+ void DiscoverMtu();
+
protected:
// Packets which have not been written to the wire.
// Owns the QuicPacket* packet.
@@ -577,8 +633,6 @@ class NET_EXPORT_PRIVATE QuicConnection
// such a version exists, false otherwise.
bool SelectMutualVersion(const QuicVersionVector& available_versions);
- QuicPacketWriter* writer() { return writer_; }
-
bool peer_port_changed() const { return peer_port_changed_; }
private:
@@ -674,6 +728,12 @@ class NET_EXPORT_PRIVATE QuicConnection
// Sets the ping alarm to the appropriate value, if any.
void SetPingAlarm();
+ // Sets the retransmission alarm based on SentPacketManager.
+ void SetRetransmissionAlarm();
+
+ // Sets the MTU discovery alarm if necessary.
+ void MaybeSetMtuAlarm();
+
// On arrival of a new packet, checks to see if the socket addresses have
// changed since the last packet we saw on this connection.
void CheckForAddressMigration(const IPEndPoint& self_address,
@@ -766,6 +826,12 @@ class NET_EXPORT_PRIVATE QuicConnection
// the peer needs to stop waiting for some packets.
int stop_waiting_count_;
+ // Indicates the retransmit alarm is going to be set by the
+ // ScopedRetransmitAlarmDelayer
+ bool delay_setting_retransmission_alarm_;
+ // Indicates the retransmission alarm needs to be set.
+ bool pending_retransmission_alarm_;
+
// An alarm that fires when an ACK should be sent to the peer.
scoped_ptr<QuicAlarm> ack_alarm_;
// An alarm that fires when a packet needs to be retransmitted.
@@ -780,6 +846,8 @@ class NET_EXPORT_PRIVATE QuicConnection
scoped_ptr<QuicAlarm> timeout_alarm_;
// An alarm that fires when a ping should be sent.
scoped_ptr<QuicAlarm> ping_alarm_;
+ // An alarm that fires when an MTU probe should be sent.
+ scoped_ptr<QuicAlarm> mtu_discovery_alarm_;
// Neither visitor is owned by this class.
QuicConnectionVisitorInterface* visitor_;
@@ -852,6 +920,22 @@ class NET_EXPORT_PRIVATE QuicConnection
// True if this is a secure QUIC connection.
bool is_secure_;
+ // The size of the packet we are targeting while doing path MTU discovery.
+ QuicByteCount mtu_discovery_target_;
+
+ // The number of MTU probes already sent.
+ size_t mtu_probe_count_;
+
+ // The number of packets between MTU probes.
+ QuicPacketCount packets_between_mtu_probes_;
+
+ // The sequence number of the packet after which the next MTU probe will be
+ // sent.
+ QuicPacketSequenceNumber next_mtu_probe_at_;
+
+ // The size of the largest packet received from peer.
+ QuicByteCount largest_received_packet_size_;
+
DISALLOW_COPY_AND_ASSIGN(QuicConnection);
};
diff --git a/chromium/net/quic/quic_connection_logger.cc b/chromium/net/quic/quic_connection_logger.cc
index fd60d8e8d52..8f55eae54cf 100644
--- a/chromium/net/quic/quic_connection_logger.cc
+++ b/chromium/net/quic/quic_connection_logger.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/profiler/scoped_tracker.h"
#include "base/strings/string_number_conversions.h"
@@ -35,51 +35,52 @@ namespace {
// Hence the largest sample is bounded by the sum of those numbers.
const int kBoundingSampleInCumulativeHistogram = ((2 + 22) * 21) / 2;
-base::Value* NetLogQuicPacketCallback(const IPEndPoint* self_address,
- const IPEndPoint* peer_address,
- size_t packet_size,
- NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+scoped_ptr<base::Value> NetLogQuicPacketCallback(
+ const IPEndPoint* self_address,
+ const IPEndPoint* peer_address,
+ size_t packet_size,
+ NetLogCaptureMode /* capture_mode */) {
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("self_address", self_address->ToString());
dict->SetString("peer_address", peer_address->ToString());
dict->SetInteger("size", packet_size);
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicPacketSentCallback(
+scoped_ptr<base::Value> NetLogQuicPacketSentCallback(
const SerializedPacket& serialized_packet,
EncryptionLevel level,
TransmissionType transmission_type,
size_t packet_size,
QuicTime sent_time,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetInteger("encryption_level", level);
dict->SetInteger("transmission_type", transmission_type);
dict->SetString("packet_sequence_number",
base::Uint64ToString(serialized_packet.sequence_number));
dict->SetInteger("size", packet_size);
- dict->SetInteger("sent_time_us",
- static_cast<int>(sent_time.ToDebuggingValue()));
- return dict;
+ dict->SetString("sent_time_us",
+ base::Int64ToString(sent_time.ToDebuggingValue()));
+ return dict.Pass();
}
-base::Value* NetLogQuicPacketRetransmittedCallback(
+scoped_ptr<base::Value> NetLogQuicPacketRetransmittedCallback(
QuicPacketSequenceNumber old_sequence_number,
QuicPacketSequenceNumber new_sequence_number,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("old_packet_sequence_number",
base::Uint64ToString(old_sequence_number));
dict->SetString("new_packet_sequence_number",
base::Uint64ToString(new_sequence_number));
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicPacketHeaderCallback(
+scoped_ptr<base::Value> NetLogQuicPacketHeaderCallback(
const QuicPacketHeader* header,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("connection_id",
base::Uint64ToString(header->public_header.connection_id));
dict->SetInteger("reset_flag", header->public_header.reset_flag);
@@ -89,28 +90,29 @@ base::Value* NetLogQuicPacketHeaderCallback(
dict->SetInteger("entropy_flag", header->entropy_flag);
dict->SetInteger("fec_flag", header->fec_flag);
dict->SetInteger("fec_group", static_cast<int>(header->fec_group));
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicStreamFrameCallback(
+scoped_ptr<base::Value> NetLogQuicStreamFrameCallback(
const QuicStreamFrame* frame,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetInteger("stream_id", frame->stream_id);
dict->SetBoolean("fin", frame->fin);
dict->SetString("offset", base::Uint64ToString(frame->offset));
- dict->SetInteger("length", frame->data.TotalBufferSize());
- return dict;
+ dict->SetInteger("length", frame->data.size());
+ return dict.Pass();
}
-base::Value* NetLogQuicAckFrameCallback(const QuicAckFrame* frame,
- NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+scoped_ptr<base::Value> NetLogQuicAckFrameCallback(
+ const QuicAckFrame* frame,
+ NetLogCaptureMode /* capture_mode */) {
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("largest_observed",
base::Uint64ToString(frame->largest_observed));
- dict->SetInteger(
+ dict->SetString(
"delta_time_largest_observed_us",
- static_cast<int>(frame->delta_time_largest_observed.ToMicroseconds()));
+ base::Int64ToString(frame->delta_time_largest_observed.ToMicroseconds()));
dict->SetInteger("entropy_hash",
frame->entropy_hash);
dict->SetBoolean("truncated", frame->is_truncated);
@@ -138,117 +140,117 @@ base::Value* NetLogQuicAckFrameCallback(const QuicAckFrame* frame,
it != received_times.end(); ++it) {
base::DictionaryValue* info = new base::DictionaryValue();
info->SetInteger("sequence_number", static_cast<int>(it->first));
- info->SetInteger("received",
- static_cast<int>(it->second.ToDebuggingValue()));
+ info->SetString("received",
+ base::Int64ToString(it->second.ToDebuggingValue()));
received->Append(info);
}
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicRstStreamFrameCallback(
+scoped_ptr<base::Value> NetLogQuicRstStreamFrameCallback(
const QuicRstStreamFrame* frame,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetInteger("stream_id", frame->stream_id);
dict->SetInteger("quic_rst_stream_error", frame->error_code);
dict->SetString("details", frame->error_details);
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicConnectionCloseFrameCallback(
+scoped_ptr<base::Value> NetLogQuicConnectionCloseFrameCallback(
const QuicConnectionCloseFrame* frame,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetInteger("quic_error", frame->error_code);
dict->SetString("details", frame->error_details);
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicWindowUpdateFrameCallback(
+scoped_ptr<base::Value> NetLogQuicWindowUpdateFrameCallback(
const QuicWindowUpdateFrame* frame,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetInteger("stream_id", frame->stream_id);
dict->SetString("byte_offset", base::Uint64ToString(frame->byte_offset));
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicBlockedFrameCallback(
+scoped_ptr<base::Value> NetLogQuicBlockedFrameCallback(
const QuicBlockedFrame* frame,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetInteger("stream_id", frame->stream_id);
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicGoAwayFrameCallback(
+scoped_ptr<base::Value> NetLogQuicGoAwayFrameCallback(
const QuicGoAwayFrame* frame,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetInteger("quic_error", frame->error_code);
dict->SetInteger("last_good_stream_id", frame->last_good_stream_id);
dict->SetString("reason_phrase", frame->reason_phrase);
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicStopWaitingFrameCallback(
+scoped_ptr<base::Value> NetLogQuicStopWaitingFrameCallback(
const QuicStopWaitingFrame* frame,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
base::DictionaryValue* sent_info = new base::DictionaryValue();
dict->Set("sent_info", sent_info);
sent_info->SetString("least_unacked",
base::Uint64ToString(frame->least_unacked));
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicVersionNegotiationPacketCallback(
+scoped_ptr<base::Value> NetLogQuicVersionNegotiationPacketCallback(
const QuicVersionNegotiationPacket* packet,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
base::ListValue* versions = new base::ListValue();
dict->Set("versions", versions);
for (QuicVersionVector::const_iterator it = packet->versions.begin();
it != packet->versions.end(); ++it) {
versions->AppendString(QuicVersionToString(*it));
}
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicCryptoHandshakeMessageCallback(
+scoped_ptr<base::Value> NetLogQuicCryptoHandshakeMessageCallback(
const CryptoHandshakeMessage* message,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("quic_crypto_handshake_message", message->DebugString());
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicOnConnectionClosedCallback(
+scoped_ptr<base::Value> NetLogQuicOnConnectionClosedCallback(
QuicErrorCode error,
bool from_peer,
NetLogCaptureMode /* capture_mode */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetInteger("quic_error", error);
dict->SetBoolean("from_peer", from_peer);
- return dict;
+ return dict.Pass();
}
-base::Value* NetLogQuicCertificateVerifiedCallback(
+scoped_ptr<base::Value> NetLogQuicCertificateVerifiedCallback(
scoped_refptr<X509Certificate> cert,
NetLogCaptureMode /* capture_mode */) {
// Only the subjects are logged so that we can investigate connection pooling.
// More fields could be logged in the future.
std::vector<std::string> dns_names;
cert->GetDNSNames(&dns_names);
- base::DictionaryValue* dict = new base::DictionaryValue();
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
base::ListValue* subjects = new base::ListValue();
for (std::vector<std::string>::const_iterator it = dns_names.begin();
it != dns_names.end(); it++) {
subjects->Append(new base::StringValue(*it));
}
dict->Set("subjects", subjects);
- return dict;
+ return dict.Pass();
}
void UpdatePacketGapSentHistogram(size_t num_consecutive_missing_packets) {
@@ -279,7 +281,7 @@ AddressFamily GetRealAddressFamily(const IPAddressNumber& address) {
} // namespace
QuicConnectionLogger::QuicConnectionLogger(
- QuicSession* session,
+ QuicSpdySession* session,
const char* const connection_description,
const BoundNetLog& net_log)
: net_log_(net_log),
@@ -426,6 +428,10 @@ void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) {
// PingFrame has no contents to log, so just record that it was sent.
net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PING_FRAME_SENT);
break;
+ case MTU_DISCOVERY_FRAME:
+ // MtuDiscoveryFrame is PingFrame on wire, it does not have any payload.
+ net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_MTU_DISCOVERY_FRAME_SENT);
+ break;
default:
DCHECK(false) << "Illegal frame type: " << frame.type;
}
diff --git a/chromium/net/quic/quic_connection_logger.h b/chromium/net/quic/quic_connection_logger.h
index 4812596be89..6e81e217c9e 100644
--- a/chromium/net/quic/quic_connection_logger.h
+++ b/chromium/net/quic/quic_connection_logger.h
@@ -12,7 +12,7 @@
#include "net/log/net_log.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_session.h"
+#include "net/quic/quic_spdy_session.h"
namespace net {
namespace test {
@@ -27,7 +27,7 @@ class CertVerifyResult;
class NET_EXPORT_PRIVATE QuicConnectionLogger
: public QuicConnectionDebugVisitor {
public:
- QuicConnectionLogger(QuicSession* session,
+ QuicConnectionLogger(QuicSpdySession* session,
const char* const connection_description,
const BoundNetLog& net_log);
@@ -118,7 +118,7 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger
void RecordLossHistograms() const;
BoundNetLog net_log_;
- QuicSession* session_; // Unowned.
+ QuicSpdySession* session_; // Unowned.
// The last packet sequence number received.
QuicPacketSequenceNumber last_received_packet_sequence_number_;
// The size of the most recently received packet.
diff --git a/chromium/net/quic/quic_connection_logger_unittest.cc b/chromium/net/quic/quic_connection_logger_unittest.cc
index 9f14a09ef94..8bdb78ecdeb 100644
--- a/chromium/net/quic/quic_connection_logger_unittest.cc
+++ b/chromium/net/quic/quic_connection_logger_unittest.cc
@@ -36,7 +36,7 @@ class QuicConnectionLoggerTest : public ::testing::Test {
logger_(&session_, "CONNECTION_UNKNOWN", net_log_) {}
BoundNetLog net_log_;
- MockSession session_;
+ MockQuicSpdySession session_;
QuicConnectionLogger logger_;
};
diff --git a/chromium/net/quic/quic_connection_stats.cc b/chromium/net/quic/quic_connection_stats.cc
index 02938c2a108..e581c17c254 100644
--- a/chromium/net/quic/quic_connection_stats.cc
+++ b/chromium/net/quic/quic_connection_stats.cc
@@ -33,6 +33,7 @@ QuicConnectionStats::QuicConnectionStats()
min_rtt_us(0),
srtt_us(0),
max_packet_size(0),
+ max_received_packet_size(0),
estimated_bandwidth(QuicBandwidth::Zero()),
packets_reordered(0),
max_sequence_reordering(0),
diff --git a/chromium/net/quic/quic_connection_stats.h b/chromium/net/quic/quic_connection_stats.h
index cd321a95601..ca3fb91041c 100644
--- a/chromium/net/quic/quic_connection_stats.h
+++ b/chromium/net/quic/quic_connection_stats.h
@@ -63,6 +63,7 @@ struct NET_EXPORT_PRIVATE QuicConnectionStats {
int64 min_rtt_us; // Minimum RTT in microseconds.
int64 srtt_us; // Smoothed RTT in microseconds.
QuicByteCount max_packet_size;
+ QuicByteCount max_received_packet_size;
QuicBandwidth estimated_bandwidth;
// Reordering stats for received packets.
diff --git a/chromium/net/quic/quic_connection_test.cc b/chromium/net/quic/quic_connection_test.cc
index fec998e1606..fcc9efece0a 100644
--- a/chromium/net/quic/quic_connection_test.cc
+++ b/chromium/net/quic/quic_connection_test.cc
@@ -4,6 +4,8 @@
#include "net/quic/quic_connection.h"
+#include <ostream>
+
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
@@ -34,6 +36,7 @@
using base::StringPiece;
using std::map;
+using std::ostream;
using std::string;
using std::vector;
using testing::AnyNumber;
@@ -78,16 +81,6 @@ class TaggingEncrypter : public QuicEncrypter {
bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
- bool Encrypt(StringPiece nonce,
- StringPiece associated_data,
- StringPiece plaintext,
- unsigned char* output) override {
- memcpy(output, plaintext.data(), plaintext.size());
- output += plaintext.size();
- memset(output, tag_, kTagSize);
- return true;
- }
-
bool EncryptPacket(QuicPacketSequenceNumber sequence_number,
StringPiece associated_data,
StringPiece plaintext,
@@ -98,8 +91,9 @@ class TaggingEncrypter : public QuicEncrypter {
if (max_output_length < len) {
return false;
}
- Encrypt(StringPiece(), associated_data, plaintext,
- reinterpret_cast<unsigned char*>(output));
+ memcpy(output, plaintext.data(), plaintext.size());
+ output += plaintext.size();
+ memset(output, tag_, kTagSize);
*output_length = len;
return true;
}
@@ -262,7 +256,7 @@ class TestPacketWriter : public QuicPacketWriter {
}
if (use_tagging_decrypter_) {
- framer_.framer()->SetDecrypter(new TaggingDecrypter, ENCRYPTION_NONE);
+ framer_.framer()->SetDecrypter(ENCRYPTION_NONE, new TaggingDecrypter);
}
EXPECT_TRUE(framer_.ProcessPacket(packet));
if (block_on_next_write_) {
@@ -432,7 +426,7 @@ class TestConnection : public QuicConnection {
: nullptr;
char buffer[kMaxPacketSize];
QuicEncryptedPacket* encrypted =
- QuicConnectionPeer::GetFramer(this)->EncryptPacket(
+ QuicConnectionPeer::GetFramer(this)->EncryptPayload(
ENCRYPTION_NONE, sequence_number, *packet, buffer, kMaxPacketSize);
delete packet;
OnSerializedPacket(SerializedPacket(sequence_number,
@@ -467,10 +461,8 @@ class TestConnection : public QuicConnection {
bool fin,
FecProtection fec_protection,
QuicAckNotifier::DelegateInterface* delegate) {
- IOVector data_iov;
- if (!data.empty()) {
- data_iov.Append(const_cast<char*>(data.data()), data.size());
- }
+ struct iovec iov;
+ QuicIOVector data_iov(MakeIOVector(data, &iov));
return QuicConnection::SendStreamData(id, data_iov, offset, fin,
fec_protection, delegate);
}
@@ -523,6 +515,27 @@ class TestConnection : public QuicConnection {
QuicConnectionPeer::SetPerspective(this, perspective);
}
+ // Enable path MTU discovery. Assumes that the test is performed from the
+ // client perspective and the higher value of MTU target is used.
+ void EnablePathMtuDiscovery(MockSendAlgorithm* send_algorithm) {
+ ASSERT_EQ(Perspective::IS_CLIENT, perspective());
+
+ FLAGS_quic_do_path_mtu_discovery = true;
+
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kMTUH);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm, SetFromConfig(_, _));
+ SetFromConfig(config);
+
+ // Normally, the pacing would be disabled in the test, but calling
+ // SetFromConfig enables it. Set nearly-infinite bandwidth to make the
+ // pacing algorithm work.
+ EXPECT_CALL(*send_algorithm, PacingRate())
+ .WillRepeatedly(Return(QuicBandwidth::FromKBytesPerSecond(10000)));
+ }
+
TestConnectionHelper::TestAlarm* GetAckAlarm() {
return reinterpret_cast<TestConnectionHelper::TestAlarm*>(
QuicConnectionPeer::GetAckAlarm(this));
@@ -558,6 +571,11 @@ class TestConnection : public QuicConnection {
QuicConnectionPeer::GetTimeoutAlarm(this));
}
+ TestConnectionHelper::TestAlarm* GetMtuDiscoveryAlarm() {
+ return reinterpret_cast<TestConnectionHelper::TestAlarm*>(
+ QuicConnectionPeer::GetMtuDiscoveryAlarm(this));
+ }
+
using QuicConnection::SelectMutualVersion;
private:
@@ -596,7 +614,33 @@ class MockPacketWriterFactory : public QuicConnection::PacketWriterFactory {
MOCK_CONST_METHOD1(Create, QuicPacketWriter*(QuicConnection* connection));
};
-class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
+// Run tests with combinations of {QuicVersion, fec_send_policy}.
+struct TestParams {
+ TestParams(QuicVersion version, FecSendPolicy fec_send_policy)
+ : version(version), fec_send_policy(fec_send_policy) {}
+
+ friend ostream& operator<<(ostream& os, const TestParams& p) {
+ os << "{ client_version: " << QuicVersionToString(p.version)
+ << " fec_send_policy: " << p.fec_send_policy << " }";
+ return os;
+ }
+
+ QuicVersion version;
+ FecSendPolicy fec_send_policy;
+};
+
+// Constructs various test permutations.
+vector<TestParams> GetTestParams() {
+ vector<TestParams> params;
+ QuicVersionVector all_supported_versions = QuicSupportedVersions();
+ for (size_t i = 0; i < all_supported_versions.size(); ++i) {
+ params.push_back(TestParams(all_supported_versions[i], FEC_ANY_TRIGGER));
+ params.push_back(TestParams(all_supported_versions[i], FEC_ALARM_TRIGGER));
+ }
+ return params;
+}
+
+class QuicConnectionTest : public ::testing::TestWithParam<TestParams> {
protected:
QuicConnectionTest()
: connection_id_(42),
@@ -618,14 +662,15 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
creator_(QuicConnectionPeer::GetPacketCreator(&connection_)),
generator_(QuicConnectionPeer::GetPacketGenerator(&connection_)),
manager_(QuicConnectionPeer::GetSentPacketManager(&connection_)),
- frame1_(1, false, 0, MakeIOVector(data1)),
- frame2_(1, false, 3, MakeIOVector(data2)),
+ frame1_(1, false, 0, StringPiece(data1)),
+ frame2_(1, false, 3, StringPiece(data2)),
sequence_number_length_(PACKET_6BYTE_SEQUENCE_NUMBER),
connection_id_length_(PACKET_8BYTE_CONNECTION_ID) {
connection_.set_visitor(&visitor_);
connection_.SetSendAlgorithm(send_algorithm_);
connection_.SetLossAlgorithm(loss_algorithm_);
framer_.set_received_entropy_calculator(&entropy_calculator_);
+ generator_->set_fec_send_policy(GetParam().fec_send_policy);
EXPECT_CALL(
*send_algorithm_, TimeUntilSend(_, _, _)).WillRepeatedly(Return(
QuicTime::Delta::Zero()));
@@ -647,7 +692,8 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
EXPECT_CALL(visitor_, WillingAndAbleToWrite()).Times(AnyNumber());
EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber());
EXPECT_CALL(visitor_, OnCanWrite()).Times(AnyNumber());
- EXPECT_CALL(visitor_, HasOpenDataStreams()).WillRepeatedly(Return(false));
+ EXPECT_CALL(visitor_, HasOpenDynamicStreams())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(visitor_, OnCongestionWindowChange(_)).Times(AnyNumber());
EXPECT_CALL(*loss_algorithm_, GetLossTimeout())
@@ -656,9 +702,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
.WillRepeatedly(Return(SequenceNumberSet()));
}
- QuicVersion version() {
- return GetParam();
- }
+ QuicVersion version() { return GetParam().version; }
QuicAckFrame* outgoing_ack() {
QuicConnectionPeer::PopulateAckFrame(&connection_, &ack_);
@@ -715,7 +759,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
entropy_flag));
char buffer[kMaxPacketSize];
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer_.EncryptPacket(level, number, *packet, buffer, kMaxPacketSize));
+ framer_.EncryptPayload(level, number, *packet, buffer, kMaxPacketSize));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
return encrypted->length();
}
@@ -724,7 +768,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
QuicFecGroupNumber fec_group) {
scoped_ptr<QuicPacket> packet(ConstructClosePacket(number, fec_group));
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
ENCRYPTION_NONE, number, *packet, buffer, kMaxPacketSize));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
@@ -788,7 +832,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
scoped_ptr<QuicPacket> fec_packet(framer_.BuildFecPacket(header, fec_data));
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
ENCRYPTION_NONE, number, *fec_packet, buffer, kMaxPacketSize));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
@@ -819,6 +863,12 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
.Times(AnyNumber());
}
+ void ProcessAckPacket(QuicPacketSequenceNumber packet_number,
+ QuicAckFrame* frame) {
+ QuicPacketCreatorPeer::SetSequenceNumber(&peer_creator_, packet_number - 1);
+ ProcessFramePacket(QuicFrame(frame));
+ }
+
QuicPacketEntropyHash ProcessAckPacket(QuicAckFrame* frame) {
return ProcessFramePacket(QuicFrame(frame));
}
@@ -979,7 +1029,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
// Run all end to end tests with all supported versions.
INSTANTIATE_TEST_CASE_P(SupportedVersion,
QuicConnectionTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(GetTestParams()));
TEST_P(QuicConnectionTest, MaxPacketSize) {
EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
@@ -1011,7 +1061,7 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) {
frames.push_back(QuicFrame(&padding));
scoped_ptr<QuicPacket> packet(ConstructPacket(header, frames));
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize));
EXPECT_EQ(kMaxPacketSize, encrypted->length());
@@ -1094,10 +1144,9 @@ TEST_P(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
// packet the peer will not retransmit. It indicates this by sending 'least
// awaiting' is 4. The connection should then realize 1 will not be
// retransmitted, and will remove it from the missing list.
- QuicPacketCreatorPeer::SetSequenceNumber(&peer_creator_, 5);
QuicAckFrame frame = InitAckFrame(1);
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _));
- ProcessAckPacket(&frame);
+ ProcessAckPacket(6, &frame);
// Force an ack to be sent.
SendAckPacketToPeer();
@@ -1183,9 +1232,8 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) {
TimeUntilSend(_, _, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
// Skip a packet and then record an ack.
- QuicPacketCreatorPeer::SetSequenceNumber(&peer_creator_, 2);
QuicAckFrame frame = InitAckFrame(0);
- ProcessAckPacket(&frame);
+ ProcessAckPacket(3, &frame);
}
TEST_P(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) {
@@ -1208,6 +1256,46 @@ TEST_P(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) {
EXPECT_EQ(3u, writer_->packets_write_attempts());
}
+TEST_P(QuicConnectionTest, OutOfOrderAckReceiptCausesNoAck) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_dont_ack_acks, true);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
+ SendStreamDataToPeer(1, "bar", 3, !kFin, nullptr);
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+
+ QuicAckFrame ack1 = InitAckFrame(1);
+ QuicAckFrame ack2 = InitAckFrame(2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(2, &ack2);
+ // Should ack immediately since we have missing packets.
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+
+ ProcessAckPacket(1, &ack1);
+ // Should not ack an ack filling a missing packet.
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+}
+
+TEST_P(QuicConnectionTest, OutOfOrderAckReceiptCausesOneAck) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_dont_ack_acks, false);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
+ SendStreamDataToPeer(1, "bar", 3, !kFin, nullptr);
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+
+ QuicAckFrame ack1 = InitAckFrame(1);
+ QuicAckFrame ack2 = InitAckFrame(2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(2, &ack2);
+ // Should ack immediately since we have missing packets.
+ EXPECT_EQ(3u, writer_->packets_write_attempts());
+
+ ProcessAckPacket(1, &ack1);
+ // Should not ack an ack filling a missing packet.
+ EXPECT_EQ(3u, writer_->packets_write_attempts());
+}
+
TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -1319,7 +1407,8 @@ TEST_P(QuicConnectionTest, LeastUnackedLower) {
TEST_P(QuicConnectionTest, TooManySentPackets) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- for (int i = 0; i < 3100; ++i) {
+ const int num_packets = kMaxTrackedPackets + 100;
+ for (int i = 0; i < num_packets; ++i) {
SendStreamDataToPeer(1, "foo", 3 * i, !kFin, nullptr);
}
@@ -1330,27 +1419,28 @@ TEST_P(QuicConnectionTest, TooManySentPackets) {
// We're receive buffer limited, so the connection won't try to write more.
EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
- // Nack every packet except the last one, leaving a huge gap.
- QuicAckFrame frame1 = InitAckFrame(3100);
- for (QuicPacketSequenceNumber i = 1; i < 3100; ++i) {
- NackPacket(i, &frame1);
- }
+ // Nack the first packet and ack the rest, leaving a huge gap.
+ QuicAckFrame frame1 = InitAckFrame(num_packets);
+ NackPacket(1, &frame1);
ProcessAckPacket(&frame1);
}
+// Flaky time out on Windows 7. http://crbug.com/501812
+#if !defined(OS_WIN)
TEST_P(QuicConnectionTest, TooManyReceivedPackets) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(visitor_, OnConnectionClosed(
QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS, false));
- // Miss every other packet for 3000 packets.
- for (QuicPacketSequenceNumber i = 1; i < 3000; ++i) {
- ProcessPacket(i * 2);
+ // Miss 99 of every 100 packets for 5500 packets.
+ for (QuicPacketSequenceNumber i = 1; i < kMaxTrackedPackets + 500; i += 100) {
+ ProcessPacket(i);
if (!connection_.connected()) {
break;
}
}
}
+#endif
TEST_P(QuicConnectionTest, LargestObservedLower) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -1584,11 +1674,17 @@ TEST_P(QuicConnectionTest, FECSending) {
connection_.version(), kIncludeVersion,
PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_SEQUENCE_NUMBER,
IN_FEC_GROUP, &payload_length);
- creator_->SetMaxPacketLength(length);
+ connection_.set_max_packet_length(length);
- // Send 4 protected data packets, which should also trigger 1 FEC packet.
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(5);
+ if (generator_->fec_send_policy() == FEC_ALARM_TRIGGER) {
+ // Send 4 protected data packets. FEC packet is not sent.
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(4);
+ } else {
+ // Send 4 protected data packets, which should also trigger 1 FEC packet.
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(5);
+ }
// The first stream frame will have 2 fewer overhead bytes than the other 3.
const string payload(payload_length * 4 + 2, 'a');
connection_.SendStreamDataWithStringWithFec(1, payload, 0, !kFin, nullptr);
@@ -1604,7 +1700,7 @@ TEST_P(QuicConnectionTest, FECQueueing) {
connection_.version(), kIncludeVersion,
PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_SEQUENCE_NUMBER,
IN_FEC_GROUP, &payload_length);
- creator_->SetMaxPacketLength(length);
+ connection_.set_max_packet_length(length);
EXPECT_TRUE(creator_->IsFecEnabled());
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -1613,8 +1709,13 @@ TEST_P(QuicConnectionTest, FECQueueing) {
connection_.SendStreamDataWithStringWithFec(1, payload, 0, !kFin, nullptr);
EXPECT_FALSE(creator_->IsFecGroupOpen());
EXPECT_FALSE(creator_->IsFecProtected());
- // Expect the first data packet and the fec packet to be queued.
- EXPECT_EQ(2u, connection_.NumQueuedPackets());
+ if (generator_->fec_send_policy() == FEC_ALARM_TRIGGER) {
+ // Expect the first data packet to be queued and not the FEC packet.
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+ } else {
+ // Expect the first data packet and the fec packet to be queued.
+ EXPECT_EQ(2u, connection_.NumQueuedPackets());
+ }
}
TEST_P(QuicConnectionTest, FECAlarmStoppedWhenFECPacketSent) {
@@ -1630,11 +1731,21 @@ TEST_P(QuicConnectionTest, FECAlarmStoppedWhenFECPacketSent) {
connection_.SendStreamDataWithStringWithFec(3, "foo", 0, true, nullptr);
EXPECT_TRUE(connection_.GetFecAlarm()->IsSet());
- // Second data packet triggers FEC packet out. FEC alarm should not be set.
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(2);
+ if (generator_->fec_send_policy() == FEC_ALARM_TRIGGER) {
+ // If FEC send policy is FEC_ALARM_TRIGGER, FEC packet is not sent.
+ // FEC alarm should not be set.
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(1);
+ } else {
+ // Second data packet triggers FEC packet out. FEC alarm should not be set.
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(2);
+ }
connection_.SendStreamDataWithStringWithFec(5, "foo", 0, true, nullptr);
- EXPECT_TRUE(writer_->header().fec_flag);
+ if (generator_->fec_send_policy() == FEC_ANY_TRIGGER) {
+ EXPECT_TRUE(writer_->header().fec_flag);
+ }
+ EXPECT_FALSE(creator_->IsFecGroupOpen());
EXPECT_FALSE(connection_.GetFecAlarm()->IsSet());
}
@@ -2054,9 +2165,8 @@ TEST_P(QuicConnectionTest, FramePackingAckResponse) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
// Process an ack to cause the visitor's OnCanWrite to be invoked.
- QuicPacketCreatorPeer::SetSequenceNumber(&peer_creator_, 2);
QuicAckFrame ack_one = InitAckFrame(0);
- ProcessAckPacket(&ack_one);
+ ProcessAckPacket(3, &ack_one);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -2077,10 +2187,13 @@ TEST_P(QuicConnectionTest, FramePackingSendv) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
char data[] = "ABCD";
- IOVector data_iov;
- data_iov.AppendNoCoalesce(data, 2);
- data_iov.AppendNoCoalesce(data + 2, 2);
- connection_.SendStreamData(1, data_iov, 0, !kFin, MAY_FEC_PROTECT, nullptr);
+ struct iovec iov[2];
+ iov[0].iov_base = data;
+ iov[0].iov_len = 2;
+ iov[1].iov_base = data + 2;
+ iov[1].iov_len = 2;
+ connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin,
+ MAY_FEC_PROTECT, nullptr);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -2091,9 +2204,7 @@ TEST_P(QuicConnectionTest, FramePackingSendv) {
EXPECT_EQ(1u, writer_->stream_frames().size());
QuicStreamFrame frame = writer_->stream_frames()[0];
EXPECT_EQ(1u, frame.stream_id);
- EXPECT_EQ("ABCD", string(static_cast<char*>
- (frame.data.iovec()[0].iov_base),
- (frame.data.iovec()[0].iov_len)));
+ EXPECT_EQ("ABCD", frame.data);
}
TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
@@ -2102,10 +2213,13 @@ TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
BlockOnNextWrite();
char data[] = "ABCD";
- IOVector data_iov;
- data_iov.AppendNoCoalesce(data, 2);
- data_iov.AppendNoCoalesce(data + 2, 2);
- connection_.SendStreamData(1, data_iov, 0, !kFin, MAY_FEC_PROTECT, nullptr);
+ struct iovec iov[2];
+ iov[0].iov_base = data;
+ iov[0].iov_len = 2;
+ iov[1].iov_base = data + 2;
+ iov[1].iov_len = 2;
+ connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin,
+ MAY_FEC_PROTECT, nullptr);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
EXPECT_TRUE(connection_.HasQueuedData());
@@ -2124,7 +2238,7 @@ TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
TEST_P(QuicConnectionTest, SendingZeroBytes) {
// Send a zero byte write with a fin using writev.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- IOVector empty_iov;
+ QuicIOVector empty_iov(nullptr, 0, 0);
connection_.SendStreamData(1, empty_iov, 0, kFin, MAY_FEC_PROTECT, nullptr);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -2858,8 +2972,7 @@ TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
// Transition to the new encryption state and process another encrypted packet
// which should result in the original packet being processed.
- connection_.SetDecrypter(new StrictTaggingDecrypter(tag),
- ENCRYPTION_INITIAL);
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
EXPECT_CALL(visitor_, OnStreamFrames(_)).Times(2);
@@ -2891,7 +3004,7 @@ TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) {
// Transition to the new encryption state and process another encrypted packet
// which should result in the original packets being processed.
- connection_.SetDecrypter(new StrictTaggingDecrypter(tag), ENCRYPTION_INITIAL);
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
EXPECT_CALL(visitor_, OnStreamFrames(_)).Times(101);
@@ -3044,6 +3157,7 @@ TEST_P(QuicConnectionTest, InitialTimeout) {
EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet());
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
}
TEST_P(QuicConnectionTest, OverallTimeout) {
@@ -3091,7 +3205,7 @@ TEST_P(QuicConnectionTest, OverallTimeout) {
TEST_P(QuicConnectionTest, PingAfterSend) {
EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(visitor_, HasOpenDataStreams()).WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(true));
EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
// Advance to 5ms, and send a packet to the peer, which will set
@@ -3124,13 +3238,192 @@ TEST_P(QuicConnectionTest, PingAfterSend) {
ASSERT_EQ(1u, writer_->ping_frames().size());
writer_->Reset();
- EXPECT_CALL(visitor_, HasOpenDataStreams()).WillRepeatedly(Return(false));
+ EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(false));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
SendAckPacketToPeer();
EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
}
+// Tests whether sending an MTU discovery packet to peer successfully causes the
+// maximum packet size to increase.
+TEST_P(QuicConnectionTest, SendMtuDiscoveryPacket) {
+ EXPECT_TRUE(connection_.connected());
+
+ // Send an MTU probe.
+ const size_t new_mtu = kDefaultMaxPacketSize + 100;
+ QuicByteCount mtu_probe_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&mtu_probe_size), Return(true)));
+ connection_.SendMtuDiscoveryPacket(new_mtu);
+ EXPECT_EQ(new_mtu, mtu_probe_size);
+ EXPECT_EQ(1u, creator_->sequence_number());
+
+ // Send more than MTU worth of data. No acknowledgement was received so far,
+ // so the MTU should be at its old value.
+ const string data(kDefaultMaxPacketSize + 1, '.');
+ QuicByteCount size_before_mtu_change;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&size_before_mtu_change), Return(true)))
+ .WillOnce(Return(true));
+ connection_.SendStreamDataWithString(3, data, 0, kFin, nullptr);
+ EXPECT_EQ(3u, creator_->sequence_number());
+ EXPECT_EQ(kDefaultMaxPacketSize, size_before_mtu_change);
+
+ // Acknowledge all packets so far.
+ QuicAckFrame probe_ack = InitAckFrame(3);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&probe_ack);
+ EXPECT_EQ(new_mtu, connection_.max_packet_length());
+
+ // Send the same data again. Check that it fits into a single packet now.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendStreamDataWithString(3, data, 0, kFin, nullptr);
+ EXPECT_EQ(4u, creator_->sequence_number());
+}
+
+// Tests whether MTU discovery does not happen when it is not explicitly enabled
+// by the connection options.
+TEST_P(QuicConnectionTest, MtuDiscoveryDisabled) {
+ EXPECT_TRUE(connection_.connected());
+
+ // Restore the current value FLAGS_quic_do_path_mtu_discovery after the test.
+ ValueRestore<bool> old_flag(&FLAGS_quic_do_path_mtu_discovery, true);
+
+ const QuicPacketCount number_of_packets = kPacketsBetweenMtuProbesBase * 2;
+ for (QuicPacketCount i = 0; i < number_of_packets; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+}
+
+// Tests whether MTU discovery works when the probe gets acknowledged on the
+// first try.
+TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) {
+ EXPECT_TRUE(connection_.connected());
+
+ // Restore the current value FLAGS_quic_do_path_mtu_discovery after the test.
+ ValueRestore<bool> old_flag(&FLAGS_quic_do_path_mtu_discovery, true);
+ connection_.EnablePathMtuDiscovery(send_algorithm_);
+
+ // Send enough packets so that the next one triggers path MTU discovery.
+ for (QuicPacketCount i = 0; i < kPacketsBetweenMtuProbesBase - 1; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ // Trigger the probe.
+ SendStreamDataToPeer(3, "!", kPacketsBetweenMtuProbesBase,
+ /*fin=*/false, nullptr);
+ ASSERT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ QuicByteCount probe_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&probe_size), Return(true)));
+ connection_.GetMtuDiscoveryAlarm()->Fire();
+ EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, probe_size);
+
+ const QuicPacketCount probe_sequence_number =
+ kPacketsBetweenMtuProbesBase + 1;
+ ASSERT_EQ(probe_sequence_number, creator_->sequence_number());
+
+ // Acknowledge all packets sent so far.
+ QuicAckFrame probe_ack = InitAckFrame(probe_sequence_number);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&probe_ack);
+ EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, connection_.max_packet_length());
+
+ // Send more packets, and ensure that none of them sets the alarm.
+ for (QuicPacketCount i = 0; i < 4 * kPacketsBetweenMtuProbesBase; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+}
+
+// Tests whether MTU discovery works correctly when the probes never get
+// acknowledged.
+TEST_P(QuicConnectionTest, MtuDiscoveryFailed) {
+ EXPECT_TRUE(connection_.connected());
+
+ // Restore the current value FLAGS_quic_do_path_mtu_discovery after the test.
+ ValueRestore<bool> old_flag(&FLAGS_quic_do_path_mtu_discovery, true);
+ connection_.EnablePathMtuDiscovery(send_algorithm_);
+
+ const QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100);
+
+ // This tests sends more packets than strictly necessary to make sure that if
+ // the connection was to send more discovery packets than needed, those would
+ // get caught as well.
+ const QuicPacketCount number_of_packets =
+ kPacketsBetweenMtuProbesBase * (1 << (kMtuDiscoveryAttempts + 1));
+ vector<QuicPacketSequenceNumber> mtu_discovery_packets;
+ // Called by the first ack.
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ // Called on many acks.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _))
+ .Times(AnyNumber());
+ for (QuicPacketCount i = 0; i < number_of_packets; i++) {
+ SendStreamDataToPeer(3, "!", i, /*fin=*/false, nullptr);
+ clock_.AdvanceTime(rtt);
+
+ // Receive an ACK, which marks all data packets as received, and all MTU
+ // discovery packets as missing.
+ QuicAckFrame ack = InitAckFrame(creator_->sequence_number());
+ ack.missing_packets = SequenceNumberSet(mtu_discovery_packets.begin(),
+ mtu_discovery_packets.end());
+ ProcessAckPacket(&ack);
+
+ // Trigger MTU probe if it would be scheduled now.
+ if (!connection_.GetMtuDiscoveryAlarm()->IsSet()) {
+ continue;
+ }
+
+ // Fire the alarm. The alarm should cause a packet to be sent.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(Return(true));
+ connection_.GetMtuDiscoveryAlarm()->Fire();
+ // Record the sequence number of the MTU discovery packet in order to
+ // mark it as NACK'd.
+ mtu_discovery_packets.push_back(creator_->sequence_number());
+ }
+
+ // Ensure the number of packets between probes grows exponentially by checking
+ // it against the closed-form expression for the sequence number.
+ ASSERT_EQ(kMtuDiscoveryAttempts, mtu_discovery_packets.size());
+ for (QuicPacketSequenceNumber i = 0; i < kMtuDiscoveryAttempts; i++) {
+ // 2^0 + 2^1 + 2^2 + ... + 2^n = 2^(n + 1) - 1
+ const QuicPacketCount packets_between_probes =
+ kPacketsBetweenMtuProbesBase * ((1 << (i + 1)) - 1);
+ EXPECT_EQ(packets_between_probes + (i + 1), mtu_discovery_packets[i]);
+ }
+
+ EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ EXPECT_EQ(kDefaultMaxPacketSize, connection_.max_packet_length());
+}
+
+TEST_P(QuicConnectionTest, NoMtuDiscoveryAfterConnectionClosed) {
+ EXPECT_TRUE(connection_.connected());
+
+ // Restore the current value FLAGS_quic_do_path_mtu_discovery after the test.
+ ValueRestore<bool> old_flag(&FLAGS_quic_do_path_mtu_discovery, true);
+ connection_.EnablePathMtuDiscovery(send_algorithm_);
+
+ // Send enough packets so that the next one triggers path MTU discovery.
+ for (QuicPacketCount i = 0; i < kPacketsBetweenMtuProbesBase - 1; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ SendStreamDataToPeer(3, "!", kPacketsBetweenMtuProbesBase,
+ /*fin=*/false, nullptr);
+ EXPECT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
+ connection_.CloseConnection(QUIC_INTERNAL_ERROR, /*from_peer=*/false);
+ EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+}
+
TEST_P(QuicConnectionTest, TimeoutAfterSend) {
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
@@ -3254,7 +3547,7 @@ TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
connection_.version(), kIncludeVersion,
PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_SEQUENCE_NUMBER,
NOT_IN_FEC_GROUP, &payload_length);
- creator_->SetMaxPacketLength(length);
+ connection_.set_max_packet_length(length);
// Queue the first packet.
EXPECT_CALL(*send_algorithm_,
@@ -3278,7 +3571,7 @@ TEST_P(QuicConnectionTest, LoopThroughSendingPackets) {
connection_.version(), kIncludeVersion,
PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_SEQUENCE_NUMBER,
NOT_IN_FEC_GROUP, &payload_length);
- creator_->SetMaxPacketLength(length);
+ connection_.set_max_packet_length(length);
// Queue the first packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(7);
@@ -3342,8 +3635,7 @@ TEST_P(QuicConnectionTest, SendDelayedAck) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
const uint8 tag = 0x07;
- connection_.SetDecrypter(new StrictTaggingDecrypter(tag),
- ENCRYPTION_INITIAL);
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
// Process a packet from the non-crypto stream.
frame1_.stream_id = 3;
@@ -3712,7 +4004,7 @@ TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacket) {
frames.push_back(QuicFrame(&frame1_));
scoped_ptr<QuicPacket> packet(ConstructPacket(header, frames));
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize));
framer_.set_version(version());
@@ -3745,7 +4037,7 @@ TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) {
frames.push_back(QuicFrame(&frame1_));
scoped_ptr<QuicPacket> packet(ConstructPacket(header, frames));
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize));
framer_.set_version(version());
@@ -3785,7 +4077,7 @@ TEST_P(QuicConnectionTest,
frames.push_back(QuicFrame(&frame1_));
scoped_ptr<QuicPacket> packet(ConstructPacket(header, frames));
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize));
framer_.set_version(version());
@@ -3825,8 +4117,8 @@ TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) {
frames.push_back(QuicFrame(&frame1_));
scoped_ptr<QuicPacket> packet(ConstructPacket(header, frames));
char buffer[kMaxPacketSize];
- encrypted.reset(framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet, buffer,
- kMaxPacketSize));
+ encrypted.reset(framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet, buffer,
+ kMaxPacketSize));
EXPECT_CALL(visitor_, OnStreamFrames(_)).Times(1);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
@@ -3883,7 +4175,7 @@ TEST_P(QuicConnectionTest, CheckSendStats) {
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(visitor_, OnCanWrite()).Times(2);
+ EXPECT_CALL(visitor_, OnCanWrite());
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessAckPacket(&nack_three);
@@ -3960,7 +4252,7 @@ TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
scoped_ptr<QuicPacket> packet(ConstructPacket(header, frames));
EXPECT_TRUE(nullptr != packet.get());
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
ENCRYPTION_NONE, 1, *packet, buffer, kMaxPacketSize));
EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, true));
@@ -4353,6 +4645,27 @@ TEST_P(QuicConnectionTest, NoDataNoFin) {
"Attempt to send empty stream frame");
}
+TEST_P(QuicConnectionTest, FecSendPolicyReceivedConnectionOption) {
+ // Test sending SetReceivedConnectionOptions when FEC send policy is
+ // FEC_ANY_TRIGGER.
+ if (GetParam().fec_send_policy == FEC_ALARM_TRIGGER) {
+ return;
+ }
+ ValueRestore<bool> old_flag(&FLAGS_quic_send_fec_packet_only_on_fec_alarm,
+ true);
+ connection_.set_perspective(Perspective::IS_SERVER);
+
+ // Test ReceivedConnectionOptions.
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ QuicTagVector copt;
+ copt.push_back(kFSPA);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, copt);
+ EXPECT_EQ(FEC_ANY_TRIGGER, generator_->fec_send_policy());
+ connection_.SetFromConfig(config);
+ EXPECT_EQ(FEC_ALARM_TRIGGER, generator_->fec_send_policy());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/quic_crypto_client_stream.cc b/chromium/net/quic/quic_crypto_client_stream.cc
index 0895700912f..84c994c18fa 100644
--- a/chromium/net/quic/quic_crypto_client_stream.cc
+++ b/chromium/net/quic/quic_crypto_client_stream.cc
@@ -4,12 +4,13 @@
#include "net/quic/quic_crypto_client_stream.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/profiler/scoped_tracker.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/null_encrypter.h"
#include "net/quic/quic_client_session_base.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_session.h"
@@ -301,6 +302,15 @@ void QuicCryptoClientStream::DoSendCHLO(
return;
}
+ // If the server nonce is empty, copy over the server nonce from a previous
+ // SREJ, if there is one.
+ if (FLAGS_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_,
@@ -330,8 +340,8 @@ void QuicCryptoClientStream::DoSendCHLO(
SendHandshakeMessage(out);
// Be prepared to decrypt with the new server write key.
session()->connection()->SetAlternativeDecrypter(
- crypto_negotiated_params_.initial_crypters.decrypter.release(),
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.
@@ -563,7 +573,7 @@ void QuicCryptoClientStream::DoReceiveSHLO(
// with the FORWARD_SECURE key until it receives a FORWARD_SECURE
// packet from the client.
session()->connection()->SetAlternativeDecrypter(
- crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
+ ENCRYPTION_FORWARD_SECURE, crypters->decrypter.release(),
false /* don't latch */);
session()->connection()->SetEncrypter(
ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
diff --git a/chromium/net/quic/quic_crypto_client_stream_test.cc b/chromium/net/quic/quic_crypto_client_stream_test.cc
index de3d68e251d..72bf40f4a2f 100644
--- a/chromium/net/quic/quic_crypto_client_stream_test.cc
+++ b/chromium/net/quic/quic_crypto_client_stream_test.cc
@@ -30,21 +30,22 @@ const uint16 kServerPort = 80;
class QuicCryptoClientStreamTest : public ::testing::Test {
public:
QuicCryptoClientStreamTest()
- : connection_(new PacketSavingConnection(Perspective::IS_CLIENT)),
- session_(new TestClientSession(connection_, DefaultQuicConfig())),
- server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED),
- stream_(new QuicCryptoClientStream(server_id_,
- session_.get(),
- nullptr,
- &crypto_config_)) {
- session_->SetCryptoStream(stream_.get());
+ : server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED) {
+ CreateConnection();
+ }
+
+ void CreateConnection() {
+ connection_ = new PacketSavingConnection(Perspective::IS_CLIENT);
// Advance the time, because timers do not like uninitialized times.
connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+
+ session_.reset(new TestQuicSpdyClientSession(
+ connection_, DefaultQuicConfig(), server_id_, &crypto_config_));
}
void CompleteCryptoHandshake() {
- stream_->CryptoConnect();
- CryptoTestUtils::HandshakeWithFakeServer(connection_, stream_.get());
+ stream()->CryptoConnect();
+ CryptoTestUtils::HandshakeWithFakeServer(connection_, stream());
}
void ConstructHandshakeMessage() {
@@ -52,24 +53,25 @@ class QuicCryptoClientStreamTest : public ::testing::Test {
message_data_.reset(framer.ConstructHandshakeMessage(message_));
}
+ QuicCryptoClientStream* stream() { return session_->GetCryptoStream(); }
+
PacketSavingConnection* connection_;
- scoped_ptr<TestClientSession> session_;
+ scoped_ptr<TestQuicSpdyClientSession> session_;
QuicServerId server_id_;
- scoped_ptr<QuicCryptoClientStream> stream_;
CryptoHandshakeMessage message_;
scoped_ptr<QuicData> message_data_;
QuicCryptoClientConfig crypto_config_;
};
TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
- EXPECT_FALSE(stream_->encryption_established());
- EXPECT_FALSE(stream_->handshake_confirmed());
+ EXPECT_FALSE(stream()->encryption_established());
+ EXPECT_FALSE(stream()->handshake_confirmed());
}
TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
CompleteCryptoHandshake();
- EXPECT_TRUE(stream_->encryption_established());
- EXPECT_TRUE(stream_->handshake_confirmed());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
}
TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
@@ -79,18 +81,18 @@ TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
message_.set_tag(kCHLO);
ConstructHandshakeMessage();
- stream_->ProcessRawData(message_data_->data(), message_data_->length());
+ stream()->ProcessRawData(message_data_->data(), message_data_->length());
}
TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
- stream_->CryptoConnect();
+ stream()->CryptoConnect();
message_.set_tag(kCHLO);
ConstructHandshakeMessage();
EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(
QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "Expected REJ"));
- stream_->ProcessRawData(message_data_->data(), message_data_->length());
+ stream()->ProcessRawData(message_data_->data(), message_data_->length());
}
TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
@@ -103,39 +105,35 @@ TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
config->MaxStreamsPerConnection());
const QuicCryptoNegotiatedParameters& crypto_params(
- stream_->crypto_negotiated_params());
+ stream()->crypto_negotiated_params());
EXPECT_EQ(crypto_config_.aead[0], crypto_params.aead);
EXPECT_EQ(crypto_config_.kexs[0], crypto_params.key_exchange);
}
TEST_F(QuicCryptoClientStreamTest, InvalidHostname) {
- QuicServerId server_id("invalid", 80, false, PRIVACY_MODE_DISABLED);
- stream_.reset(new QuicCryptoClientStream(server_id, session_.get(), nullptr,
- &crypto_config_));
- session_->SetCryptoStream(stream_.get());
+ server_id_ =
+ QuicServerId("invalid", kServerPort, false, PRIVACY_MODE_DISABLED);
+
+ CreateConnection();
CompleteCryptoHandshake();
- EXPECT_TRUE(stream_->encryption_established());
- EXPECT_TRUE(stream_->handshake_confirmed());
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
}
TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
// Seed the config with a cached server config.
CompleteCryptoHandshake();
- connection_ = new PacketSavingConnection(Perspective::IS_CLIENT);
- session_.reset(new TestClientSession(connection_, DefaultQuicConfig()));
- stream_.reset(new QuicCryptoClientStream(server_id_, session_.get(), nullptr,
- &crypto_config_));
-
- session_->SetCryptoStream(stream_.get());
+ // Recreate connection with the new config.
+ CreateConnection();
// Advance time 5 years to ensure that we pass the expiry time of the cached
// server config.
connection_->AdvanceTime(
QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
- stream_->CryptoConnect();
+ stream()->CryptoConnect();
// Check that a client hello was sent.
ASSERT_EQ(1u, connection_->encrypted_packets_.size());
}
@@ -179,7 +177,7 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
scoped_ptr<QuicData> data(
CryptoFramer::ConstructHandshakeMessage(server_config_update));
- stream_->ProcessRawData(data->data(), data->length());
+ stream()->ProcessRawData(data->data(), data->length());
// Make sure that the STK and SCFG are cached correctly.
EXPECT_EQ("xstk", state->source_address_token());
@@ -197,7 +195,7 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) {
server_config_update.set_tag(kSCUP);
scoped_ptr<QuicData> data(
CryptoFramer::ConstructHandshakeMessage(server_config_update));
- stream_->ProcessRawData(data->data(), data->length());
+ stream()->ProcessRawData(data->data(), data->length());
}
class QuicCryptoClientStreamStatelessTest : public ::testing::Test {
@@ -206,55 +204,50 @@ class QuicCryptoClientStreamStatelessTest : public ::testing::Test {
: server_crypto_config_(QuicCryptoServerConfig::TESTING,
QuicRandom::GetInstance()),
server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED) {
- TestClientSession* client_session = nullptr;
- QuicCryptoClientStream* client_stream = nullptr;
- SetupCryptoClientStreamForTest(server_id_,
- /* supports_stateless_rejects= */ true,
- QuicTime::Delta::FromSeconds(100000),
- &client_crypto_config_, &client_connection_,
- &client_session, &client_stream);
+ TestQuicSpdyClientSession* client_session = nullptr;
+ CreateClientSessionForTest(server_id_,
+ /* supports_stateless_rejects= */ true,
+ QuicTime::Delta::FromSeconds(100000),
+ &client_crypto_config_, &client_connection_,
+ &client_session);
CHECK(client_session);
- CHECK(client_stream);
client_session_.reset(client_session);
- client_stream_.reset(client_stream);
+ }
+
+ QuicCryptoServerStream* server_stream() {
+ return server_session_->GetCryptoStream();
}
void AdvanceHandshakeWithFakeServer() {
- client_stream_->CryptoConnect();
- CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream_.get(),
- 0, server_connection_,
- server_stream_.get(), 0);
+ client_session_->GetCryptoStream()->CryptoConnect();
+ CryptoTestUtils::AdvanceHandshake(client_connection_,
+ client_session_->GetCryptoStream(), 0,
+ server_connection_, server_stream(), 0);
}
// Initializes the server_stream_ for stateless rejects.
void InitializeFakeStatelessRejectServer() {
- TestServerSession* server_session = nullptr;
- QuicCryptoServerStream* server_stream = nullptr;
- SetupCryptoServerStreamForTest(server_id_,
- QuicTime::Delta::FromSeconds(100000),
- &server_crypto_config_, &server_connection_,
- &server_session, &server_stream);
+ TestQuicSpdyServerSession* server_session = nullptr;
+ CreateServerSessionForTest(server_id_, QuicTime::Delta::FromSeconds(100000),
+ &server_crypto_config_, &server_connection_,
+ &server_session);
CHECK(server_session);
- CHECK(server_stream);
server_session_.reset(server_session);
- server_stream_.reset(server_stream);
CryptoTestUtils::SetupCryptoServerConfigForTest(
server_connection_->clock(), server_connection_->random_generator(),
server_session_->config(), &server_crypto_config_);
- server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+ server_stream()->set_use_stateless_rejects_if_peer_supported(true);
}
// Client crypto stream state
PacketSavingConnection* client_connection_;
- scoped_ptr<TestClientSession> client_session_;
- scoped_ptr<QuicCryptoClientStream> client_stream_;
+ scoped_ptr<TestQuicSpdyClientSession> client_session_;
QuicCryptoClientConfig client_crypto_config_;
// Server crypto stream state
PacketSavingConnection* server_connection_;
- scoped_ptr<TestServerSession> server_session_;
+ scoped_ptr<TestQuicSpdyServerSession> server_session_;
QuicCryptoServerConfig server_crypto_config_;
- scoped_ptr<QuicCryptoServerStream> server_stream_;
QuicServerId server_id_;
};
@@ -271,12 +264,17 @@ TEST_F(QuicCryptoClientStreamStatelessTest, StatelessReject) {
InitializeFakeStatelessRejectServer();
AdvanceHandshakeWithFakeServer();
- EXPECT_FALSE(client_stream_->encryption_established());
- EXPECT_FALSE(client_stream_->handshake_confirmed());
+ EXPECT_EQ(1, server_stream()->num_handshake_messages());
+ EXPECT_EQ(0, server_stream()->num_handshake_messages_with_server_nonces());
+
+ EXPECT_FALSE(client_session_->GetCryptoStream()->encryption_established());
+ EXPECT_FALSE(client_session_->GetCryptoStream()->handshake_confirmed());
// Even though the handshake was not complete, the cached client_state is
// complete, and can be used for a subsequent successful handshake.
EXPECT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
+ ASSERT_TRUE(client_state->has_server_nonce());
+ ASSERT_FALSE(client_state->GetNextServerNonce().empty());
ASSERT_TRUE(client_state->has_server_designated_connection_id());
QuicConnectionId server_designated_id =
client_state->GetNextServerDesignatedConnectionId();
diff --git a/chromium/net/quic/quic_crypto_server_stream.cc b/chromium/net/quic/quic_crypto_server_stream.cc
index ec243c6f19f..dd22a8e450d 100644
--- a/chromium/net/quic/quic_crypto_server_stream.cc
+++ b/chromium/net/quic/quic_crypto_server_stream.cc
@@ -34,6 +34,7 @@ QuicCryptoServerStream::QuicCryptoServerStream(
crypto_config_(crypto_config),
validate_client_hello_cb_(nullptr),
num_handshake_messages_(0),
+ num_handshake_messages_with_server_nonces_(0),
num_server_config_update_messages_sent_(0),
use_stateless_rejects_if_peer_supported_(false),
peer_supports_stateless_rejects_(false) {
@@ -134,8 +135,8 @@ void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
// Set the decrypter immediately so that we no longer accept unencrypted
// packets.
session()->connection()->SetDecrypter(
- crypto_negotiated_params_.initial_crypters.decrypter.release(),
- ENCRYPTION_INITIAL);
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_.initial_crypters.decrypter.release());
// We want to be notified when the SHLO is ACKed so that we can disable
// HANDSHAKE_MODE in the sent packet manager.
@@ -147,8 +148,9 @@ void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
ENCRYPTION_FORWARD_SECURE,
crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
session()->connection()->SetAlternativeDecrypter(
+ ENCRYPTION_FORWARD_SECURE,
crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
- ENCRYPTION_FORWARD_SECURE, false /* don't latch */);
+ false /* don't latch */);
encryption_established_ = true;
handshake_confirmed_ = true;
@@ -227,6 +229,9 @@ QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
const ValidateClientHelloResultCallback::Result& result,
CryptoHandshakeMessage* reply,
string* error_details) {
+ if (!result.info.server_nonce.empty()) {
+ ++num_handshake_messages_with_server_nonces_;
+ }
// Store the bandwidth estimate from the client.
if (result.cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
previous_cached_network_params_.reset(
diff --git a/chromium/net/quic/quic_crypto_server_stream.h b/chromium/net/quic/quic_crypto_server_stream.h
index 27f6f958482..0a1a61a4f7a 100644
--- a/chromium/net/quic/quic_crypto_server_stream.h
+++ b/chromium/net/quic/quic_crypto_server_stream.h
@@ -68,6 +68,10 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
uint8 num_handshake_messages() const { return num_handshake_messages_; }
+ uint8 num_handshake_messages_with_server_nonces() const {
+ return num_handshake_messages_with_server_nonces_;
+ }
+
int num_server_config_update_messages_sent() const {
return num_server_config_update_messages_sent_;
}
@@ -167,6 +171,11 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
// Number of handshake messages received by this stream.
uint8 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 num_handshake_messages_with_server_nonces_;
+
// Number of server config update (SCUP) messages sent by this stream.
int num_server_config_update_messages_sent_;
diff --git a/chromium/net/quic/quic_crypto_server_stream_test.cc b/chromium/net/quic/quic_crypto_server_stream_test.cc
index 6874612dd1b..aa3828bbf67 100644
--- a/chromium/net/quic/quic_crypto_server_stream_test.cc
+++ b/chromium/net/quic/quic_crypto_server_stream_test.cc
@@ -95,34 +95,35 @@ class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> {
// Initializes the crypto server stream state for testing. May be
// called multiple times.
void InitializeServer() {
- TestServerSession* server_session = nullptr;
- QuicCryptoServerStream* server_stream = nullptr;
- SetupCryptoServerStreamForTest(server_id_,
- QuicTime::Delta::FromSeconds(100000),
- &server_crypto_config_, &server_connection_,
- &server_session, &server_stream);
+ TestQuicSpdyServerSession* server_session = nullptr;
+ CreateServerSessionForTest(server_id_, QuicTime::Delta::FromSeconds(100000),
+ &server_crypto_config_, &server_connection_,
+ &server_session);
CHECK(server_session);
- CHECK(server_stream);
server_session_.reset(server_session);
- server_stream_.reset(server_stream);
CryptoTestUtils::SetupCryptoServerConfigForTest(
server_connection_->clock(), server_connection_->random_generator(),
server_session_->config(), &server_crypto_config_);
}
+ QuicCryptoServerStream* server_stream() {
+ return server_session_->GetCryptoStream();
+ }
+
+ QuicCryptoClientStream* client_stream() {
+ return client_session_->GetCryptoStream();
+ }
+
// Initializes a fake client, and all its associated state, for
// testing. May be called multiple times.
void InitializeFakeClient(bool supports_stateless_rejects) {
- TestClientSession* client_session = nullptr;
- QuicCryptoClientStream* client_stream = nullptr;
- SetupCryptoClientStreamForTest(server_id_, supports_stateless_rejects,
- QuicTime::Delta::FromSeconds(100000),
- &client_crypto_config_, &client_connection_,
- &client_session, &client_stream);
+ TestQuicSpdyClientSession* client_session = nullptr;
+ CreateClientSessionForTest(server_id_, supports_stateless_rejects,
+ QuicTime::Delta::FromSeconds(100000),
+ &client_crypto_config_, &client_connection_,
+ &client_session);
CHECK(client_session);
- CHECK(client_stream);
client_session_.reset(client_session);
- client_stream_.reset(client_stream);
}
bool AsyncStrikeRegisterVerification() {
@@ -136,39 +137,34 @@ class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> {
int CompleteCryptoHandshake() {
CHECK(server_connection_);
- CHECK(server_stream_ != nullptr);
+ CHECK(server_session_ != nullptr);
return CryptoTestUtils::HandshakeWithFakeClient(
- server_connection_, server_stream_.get(), client_options_);
+ server_connection_, server_stream(), client_options_);
}
// Performs a single round of handshake message-exchange between the
// client and server.
void AdvanceHandshakeWithFakeClient() {
CHECK(server_connection_);
- CHECK(server_stream_ != nullptr);
CHECK(client_session_ != nullptr);
- CHECK(client_stream_ != nullptr);
EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber());
- client_stream_->CryptoConnect();
- CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream_.get(),
- 0, server_connection_,
- server_stream_.get(), 0);
+ client_stream()->CryptoConnect();
+ CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 0,
+ server_connection_, server_stream(), 0);
}
protected:
// Server state
PacketSavingConnection* server_connection_;
- scoped_ptr<TestServerSession> server_session_;
+ scoped_ptr<TestQuicSpdyServerSession> server_session_;
QuicCryptoServerConfig server_crypto_config_;
- scoped_ptr<QuicCryptoServerStream> server_stream_;
QuicServerId server_id_;
// Client state
PacketSavingConnection* client_connection_;
QuicCryptoClientConfig client_crypto_config_;
- scoped_ptr<TestClientSession> client_session_;
- scoped_ptr<QuicCryptoClientStream> client_stream_;
+ scoped_ptr<TestQuicSpdyClientSession> client_session_;
CryptoHandshakeMessage message_;
scoped_ptr<QuicData> message_data_;
@@ -179,13 +175,13 @@ class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> {
INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool());
TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) {
- EXPECT_FALSE(server_stream_->encryption_established());
- EXPECT_FALSE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
}
TEST_P(QuicCryptoServerStreamTest, NotInitiallySendingStatelessRejects) {
- EXPECT_FALSE(server_stream_->use_stateless_rejects_if_peer_supported());
- EXPECT_FALSE(server_stream_->peer_supports_stateless_rejects());
+ EXPECT_FALSE(server_stream()->use_stateless_rejects_if_peer_supported());
+ EXPECT_FALSE(server_stream()->peer_supports_stateless_rejects());
}
TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
@@ -194,27 +190,31 @@ TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
// * One to get a source-address token and certificates.
// * One to complete the handshake.
EXPECT_EQ(2, CompleteCryptoHandshake());
- EXPECT_TRUE(server_stream_->encryption_established());
- EXPECT_TRUE(server_stream_->handshake_confirmed());
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
}
TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) {
ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
true);
- server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+ server_stream()->set_use_stateless_rejects_if_peer_supported(true);
InitializeFakeClient(/* supports_stateless_rejects= */ true);
AdvanceHandshakeWithFakeClient();
// Check the server to make the sure the handshake did not succeed.
- EXPECT_FALSE(server_stream_->encryption_established());
- EXPECT_FALSE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
- // Check the client state to make sure that it received a
- // server-designated connection id.
+ // Check the client state to make sure that it received a server-designated
+ // connection id.
QuicCryptoClientConfig::CachedState* client_state =
client_crypto_config_.LookupOrCreate(server_id_);
+ ASSERT_TRUE(client_state->has_server_nonce());
+ ASSERT_FALSE(client_state->GetNextServerNonce().empty());
+ ASSERT_FALSE(client_state->has_server_nonce());
+
ASSERT_TRUE(client_state->has_server_designated_connection_id());
const QuicConnectionId server_designated_connection_id =
client_state->GetNextServerDesignatedConnectionId();
@@ -229,14 +229,16 @@ TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) {
TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) {
ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
true);
- server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+ server_stream()->set_use_stateless_rejects_if_peer_supported(true);
InitializeFakeClient(/* supports_stateless_rejects= */ true);
AdvanceHandshakeWithFakeClient();
// On the first round, encryption will not be established.
- EXPECT_FALSE(server_stream_->encryption_established());
- EXPECT_FALSE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+ EXPECT_EQ(1, server_stream()->num_handshake_messages());
+ EXPECT_EQ(0, server_stream()->num_handshake_messages_with_server_nonces());
// Now check the client state.
QuicCryptoClientConfig::CachedState* client_state =
@@ -255,58 +257,37 @@ TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) {
// Now create new client and server streams with the existing config
// and try the handshake again (0-RTT handshake).
InitializeServer();
- server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+ server_stream()->set_use_stateless_rejects_if_peer_supported(true);
InitializeFakeClient(/* supports_stateless_rejects= */ true);
- client_stream_->CryptoConnect();
- if (AsyncStrikeRegisterVerification()) {
- EXPECT_FALSE(client_stream_->handshake_confirmed());
- EXPECT_FALSE(server_stream_->handshake_confirmed());
+ client_stream()->CryptoConnect();
- // Advance the handshake. Expect that the server will be stuck
- // waiting for client nonce verification to complete.
- pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake(
- client_connection_, client_stream_.get(), 0, server_connection_,
- server_stream_.get(), 0);
- EXPECT_EQ(1u, messages_moved.first);
- EXPECT_EQ(0u, messages_moved.second);
- EXPECT_EQ(1, strike_register_client_->PendingVerifications());
- EXPECT_FALSE(client_stream_->handshake_confirmed());
- EXPECT_FALSE(server_stream_->handshake_confirmed());
-
- // The server handshake completes once the nonce verification completes.
- strike_register_client_->RunPendingVerifications();
- EXPECT_FALSE(client_stream_->handshake_confirmed());
- EXPECT_TRUE(server_stream_->handshake_confirmed());
-
- messages_moved = CryptoTestUtils::AdvanceHandshake(
- client_connection_, client_stream_.get(), messages_moved.first,
- server_connection_, server_stream_.get(), messages_moved.second);
- EXPECT_EQ(1u, messages_moved.first);
- EXPECT_EQ(1u, messages_moved.second);
- } else {
- AdvanceHandshakeWithFakeClient();
- }
+ // In the stateless case, the second handshake contains a server-nonce, so the
+ // AsyncStrikeRegisterVerification() case will still succeed (unlike a 0-RTT
+ // handshake).
+ AdvanceHandshakeWithFakeClient();
// On the second round, encryption will be established.
- EXPECT_TRUE(server_stream_->encryption_established());
- EXPECT_TRUE(server_stream_->handshake_confirmed());
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+ EXPECT_EQ(2, server_stream()->num_handshake_messages());
+ EXPECT_EQ(1, server_stream()->num_handshake_messages_with_server_nonces());
}
TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) {
ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
true);
- server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+ server_stream()->set_use_stateless_rejects_if_peer_supported(true);
- // The server is configured to use stateless rejects, but the client
- // does not support it.
+ // The server is configured to use stateless rejects, but the client does not
+ // support it.
InitializeFakeClient(/* supports_stateless_rejects= */ false);
AdvanceHandshakeWithFakeClient();
// Check the server to make the sure the handshake did not succeed.
- EXPECT_FALSE(server_stream_->encryption_established());
- EXPECT_FALSE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
// Check the client state to make sure that it did not receive a
// server-designated connection id.
@@ -329,42 +310,42 @@ TEST_P(QuicCryptoServerStreamTest, ZeroRTT) {
InitializeFakeClient(/* supports_stateless_rejects= */ false);
InitializeServer();
- client_stream_->CryptoConnect();
+ client_stream()->CryptoConnect();
if (AsyncStrikeRegisterVerification()) {
- EXPECT_FALSE(client_stream_->handshake_confirmed());
- EXPECT_FALSE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(client_stream()->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
- // Advance the handshake. Expect that the server will be stuck
- // waiting for client nonce verification to complete.
+ // Advance the handshake. Expect that the server will be stuck waiting for
+ // client nonce verification to complete.
pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake(
- client_connection_, client_stream_.get(), 0, server_connection_,
- server_stream_.get(), 0);
+ client_connection_, client_stream(), 0, server_connection_,
+ server_stream(), 0);
EXPECT_EQ(1u, messages_moved.first);
EXPECT_EQ(0u, messages_moved.second);
EXPECT_EQ(1, strike_register_client_->PendingVerifications());
- EXPECT_FALSE(client_stream_->handshake_confirmed());
- EXPECT_FALSE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(client_stream()->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
// The server handshake completes once the nonce verification completes.
strike_register_client_->RunPendingVerifications();
- EXPECT_FALSE(client_stream_->handshake_confirmed());
- EXPECT_TRUE(server_stream_->handshake_confirmed());
+ EXPECT_FALSE(client_stream()->handshake_confirmed());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
messages_moved = CryptoTestUtils::AdvanceHandshake(
- client_connection_, client_stream_.get(), messages_moved.first,
- server_connection_, server_stream_.get(), messages_moved.second);
+ client_connection_, client_stream(), messages_moved.first,
+ server_connection_, server_stream(), messages_moved.second);
EXPECT_EQ(1u, messages_moved.first);
EXPECT_EQ(1u, messages_moved.second);
- EXPECT_TRUE(client_stream_->handshake_confirmed());
- EXPECT_TRUE(server_stream_->handshake_confirmed());
+ EXPECT_TRUE(client_stream()->handshake_confirmed());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
} else {
CryptoTestUtils::CommunicateHandshakeMessages(
- client_connection_, client_stream_.get(), server_connection_,
- server_stream_.get());
+ client_connection_, client_stream(), server_connection_,
+ server_stream());
}
- EXPECT_EQ(1, client_stream_->num_sent_client_hellos());
+ EXPECT_EQ(1, client_stream()->num_sent_client_hellos());
}
TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
@@ -374,8 +355,8 @@ TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
SendConnectionClose(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
message_.set_tag(kCHLO);
ConstructHandshakeMessage();
- server_stream_->ProcessRawData(message_data_->data(),
- message_data_->length());
+ server_stream()->ProcessRawData(message_data_->data(),
+ message_data_->length());
}
TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
@@ -383,8 +364,8 @@ TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
ConstructHandshakeMessage();
EXPECT_CALL(*server_connection_,
SendConnectionClose(QUIC_INVALID_CRYPTO_MESSAGE_TYPE));
- server_stream_->ProcessRawData(message_data_->data(),
- message_data_->length());
+ server_stream()->ProcessRawData(message_data_->data(),
+ message_data_->length());
}
TEST_P(QuicCryptoServerStreamTest, WithoutCertificates) {
@@ -394,34 +375,34 @@ TEST_P(QuicCryptoServerStreamTest, WithoutCertificates) {
// Only 2 client hellos need to be sent in the no-certs case: one to get the
// source-address token and the second to finish.
EXPECT_EQ(2, CompleteCryptoHandshake());
- EXPECT_TRUE(server_stream_->encryption_established());
- EXPECT_TRUE(server_stream_->handshake_confirmed());
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
}
TEST_P(QuicCryptoServerStreamTest, ChannelID) {
client_options_.channel_id_enabled = true;
client_options_.channel_id_source_async = false;
// CompleteCryptoHandshake verifies
- // server_stream_->crypto_negotiated_params().channel_id is correct.
+ // server_stream()->crypto_negotiated_params().channel_id is correct.
EXPECT_EQ(2, CompleteCryptoHandshake());
- EXPECT_TRUE(server_stream_->encryption_established());
- EXPECT_TRUE(server_stream_->handshake_confirmed());
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
}
TEST_P(QuicCryptoServerStreamTest, ChannelIDAsync) {
client_options_.channel_id_enabled = true;
client_options_.channel_id_source_async = true;
// CompleteCryptoHandshake verifies
- // server_stream_->crypto_negotiated_params().channel_id is correct.
+ // server_stream()->crypto_negotiated_params().channel_id is correct.
EXPECT_EQ(2, CompleteCryptoHandshake());
- EXPECT_TRUE(server_stream_->encryption_established());
- EXPECT_TRUE(server_stream_->handshake_confirmed());
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
}
TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
// An attempt to send a SCUP before completing handshake should fail.
- server_stream_->SendServerConfigUpdate(nullptr);
- EXPECT_EQ(0, server_stream_->num_server_config_update_messages_sent());
+ server_stream()->SendServerConfigUpdate(nullptr);
+ EXPECT_EQ(0, server_stream()->num_server_config_update_messages_sent());
}
TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) {
diff --git a/chromium/net/quic/quic_crypto_stream_test.cc b/chromium/net/quic/quic_crypto_stream_test.cc
index 8c83e923d17..5d7001923d0 100644
--- a/chromium/net/quic/quic_crypto_stream_test.cc
+++ b/chromium/net/quic/quic_crypto_stream_test.cc
@@ -62,7 +62,7 @@ class QuicCryptoStreamTest : public ::testing::Test {
protected:
MockConnection* connection_;
- MockSession session_;
+ MockQuicSpdySession session_;
MockQuicCryptoStream stream_;
CryptoHandshakeMessage message_;
scoped_ptr<QuicData> message_data_;
diff --git a/chromium/net/quic/quic_data_stream.cc b/chromium/net/quic/quic_data_stream.cc
index a817b5b3571..4b24c990006 100644
--- a/chromium/net/quic/quic_data_stream.cc
+++ b/chromium/net/quic/quic_data_stream.cc
@@ -5,7 +5,7 @@
#include "net/quic/quic_data_stream.h"
#include "base/logging.h"
-#include "net/quic/quic_session.h"
+#include "net/quic/quic_spdy_session.h"
#include "net/quic/quic_utils.h"
#include "net/quic/quic_write_blocked_list.h"
@@ -28,8 +28,9 @@ QuicPriority kDefaultPriority = 3;
} // namespace
-QuicDataStream::QuicDataStream(QuicStreamId id, QuicSession* session)
- : ReliableQuicStream(id, session),
+QuicDataStream::QuicDataStream(QuicStreamId id, QuicSpdySession* spdy_session)
+ : ReliableQuicStream(id, spdy_session),
+ spdy_session_(spdy_session),
visitor_(nullptr),
headers_decompressed_(false),
priority_(kDefaultPriority) {
@@ -46,7 +47,7 @@ size_t QuicDataStream::WriteHeaders(
const SpdyHeaderBlock& header_block,
bool fin,
QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
- size_t bytes_written = session()->WriteHeaders(
+ size_t bytes_written = spdy_session_->WriteHeaders(
id(), header_block, fin, priority_, ack_notifier_delegate);
if (fin) {
// TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent.
@@ -57,42 +58,13 @@ size_t QuicDataStream::WriteHeaders(
}
size_t QuicDataStream::Readv(const struct iovec* iov, size_t iov_len) {
- if (FinishedReadingHeaders()) {
- // If the headers have been read, simply delegate to the sequencer's
- // Readv method.
- return sequencer()->Readv(iov, iov_len);
- }
- // Otherwise, copy decompressed header data into |iov|.
- size_t bytes_consumed = 0;
- size_t iov_index = 0;
- while (iov_index < iov_len &&
- decompressed_headers_.length() > bytes_consumed) {
- size_t bytes_to_read = min(iov[iov_index].iov_len,
- decompressed_headers_.length() - bytes_consumed);
- char* iov_ptr = static_cast<char*>(iov[iov_index].iov_base);
- memcpy(iov_ptr,
- decompressed_headers_.data() + bytes_consumed, bytes_to_read);
- bytes_consumed += bytes_to_read;
- ++iov_index;
- }
- decompressed_headers_.erase(0, bytes_consumed);
- if (FinishedReadingHeaders()) {
- sequencer()->FlushBufferedFrames();
- }
- return bytes_consumed;
+ DCHECK(FinishedReadingHeaders());
+ return sequencer()->Readv(iov, iov_len);
}
-int QuicDataStream::GetReadableRegions(iovec* iov, size_t iov_len) {
- if (FinishedReadingHeaders()) {
- return sequencer()->GetReadableRegions(iov, iov_len);
- }
- if (iov_len == 0) {
- return 0;
- }
- iov[0].iov_base = static_cast<void*>(
- const_cast<char*>(decompressed_headers_.data()));
- iov[0].iov_len = decompressed_headers_.length();
- return 1;
+int QuicDataStream::GetReadableRegions(iovec* iov, size_t iov_len) const {
+ DCHECK(FinishedReadingHeaders());
+ return sequencer()->GetReadableRegions(iov, iov_len);
}
bool QuicDataStream::IsDoneReading() const {
@@ -106,6 +78,13 @@ bool QuicDataStream::HasBytesToRead() const {
return !decompressed_headers_.empty() || sequencer()->HasBytesToRead();
}
+void QuicDataStream::MarkHeadersConsumed(size_t bytes_consumed) {
+ decompressed_headers_.erase(0, bytes_consumed);
+ if (FinishedReadingHeaders()) {
+ sequencer()->FlushBufferedFrames();
+ }
+}
+
void QuicDataStream::set_priority(QuicPriority priority) {
DCHECK_EQ(0u, stream_bytes_written());
priority_ = priority;
@@ -123,24 +102,8 @@ uint32 QuicDataStream::ProcessRawData(const char* data, uint32 data_len) {
return ProcessData(data, data_len);
}
-uint32 QuicDataStream::ProcessHeaderData() {
- if (decompressed_headers_.empty()) {
- return 0;
- }
-
- size_t bytes_processed = ProcessData(decompressed_headers_.data(),
- decompressed_headers_.length());
- if (bytes_processed == decompressed_headers_.length()) {
- decompressed_headers_.clear();
- } else {
- decompressed_headers_ = decompressed_headers_.erase(0, bytes_processed);
- }
- return bytes_processed;
-}
-
void QuicDataStream::OnStreamHeaders(StringPiece headers_data) {
headers_data.AppendToString(&decompressed_headers_);
- ProcessHeaderData();
}
void QuicDataStream::OnStreamHeadersPriority(QuicPriority priority) {
@@ -151,9 +114,8 @@ void QuicDataStream::OnStreamHeadersPriority(QuicPriority priority) {
void QuicDataStream::OnStreamHeadersComplete(bool fin, size_t frame_len) {
headers_decompressed_ = true;
if (fin) {
- sequencer()->OnStreamFrame(QuicStreamFrame(id(), fin, 0, IOVector()));
+ sequencer()->OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece()));
}
- ProcessHeaderData();
if (FinishedReadingHeaders()) {
sequencer()->FlushBufferedFrames();
}
@@ -171,7 +133,7 @@ void QuicDataStream::OnClose() {
}
}
-bool QuicDataStream::FinishedReadingHeaders() {
+bool QuicDataStream::FinishedReadingHeaders() const {
return headers_decompressed_ && decompressed_headers_.empty();
}
diff --git a/chromium/net/quic/quic_data_stream.h b/chromium/net/quic/quic_data_stream.h
index aa4a7c3dc44..60356a142ba 100644
--- a/chromium/net/quic/quic_data_stream.h
+++ b/chromium/net/quic/quic_data_stream.h
@@ -32,9 +32,9 @@ class QuicDataStreamPeer;
class ReliableQuicStreamPeer;
} // namespace test
-class QuicSession;
+class QuicSpdySession;
-// All this does right now is send data to subclasses via the sequencer.
+// A QUIC data stream that can also send and receive headers.
class NET_EXPORT_PRIVATE QuicDataStream : public ReliableQuicStream {
public:
// Visitor receives callbacks from the stream.
@@ -52,13 +52,13 @@ class NET_EXPORT_PRIVATE QuicDataStream : public ReliableQuicStream {
DISALLOW_COPY_AND_ASSIGN(Visitor);
};
- QuicDataStream(QuicStreamId id, QuicSession* session);
-
+ QuicDataStream(QuicStreamId id, QuicSpdySession* spdy_session);
~QuicDataStream() override;
// ReliableQuicStream implementation
void OnClose() override;
uint32 ProcessRawData(const char* data, uint32 data_len) override;
+
// By default, this is the same as priority(), however it allows streams
// to temporarily alter effective priority. For example if a SPDY stream has
// compressed but not written headers it can write the headers with a higher
@@ -91,19 +91,26 @@ class NET_EXPORT_PRIVATE QuicDataStream : public ReliableQuicStream {
bool fin,
QuicAckNotifier::DelegateInterface* ack_notifier_delegate);
+ // Marks |bytes_consumed| of the headers data as consumed.
+ void MarkHeadersConsumed(size_t bytes_consumed);
+
// This block of functions wraps the sequencer's functions of the same
// name. These methods return uncompressed data until that has
// been fully processed. Then they simply delegate to the sequencer.
virtual size_t Readv(const struct iovec* iov, size_t iov_len);
- virtual int GetReadableRegions(iovec* iov, size_t iov_len);
+ virtual int GetReadableRegions(iovec* iov, size_t iov_len) const;
// Returns true when all data has been read from the peer, including the fin.
- virtual bool IsDoneReading() const;
- virtual bool HasBytesToRead() const;
+ bool IsDoneReading() const;
+ bool HasBytesToRead() const;
void set_visitor(Visitor* visitor) { visitor_ = visitor; }
bool headers_decompressed() const { return headers_decompressed_; }
+ const std::string& decompressed_headers() const {
+ return decompressed_headers_;
+ }
+
protected:
// Sets priority_ to priority. This should only be called before bytes are
// written to the server.
@@ -112,17 +119,17 @@ class NET_EXPORT_PRIVATE QuicDataStream : public ReliableQuicStream {
// instead.
QuicPriority priority() const { return priority_; }
+ bool FinishedReadingHeaders() const;
+
private:
friend class test::QuicDataStreamPeer;
friend class test::ReliableQuicStreamPeer;
friend class QuicStreamUtils;
- uint32 ProcessHeaderData();
-
- bool FinishedReadingHeaders();
+ QuicSpdySession* spdy_session_;
Visitor* visitor_;
- // True if the headers have been completely decompresssed.
+ // True if the headers have been completely decompressed.
bool headers_decompressed_;
// The priority of the stream, once parsed.
QuicPriority priority_;
diff --git a/chromium/net/quic/quic_data_stream_test.cc b/chromium/net/quic/quic_data_stream_test.cc
index 55fab6be427..e063367bc81 100644
--- a/chromium/net/quic/quic_data_stream_test.cc
+++ b/chromium/net/quic/quic_data_stream_test.cc
@@ -35,7 +35,7 @@ const bool kShouldProcessData = true;
class TestStream : public QuicDataStream {
public:
TestStream(QuicStreamId id,
- QuicSession* session,
+ QuicSpdySession* session,
bool should_process_data)
: QuicDataStream(id, session),
should_process_data_(should_process_data) {}
@@ -93,7 +93,7 @@ class QuicDataStreamTest : public ::testing::TestWithParam<QuicVersion> {
void Initialize(bool stream_should_process_data) {
connection_ = new testing::StrictMock<MockConnection>(
Perspective::IS_SERVER, SupportedVersions(GetParam()));
- session_.reset(new testing::StrictMock<MockSession>(connection_));
+ session_.reset(new testing::StrictMock<MockQuicSpdySession>(connection_));
stream_.reset(new TestStream(kClientDataStreamId1, session_.get(),
stream_should_process_data));
stream2_.reset(new TestStream(kClientDataStreamId2, session_.get(),
@@ -104,7 +104,7 @@ class QuicDataStreamTest : public ::testing::TestWithParam<QuicVersion> {
protected:
MockConnection* connection_;
- scoped_ptr<MockSession> session_;
+ scoped_ptr<MockQuicSpdySession> session_;
scoped_ptr<TestStream> stream_;
scoped_ptr<TestStream> stream2_;
SpdyHeaderBlock headers_;
@@ -121,13 +121,34 @@ TEST_P(QuicDataStreamTest, ProcessHeaders) {
SpdyUtils::SerializeUncompressedHeaders(headers_, GetParam());
stream_->OnStreamHeadersPriority(QuicUtils::HighestPriority());
stream_->OnStreamHeaders(headers);
- EXPECT_EQ(headers, stream_->data());
+ EXPECT_EQ("", stream_->data());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
stream_->OnStreamHeadersComplete(false, headers.size());
EXPECT_EQ(QuicUtils::HighestPriority(), stream_->EffectivePriority());
- EXPECT_EQ(headers, stream_->data());
+ EXPECT_EQ("", stream_->data());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
EXPECT_FALSE(stream_->IsDoneReading());
}
+TEST_P(QuicDataStreamTest, MarkHeadersConsumed) {
+ Initialize(kShouldProcessData);
+
+ string headers =
+ SpdyUtils::SerializeUncompressedHeaders(headers_, GetParam());
+ string body = "this is the body";
+
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+
+ headers.erase(0, 10);
+ stream_->MarkHeadersConsumed(10);
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+
+ stream_->MarkHeadersConsumed(headers.length());
+ EXPECT_EQ("", stream_->decompressed_headers());
+}
+
TEST_P(QuicDataStreamTest, ProcessHeadersAndBody) {
Initialize(kShouldProcessData);
@@ -136,12 +157,15 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBody) {
string body = "this is the body";
stream_->OnStreamHeaders(headers);
- EXPECT_EQ(headers, stream_->data());
+ EXPECT_EQ("", stream_->data());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+ stream_->MarkHeadersConsumed(headers.length());
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
stream_->OnStreamFrame(frame);
-
- EXPECT_EQ(headers + body, stream_->data());
+ EXPECT_EQ("", stream_->decompressed_headers());
+ EXPECT_EQ(body, stream_->data());
}
TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyFragments) {
@@ -160,16 +184,18 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyFragments) {
stream_->OnStreamHeaders(fragment);
}
stream_->OnStreamHeadersComplete(false, headers.size());
+ ASSERT_EQ(headers, stream_->decompressed_headers())
+ << "fragment_size: " << fragment_size;
+ stream_->MarkHeadersConsumed(headers.length());
for (size_t offset = 0; offset < body.size(); offset += fragment_size) {
size_t remaining_data = body.size() - offset;
StringPiece fragment(body.data() + offset,
min(fragment_size, remaining_data));
QuicStreamFrame frame(kClientDataStreamId1, false, offset,
- MakeIOVector(fragment));
+ StringPiece(fragment));
stream_->OnStreamFrame(frame);
}
- ASSERT_EQ(headers + body,
- stream_->data()) << "fragment_size: " << fragment_size;
+ ASSERT_EQ(body, stream_->data()) << "fragment_size: " << fragment_size;
}
}
@@ -187,20 +213,22 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyFragmentsSplit) {
headers.size() - split_point);
stream_->OnStreamHeaders(headers2);
stream_->OnStreamHeadersComplete(false, headers.size());
+ ASSERT_EQ(headers, stream_->decompressed_headers())
+ << "split_point: " << split_point;
+ stream_->MarkHeadersConsumed(headers.length());
StringPiece fragment1(body.data(), split_point);
QuicStreamFrame frame1(kClientDataStreamId1, false, 0,
- MakeIOVector(fragment1));
+ StringPiece(fragment1));
stream_->OnStreamFrame(frame1);
StringPiece fragment2(body.data() + split_point,
body.size() - split_point);
QuicStreamFrame frame2(kClientDataStreamId1, false, split_point,
- MakeIOVector(fragment2));
+ StringPiece(fragment2));
stream_->OnStreamFrame(frame2);
- ASSERT_EQ(headers + body,
- stream_->data()) << "split_point: " << split_point;
+ ASSERT_EQ(body, stream_->data()) << "split_point: " << split_point;
}
}
@@ -212,22 +240,18 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyReadv) {
string body = "this is the body";
stream_->OnStreamHeaders(headers);
- EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
stream_->OnStreamFrame(frame);
+ stream_->MarkHeadersConsumed(headers.length());
char buffer[2048];
- ASSERT_LT(headers.length() + body.length(), arraysize(buffer));
+ ASSERT_LT(body.length(), arraysize(buffer));
struct iovec vec;
vec.iov_base = buffer;
vec.iov_len = arraysize(buffer);
size_t bytes_read = stream_->Readv(&vec, 1);
- EXPECT_EQ(headers.length(), bytes_read);
- EXPECT_EQ(headers, string(buffer, bytes_read));
-
- bytes_read = stream_->Readv(&vec, 1);
EXPECT_EQ(body.length(), bytes_read);
EXPECT_EQ(body, string(buffer, bytes_read));
}
@@ -239,21 +263,20 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyIncrementalReadv) {
SpdyUtils::SerializeUncompressedHeaders(headers_, GetParam());
string body = "this is the body";
stream_->OnStreamHeaders(headers);
- EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
stream_->OnStreamFrame(frame);
+ stream_->MarkHeadersConsumed(headers.length());
char buffer[1];
struct iovec vec;
vec.iov_base = buffer;
vec.iov_len = arraysize(buffer);
- string data = headers + body;
- for (size_t i = 0; i < data.length(); ++i) {
+ for (size_t i = 0; i < body.length(); ++i) {
size_t bytes_read = stream_->Readv(&vec, 1);
ASSERT_EQ(1u, bytes_read);
- EXPECT_EQ(data.data()[i], buffer[0]);
+ EXPECT_EQ(body.data()[i], buffer[0]);
}
}
@@ -264,10 +287,10 @@ TEST_P(QuicDataStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) {
SpdyUtils::SerializeUncompressedHeaders(headers_, GetParam());
string body = "this is the body";
stream_->OnStreamHeaders(headers);
- EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
stream_->OnStreamFrame(frame);
+ stream_->MarkHeadersConsumed(headers.length());
char buffer1[1];
char buffer2[1];
@@ -276,12 +299,12 @@ TEST_P(QuicDataStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) {
vec[0].iov_len = arraysize(buffer1);
vec[1].iov_base = buffer2;
vec[1].iov_len = arraysize(buffer2);
- string data = headers + body;
- for (size_t i = 0; i < data.length(); i += 2) {
+
+ for (size_t i = 0; i < body.length(); i += 2) {
size_t bytes_read = stream_->Readv(vec, 2);
ASSERT_EQ(2u, bytes_read) << i;
- ASSERT_EQ(data.data()[i], buffer1[0]) << i;
- ASSERT_EQ(data.data()[i + 1], buffer2[0]) << i;
+ ASSERT_EQ(body.data()[i], buffer1[0]) << i;
+ ASSERT_EQ(body.data()[i + 1], buffer2[0]) << i;
}
}
@@ -345,10 +368,9 @@ TEST_P(QuicDataStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) {
string body;
GenerateBody(&body, kWindow / 3);
stream_->OnStreamHeaders(headers);
- EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame1(kClientDataStreamId1, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
stream_->OnStreamFrame(frame1);
EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize(
stream_->flow_controller()));
@@ -357,7 +379,7 @@ TEST_P(QuicDataStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) {
// half full. This should all be buffered, decreasing the receive window but
// not sending WINDOW_UPDATE.
QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3,
- MakeIOVector(body));
+ StringPiece(body));
stream_->OnStreamFrame(frame2);
EXPECT_EQ(
kWindow - (2 * kWindow / 3),
@@ -385,10 +407,10 @@ TEST_P(QuicDataStreamTest, StreamFlowControlWindowUpdate) {
string body;
GenerateBody(&body, kWindow / 3);
stream_->OnStreamHeaders(headers);
- EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
+ stream_->MarkHeadersConsumed(headers.length());
- QuicStreamFrame frame1(kClientDataStreamId1, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
stream_->OnStreamFrame(frame1);
EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize(
stream_->flow_controller()));
@@ -398,7 +420,7 @@ TEST_P(QuicDataStreamTest, StreamFlowControlWindowUpdate) {
// offset and send a WINDOW_UPDATE. The result will be again an available
// window of kWindow bytes.
QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3,
- MakeIOVector(body));
+ StringPiece(body));
EXPECT_CALL(*connection_,
SendWindowUpdate(kClientDataStreamId1,
QuicFlowControllerPeer::ReceiveWindowOffset(
@@ -435,16 +457,18 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlWindowUpdate) {
SpdyUtils::SerializeUncompressedHeaders(headers_, GetParam());
stream_->OnStreamHeaders(headers);
stream_->OnStreamHeadersComplete(false, headers.size());
+ stream_->MarkHeadersConsumed(headers.length());
stream2_->OnStreamHeaders(headers);
stream2_->OnStreamHeadersComplete(false, headers.size());
+ stream2_->MarkHeadersConsumed(headers.length());
// Each stream gets a quarter window of data. This should not trigger a
// WINDOW_UPDATE for either stream, nor for the connection.
string body;
GenerateBody(&body, kWindow / 4);
- QuicStreamFrame frame1(kClientDataStreamId1, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
stream_->OnStreamFrame(frame1);
- QuicStreamFrame frame2(kClientDataStreamId2, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame2(kClientDataStreamId2, false, 0, StringPiece(body));
stream2_->OnStreamFrame(frame2);
// Now receive a further single byte on one stream - again this does not
@@ -457,7 +481,7 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlWindowUpdate) {
session_->flow_controller()) +
1 + kWindow / 2));
QuicStreamFrame frame3(kClientDataStreamId1, false, (kWindow / 4),
- MakeIOVector("a"));
+ StringPiece("a"));
stream_->OnStreamFrame(frame3);
}
@@ -477,13 +501,12 @@ TEST_P(QuicDataStreamTest, StreamFlowControlViolation) {
string headers =
SpdyUtils::SerializeUncompressedHeaders(headers_, GetParam());
stream_->OnStreamHeaders(headers);
- EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
// Receive data to overflow the window, violating flow control.
string body;
GenerateBody(&body, kWindow + 1);
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
EXPECT_CALL(*connection_,
SendConnectionClose(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA));
stream_->OnStreamFrame(frame);
@@ -509,14 +532,13 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlViolation) {
string headers =
SpdyUtils::SerializeUncompressedHeaders(headers_, GetParam());
stream_->OnStreamHeaders(headers);
- EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
// Send enough data to overflow the connection level flow control window.
string body;
GenerateBody(&body, kConnectionWindow + 1);
EXPECT_LT(body.size(), kStreamWindow);
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
EXPECT_CALL(*connection_,
SendConnectionClose(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA));
diff --git a/chromium/net/quic/quic_data_writer.cc b/chromium/net/quic/quic_data_writer.cc
index 4ebfab07da5..49257829389 100644
--- a/chromium/net/quic/quic_data_writer.cc
+++ b/chromium/net/quic/quic_data_writer.cc
@@ -4,6 +4,7 @@
#include "net/quic/quic_data_writer.h"
+#include <stdint.h>
#include <algorithm>
#include <limits>
@@ -47,7 +48,7 @@ bool QuicDataWriter::WriteUInt64(uint64 value) {
bool QuicDataWriter::WriteUFloat16(uint64 value) {
uint16 result;
- if (value < (GG_UINT64_C(1) << kUFloat16MantissaEffectiveBits)) {
+ if (value < (UINT64_C(1) << kUFloat16MantissaEffectiveBits)) {
// Fast path: either the value is denormalized, or has exponent zero.
// Both cases are represented by the value itself.
result = static_cast<uint16>(value);
@@ -64,7 +65,7 @@ bool QuicDataWriter::WriteUFloat16(uint64 value) {
// Right-shift the value until the highest bit is in position 11.
// For offset of 16, 8, 4, 2 and 1 (binary search over 1-30),
// shift if the bit is at or above 11 + offset.
- if (value >= (GG_UINT64_C(1) << (kUFloat16MantissaBits + offset))) {
+ if (value >= (UINT64_C(1) << (kUFloat16MantissaBits + offset))) {
exponent += offset;
value >>= offset;
}
@@ -72,8 +73,8 @@ bool QuicDataWriter::WriteUFloat16(uint64 value) {
DCHECK_GE(exponent, 1);
DCHECK_LE(exponent, kUFloat16MaxExponent);
- DCHECK_GE(value, GG_UINT64_C(1) << kUFloat16MantissaBits);
- DCHECK_LT(value, GG_UINT64_C(1) << kUFloat16MantissaEffectiveBits);
+ DCHECK_GE(value, UINT64_C(1) << kUFloat16MantissaBits);
+ DCHECK_LT(value, UINT64_C(1) << kUFloat16MantissaEffectiveBits);
// Hidden bit (position 11) is set. We should remove it and increment the
// exponent. Equivalently, we just add it to the exponent.
@@ -94,18 +95,6 @@ bool QuicDataWriter::WriteStringPiece16(StringPiece val) {
return WriteBytes(val.data(), val.size());
}
-bool QuicDataWriter::WriteIOVector(const IOVector& data) {
- char *dest = BeginWrite(data.TotalBufferSize());
- if (!dest) {
- return false;
- }
- for (size_t i = 0; i < data.Size(); ++i) {
- WriteBytes(data.iovec()[i].iov_base, data.iovec()[i].iov_len);
- }
-
- return true;
-}
-
char* QuicDataWriter::BeginWrite(size_t length) {
if (length_ > capacity_) {
return nullptr;
diff --git a/chromium/net/quic/quic_data_writer.h b/chromium/net/quic/quic_data_writer.h
index 762c3aaee49..0f1df204654 100644
--- a/chromium/net/quic/quic_data_writer.h
+++ b/chromium/net/quic/quic_data_writer.h
@@ -10,7 +10,6 @@
#include "base/basictypes.h"
#include "base/logging.h"
-#include "base/port.h"
#include "base/strings/string_piece.h"
#include "net/base/int128.h"
#include "net/base/net_export.h"
@@ -49,7 +48,6 @@ class NET_EXPORT_PRIVATE QuicDataWriter {
// not be represented directly are rounded down.
bool WriteUFloat16(uint64 value);
bool WriteStringPiece16(base::StringPiece val);
- bool WriteIOVector(const IOVector& data);
bool WriteBytes(const void* data, size_t data_len);
bool WriteRepeatedByte(uint8 byte, size_t count);
// Fills the remaining buffer with null characters.
diff --git a/chromium/net/quic/quic_data_writer_test.cc b/chromium/net/quic/quic_data_writer_test.cc
index a7ac2a8ea41..d34e5cef570 100644
--- a/chromium/net/quic/quic_data_writer_test.cc
+++ b/chromium/net/quic/quic_data_writer_test.cc
@@ -4,6 +4,8 @@
#include "net/quic/quic_data_writer.h"
+#include <stdint.h>
+
#include "base/memory/scoped_ptr.h"
#include "net/quic/quic_data_reader.h"
#include "net/test/gtest_util.h"
@@ -19,7 +21,7 @@ TEST(QuicDataWriterTest, SanityCheckUFloat16Consts) {
EXPECT_EQ(30, kUFloat16MaxExponent);
EXPECT_EQ(11, kUFloat16MantissaBits);
EXPECT_EQ(12, kUFloat16MantissaEffectiveBits);
- EXPECT_EQ(GG_UINT64_C(0x3FFC0000000), kUFloat16MaxValue);
+ EXPECT_EQ(UINT64_C(0x3FFC0000000), kUFloat16MaxValue);
}
TEST(QuicDataWriterTest, WriteUFloat16) {
@@ -118,7 +120,7 @@ TEST(QuicDataWriterTest, RoundTripUFloat16) {
if (i > 2000)
EXPECT_GT(previous_value * 1005, value * 1000);
// Check we're always within the promised range.
- EXPECT_LT(value, GG_UINT64_C(0x3FFC0000000));
+ EXPECT_LT(value, UINT64_C(0x3FFC0000000));
previous_value = value;
char buffer[6];
QuicDataWriter writer(6, buffer);
diff --git a/chromium/net/quic/quic_default_packet_writer.cc b/chromium/net/quic/quic_default_packet_writer.cc
index aea9e9bf912..2fdb27ac1d9 100644
--- a/chromium/net/quic/quic_default_packet_writer.cc
+++ b/chromium/net/quic/quic_default_packet_writer.cc
@@ -6,7 +6,7 @@
#include "base/location.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
diff --git a/chromium/net/quic/quic_flags.cc b/chromium/net/quic/quic_flags.cc
index cf3b2629363..6c4a082a9ae 100644
--- a/chromium/net/quic/quic_flags.cc
+++ b/chromium/net/quic/quic_flags.cc
@@ -40,8 +40,24 @@ int64 FLAGS_quic_time_wait_list_seconds = 5;
int64 FLAGS_quic_time_wait_list_max_connections = 50000;
// Enables server-side support for QUIC stateless rejects.
-bool FLAGS_enable_quic_stateless_reject_support = false;
+bool FLAGS_enable_quic_stateless_reject_support = true;
-// If true, stop processing quic data as soon as the connection is closed rather
-// than processing a full packet.
-bool FLAGS_quic_stop_early = true;
+// If true, flow controller may grow the receive window size if necessary.
+bool FLAGS_quic_auto_tune_receive_window = true;
+
+// Don't ack acks in QUIC, even when there is a recent missing packet.
+bool FLAGS_quic_dont_ack_acks = true;
+
+// Enables sending of FEC packet only when FEC alarm goes off.
+bool FLAGS_quic_send_fec_packet_only_on_fec_alarm = true;
+
+// Change from using IsPacketRemovable to IsPacketUseless in
+// QuicUnackedPacketMap.
+bool FLAGS_quic_use_is_useless_packet = true;
+
+// Delay setting QUIC's retransmission alarm until an ack is fully
+// processed or a write is complete.
+bool FLAGS_quic_delay_retransmission_alarm = true;
+
+// Enables server-side path MTU discovery in QUIC.
+bool FLAGS_quic_do_path_mtu_discovery = true;
diff --git a/chromium/net/quic/quic_flags.h b/chromium/net/quic/quic_flags.h
index 30bf0ae865e..f54d079ed31 100644
--- a/chromium/net/quic/quic_flags.h
+++ b/chromium/net/quic/quic_flags.h
@@ -18,6 +18,11 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_too_many_outstanding_packets;
NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_seconds;
NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_max_connections;
NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_stateless_reject_support;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_stop_early;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_auto_tune_receive_window;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_dont_ack_acks;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_send_fec_packet_only_on_fec_alarm;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_is_useless_packet;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_delay_retransmission_alarm;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_do_path_mtu_discovery;
#endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/chromium/net/quic/quic_flow_controller.cc b/chromium/net/quic/quic_flow_controller.cc
index af79b956434..699f836d20d 100644
--- a/chromium/net/quic/quic_flow_controller.cc
+++ b/chromium/net/quic/quic_flow_controller.cc
@@ -11,6 +11,11 @@
namespace net {
+namespace {
+const QuicByteCount kStreamReceiveWindowLimit = 16 * 1024 * 1024; // 16 MB
+const QuicByteCount kSessionReceiveWindowLimit = 24 * 1024 * 1024; // 24 MB
+}
+
#define ENDPOINT \
(perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
@@ -19,22 +24,28 @@ QuicFlowController::QuicFlowController(QuicConnection* connection,
Perspective perspective,
QuicStreamOffset send_window_offset,
QuicStreamOffset receive_window_offset,
- QuicByteCount max_receive_window)
+ bool should_auto_tune_receive_window)
: connection_(connection),
id_(id),
perspective_(perspective),
- bytes_consumed_(0),
- highest_received_byte_offset_(0),
bytes_sent_(0),
send_window_offset_(send_window_offset),
+ bytes_consumed_(0),
+ highest_received_byte_offset_(0),
receive_window_offset_(receive_window_offset),
- max_receive_window_(max_receive_window),
- last_blocked_send_window_offset_(0) {
+ receive_window_size_(receive_window_offset),
+ auto_tune_receive_window_(should_auto_tune_receive_window),
+ last_blocked_send_window_offset_(0),
+ prev_window_update_time_(QuicTime::Zero()) {
+ receive_window_size_limit_ = (id_ == kConnectionLevelId)
+ ? kSessionReceiveWindowLimit
+ : kStreamReceiveWindowLimit;
+
DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_
<< ", setting initial receive window offset to: "
<< receive_window_offset_
- << ", max receive window to: "
- << max_receive_window_
+ << ", max receive window to: " << receive_window_size_
+ << ", max receive window limit to: " << receive_window_size_limit_
<< ", setting send window offset to: " << send_window_offset_;
}
@@ -87,28 +98,102 @@ bool QuicFlowController::FlowControlViolation() {
return false;
}
+void QuicFlowController::MaybeIncreaseMaxWindowSize() {
+ // Core of receive window auto tuning. This method should be called before a
+ // WINDOW_UPDATE frame is sent. Ideally, window updates should occur close to
+ // once per RTT. If a window update happens much faster than RTT, it implies
+ // that the flow control window is imposing a bottleneck. To prevent this,
+ // this method will increase the receive window size (subject to a reasonable
+ // upper bound). For simplicity this algorithm is deliberately asymmetric, in
+ // that it may increase window size but never decreases.
+
+ if (!FLAGS_quic_auto_tune_receive_window) {
+ return;
+ }
+
+ // Keep track of timing between successive window updates.
+ QuicTime now = connection_->clock()->ApproximateNow();
+ QuicTime prev = prev_window_update_time_;
+ prev_window_update_time_ = now;
+ if (!prev.IsInitialized()) {
+ DVLOG(1) << ENDPOINT << "first window update for stream " << id_;
+ return;
+ }
+
+ if (!auto_tune_receive_window_) {
+ return;
+ }
+
+ // Get outbound RTT.
+ QuicTime::Delta rtt =
+ connection_->sent_packet_manager().GetRttStats()->smoothed_rtt();
+ if (rtt.IsZero()) {
+ DVLOG(1) << ENDPOINT << "rtt zero for stream " << id_;
+ return;
+ }
+
+ // Now we can compare timing of window updates with RTT.
+ QuicTime::Delta since_last = now.Subtract(prev);
+ QuicTime::Delta two_rtt = rtt.Multiply(2);
+
+ if (since_last >= two_rtt) {
+ // If interval between window updates is sufficiently large, there
+ // is no need to increase receive_window_size_.
+ return;
+ }
+
+ QuicByteCount old_window = receive_window_size_;
+ receive_window_size_ *= 2;
+ receive_window_size_ =
+ std::min(receive_window_size_, receive_window_size_limit_);
+
+ if (receive_window_size_ > old_window) {
+ DVLOG(1) << ENDPOINT << "New max window increase for stream " << id_
+ << " after " << since_last.ToMicroseconds() << " us, and RTT is "
+ << rtt.ToMicroseconds()
+ << "us. max wndw: " << receive_window_size_;
+ } else {
+ // TODO(ckrasic) - add a varz to track this (?).
+ DVLOG(1) << ENDPOINT << "Max window at limit for stream " << id_
+ << " after " << since_last.ToMicroseconds() << " us, and RTT is "
+ << rtt.ToMicroseconds()
+ << "us. Limit size: " << receive_window_size_;
+ }
+}
+
+QuicByteCount QuicFlowController::WindowUpdateThreshold() {
+ return receive_window_size_ / 2;
+}
+
void QuicFlowController::MaybeSendWindowUpdate() {
// Send WindowUpdate to increase receive window if
// (receive window offset - consumed bytes) < (max window / 2).
// This is behaviour copied from SPDY.
- DCHECK_LT(bytes_consumed_, receive_window_offset_);
+ DCHECK_LE(bytes_consumed_, receive_window_offset_);
QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_;
- QuicByteCount threshold = (max_receive_window_ / 2);
-
- if (available_window < threshold) {
- // Update our receive window.
- receive_window_offset_ += (max_receive_window_ - available_window);
+ QuicByteCount threshold = WindowUpdateThreshold();
- DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
- << ", consumed bytes: " << bytes_consumed_
+ if (available_window >= threshold) {
+ DVLOG(1) << ENDPOINT << "Not sending WindowUpdate for stream " << id_
<< ", available window: " << available_window
- << ", and threshold: " << threshold
- << ", and max recvw: " << max_receive_window_
- << ". New receive window offset is: " << receive_window_offset_;
-
- // Inform the peer of our new receive window.
- connection_->SendWindowUpdate(id_, receive_window_offset_);
+ << ">= threshold: " << threshold;
+ return;
}
+
+ MaybeIncreaseMaxWindowSize();
+
+ // Update our receive window.
+ receive_window_offset_ += (receive_window_size_ - available_window);
+
+ DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
+ << ", consumed bytes: " << bytes_consumed_
+ << ", available window: " << available_window
+ << ", and threshold: " << threshold
+ << ", and receive window size: " << receive_window_size_
+ << ". New receive window offset is: " << receive_window_offset_;
+
+ // Inform the peer of our new receive window.
+ connection_->SendWindowUpdate(id_, receive_window_offset_);
}
void QuicFlowController::MaybeSendBlocked() {
diff --git a/chromium/net/quic/quic_flow_controller.h b/chromium/net/quic/quic_flow_controller.h
index afa022b1cf2..f1973f2cb56 100644
--- a/chromium/net/quic/quic_flow_controller.h
+++ b/chromium/net/quic/quic_flow_controller.h
@@ -30,7 +30,8 @@ class NET_EXPORT_PRIVATE QuicFlowController {
Perspective perspective,
QuicStreamOffset send_window_offset,
QuicStreamOffset receive_window_offset,
- QuicByteCount max_receive_window);
+ bool should_auto_tune_receive_window);
+
~QuicFlowController() {}
// Called when we see a new highest received byte offset from the peer, either
@@ -68,12 +69,26 @@ class NET_EXPORT_PRIVATE QuicFlowController {
return highest_received_byte_offset_;
}
+ void set_receive_window_size_limit(QuicByteCount receive_window_size_limit) {
+ DCHECK_GE(receive_window_size_limit, receive_window_size_limit_);
+ receive_window_size_limit_ = receive_window_size_limit;
+ }
+
+ void set_auto_tune_receive_window(bool enable) {
+ auto_tune_receive_window_ = enable;
+ }
+
+ bool auto_tune_receive_window() { return auto_tune_receive_window_; }
+
private:
friend class test::QuicFlowControllerPeer;
// Send a WINDOW_UPDATE frame if appropriate.
void MaybeSendWindowUpdate();
+ // Auto-tune the max receive window size.
+ void MaybeIncreaseMaxWindowSize();
+
// The parent connection, used to send connection close on flow control
// violation, and WINDOW_UPDATE and BLOCKED frames when appropriate.
// Not owned.
@@ -86,6 +101,33 @@ class NET_EXPORT_PRIVATE QuicFlowController {
// Tracks if this is owned by a server or a client.
Perspective perspective_;
+ // Tracks number of bytes sent to the peer.
+ QuicByteCount bytes_sent_;
+
+ // The absolute offset in the outgoing byte stream. If this offset is reached
+ // then we become flow control blocked until we receive a WINDOW_UPDATE.
+ QuicStreamOffset send_window_offset_;
+
+ // Overview of receive flow controller.
+ //
+ // 0=...===1=======2-------3 ...... FIN
+ // |<--- <= 4 --->|
+ //
+
+ // 1) bytes_consumed_ - moves forward when data is read out of the
+ // stream.
+ //
+ // 2) highest_received_byte_offset_ - moves when data is received
+ // from the peer.
+ //
+ // 3) receive_window_offset_ - moves when WINDOW_UPDATE is sent.
+ //
+ // 4) receive_window_size_ - maximum allowed unread data (3 - 1).
+ // This value may be increased by auto-tuning.
+ //
+ // 5) receive_window_size_limit_ - limit on receive_window_size_;
+ // auto-tuning will not increase window size beyond this limit.
+
// Track number of bytes received from the peer, which have been consumed
// locally.
QuicByteCount bytes_consumed_;
@@ -94,24 +136,31 @@ class NET_EXPORT_PRIVATE QuicFlowController {
// highest offset in a data frame, or a final value in a RST.
QuicStreamOffset highest_received_byte_offset_;
- // Tracks number of bytes sent to the peer.
- QuicByteCount bytes_sent_;
-
- // The absolute offset in the outgoing byte stream. If this offset is reached
- // then we become flow control blocked until we receive a WINDOW_UPDATE.
- QuicStreamOffset send_window_offset_;
// The absolute offset in the incoming byte stream. The peer should never send
// us bytes which are beyond this offset.
QuicStreamOffset receive_window_offset_;
// Largest size the receive window can grow to.
- QuicByteCount max_receive_window_;
+ QuicByteCount receive_window_size_;
+
+ // Upper limit on receive_window_size_;
+ QuicByteCount receive_window_size_limit_;
+
+ // Used to dynamically enable receive window auto-tuning.
+ bool auto_tune_receive_window_;
+
+ // Send window update when receive window size drops below this.
+ QuicByteCount WindowUpdateThreshold();
// Keep track of the last time we sent a BLOCKED frame. We should only send
// another when the number of bytes we have sent has changed.
QuicStreamOffset last_blocked_send_window_offset_;
+ // Keep time of the last time a window update was sent. We use this
+ // as part of the receive window auto tuning.
+ QuicTime prev_window_update_time_;
+
DISALLOW_COPY_AND_ASSIGN(QuicFlowController);
};
diff --git a/chromium/net/quic/quic_flow_controller_test.cc b/chromium/net/quic/quic_flow_controller_test.cc
index 4562a142d3b..dffbd56d7f6 100644
--- a/chromium/net/quic/quic_flow_controller_test.cc
+++ b/chromium/net/quic/quic_flow_controller_test.cc
@@ -6,9 +6,11 @@
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_flow_controller_peer.h"
+#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -16,26 +18,27 @@
namespace net {
namespace test {
+// Receive window auto-tuning uses RTT in its logic.
+const int64 kRtt = 100;
+
class QuicFlowControllerTest : public ::testing::Test {
public:
QuicFlowControllerTest()
: stream_id_(1234),
send_window_(kInitialSessionFlowControlWindowForTest),
receive_window_(kInitialSessionFlowControlWindowForTest),
- max_receive_window_(kInitialSessionFlowControlWindowForTest),
connection_(Perspective::IS_CLIENT) {}
void Initialize() {
- flow_controller_.reset(new QuicFlowController(
- &connection_, stream_id_, Perspective::IS_CLIENT, send_window_,
- receive_window_, max_receive_window_));
+ flow_controller_.reset(
+ new QuicFlowController(&connection_, stream_id_, Perspective::IS_CLIENT,
+ send_window_, receive_window_, false));
}
protected:
QuicStreamId stream_id_;
QuicByteCount send_window_;
QuicByteCount receive_window_;
- QuicByteCount max_receive_window_;
scoped_ptr<QuicFlowController> flow_controller_;
MockConnection connection_;
};
@@ -147,5 +150,225 @@ TEST_F(QuicFlowControllerTest, OnlySendBlockedFrameOncePerOffset) {
flow_controller_->MaybeSendBlocked();
}
+TEST_F(QuicFlowControllerTest, ReceivingBytesFastIncreasesFlowWindow) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_auto_tune_receive_window, true);
+ // This test will generate two WINDOW_UPDATE frames.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+ Initialize();
+ flow_controller_->set_auto_tune_receive_window(true);
+
+ // Make sure clock is inititialized.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+ QuicSentPacketManager* manager =
+ QuicConnectionPeer::GetSentPacketManager(&connection_);
+
+ RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager);
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ QuicByteCount threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ QuicStreamOffset receive_offset = threshold + 1;
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Consume enough bytes to send a WINDOW_UPDATE frame.
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Move time forward, but by less than two RTTs. Then receive and consume
+ // some more, forcing a second WINDOW_UPDATE with an increased max window
+ // size.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt - 1));
+ receive_offset += threshold + 1;
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ QuicByteCount new_threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+ EXPECT_GT(new_threshold, threshold);
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesFastStatusQuo) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_auto_tune_receive_window, false);
+ // This test will generate two WINDOW_UPDATE frames.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+ Initialize();
+ flow_controller_->set_auto_tune_receive_window(true);
+
+ // Make sure clock is inititialized.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+ QuicSentPacketManager* manager =
+ QuicConnectionPeer::GetSentPacketManager(&connection_);
+
+ RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager);
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ QuicByteCount threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ QuicStreamOffset receive_offset = threshold + 1;
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Consume enough bytes to send a WINDOW_UPDATE frame.
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Move time forward, but by less than two RTTs. Then receive and consume
+ // some more, forcing a second WINDOW_UPDATE with an increased max window
+ // size.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt - 1));
+ receive_offset += threshold + 1;
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ QuicByteCount new_threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+ EXPECT_EQ(new_threshold, threshold);
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStableFlowWindow) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_auto_tune_receive_window, true);
+ // This test will generate two WINDOW_UPDATE frames.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+ Initialize();
+ flow_controller_->set_auto_tune_receive_window(true);
+
+ // Make sure clock is inititialized.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+ QuicSentPacketManager* manager =
+ QuicConnectionPeer::GetSentPacketManager(&connection_);
+ RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager);
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ QuicByteCount threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ QuicStreamOffset receive_offset = threshold + 1;
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ flow_controller_->AddBytesConsumed(threshold + 1);
+
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Move time forward, but by more than two RTTs. Then receive and consume
+ // some more, forcing a second WINDOW_UPDATE with unchanged max window size.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt + 1));
+
+ receive_offset += threshold + 1;
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+
+ QuicByteCount new_threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ EXPECT_EQ(new_threshold, threshold);
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStatusQuo) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_auto_tune_receive_window, false);
+ // This test will generate two WINDOW_UPDATE frames.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+ Initialize();
+ flow_controller_->set_auto_tune_receive_window(true);
+
+ // Make sure clock is inititialized.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+ QuicSentPacketManager* manager =
+ QuicConnectionPeer::GetSentPacketManager(&connection_);
+ RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager);
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ QuicByteCount threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ QuicStreamOffset receive_offset = threshold + 1;
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ flow_controller_->AddBytesConsumed(threshold + 1);
+
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Move time forward, but by more than two RTTs. Then receive and consume
+ // some more, forcing a second WINDOW_UPDATE with unchanged max window size.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt + 1));
+
+ receive_offset += threshold + 1;
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+
+ QuicByteCount new_threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ EXPECT_EQ(new_threshold, threshold);
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/quic_framer.cc b/chromium/net/quic/quic_framer.cc
index db0d39dd880..ed5c011ff6c 100644
--- a/chromium/net/quic/quic_framer.cc
+++ b/chromium/net/quic/quic_framer.cc
@@ -4,6 +4,8 @@
#include "net/quic/quic_framer.h"
+#include <stdint.h>
+
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/stl_util.h"
@@ -31,16 +33,16 @@ namespace {
// Mask to select the lowest 48 bits of a sequence number.
const QuicPacketSequenceNumber k6ByteSequenceNumberMask =
- GG_UINT64_C(0x0000FFFFFFFFFFFF);
+ UINT64_C(0x0000FFFFFFFFFFFF);
const QuicPacketSequenceNumber k4ByteSequenceNumberMask =
- GG_UINT64_C(0x00000000FFFFFFFF);
+ UINT64_C(0x00000000FFFFFFFF);
const QuicPacketSequenceNumber k2ByteSequenceNumberMask =
- GG_UINT64_C(0x000000000000FFFF);
+ UINT64_C(0x000000000000FFFF);
const QuicPacketSequenceNumber k1ByteSequenceNumberMask =
- GG_UINT64_C(0x00000000000000FF);
+ UINT64_C(0x00000000000000FF);
-const QuicConnectionId k1ByteConnectionIdMask = GG_UINT64_C(0x00000000000000FF);
-const QuicConnectionId k4ByteConnectionIdMask = GG_UINT64_C(0x00000000FFFFFFFF);
+const QuicConnectionId k1ByteConnectionIdMask = UINT64_C(0x00000000000000FF);
+const QuicConnectionId k4ByteConnectionIdMask = UINT64_C(0x00000000FFFFFFFF);
// Number of bits the sequence number length bits are shifted from the right
// edge of the public header.
@@ -133,15 +135,6 @@ QuicSequenceNumberLength ReadSequenceNumberLength(uint8 flags) {
} // namespace
-bool QuicFramerVisitorInterface::OnWindowUpdateFrame(
- const QuicWindowUpdateFrame& frame) {
- return true;
-}
-
-bool QuicFramerVisitorInterface::OnBlockedFrame(const QuicBlockedFrame& frame) {
- return true;
-}
-
QuicFramer::QuicFramer(const QuicVersionVector& supported_versions,
QuicTime creation_time,
Perspective perspective)
@@ -180,7 +173,6 @@ size_t QuicFramer::GetMinStreamFrameSize(QuicStreamId stream_id,
// static
size_t QuicFramer::GetMinAckFrameSize(
- QuicSequenceNumberLength sequence_number_length,
QuicSequenceNumberLength largest_observed_length) {
return kQuicFrameTypeSize + kQuicEntropyHashSize +
largest_observed_length + kQuicDeltaTimeLargestObservedSize;
@@ -308,9 +300,9 @@ size_t QuicFramer::GetSerializedFrameLength(
if (!first_frame) {
return 0;
}
- bool can_truncate = frame.type == ACK_FRAME &&
- free_bytes >= GetMinAckFrameSize(PACKET_6BYTE_SEQUENCE_NUMBER,
- PACKET_6BYTE_SEQUENCE_NUMBER);
+ bool can_truncate =
+ frame.type == ACK_FRAME &&
+ free_bytes >= GetMinAckFrameSize(PACKET_6BYTE_SEQUENCE_NUMBER);
if (can_truncate) {
// Truncate the frame so the packet will not exceed kMaxPacketSize.
// Note that we may not use every byte of the writer in this case.
@@ -380,6 +372,8 @@ QuicPacket* QuicFramer::BuildDataPacket(const QuicPacketHeader& header,
return nullptr;
}
break;
+ case MTU_DISCOVERY_FRAME:
+ // MTU discovery frames are serialized as ping frames.
case PING_FRAME:
// Ping has no payload.
break;
@@ -810,7 +804,7 @@ const QuicTime::Delta QuicFramer::CalculateTimestampFromWire(
//
// epoch_delta is the delta between epochs. A delta is 4 bytes of
// microseconds.
- const uint64 epoch_delta = GG_UINT64_C(1) << 32;
+ const uint64 epoch_delta = UINT64_C(1) << 32;
uint64 epoch = last_timestamp_.ToMicroseconds() & ~(epoch_delta - 1);
// Wrapping is safe here because a wrapped value will not be ClosestTo below.
uint64 prev_epoch = epoch - epoch_delta;
@@ -837,7 +831,7 @@ QuicPacketSequenceNumber QuicFramer::CalculatePacketSequenceNumberFromWire(
// with, so the correct value is likely the same epoch as the last sequence
// number or an adjacent epoch.
const QuicPacketSequenceNumber epoch_delta =
- GG_UINT64_C(1) << (8 * sequence_number_length);
+ UINT64_C(1) << (8 * sequence_number_length);
QuicPacketSequenceNumber next_sequence_number = last_sequence_number_ + 1;
QuicPacketSequenceNumber epoch = last_sequence_number_ & ~(epoch_delta - 1);
QuicPacketSequenceNumber prev_epoch = epoch - epoch_delta;
@@ -955,7 +949,7 @@ QuicSequenceNumberLength QuicFramer::GetMinSequenceNumberLength(
} else if (sequence_number < 1 << (PACKET_2BYTE_SEQUENCE_NUMBER * 8)) {
return PACKET_2BYTE_SEQUENCE_NUMBER;
} else if (sequence_number <
- GG_UINT64_C(1) << (PACKET_4BYTE_SEQUENCE_NUMBER * 8)) {
+ UINT64_C(1) << (PACKET_4BYTE_SEQUENCE_NUMBER * 8)) {
return PACKET_4BYTE_SEQUENCE_NUMBER;
} else {
return PACKET_6BYTE_SEQUENCE_NUMBER;
@@ -1279,23 +1273,17 @@ bool QuicFramer::ProcessStreamFrame(uint8 frame_type,
return false;
}
- StringPiece frame_data;
if (has_data_length) {
- if (!reader_->ReadStringPiece16(&frame_data)) {
+ if (!reader_->ReadStringPiece16(&frame->data)) {
set_detailed_error("Unable to read frame data.");
return false;
}
} else {
- if (!reader_->ReadStringPiece(&frame_data, reader_->BytesRemaining())) {
+ if (!reader_->ReadStringPiece(&frame->data, reader_->BytesRemaining())) {
set_detailed_error("Unable to read frame data.");
return false;
}
}
- // Point frame to the right data.
- frame->data.Clear();
- if (!frame_data.empty()) {
- frame->data.Append(const_cast<char*>(frame_data.data()), frame_data.size());
- }
return true;
}
@@ -1596,16 +1584,15 @@ StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket(
- kStartOfHashData);
}
-void QuicFramer::SetDecrypter(QuicDecrypter* decrypter,
- EncryptionLevel level) {
+void QuicFramer::SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter) {
DCHECK(alternative_decrypter_.get() == nullptr);
DCHECK_GE(level, decrypter_level_);
decrypter_.reset(decrypter);
decrypter_level_ = level;
}
-void QuicFramer::SetAlternativeDecrypter(QuicDecrypter* decrypter,
- EncryptionLevel level,
+void QuicFramer::SetAlternativeDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter,
bool latch_once_used) {
alternative_decrypter_.reset(decrypter);
alternative_decrypter_level_ = level;
@@ -1627,7 +1614,7 @@ void QuicFramer::SetEncrypter(EncryptionLevel level,
encrypter_[level].reset(encrypter);
}
-QuicEncryptedPacket* QuicFramer::EncryptPacket(
+QuicEncryptedPacket* QuicFramer::EncryptPayload(
EncryptionLevel level,
QuicPacketSequenceNumber packet_sequence_number,
const QuicPacket& packet,
@@ -1742,8 +1729,7 @@ size_t QuicFramer::GetAckFrameSize(
QuicSequenceNumberLength missing_sequence_number_length =
GetMinSequenceNumberLength(ack_info.max_delta);
- size_t ack_size = GetMinAckFrameSize(sequence_number_length,
- largest_observed_length);
+ size_t ack_size = GetMinAckFrameSize(largest_observed_length);
if (!ack_info.nack_ranges.empty()) {
ack_size += kNumberOfNackRangesSize + kNumberOfRevivedPacketsSize;
ack_size += min(ack_info.nack_ranges.size(), kMaxNackRanges) *
@@ -1780,14 +1766,15 @@ size_t QuicFramer::ComputeFrameLength(
case STREAM_FRAME:
return GetMinStreamFrameSize(frame.stream_frame->stream_id,
frame.stream_frame->offset,
- last_frame_in_packet,
- is_in_fec_group) +
- frame.stream_frame->data.TotalBufferSize();
+ last_frame_in_packet, is_in_fec_group) +
+ frame.stream_frame->data.length();
case ACK_FRAME: {
return GetAckFrameSize(*frame.ack_frame, sequence_number_length);
}
case STOP_WAITING_FRAME:
return GetStopWaitingFrameSize(sequence_number_length);
+ case MTU_DISCOVERY_FRAME:
+ // MTU discovery frames are serialized as ping frames.
case PING_FRAME:
// Ping has no payload.
return kQuicFrameTypeSize;
@@ -1850,6 +1837,9 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame,
}
case ACK_FRAME:
return true;
+ case MTU_DISCOVERY_FRAME:
+ type_byte = static_cast<uint8>(PING_FRAME);
+ break;
default:
type_byte = static_cast<uint8>(frame.type);
break;
@@ -1904,15 +1894,14 @@ bool QuicFramer::AppendStreamFrame(
return false;
}
if (!no_stream_frame_length) {
- if ((frame.data.TotalBufferSize() > numeric_limits<uint16>::max()) ||
- !writer->WriteUInt16(
- static_cast<uint16>(frame.data.TotalBufferSize()))) {
+ if ((frame.data.size() > numeric_limits<uint16>::max()) ||
+ !writer->WriteUInt16(static_cast<uint16>(frame.data.size()))) {
LOG(DFATAL) << "Writing stream frame length failed";
return false;
}
}
- if (!writer->WriteIOVector(frame.data)) {
+ if (!writer->WriteBytes(frame.data.data(), frame.data.size())) {
LOG(DFATAL) << "Writing frame data failed.";
return false;
}
@@ -1935,10 +1924,9 @@ bool QuicFramer::AppendAckFrameAndTypeByte(
QuicSequenceNumberLength missing_sequence_number_length =
GetMinSequenceNumberLength(ack_info.max_delta);
// Determine whether we need to truncate ranges.
- size_t available_range_bytes = writer->capacity() - writer->length() -
- kNumberOfRevivedPacketsSize - kNumberOfNackRangesSize -
- GetMinAckFrameSize(header.public_header.sequence_number_length,
- largest_observed_length);
+ size_t available_range_bytes =
+ writer->capacity() - writer->length() - kNumberOfRevivedPacketsSize -
+ kNumberOfNackRangesSize - GetMinAckFrameSize(largest_observed_length);
size_t max_num_ranges = available_range_bytes /
(missing_sequence_number_length + PACKET_1BYTE_SEQUENCE_NUMBER);
max_num_ranges = min(kMaxNackRanges, max_num_ranges);
@@ -2100,7 +2088,7 @@ bool QuicFramer::AppendTimestampToAckFrame(const QuicAckFrame& frame,
}
// Use the lowest 4 bytes of the time delta from the creation_time_.
- const uint64 time_epoch_delta_us = GG_UINT64_C(1) << 32;
+ const uint64 time_epoch_delta_us = UINT64_C(1) << 32;
uint32 time_delta_us =
static_cast<uint32>(it->second.Subtract(creation_time_).ToMicroseconds()
& (time_epoch_delta_us - 1));
diff --git a/chromium/net/quic/quic_framer.h b/chromium/net/quic/quic_framer.h
index c0c2c662fb5..c994c2ef3f7 100644
--- a/chromium/net/quic/quic_framer.h
+++ b/chromium/net/quic/quic_framer.h
@@ -243,7 +243,6 @@ class NET_EXPORT_PRIVATE QuicFramer {
InFecGroup is_in_fec_group);
// Size in bytes of all ack frame fields without the missing packets.
static size_t GetMinAckFrameSize(
- QuicSequenceNumberLength sequence_number_length,
QuicSequenceNumberLength largest_observed_length);
// Size in bytes of a stop waiting frame.
static size_t GetStopWaitingFrameSize(
@@ -315,7 +314,7 @@ class NET_EXPORT_PRIVATE QuicFramer {
// function DCHECKs. This is intended for cases where one knows that future
// packets will be using the new decrypter and the previous decrypter is now
// obsolete. |level| indicates the encryption level of the new decrypter.
- void SetDecrypter(QuicDecrypter* decrypter, EncryptionLevel level);
+ void SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter);
// SetAlternativeDecrypter sets a decrypter that may be used to decrypt
// future packets and takes ownership of it. |level| indicates the encryption
@@ -323,8 +322,8 @@ class NET_EXPORT_PRIVATE QuicFramer {
// that the decrypter is successful it will replace the primary decrypter.
// Otherwise both decrypters will remain active and the primary decrypter
// will be the one last used.
- void SetAlternativeDecrypter(QuicDecrypter* decrypter,
- EncryptionLevel level,
+ void SetAlternativeDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter,
bool latch_once_used);
const QuicDecrypter* decrypter() const;
@@ -337,11 +336,11 @@ class NET_EXPORT_PRIVATE QuicFramer {
// Returns a new encrypted packet, owned by the caller.
// Encrypts into |buffer| if |buffer_len| is long enough, and otherwise
// constructs a new buffer owned by the EncryptedPacket.
- QuicEncryptedPacket* EncryptPacket(EncryptionLevel level,
- QuicPacketSequenceNumber sequence_number,
- const QuicPacket& packet,
- char* buffer,
- size_t buffer_len);
+ QuicEncryptedPacket* EncryptPayload(EncryptionLevel level,
+ QuicPacketSequenceNumber sequence_number,
+ const QuicPacket& packet,
+ char* buffer,
+ size_t buffer_len);
// Returns the maximum length of plaintext that can be encrypted
// to ciphertext no larger than |ciphertext_size|.
@@ -518,7 +517,7 @@ class NET_EXPORT_PRIVATE QuicFramer {
// successfully decrypts a packet, we should install it as the only
// decrypter.
bool alternative_decrypter_latch_;
- // Encrypters used to encrypt packets via EncryptPacket().
+ // Encrypters used to encrypt packets via EncryptPayload().
scoped_ptr<QuicEncrypter> encrypter_[NUM_ENCRYPTION_LEVELS];
// Tracks if the framer is being used by the entity that received the
// connection or the entity that initiated it.
diff --git a/chromium/net/quic/quic_framer_test.cc b/chromium/net/quic/quic_framer_test.cc
index 16383620b5f..7f564f33a4d 100644
--- a/chromium/net/quic/quic_framer_test.cc
+++ b/chromium/net/quic/quic_framer_test.cc
@@ -4,6 +4,7 @@
#include "net/quic/quic_framer.h"
+#include <stdint.h>
#include <algorithm>
#include <map>
#include <string>
@@ -12,7 +13,6 @@
#include "base/containers/hash_tables.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/port.h"
#include "base/stl_util.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
@@ -31,12 +31,13 @@ using std::pair;
using std::string;
using std::vector;
using testing::Return;
+using testing::Truly;
using testing::_;
namespace net {
namespace test {
-const QuicPacketSequenceNumber kEpoch = GG_UINT64_C(1) << 48;
+const QuicPacketSequenceNumber kEpoch = UINT64_C(1) << 48;
const QuicPacketSequenceNumber kMask = kEpoch - 1;
// Index into the connection_id offset in the header.
@@ -106,13 +107,6 @@ class TestEncrypter : public QuicEncrypter {
~TestEncrypter() override {}
bool SetKey(StringPiece key) override { return true; }
bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
- bool Encrypt(StringPiece nonce,
- StringPiece associated_data,
- StringPiece plaintext,
- unsigned char* output) override {
- CHECK(false) << "Not implemented";
- return false;
- }
bool EncryptPacket(QuicPacketSequenceNumber sequence_number,
StringPiece associated_data,
StringPiece plaintext,
@@ -236,12 +230,12 @@ class TestQuicVisitor : public QuicFramerVisitorInterface {
bool OnStreamFrame(const QuicStreamFrame& frame) override {
++frame_count_;
// Save a copy of the data so it is valid after the packet is processed.
- stream_data_.push_back(frame.GetDataAsString());
+ string* string_data = new string();
+ frame.data.AppendToString(string_data);
+ stream_data_.push_back(string_data);
QuicStreamFrame* stream_frame = new QuicStreamFrame(frame);
// Make sure that the stream frame points to this data.
- stream_frame->data.Clear();
- stream_frame->data.Append(const_cast<char*>(stream_data_.back()->data()),
- stream_data_.back()->size());
+ stream_frame->data = StringPiece(*string_data);
stream_frames_.push_back(stream_frame);
return true;
}
@@ -345,7 +339,7 @@ class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
framer_(QuicSupportedVersions(), start_, Perspective::IS_SERVER) {
version_ = GetParam();
framer_.set_version(version_);
- framer_.SetDecrypter(decrypter_, ENCRYPTION_NONE);
+ framer_.SetDecrypter(ENCRYPTION_NONE, decrypter_);
framer_.SetEncrypter(ENCRYPTION_NONE, encrypter_);
framer_.set_visitor(&visitor_);
framer_.set_received_entropy_calculator(&entropy_calculator_);
@@ -434,8 +428,7 @@ class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
// Checks if the supplied string matches data in the supplied StreamFrame.
void CheckStreamFrameData(string str, QuicStreamFrame* frame) {
- scoped_ptr<string> frame_data(frame->GetDataAsString());
- EXPECT_EQ(str, *frame_data);
+ EXPECT_EQ(str, frame->data);
}
void CheckStreamFrameBoundaries(unsigned char* packet,
@@ -501,7 +494,7 @@ INSTANTIATE_TEST_CASE_P(QuicFramerTests,
TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochStart) {
// A few quick manual sanity checks
- CheckCalculatePacketSequenceNumber(GG_UINT64_C(1), GG_UINT64_C(0));
+ CheckCalculatePacketSequenceNumber(UINT64_C(1), UINT64_C(0));
CheckCalculatePacketSequenceNumber(kEpoch + 1, kMask);
CheckCalculatePacketSequenceNumber(kEpoch, kMask);
@@ -643,7 +636,7 @@ TEST_P(QuicFramerTest, LargePacket) {
ASSERT_TRUE(visitor_.header_.get());
// Make sure we've parsed the packet header, so we can send an error.
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
// Make sure the correct error is propagated.
EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error());
@@ -667,14 +660,14 @@ TEST_P(QuicFramerTest, PacketHeader) {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
+ EXPECT_EQ(UINT64_C(0x123456789ABC),
visitor_.header_->packet_sequence_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
@@ -702,7 +695,7 @@ TEST_P(QuicFramerTest, PacketHeader) {
TEST_P(QuicFramerTest, PacketHeaderWith4ByteConnectionId) {
QuicFramerPeer::SetLastSerializedConnectionId(
- &framer_, GG_UINT64_C(0xFEDCBA9876543210));
+ &framer_, UINT64_C(0xFEDCBA9876543210));
unsigned char packet[] = {
// public flags (4 byte connection_id)
@@ -720,14 +713,14 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteConnectionId) {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
+ EXPECT_EQ(UINT64_C(0x123456789ABC),
visitor_.header_->packet_sequence_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
@@ -758,7 +751,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteConnectionId) {
TEST_P(QuicFramerTest, PacketHeader1ByteConnectionId) {
QuicFramerPeer::SetLastSerializedConnectionId(
- &framer_, GG_UINT64_C(0xFEDCBA9876543210));
+ &framer_, UINT64_C(0xFEDCBA9876543210));
unsigned char packet[] = {
// public flags (1 byte connection_id)
@@ -776,14 +769,14 @@ TEST_P(QuicFramerTest, PacketHeader1ByteConnectionId) {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
+ EXPECT_EQ(UINT64_C(0x123456789ABC),
visitor_.header_->packet_sequence_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
@@ -814,7 +807,7 @@ TEST_P(QuicFramerTest, PacketHeader1ByteConnectionId) {
TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
QuicFramerPeer::SetLastSerializedConnectionId(
- &framer_, GG_UINT64_C(0xFEDCBA9876543210));
+ &framer_, UINT64_C(0xFEDCBA9876543210));
unsigned char packet[] = {
// public flags (0 byte connection_id)
@@ -831,14 +824,14 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
+ EXPECT_EQ(UINT64_C(0x123456789ABC),
visitor_.header_->packet_sequence_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
@@ -887,7 +880,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_TRUE(visitor_.header_->public_header.version_flag);
@@ -895,7 +888,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
+ EXPECT_EQ(UINT64_C(0x123456789ABC),
visitor_.header_->packet_sequence_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
@@ -924,8 +917,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
}
TEST_P(QuicFramerTest, PacketHeaderWith4ByteSequenceNumber) {
- QuicFramerPeer::SetLastSequenceNumber(&framer_,
- GG_UINT64_C(0x123456789ABA));
+ QuicFramerPeer::SetLastSequenceNumber(&framer_, UINT64_C(0x123456789ABA));
unsigned char packet[] = {
// public flags (8 byte connection_id and 4 byte sequence number)
@@ -943,15 +935,14 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteSequenceNumber) {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
- visitor_.header_->packet_sequence_number);
+ EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
@@ -979,8 +970,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteSequenceNumber) {
}
TEST_P(QuicFramerTest, PacketHeaderWith2ByteSequenceNumber) {
- QuicFramerPeer::SetLastSequenceNumber(&framer_,
- GG_UINT64_C(0x123456789ABA));
+ QuicFramerPeer::SetLastSequenceNumber(&framer_, UINT64_C(0x123456789ABA));
unsigned char packet[] = {
// public flags (8 byte connection_id and 2 byte sequence number)
@@ -998,15 +988,14 @@ TEST_P(QuicFramerTest, PacketHeaderWith2ByteSequenceNumber) {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
- visitor_.header_->packet_sequence_number);
+ EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
@@ -1034,8 +1023,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith2ByteSequenceNumber) {
}
TEST_P(QuicFramerTest, PacketHeaderWith1ByteSequenceNumber) {
- QuicFramerPeer::SetLastSequenceNumber(&framer_,
- GG_UINT64_C(0x123456789ABA));
+ QuicFramerPeer::SetLastSequenceNumber(&framer_, UINT64_C(0x123456789ABA));
unsigned char packet[] = {
// public flags (8 byte connection_id and 1 byte sequence number)
@@ -1053,15 +1041,14 @@ TEST_P(QuicFramerTest, PacketHeaderWith1ByteSequenceNumber) {
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
- visitor_.header_->packet_sequence_number);
+ EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
@@ -1300,8 +1287,7 @@ TEST_P(QuicFramerTest, StreamFrame) {
EXPECT_EQ(static_cast<uint64>(0x01020304),
visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
- visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1345,10 +1331,9 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(GG_UINT64_C(0x00020304), visitor_.stream_frames_[0]->stream_id);
+ EXPECT_EQ(UINT64_C(0x00020304), visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
- visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1396,8 +1381,7 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
EXPECT_EQ(static_cast<uint64>(0x00000304),
visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
- visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1445,8 +1429,7 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
EXPECT_EQ(static_cast<uint64>(0x00000004),
visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
- visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1498,8 +1481,7 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
EXPECT_EQ(static_cast<uint64>(0x01020304),
visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
- visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1584,12 +1566,12 @@ TEST_P(QuicFramerTest, RevivedStreamFrame) {
};
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = true;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
// Do not encrypt the payload because the revived payload is post-encryption.
@@ -1600,7 +1582,7 @@ TEST_P(QuicFramerTest, RevivedStreamFrame) {
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_EQ(1, visitor_.revived_packets_);
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
@@ -1608,17 +1590,15 @@ TEST_P(QuicFramerTest, RevivedStreamFrame) {
EXPECT_TRUE(visitor_.header_->entropy_flag);
EXPECT_EQ(1 << (header.packet_sequence_number % 8),
visitor_.header_->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
- visitor_.header_->packet_sequence_number);
+ EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.stream_frames_[0]->stream_id);
+ EXPECT_EQ(UINT64_C(0x01020304), visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
- visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
}
@@ -1659,8 +1639,7 @@ TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
EXPECT_EQ(IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(GG_UINT64_C(0x341256789ABA),
- visitor_.header_->fec_group);
+ EXPECT_EQ(UINT64_C(0x341256789ABA), visitor_.header_->fec_group);
const size_t fec_offset =
GetStartOfFecProtectedData(PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion,
@@ -1671,10 +1650,9 @@ TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.stream_frames_[0]->stream_id);
+ EXPECT_EQ(UINT64_C(0x01020304), visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
- visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
}
@@ -1729,12 +1707,12 @@ TEST_P(QuicFramerTest, AckFrameTwoTimestamp) {
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+ EXPECT_EQ(UINT64_C(0x0123456789ABF), frame.largest_observed);
ASSERT_EQ(1u, frame.missing_packets.size());
ASSERT_EQ(2u, frame.received_packet_times.size());
SequenceNumberSet::const_iterator missing_iter =
frame.missing_packets.begin();
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+ EXPECT_EQ(UINT64_C(0x0123456789ABE), *missing_iter);
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset = kReceivedEntropyOffset +
@@ -1846,12 +1824,12 @@ TEST_P(QuicFramerTest, AckFrameOneTimestamp) {
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+ EXPECT_EQ(UINT64_C(0x0123456789ABF), frame.largest_observed);
ASSERT_EQ(1u, frame.missing_packets.size());
ASSERT_EQ(1u, frame.received_packet_times.size());
SequenceNumberSet::const_iterator missing_iter =
frame.missing_packets.begin();
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+ EXPECT_EQ(UINT64_C(0x0123456789ABE), *missing_iter);
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset = kReceivedEntropyOffset +
@@ -1949,11 +1927,11 @@ TEST_P(QuicFramerTest, AckFrame) {
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+ EXPECT_EQ(UINT64_C(0x0123456789ABF), frame.largest_observed);
ASSERT_EQ(1u, frame.missing_packets.size());
SequenceNumberSet::const_iterator missing_iter =
frame.missing_packets.begin();
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+ EXPECT_EQ(UINT64_C(0x0123456789ABE), *missing_iter);
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset = kReceivedEntropyOffset +
@@ -2047,11 +2025,11 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+ EXPECT_EQ(UINT64_C(0x0123456789ABF), frame.largest_observed);
ASSERT_EQ(1u, frame.missing_packets.size());
SequenceNumberSet::const_iterator missing_iter =
frame.missing_packets.begin();
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+ EXPECT_EQ(UINT64_C(0x0123456789ABE), *missing_iter);
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset = kReceivedEntropyOffset +
@@ -2139,7 +2117,7 @@ TEST_P(QuicFramerTest, AckFrameNoNacks) {
ASSERT_EQ(1u, visitor_.ack_frames_.size());
QuicAckFrame* frame = visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame->largest_observed);
+ EXPECT_EQ(UINT64_C(0x0123456789ABF), frame->largest_observed);
ASSERT_EQ(0u, frame->missing_packets.size());
// Verify that the packet re-serializes identically.
@@ -2202,15 +2180,15 @@ TEST_P(QuicFramerTest, AckFrame500Nacks) {
ASSERT_EQ(1u, visitor_.ack_frames_.size());
QuicAckFrame* frame = visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame->entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame->largest_observed);
+ EXPECT_EQ(UINT64_C(0x0123456789ABF), frame->largest_observed);
EXPECT_EQ(0u, frame->revived_packets.size());
ASSERT_EQ(500u, frame->missing_packets.size());
SequenceNumberSet::const_iterator first_missing_iter =
frame->missing_packets.begin();
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABE) - 499, *first_missing_iter);
+ EXPECT_EQ(UINT64_C(0x0123456789ABE) - 499, *first_missing_iter);
SequenceNumberSet::const_reverse_iterator last_missing_iter =
frame->missing_packets.rbegin();
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *last_missing_iter);
+ EXPECT_EQ(UINT64_C(0x0123456789ABE), *last_missing_iter);
// Verify that the packet re-serializes identically.
QuicFrames frames;
@@ -2257,7 +2235,7 @@ TEST_P(QuicFramerTest, StopWaitingFrame) {
ASSERT_EQ(1u, visitor_.stop_waiting_frames_.size());
const QuicStopWaitingFrame& frame = *visitor_.stop_waiting_frames_[0];
EXPECT_EQ(0xAB, frame.entropy_hash);
- EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.least_unacked);
+ EXPECT_EQ(UINT64_C(0x0123456789AA0), frame.least_unacked);
const size_t kSentEntropyOffset = kQuicFrameTypeSize;
const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize;
@@ -2323,10 +2301,10 @@ TEST_P(QuicFramerTest, RstStreamFrameQuicVersion24) {
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
- EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id);
+ EXPECT_EQ(UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id);
EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code);
EXPECT_EQ("because I can", visitor_.rst_stream_frame_.error_details);
- EXPECT_EQ(GG_UINT64_C(0x0807060504030201),
+ EXPECT_EQ(UINT64_C(0x0807060504030201),
visitor_.rst_stream_frame_.byte_offset);
// Now test framing boundaries.
@@ -2392,9 +2370,9 @@ TEST_P(QuicFramerTest, RstStreamFrameQuic) {
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
- EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id);
+ EXPECT_EQ(UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id);
EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code);
- EXPECT_EQ(GG_UINT64_C(0x0807060504030201),
+ EXPECT_EQ(UINT64_C(0x0807060504030201),
visitor_.rst_stream_frame_.byte_offset);
// Now test framing boundaries.
@@ -2511,8 +2489,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) {
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
- EXPECT_EQ(GG_UINT64_C(0x01020304),
- visitor_.goaway_frame_.last_good_stream_id);
+ EXPECT_EQ(UINT64_C(0x01020304), visitor_.goaway_frame_.last_good_stream_id);
EXPECT_EQ(0x9, visitor_.goaway_frame_.error_code);
EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase);
@@ -2567,9 +2544,8 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) {
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
- EXPECT_EQ(GG_UINT64_C(0x01020304),
- visitor_.window_update_frame_.stream_id);
- EXPECT_EQ(GG_UINT64_C(0x0c0b0a0908070605),
+ EXPECT_EQ(UINT64_C(0x01020304), visitor_.window_update_frame_.stream_id);
+ EXPECT_EQ(UINT64_C(0x0c0b0a0908070605),
visitor_.window_update_frame_.byte_offset);
// Now test framing boundaries.
@@ -2616,8 +2592,7 @@ TEST_P(QuicFramerTest, BlockedFrame) {
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
- EXPECT_EQ(GG_UINT64_C(0x01020304),
- visitor_.blocked_frame_.stream_id);
+ EXPECT_EQ(UINT64_C(0x01020304), visitor_.blocked_frame_.stream_id);
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetBlockedFrameSize();
@@ -2691,13 +2666,13 @@ TEST_P(QuicFramerTest, PublicResetPacket) {
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.public_reset_packet_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.public_reset_packet_->public_header.connection_id);
EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
- EXPECT_EQ(GG_UINT64_C(0xABCDEF0123456789),
+ EXPECT_EQ(UINT64_C(0xABCDEF0123456789),
visitor_.public_reset_packet_->nonce_proof);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
+ EXPECT_EQ(UINT64_C(0x123456789ABC),
visitor_.public_reset_packet_->rejected_sequence_number);
EXPECT_TRUE(
visitor_.public_reset_packet_->client_address.address().empty());
@@ -2795,13 +2770,13 @@ TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) {
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.public_reset_packet_.get());
- EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
visitor_.public_reset_packet_->public_header.connection_id);
EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
- EXPECT_EQ(GG_UINT64_C(0xABCDEF0123456789),
+ EXPECT_EQ(UINT64_C(0xABCDEF0123456789),
visitor_.public_reset_packet_->nonce_proof);
- EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
+ EXPECT_EQ(UINT64_C(0x123456789ABC),
visitor_.public_reset_packet_->rejected_sequence_number);
EXPECT_EQ("4.31.198.44",
IPAddressToString(visitor_.public_reset_packet_->
@@ -2897,18 +2872,18 @@ TEST_P(QuicFramerTest, FecPacket) {
EXPECT_EQ(0u, visitor_.ack_frames_.size());
ASSERT_EQ(1, visitor_.fec_count_);
const QuicFecData& fec_data = *visitor_.fec_data_[0];
- EXPECT_EQ(GG_UINT64_C(0x0123456789ABB), fec_data.fec_group);
+ EXPECT_EQ(UINT64_C(0x0123456789ABB), fec_data.fec_group);
EXPECT_EQ("abcdefghijklmnop", fec_data.redundancy);
}
TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicPaddingFrame padding_frame;
@@ -2949,13 +2924,13 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.public_header.sequence_number_length = PACKET_4BYTE_SEQUENCE_NUMBER;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicPaddingFrame padding_frame;
@@ -2995,13 +2970,13 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.public_header.sequence_number_length = PACKET_2BYTE_SEQUENCE_NUMBER;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicPaddingFrame padding_frame;
@@ -3041,13 +3016,13 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.public_header.sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicPaddingFrame padding_frame;
@@ -3087,19 +3062,16 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
TEST_P(QuicFramerTest, BuildStreamFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x77123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x77123456789ABC);
header.fec_group = 0;
- QuicStreamFrame stream_frame;
- stream_frame.stream_id = 0x01020304;
- stream_frame.fin = true;
- stream_frame.offset = GG_UINT64_C(0xBA98FEDC32107654);
- stream_frame.data = MakeIOVector("hello world!");
+ QuicStreamFrame stream_frame(0x01020304, true, UINT64_C(0xBA98FEDC32107654),
+ StringPiece("hello world!"));
QuicFrames frames;
frames.push_back(QuicFrame(&stream_frame));
@@ -3139,20 +3111,17 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) {
TEST_P(QuicFramerTest, BuildStreamFramePacketInFecGroup) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x77123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x77123456789ABC);
header.is_in_fec_group = IN_FEC_GROUP;
- header.fec_group = GG_UINT64_C(0x77123456789ABC);
+ header.fec_group = UINT64_C(0x77123456789ABC);
- QuicStreamFrame stream_frame;
- stream_frame.stream_id = 0x01020304;
- stream_frame.fin = true;
- stream_frame.offset = GG_UINT64_C(0xBA98FEDC32107654);
- stream_frame.data = MakeIOVector("hello world!");
+ QuicStreamFrame stream_frame(0x01020304, true, UINT64_C(0xBA98FEDC32107654),
+ StringPiece("hello world!"));
QuicFrames frames;
frames.push_back(QuicFrame(&stream_frame));
@@ -3189,19 +3158,16 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketInFecGroup) {
TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = true;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x77123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x77123456789ABC);
header.fec_group = 0;
- QuicStreamFrame stream_frame;
- stream_frame.stream_id = 0x01020304;
- stream_frame.fin = true;
- stream_frame.offset = GG_UINT64_C(0xBA98FEDC32107654);
- stream_frame.data = MakeIOVector("hello world!");
+ QuicStreamFrame stream_frame(0x01020304, true, UINT64_C(0xBA98FEDC32107654),
+ StringPiece("hello world!"));
QuicFrames frames;
frames.push_back(QuicFrame(&stream_frame));
@@ -3275,7 +3241,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
QuicPacketPublicHeader header;
- header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.reset_flag = false;
header.version_flag = true;
@@ -3310,19 +3276,19 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
TEST_P(QuicFramerTest, BuildAckFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.packet_sequence_number = UINT64_C(0x770123456789AA8);
header.fec_group = 0;
QuicAckFrame ack_frame;
ack_frame.entropy_hash = 0x43;
- ack_frame.largest_observed = GG_UINT64_C(0x770123456789ABF);
+ ack_frame.largest_observed = UINT64_C(0x770123456789ABF);
ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
- ack_frame.missing_packets.insert(GG_UINT64_C(0x770123456789ABE));
+ ack_frame.missing_packets.insert(UINT64_C(0x770123456789ABE));
QuicFrames frames;
frames.push_back(QuicFrame(&ack_frame));
@@ -3371,12 +3337,12 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) {
TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.packet_sequence_number = UINT64_C(0x770123456789AA8);
header.fec_group = 0;
QuicAckFrame ack_frame;
@@ -3480,12 +3446,12 @@ TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.packet_sequence_number = UINT64_C(0x770123456789AA8);
header.fec_group = 0;
QuicAckFrame ack_frame;
@@ -3543,17 +3509,17 @@ TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) {
TEST_P(QuicFramerTest, BuildStopWaitingPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.packet_sequence_number = UINT64_C(0x770123456789AA8);
header.fec_group = 0;
QuicStopWaitingFrame stop_waiting_frame;
stop_waiting_frame.entropy_hash = 0x14;
- stop_waiting_frame.least_unacked = GG_UINT64_C(0x770123456789AA0);
+ stop_waiting_frame.least_unacked = UINT64_C(0x770123456789AA0);
QuicFrames frames;
frames.push_back(QuicFrame(&stop_waiting_frame));
@@ -3594,12 +3560,12 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuicVersion24) {
}
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicRstStreamFrame rst_frame;
@@ -3656,12 +3622,12 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
}
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicRstStreamFrame rst_frame;
@@ -3707,12 +3673,12 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
TEST_P(QuicFramerTest, BuildCloseFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicConnectionCloseFrame close_frame;
@@ -3757,12 +3723,12 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) {
TEST_P(QuicFramerTest, BuildGoAwayPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicGoAwayFrame goaway_frame;
@@ -3810,12 +3776,12 @@ TEST_P(QuicFramerTest, BuildGoAwayPacket) {
TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicWindowUpdateFrame window_update_frame;
@@ -3856,12 +3822,12 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
TEST_P(QuicFramerTest, BuildBlockedPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicBlockedFrame blocked_frame;
@@ -3898,12 +3864,12 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) {
TEST_P(QuicFramerTest, BuildPingPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicPingFrame ping_frame;
@@ -3935,13 +3901,55 @@ TEST_P(QuicFramerTest, BuildPingPacket) {
arraysize(packet));
}
+// Test that the MTU discovery packet is serialized correctly as a PING packet.
+TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
+ header.fec_group = 0;
+
+ QuicMtuDiscoveryFrame mtu_discovery_frame;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&mtu_discovery_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags(entropy)
+ 0x01,
+
+ // frame type (ping frame)
+ 0x07,
+ };
+ // clang-format on
+
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
TEST_P(QuicFramerTest, BuildPublicResetPacket) {
QuicPublicResetPacket reset_packet;
- reset_packet.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ reset_packet.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
reset_packet.public_header.reset_flag = true;
reset_packet.public_header.version_flag = false;
- reset_packet.rejected_sequence_number = GG_UINT64_C(0x123456789ABC);
- reset_packet.nonce_proof = GG_UINT64_C(0xABCDEF0123456789);
+ reset_packet.rejected_sequence_number = UINT64_C(0x123456789ABC);
+ reset_packet.nonce_proof = UINT64_C(0xABCDEF0123456789);
unsigned char packet[] = {
// public flags (public reset, 8 byte ConnectionId)
@@ -3980,11 +3988,11 @@ TEST_P(QuicFramerTest, BuildPublicResetPacket) {
TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) {
QuicPublicResetPacket reset_packet;
- reset_packet.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ reset_packet.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
reset_packet.public_header.reset_flag = true;
reset_packet.public_header.version_flag = false;
- reset_packet.rejected_sequence_number = GG_UINT64_C(0x123456789ABC);
- reset_packet.nonce_proof = GG_UINT64_C(0xABCDEF0123456789);
+ reset_packet.rejected_sequence_number = UINT64_C(0x123456789ABC);
+ reset_packet.nonce_proof = UINT64_C(0xABCDEF0123456789);
reset_packet.client_address = IPEndPoint(Loopback4(), 0x1234);
unsigned char packet[] = {
@@ -4032,14 +4040,14 @@ TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) {
TEST_P(QuicFramerTest, BuildFecPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = true;
header.entropy_flag = true;
- header.packet_sequence_number = (GG_UINT64_C(0x123456789ABC));
+ header.packet_sequence_number = (UINT64_C(0x123456789ABC));
header.is_in_fec_group = IN_FEC_GROUP;
- header.fec_group = GG_UINT64_C(0x123456789ABB);;
+ header.fec_group = UINT64_C(0x123456789ABB);
QuicFecData fec_data;
fec_data.fec_group = 1;
@@ -4075,7 +4083,7 @@ TEST_P(QuicFramerTest, BuildFecPacket) {
}
TEST_P(QuicFramerTest, EncryptPacket) {
- QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC);
+ QuicPacketSequenceNumber sequence_number = UINT64_C(0x123456789ABC);
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
@@ -4101,7 +4109,7 @@ TEST_P(QuicFramerTest, EncryptPacket) {
AsChars(packet), arraysize(packet), false, PACKET_8BYTE_CONNECTION_ID,
!kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER));
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
ENCRYPTION_NONE, sequence_number, *raw, buffer, kMaxPacketSize));
ASSERT_TRUE(encrypted.get() != nullptr);
@@ -4109,7 +4117,7 @@ TEST_P(QuicFramerTest, EncryptPacket) {
}
TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
- QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC);
+ QuicPacketSequenceNumber sequence_number = UINT64_C(0x123456789ABC);
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
0x3D,
@@ -4137,7 +4145,7 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
AsChars(packet), arraysize(packet), false, PACKET_8BYTE_CONNECTION_ID,
kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER));
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
ENCRYPTION_NONE, sequence_number, *raw, buffer, kMaxPacketSize));
ASSERT_TRUE(encrypted.get() != nullptr);
@@ -4146,12 +4154,12 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
TEST_P(QuicFramerTest, AckTruncationLargePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
// Create a packet with just the ack.
@@ -4167,8 +4175,8 @@ TEST_P(QuicFramerTest, AckTruncationLargePacket) {
ASSERT_TRUE(raw_ack_packet != nullptr);
char buffer[kMaxPacketSize];
scoped_ptr<QuicEncryptedPacket> ack_packet(
- framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
- *raw_ack_packet, buffer, kMaxPacketSize));
+ framer_.EncryptPayload(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_ack_packet, buffer, kMaxPacketSize));
// Now make sure we can turn our ack packet back into an ack frame.
ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
ASSERT_EQ(1u, visitor_.ack_frames_.size());
@@ -4186,12 +4194,12 @@ TEST_P(QuicFramerTest, AckTruncationLargePacket) {
TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
// Create a packet with just the ack.
@@ -4207,8 +4215,8 @@ TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
ASSERT_TRUE(raw_ack_packet != nullptr);
char buffer[kMaxPacketSize];
scoped_ptr<QuicEncryptedPacket> ack_packet(
- framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
- *raw_ack_packet, buffer, kMaxPacketSize));
+ framer_.EncryptPayload(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_ack_packet, buffer, kMaxPacketSize));
// Now make sure we can turn our ack packet back into an ack frame.
ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
ASSERT_EQ(1u, visitor_.ack_frames_.size());
@@ -4226,12 +4234,12 @@ TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
TEST_P(QuicFramerTest, CleanTruncation) {
QuicPacketHeader header;
- header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.packet_sequence_number = UINT64_C(0x123456789ABC);
header.fec_group = 0;
QuicAckFrame ack_frame;
@@ -4252,8 +4260,8 @@ TEST_P(QuicFramerTest, CleanTruncation) {
char buffer[kMaxPacketSize];
scoped_ptr<QuicEncryptedPacket> ack_packet(
- framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
- *raw_ack_packet, buffer, kMaxPacketSize));
+ framer_.EncryptPayload(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_ack_packet, buffer, kMaxPacketSize));
// Now make sure we can turn our ack packet back into an ack frame.
ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
@@ -4406,5 +4414,79 @@ TEST_P(QuicFramerTest, StopPacketProcessing) {
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
}
+static char kTestString[] = "At least 20 characters.";
+static QuicStreamId kTestQuicStreamId = 1;
+static bool ExpectedStreamFrame(const QuicStreamFrame& frame) {
+ return frame.stream_id == kTestQuicStreamId && !frame.fin &&
+ frame.offset == 0 && frame.data == kTestString;
+ // FIN is hard-coded false in ConstructEncryptedPacket.
+ // Offset 0 is hard-coded in ConstructEncryptedPacket.
+}
+
+// Verify that the packet returned by ConstructEncryptedPacket() can be properly
+// parsed by the framer.
+TEST_P(QuicFramerTest, ConstructEncryptedPacket) {
+ // Since we are using ConstructEncryptedPacket, we have to set the framer's
+ // crypto to be Null.
+ framer_.SetDecrypter(ENCRYPTION_NONE, QuicDecrypter::Create(kNULL));
+ framer_.SetEncrypter(ENCRYPTION_NONE, QuicEncrypter::Create(kNULL));
+
+ scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
+ 42, false, false, kTestQuicStreamId, kTestString,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_SEQUENCE_NUMBER));
+
+ MockFramerVisitor visitor;
+ framer_.set_visitor(&visitor);
+ EXPECT_CALL(visitor, OnPacket()).Times(1);
+ EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_))
+ .Times(1)
+ .WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnUnauthenticatedHeader(_))
+ .Times(1)
+ .WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnPacketHeader(_)).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1);
+ EXPECT_CALL(visitor, OnError(_)).Times(0);
+ EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnStreamFrame(Truly(ExpectedStreamFrame))).Times(1);
+ EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnPacketComplete()).Times(1);
+
+ EXPECT_TRUE(framer_.ProcessPacket(*packet));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+}
+
+// Verify that the packet returned by ConstructMisFramedEncryptedPacket()
+// does cause the framer to return an error.
+TEST_P(QuicFramerTest, ConstructMisFramedEncryptedPacket) {
+ // Since we are using ConstructEncryptedPacket, we have to set the framer's
+ // crypto to be Null.
+ framer_.SetDecrypter(ENCRYPTION_NONE, QuicDecrypter::Create(kNULL));
+ framer_.SetEncrypter(ENCRYPTION_NONE, QuicEncrypter::Create(kNULL));
+
+ scoped_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket(
+ 42, false, false, kTestQuicStreamId, kTestString,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_SEQUENCE_NUMBER, nullptr));
+
+ MockFramerVisitor visitor;
+ framer_.set_visitor(&visitor);
+ EXPECT_CALL(visitor, OnPacket()).Times(1);
+ EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_))
+ .Times(1)
+ .WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnUnauthenticatedHeader(_))
+ .Times(1)
+ .WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnPacketHeader(_)).Times(0);
+ EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1);
+ EXPECT_CALL(visitor, OnError(_)).Times(1);
+ EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnPacketComplete()).Times(0);
+
+ EXPECT_FALSE(framer_.ProcessPacket(*packet));
+ EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/quic_headers_stream.cc b/chromium/net/quic/quic_headers_stream.cc
index f1d972c5cfd..0b57780d544 100644
--- a/chromium/net/quic/quic_headers_stream.cc
+++ b/chromium/net/quic/quic_headers_stream.cc
@@ -5,7 +5,7 @@
#include "net/quic/quic_headers_stream.h"
#include "base/strings/stringprintf.h"
-#include "net/quic/quic_session.h"
+#include "net/quic/quic_spdy_session.h"
using base::StringPiece;
using std::string;
@@ -25,8 +25,7 @@ class QuicHeadersStream::SpdyFramerVisitor
: public SpdyFramerVisitorInterface,
public SpdyFramerDebugVisitorInterface {
public:
- SpdyFramerVisitor(SpdyMajorVersion spdy_version, QuicHeadersStream* stream)
- : spdy_version_(spdy_version), stream_(stream) {}
+ SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {}
// SpdyFramerVisitorInterface implementation
void OnSynStream(SpdyStreamId stream_id,
@@ -109,6 +108,8 @@ class QuicHeadersStream::SpdyFramerVisitor
void OnHeaders(SpdyStreamId stream_id,
bool has_priority,
SpdyPriority priority,
+ SpdyStreamId parent_stream_id,
+ bool exclusive,
bool fin,
bool end) override {
if (!stream_->IsConnected()) {
@@ -121,8 +122,7 @@ class QuicHeadersStream::SpdyFramerVisitor
}
}
- void OnWindowUpdate(SpdyStreamId stream_id,
- uint32 delta_window_size) override {
+ void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {
CloseConnection("SPDY WINDOW_UPDATE frame received.");
}
@@ -163,19 +163,19 @@ class QuicHeadersStream::SpdyFramerVisitor
}
private:
- SpdyMajorVersion spdy_version_;
QuicHeadersStream* stream_;
DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor);
};
-QuicHeadersStream::QuicHeadersStream(QuicSession* session)
+QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session)
: ReliableQuicStream(kHeadersStreamId, session),
+ spdy_session_(session),
stream_id_(kInvalidStreamId),
fin_(false),
frame_len_(0),
- spdy_framer_(SPDY4),
- spdy_framer_visitor_(new SpdyFramerVisitor(SPDY4, this)) {
+ spdy_framer_(HTTP2),
+ spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
spdy_framer_.set_visitor(spdy_framer_visitor_.get());
spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
// The headers stream is exempt from connection level flow control.
@@ -223,7 +223,7 @@ void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id,
DCHECK_EQ(kInvalidStreamId, stream_id_);
stream_id_ = stream_id;
fin_ = fin;
- session()->OnStreamHeadersPriority(stream_id, priority);
+ spdy_session_->OnStreamHeadersPriority(stream_id, priority);
}
void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id, bool fin) {
@@ -245,13 +245,13 @@ void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id,
if (len == 0) {
DCHECK_NE(0u, stream_id_);
DCHECK_NE(0u, frame_len_);
- session()->OnStreamHeadersComplete(stream_id_, fin_, frame_len_);
+ spdy_session_->OnStreamHeadersComplete(stream_id_, fin_, frame_len_);
// Reset state for the next frame.
stream_id_ = kInvalidStreamId;
fin_ = false;
frame_len_ = 0;
} else {
- session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len));
+ spdy_session_->OnStreamHeaders(stream_id_, StringPiece(header_data, len));
}
}
diff --git a/chromium/net/quic/quic_headers_stream.h b/chromium/net/quic/quic_headers_stream.h
index a9184731ae2..f0838de8485 100644
--- a/chromium/net/quic/quic_headers_stream.h
+++ b/chromium/net/quic/quic_headers_stream.h
@@ -14,13 +14,15 @@
namespace net {
+class QuicSpdySession;
+
// Headers in QUIC are sent as SPDY SYN_STREAM or SYN_REPLY frames
-// over a reserved reliable stream with the id 2. Each endpoint (client
+// over a reserved reliable stream with the id 3. Each endpoint (client
// and server) will allocate an instance of QuicHeadersStream to send
// and receive headers.
class NET_EXPORT_PRIVATE QuicHeadersStream : public ReliableQuicStream {
public:
- explicit QuicHeadersStream(QuicSession* session);
+ explicit QuicHeadersStream(QuicSpdySession* session);
~QuicHeadersStream() override;
// Writes |headers| for |stream_id| in a SYN_STREAM or SYN_REPLY
@@ -67,6 +69,8 @@ class NET_EXPORT_PRIVATE QuicHeadersStream : public ReliableQuicStream {
// Returns true if the session is still connected.
bool IsConnected();
+ QuicSpdySession* spdy_session_;
+
// Data about the stream whose headers are being processed.
QuicStreamId stream_id_;
bool fin_;
diff --git a/chromium/net/quic/quic_headers_stream_test.cc b/chromium/net/quic/quic_headers_stream_test.cc
index 9f3b59f2d22..4e417b2238e 100644
--- a/chromium/net/quic/quic_headers_stream_test.cc
+++ b/chromium/net/quic/quic_headers_stream_test.cc
@@ -7,7 +7,7 @@
#include "net/quic/quic_utils.h"
#include "net/quic/spdy_utils.h"
#include "net/quic/test_tools/quic_connection_peer.h"
-#include "net/quic/test_tools/quic_session_peer.h"
+#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
#include "net/spdy/spdy_protocol.h"
@@ -55,10 +55,16 @@ class MockVisitor : public SpdyFramerVisitorInterface {
MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
SpdyGoAwayStatus status));
- MOCK_METHOD5(OnHeaders, void(SpdyStreamId stream_id, bool has_priority,
- SpdyPriority priority, bool fin, bool end));
- MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
- uint32 delta_window_size));
+ MOCK_METHOD7(OnHeaders,
+ void(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
+ SpdyStreamId parent_stream_id,
+ bool exclusive,
+ bool fin,
+ bool end));
+ MOCK_METHOD2(OnWindowUpdate,
+ void(SpdyStreamId stream_id, int delta_window_size));
MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data,
size_t len));
MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
@@ -66,12 +72,11 @@ class MockVisitor : public SpdyFramerVisitorInterface {
SpdyStreamId promised_stream_id,
bool end));
MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
- MOCK_METHOD6(OnAltSvc, void(SpdyStreamId stream_id,
- uint32 max_age,
- uint16 port,
- StringPiece protocol_id,
- StringPiece host,
- StringPiece origin));
+ MOCK_METHOD3(OnAltSvc,
+ void(SpdyStreamId stream_id,
+ StringPiece origin,
+ const SpdyAltSvcWireFormat::AlternativeServiceVector&
+ altsvc_vector));
MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
};
@@ -107,9 +112,9 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> {
: connection_(
new StrictMock<MockConnection>(perspective(), GetVersion())),
session_(connection_),
- headers_stream_(QuicSessionPeer::GetHeadersStream(&session_)),
+ headers_stream_(QuicSpdySessionPeer::GetHeadersStream(&session_)),
body_("hello world"),
- framer_(SPDY4) {
+ framer_(HTTP2) {
headers_[":version"] = "HTTP/1.1";
headers_[":status"] = "200 Ok";
headers_["content-length"] = "11";
@@ -119,9 +124,9 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> {
VLOG(1) << GetParam();
}
- QuicConsumedData SaveIov(const IOVector& data) {
- const iovec* iov = data.iovec();
- int count = data.Capacity();
+ QuicConsumedData SaveIov(const QuicIOVector& data) {
+ const iovec* iov = data.iov;
+ int count = data.iov_count;
for (int i = 0 ; i < count; ++i) {
saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
}
@@ -159,11 +164,17 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> {
// Parse the outgoing data and check that it matches was was written.
if (type == SYN_STREAM) {
- EXPECT_CALL(visitor_, OnHeaders(stream_id, kHasPriority, priority, fin,
- kFrameComplete));
+ EXPECT_CALL(visitor_, OnHeaders(stream_id, kHasPriority, priority,
+ /*parent_stream_id=*/0,
+ /*exclusive=*/false,
+
+ fin, kFrameComplete));
} else {
- EXPECT_CALL(visitor_, OnHeaders(stream_id, !kHasPriority,
- /*priority=*/0, fin, kFrameComplete));
+ EXPECT_CALL(visitor_,
+ OnHeaders(stream_id, !kHasPriority,
+ /*priority=*/0,
+ /*parent_stream_id=*/0,
+ /*exclusive=*/false, fin, kFrameComplete));
}
EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _))
.WillRepeatedly(WithArgs<1, 2>(
@@ -207,7 +218,7 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> {
static const bool kHasPriority = true;
StrictMock<MockConnection>* connection_;
- StrictMock<MockSession> session_;
+ StrictMock<MockQuicSpdySession> session_;
QuicHeadersStream* headers_stream_;
SpdyHeaderBlock headers_;
string body_;
diff --git a/chromium/net/quic/quic_http_stream.cc b/chromium/net/quic/quic_http_stream.cc
index cce1512c788..b516aba1387 100644
--- a/chromium/net/quic/quic_http_stream.cc
+++ b/chromium/net/quic/quic_http_stream.cc
@@ -5,7 +5,7 @@
#include "net/quic/quic_http_stream.h"
#include "base/callback_helpers.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -24,8 +24,6 @@
namespace net {
-static const size_t kHeaderBufInitialSize = 4096;
-
QuicHttpStream::QuicHttpStream(const base::WeakPtr<QuicClientSession>& session)
: next_state_(STATE_NONE),
session_(session),
@@ -38,7 +36,6 @@ QuicHttpStream::QuicHttpStream(const base::WeakPtr<QuicClientSession>& session)
response_info_(nullptr),
response_status_(OK),
response_headers_received_(false),
- read_buf_(new GrowableIOBuffer()),
closed_stream_received_bytes_(0),
user_buffer_len_(0),
weak_factory_(this) {
@@ -306,25 +303,15 @@ void QuicHttpStream::SetPriority(RequestPriority priority) {
priority_ = priority;
}
+void QuicHttpStream::OnHeadersAvailable(StringPiece headers) {
+ int rv = ParseResponseHeaders(headers);
+ if (rv != ERR_IO_PENDING && !callback_.is_null()) {
+ DoCallback(rv);
+ }
+}
+
int QuicHttpStream::OnDataReceived(const char* data, int length) {
DCHECK_NE(0, length);
- // Are we still reading the response headers.
- if (!response_headers_received_) {
- // Grow the read buffer if necessary.
- if (read_buf_->RemainingCapacity() < length) {
- size_t additional_capacity = length - read_buf_->RemainingCapacity();
- if (additional_capacity < kHeaderBufInitialSize)
- additional_capacity = kHeaderBufInitialSize;
- read_buf_->SetCapacity(read_buf_->capacity() + additional_capacity);
- }
- memcpy(read_buf_->data(), data, length);
- read_buf_->set_offset(read_buf_->offset() + length);
- int rv = ParseResponseHeaders();
- if (rv != ERR_IO_PENDING && !callback_.is_null()) {
- DoCallback(rv);
- }
- return OK;
- }
if (callback_.is_null()) {
BufferResponseBody(data, length);
@@ -529,22 +516,14 @@ int QuicHttpStream::DoSendBodyComplete(int rv) {
return OK;
}
-int QuicHttpStream::ParseResponseHeaders() {
- size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
+int QuicHttpStream::ParseResponseHeaders(StringPiece headers_data) {
SpdyFramer framer(GetSpdyVersion());
SpdyHeaderBlock headers;
- char* data = read_buf_->StartOfBuffer();
- size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
- &headers);
-
- if (len == 0) {
- return ERR_IO_PENDING;
- }
-
- // Save the remaining received data.
- size_t delta = read_buf_len - len;
- if (delta > 0) {
- BufferResponseBody(data + len, delta);
+ size_t len = framer.ParseHeaderBlockInBuffer(headers_data.data(),
+ headers_data.length(), &headers);
+ if (len == 0 || len != headers_data.length()) {
+ DLOG(WARNING) << "Invalid headers";
+ return ERR_QUIC_PROTOCOL_ERROR;
}
// The URLRequest logs these headers, so only log to the QuicSession's
diff --git a/chromium/net/quic/quic_http_stream.h b/chromium/net/quic/quic_http_stream.h
index 12ca814f4a3..e78e57962f6 100644
--- a/chromium/net/quic/quic_http_stream.h
+++ b/chromium/net/quic/quic_http_stream.h
@@ -60,6 +60,7 @@ class NET_EXPORT_PRIVATE QuicHttpStream :
void SetPriority(RequestPriority priority) override;
// QuicReliableClientStream::Delegate implementation
+ void OnHeadersAvailable(StringPiece headers) override;
int OnDataReceived(const char* data, int length) override;
void OnClose(QuicErrorCode error) override;
void OnError(int error) override;
@@ -97,7 +98,7 @@ class NET_EXPORT_PRIVATE QuicHttpStream :
int DoReadResponseHeaders();
int DoReadResponseHeadersComplete(int rv);
- int ParseResponseHeaders();
+ int ParseResponseHeaders(StringPiece headers);
void BufferResponseBody(const char* data, int length);
@@ -139,9 +140,6 @@ class NET_EXPORT_PRIVATE QuicHttpStream :
// Serialized HTTP request.
std::string request_;
- // Buffer into which response header data is read.
- scoped_refptr<GrowableIOBuffer> read_buf_;
-
// We buffer the response body as it arrives asynchronously from the stream.
// TODO(rch): This is infinite buffering, which is bad.
std::list<scoped_refptr<IOBufferWithSize> > response_body_;
diff --git a/chromium/net/quic/quic_http_stream_test.cc b/chromium/net/quic/quic_http_stream_test.cc
index fb4d6ae95e2..412bd23ef2a 100644
--- a/chromium/net/quic/quic_http_stream_test.cc
+++ b/chromium/net/quic/quic_http_stream_test.cc
@@ -6,6 +6,7 @@
#include <vector>
+#include "base/thread_task_runner_handle.h"
#include "net/base/chunked_upload_data_stream.h"
#include "net/base/elements_upload_data_stream.h"
#include "net/base/net_errors.h"
@@ -82,6 +83,8 @@ class AutoClosingStream : public QuicHttpStream {
: QuicHttpStream(session) {
}
+ void OnHeadersAvailable(StringPiece headers) override { Close(false); }
+
int OnDataReceived(const char* data, int length) override {
Close(false);
return OK;
@@ -162,7 +165,8 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
}
bool AtEof() {
- return socket_data_->at_read_eof() && socket_data_->at_write_eof();
+ return socket_data_->AllReadDataConsumed() &&
+ socket_data_->AllWriteDataConsumed();
}
void ProcessPacket(scoped_ptr<QuicEncryptedPacket> packet) {
@@ -186,6 +190,8 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
socket->Connect(peer_addr_);
runner_ = new TestTaskRunner(&clock_);
send_algorithm_ = new MockSendAlgorithm();
+ EXPECT_CALL(*send_algorithm_, InRecovery()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*send_algorithm_, InSlowStart()).WillRepeatedly(Return(false));
EXPECT_CALL(*send_algorithm_,
OnPacketSent(_, _, _, _, _)).WillRepeatedly(Return(true));
EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly(
@@ -206,15 +212,15 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
connection_->set_visitor(&visitor_);
connection_->SetSendAlgorithm(send_algorithm_);
session_.reset(new QuicClientSession(
- connection_, scoped_ptr<DatagramClientSocket>(socket), nullptr,
+ connection_, scoped_ptr<DatagramClientSocket>(socket),
+ /*stream_factory=*/nullptr, &crypto_client_stream_factory_,
&transport_security_state_, make_scoped_ptr((QuicServerInfo*)nullptr),
- /*cert_verify_flags=*/0, DefaultQuicConfig(), "CONNECTION_UNKNOWN",
- base::TimeTicks::Now(),
- base::MessageLoop::current()->message_loop_proxy().get(), nullptr));
- session_->InitializeSession(
QuicServerId(kDefaultServerHostName, kDefaultServerPort,
/*is_secure=*/false, PRIVACY_MODE_DISABLED),
- &crypto_config_, &crypto_client_stream_factory_);
+ /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
+ "CONNECTION_UNKNOWN", base::TimeTicks::Now(),
+ base::ThreadTaskRunnerHandle::Get().get(), nullptr));
+ session_->Initialize();
session_->GetCryptoStream()->CryptoConnect();
EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
stream_.reset(use_closing_stream_ ?
@@ -398,13 +404,10 @@ TEST_P(QuicHttpStreamTest, GetRequestLargeResponse) {
headers[":status"] = "200 OK";
headers[":version"] = "HTTP/1.1";
headers["content-type"] = "text/plain";
- headers["big6"] = std::string(10000, 'x'); // Lots of x's.
+ headers["big6"] = std::string(1000, 'x'); // Lots of x's.
- std::string response =
- SpdyUtils::SerializeUncompressedHeaders(headers, GetParam());
- EXPECT_LT(4096u, response.length());
- stream_->OnDataReceived(response.data(), response.length());
- stream_->OnClose(QUIC_NO_ERROR);
+ response_headers_ = headers;
+ ProcessPacket(ConstructResponseHeadersPacket(2, kFin));
// Now that the headers have been processed, the callback will return.
EXPECT_EQ(OK, callback_.WaitForResult());
diff --git a/chromium/net/quic/quic_http_utils.cc b/chromium/net/quic/quic_http_utils.cc
index 9a1c6bbb896..60fbd9a4a7f 100644
--- a/chromium/net/quic/quic_http_utils.cc
+++ b/chromium/net/quic/quic_http_utils.cc
@@ -20,15 +20,16 @@ NET_EXPORT_PRIVATE RequestPriority ConvertQuicPriorityToRequestPriority(
IDLE : static_cast<RequestPriority>(HIGHEST - priority);
}
-base::Value* QuicRequestNetLogCallback(QuicStreamId stream_id,
- const SpdyHeaderBlock* headers,
- QuicPriority priority,
- NetLogCaptureMode capture_mode) {
- base::DictionaryValue* dict = static_cast<base::DictionaryValue*>(
- SpdyHeaderBlockNetLogCallback(headers, capture_mode));
+scoped_ptr<base::Value> QuicRequestNetLogCallback(
+ QuicStreamId stream_id,
+ const SpdyHeaderBlock* headers,
+ QuicPriority priority,
+ NetLogCaptureMode capture_mode) {
+ scoped_ptr<base::DictionaryValue> dict(static_cast<base::DictionaryValue*>(
+ SpdyHeaderBlockNetLogCallback(headers, capture_mode).release()));
dict->SetInteger("quic_priority", static_cast<int>(priority));
dict->SetInteger("quic_stream_id", static_cast<int>(stream_id));
- return dict;
+ return dict.Pass();
}
} // namespace net
diff --git a/chromium/net/quic/quic_http_utils.h b/chromium/net/quic/quic_http_utils.h
index 6eafbc0f092..82306d63ce2 100644
--- a/chromium/net/quic/quic_http_utils.h
+++ b/chromium/net/quic/quic_http_utils.h
@@ -19,9 +19,8 @@ NET_EXPORT_PRIVATE QuicPriority ConvertRequestPriorityToQuicPriority(
NET_EXPORT_PRIVATE RequestPriority ConvertQuicPriorityToRequestPriority(
QuicPriority priority);
-// Converts a SpdyHeaderBlock and priority into NetLog event parameters. Caller
-// takes ownership of returned value.
-NET_EXPORT base::Value* QuicRequestNetLogCallback(
+// Converts a SpdyHeaderBlock and priority into NetLog event parameters.
+NET_EXPORT scoped_ptr<base::Value> QuicRequestNetLogCallback(
QuicStreamId stream_id,
const SpdyHeaderBlock* headers,
QuicPriority priority,
diff --git a/chromium/net/quic/quic_network_transaction_unittest.cc b/chromium/net/quic/quic_network_transaction_unittest.cc
index b78bde6d58c..697e73a188f 100644
--- a/chromium/net/quic/quic_network_transaction_unittest.cc
+++ b/chromium/net/quic/quic_network_transaction_unittest.cc
@@ -252,6 +252,8 @@ class QuicNetworkTransactionTest
session_ = new HttpNetworkSession(params_);
session_->quic_stream_factory()->set_require_confirmation(false);
+ ASSERT_EQ(params_.quic_socket_receive_buffer_size,
+ session_->quic_stream_factory()->socket_receive_buffer_size());
}
void CheckWasQuicResponse(const scoped_ptr<HttpNetworkTransaction>& trans) {
@@ -331,18 +333,19 @@ class QuicNetworkTransactionTest
void ExpectBrokenAlternateProtocolMapping() {
const HostPortPair origin = HostPortPair::FromURL(request_.url);
- const AlternativeService alternative_service =
- http_server_properties_.GetAlternativeService(origin);
- EXPECT_NE(UNINITIALIZED_ALTERNATE_PROTOCOL, alternative_service.protocol);
+ const AlternativeServiceVector alternative_service_vector =
+ http_server_properties_.GetAlternativeServices(origin);
+ EXPECT_EQ(1u, alternative_service_vector.size());
EXPECT_TRUE(http_server_properties_.IsAlternativeServiceBroken(
- alternative_service));
+ alternative_service_vector[0]));
}
void ExpectQuicAlternateProtocolMapping() {
- const AlternativeService alternative_service =
- http_server_properties_.GetAlternativeService(
- HostPortPair::FromURL(request_.url));
- EXPECT_EQ(QUIC, alternative_service.protocol);
+ const HostPortPair origin = HostPortPair::FromURL(request_.url);
+ const AlternativeServiceVector alternative_service_vector =
+ http_server_properties_.GetAlternativeServices(origin);
+ EXPECT_EQ(1u, alternative_service_vector.size());
+ EXPECT_EQ(QUIC, alternative_service_vector[0].protocol);
}
void AddHangingNonAlternateProtocolSocketData() {
@@ -477,6 +480,48 @@ TEST_P(QuicNetworkTransactionTest, QuicProxy) {
SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
}
+// Regression test for https://crbug.com/492458. Test that for an HTTP
+// connection through a QUIC proxy, the certificate exhibited by the proxy is
+// checked against the proxy hostname, not the origin hostname.
+TEST_P(QuicNetworkTransactionTest, QuicProxyWithCert) {
+ const std::string origin_host = "news.example.com";
+ const std::string proxy_host = "www.example.org";
+
+ params_.enable_quic_for_proxies = true;
+ proxy_service_.reset(
+ ProxyService::CreateFixedFromPacResult("QUIC " + proxy_host + ":70"));
+
+ maker_.set_hostname(origin_host);
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "http", "/")));
+ mock_quic_data.AddRead(ConstructResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(
+ ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
+ mock_quic_data.AddRead(SYNCHRONOUS, 0);
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
+ ASSERT_TRUE(cert.get());
+ // This certificate is valid for the proxy, but not for the origin.
+ bool common_name_fallback_used;
+ EXPECT_TRUE(cert->VerifyNameMatch(proxy_host, &common_name_fallback_used));
+ EXPECT_FALSE(cert->VerifyNameMatch(origin_host, &common_name_fallback_used));
+ ProofVerifyDetailsChromium verify_details;
+ verify_details.cert_verify_result.verified_cert = cert;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ request_.url = GURL("http://" + origin_host);
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSessionWithNextProtos();
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
+}
+
TEST_P(QuicNetworkTransactionTest, ForceQuicWithErrorConnecting) {
params_.origin_to_force_quic_on =
HostPortPair::FromString("www.google.com:80");
@@ -779,6 +824,88 @@ TEST_P(QuicNetworkTransactionTest, UseAlternateProtocolForQuicForHttps) {
SendRequestAndExpectHttpResponse("hello world");
}
+class QuicAltSvcCertificateVerificationTest
+ : public QuicNetworkTransactionTest {
+ public:
+ void Run(bool valid) {
+ HostPortPair origin(valid ? "mail.example.org" : "invalid.example.org",
+ 443);
+ HostPortPair alternative("www.example.org", 443);
+ std::string url("https://");
+ url.append(origin.host());
+ url.append(":443");
+ request_.url = GURL(url);
+
+ maker_.set_hostname(origin.host());
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(
+ ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
+ mock_quic_data.AddRead(SYNCHRONOUS, 0);
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
+ ASSERT_TRUE(cert.get());
+ bool common_name_fallback_used;
+ EXPECT_EQ(valid,
+ cert->VerifyNameMatch(origin.host(), &common_name_fallback_used));
+ EXPECT_TRUE(
+ cert->VerifyNameMatch(alternative.host(), &common_name_fallback_used));
+ ProofVerifyDetailsChromium verify_details;
+ verify_details.cert_verify_result.verified_cert = cert;
+ verify_details.cert_verify_result.is_issued_by_known_root = true;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+
+ // Connection to |origin| fails, so that success of |request| depends on
+ // connection to |alternate| only.
+ MockConnect refused_connect(ASYNC, ERR_CONNECTION_REFUSED);
+ StaticSocketDataProvider refused_data;
+ refused_data.set_connect_data(refused_connect);
+ socket_factory_.AddSocketDataProvider(&refused_data);
+
+ CreateSessionWithNextProtos();
+ AlternativeService alternative_service(QUIC, alternative);
+ session_->http_server_properties()->SetAlternativeService(
+ origin, alternative_service, 1.0);
+ scoped_ptr<HttpNetworkTransaction> trans(
+ new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
+ TestCompletionCallback callback;
+ int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = callback.WaitForResult();
+ if (valid) {
+ EXPECT_EQ(OK, rv);
+ CheckWasQuicResponse(trans);
+ CheckResponsePort(trans, 443);
+ CheckResponseData(trans, "hello!");
+ } else {
+ EXPECT_EQ(ERR_CONNECTION_REFUSED, rv);
+ }
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(Version,
+ QuicAltSvcCertificateVerificationTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicAltSvcCertificateVerificationTest,
+ RequestSucceedsWithValidCertificate) {
+ Run(true);
+}
+
+TEST_P(QuicAltSvcCertificateVerificationTest,
+ RequestFailsWithInvalidCertificate) {
+ Run(false);
+}
+
TEST_P(QuicNetworkTransactionTest, HungAlternateProtocol) {
crypto_client_stream_factory_.set_handshake_mode(
MockCryptoClientStream::COLD_START);
@@ -823,18 +950,18 @@ TEST_P(QuicNetworkTransactionTest, HungAlternateProtocol) {
// Run the first request.
http_data.StopAfter(arraysize(http_reads) + arraysize(http_writes));
SendRequestAndExpectHttpResponse("hello world");
- ASSERT_TRUE(http_data.at_read_eof());
- ASSERT_TRUE(http_data.at_write_eof());
+ ASSERT_TRUE(http_data.AllReadDataConsumed());
+ ASSERT_TRUE(http_data.AllWriteDataConsumed());
// Now run the second request in which the QUIC socket hangs,
// and verify the the transaction continues over HTTP.
http_data2.StopAfter(arraysize(http_reads) + arraysize(http_writes));
SendRequestAndExpectHttpResponse("hello world");
- ASSERT_TRUE(http_data2.at_read_eof());
- ASSERT_TRUE(http_data2.at_write_eof());
- ASSERT_TRUE(!quic_data.at_read_eof());
- ASSERT_TRUE(!quic_data.at_write_eof());
+ ASSERT_TRUE(http_data2.AllReadDataConsumed());
+ ASSERT_TRUE(http_data2.AllWriteDataConsumed());
+ ASSERT_TRUE(!quic_data.AllReadDataConsumed());
+ ASSERT_TRUE(!quic_data.AllWriteDataConsumed());
}
TEST_P(QuicNetworkTransactionTest, ZeroRTTWithHttpRace) {
@@ -1104,8 +1231,8 @@ TEST_P(QuicNetworkTransactionTest, FailedZeroRttBrokenAlternateProtocol) {
ExpectBrokenAlternateProtocolMapping();
- EXPECT_TRUE(quic_data.at_read_eof());
- EXPECT_TRUE(quic_data.at_write_eof());
+ EXPECT_TRUE(quic_data.AllReadDataConsumed());
+ EXPECT_TRUE(quic_data.AllWriteDataConsumed());
}
TEST_P(QuicNetworkTransactionTest, DISABLED_HangingZeroRttFallback) {
diff --git a/chromium/net/quic/quic_packet_creator.cc b/chromium/net/quic/quic_packet_creator.cc
index 9deb614f130..7474b0b17b7 100644
--- a/chromium/net/quic/quic_packet_creator.cc
+++ b/chromium/net/quic/quic_packet_creator.cc
@@ -78,11 +78,13 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id,
should_fec_protect_(false),
fec_group_number_(0),
send_version_in_packet_(framer->perspective() == Perspective::IS_CLIENT),
+ max_packet_length_(0),
max_packets_per_fec_group_(kDefaultMaxPacketsPerFecGroup),
connection_id_length_(PACKET_8BYTE_CONNECTION_ID),
next_sequence_number_length_(PACKET_1BYTE_SEQUENCE_NUMBER),
sequence_number_length_(next_sequence_number_length_),
- packet_size_(0) {
+ packet_size_(0),
+ needs_padding_(false) {
SetMaxPacketLength(kDefaultMaxPacketSize);
}
@@ -103,9 +105,20 @@ void QuicPacketCreator::SetEncrypter(EncryptionLevel level,
max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_);
}
-void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) {
+bool QuicPacketCreator::CanSetMaxPacketLength() const {
// |max_packet_length_| should not be changed mid-packet or mid-FEC group.
- DCHECK(fec_group_.get() == nullptr && queued_frames_.empty());
+ return fec_group_.get() == nullptr && queued_frames_.empty();
+}
+
+void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) {
+ DCHECK(CanSetMaxPacketLength());
+
+ // Avoid recomputing |max_plaintext_size_| if the length does not actually
+ // change.
+ if (length == max_packet_length_) {
+ return;
+ }
+
max_packet_length_ = length;
max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_);
}
@@ -124,6 +137,15 @@ bool QuicPacketCreator::ShouldSendFec(bool force_close) const {
fec_group_->NumReceivedPackets() >= max_packets_per_fec_group_);
}
+void QuicPacketCreator::ResetFecGroup() {
+ if (HasPendingFrames()) {
+ LOG_IF(DFATAL, packet_size_ != 0)
+ << "Cannot reset FEC group with pending frames.";
+ return;
+ }
+ fec_group_.reset(nullptr);
+}
+
bool QuicPacketCreator::IsFecGroupOpen() const {
return fec_group_.get() != nullptr;
}
@@ -172,7 +194,7 @@ InFecGroup QuicPacketCreator::MaybeUpdateLengthsAndStartFec() {
}
if (!queued_frames_.empty()) {
// Don't change creator state if there are frames queued.
- return fec_group_.get() == nullptr ? NOT_IN_FEC_GROUP : IN_FEC_GROUP;
+ return NOT_IN_FEC_GROUP;
}
// Update sequence number length only on packet and FEC group boundaries.
@@ -239,13 +261,16 @@ size_t QuicPacketCreator::StreamFramePacketOverhead(
}
size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
- const IOVector& data,
+ const QuicIOVector& iov,
+ size_t iov_offset,
QuicStreamOffset offset,
bool fin,
- QuicFrame* frame) {
+ QuicFrame* frame,
+ scoped_ptr<char[]>* buffer) {
DCHECK_GT(max_packet_length_, StreamFramePacketOverhead(
connection_id_length_, kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, offset, IN_FEC_GROUP));
+ DCHECK(buffer);
InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec();
@@ -254,28 +279,49 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
<< " MinStreamFrameSize: "
<< QuicFramer::GetMinStreamFrameSize(id, offset, true, is_in_fec_group);
- if (data.Empty()) {
+ if (iov_offset == iov.total_length) {
LOG_IF(DFATAL, !fin)
<< "Creating a stream frame with no data or fin.";
// Create a new packet for the fin, if necessary.
- *frame = QuicFrame(new QuicStreamFrame(id, true, offset, data));
+ *frame = QuicFrame(new QuicStreamFrame(id, true, offset, StringPiece()));
return 0;
}
- const size_t data_size = data.TotalBufferSize();
+ const size_t data_size = iov.total_length - iov_offset;
size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
id, offset, /* last_frame_in_packet= */ true, is_in_fec_group);
size_t bytes_consumed = min<size_t>(BytesFree() - min_frame_size, data_size);
bool set_fin = fin && bytes_consumed == data_size; // Last frame.
- IOVector frame_data;
- frame_data.AppendIovecAtMostBytes(data.iovec(), data.Size(),
- bytes_consumed);
- DCHECK_EQ(frame_data.TotalBufferSize(), bytes_consumed);
- *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, frame_data));
+ buffer->reset(new char[bytes_consumed]);
+ CopyToBuffer(iov, iov_offset, bytes_consumed, buffer->get());
+ *frame = QuicFrame(new QuicStreamFrame(
+ id, set_fin, offset, StringPiece(buffer->get(), bytes_consumed)));
return bytes_consumed;
}
+// static
+void QuicPacketCreator::CopyToBuffer(const QuicIOVector& iov,
+ size_t iov_offset,
+ size_t length,
+ char* buffer) {
+ int iovnum = 0;
+ while (iovnum < iov.iov_count && iov_offset >= iov.iov[iovnum].iov_len) {
+ iov_offset -= iov.iov[iovnum].iov_len;
+ ++iovnum;
+ }
+ while (iovnum < iov.iov_count && length > 0) {
+ const size_t copy_len = min(length, iov.iov[iovnum].iov_len - iov_offset);
+ memcpy(buffer, static_cast<char*>(iov.iov[iovnum].iov_base) + iov_offset,
+ copy_len);
+ iov_offset = 0;
+ length -= copy_len;
+ buffer += copy_len;
+ ++iovnum;
+ }
+ LOG_IF(DFATAL, length > 0) << "Failed to copy entire length to buffer.";
+}
+
SerializedPacket QuicPacketCreator::ReserializeAllFrames(
const RetransmittableFrames& frames,
QuicSequenceNumberLength original_length,
@@ -286,6 +332,7 @@ SerializedPacket QuicPacketCreator::ReserializeAllFrames(
const QuicSequenceNumberLength saved_next_length =
next_sequence_number_length_;
const bool saved_should_fec_protect = should_fec_protect_;
+ const bool needs_padding = needs_padding_;
const EncryptionLevel default_encryption_level = encryption_level_;
// Temporarily set the sequence number length, stop FEC protection,
@@ -294,6 +341,7 @@ SerializedPacket QuicPacketCreator::ReserializeAllFrames(
next_sequence_number_length_ = original_length;
should_fec_protect_ = false;
encryption_level_ = frames.encryption_level();
+ needs_padding_ = frames.needs_padding();
// Serialize the packet and restore the FEC and sequence number length state.
SerializedPacket serialized_packet =
@@ -301,6 +349,7 @@ SerializedPacket QuicPacketCreator::ReserializeAllFrames(
sequence_number_length_ = saved_length;
next_sequence_number_length_ = saved_next_length;
should_fec_protect_ = saved_should_fec_protect;
+ needs_padding_ = needs_padding;
encryption_level_ = default_encryption_level;
return serialized_packet;
@@ -313,7 +362,7 @@ SerializedPacket QuicPacketCreator::SerializeAllFrames(const QuicFrames& frames,
LOG_IF(DFATAL, frames.empty())
<< "Attempt to serialize empty packet";
for (const QuicFrame& frame : frames) {
- bool success = AddFrame(frame, false);
+ bool success = AddFrame(frame, false, false, nullptr);
DCHECK(success);
}
SerializedPacket packet = SerializePacket(buffer, buffer_len);
@@ -363,7 +412,22 @@ size_t QuicPacketCreator::PacketSize() const {
}
bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame) {
- return AddFrame(frame, true);
+ return AddFrame(frame,
+ /*save_retransmittable_frames=*/true,
+ /*needs_padding=*/false, nullptr);
+}
+
+bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame, char* buffer) {
+ return AddFrame(frame,
+ /*save_retransmittable_frames=*/true,
+ /*needs_padding=*/false, buffer);
+}
+
+bool QuicPacketCreator::AddPaddedSavedFrame(const QuicFrame& frame,
+ char* buffer) {
+ return AddFrame(frame,
+ /*save_retransmittable_frames=*/true,
+ /*needs_padding=*/true, buffer);
}
SerializedPacket QuicPacketCreator::SerializePacket(
@@ -399,10 +463,14 @@ SerializedPacket QuicPacketCreator::SerializePacket(
packet.reset(framer_->BuildDataPacket(header, queued_frames_,
large_buffer.get(), packet_size_));
}
+ if (packet == nullptr) {
+ LOG(DFATAL) << "Failed to serialize " << queued_frames_.size()
+ << " frames.";
+ return NoPacket();
+ }
+
OnBuiltFecProtectedPayload(header, packet->FecProtectedData());
- LOG_IF(DFATAL, packet == nullptr) << "Failed to serialize "
- << queued_frames_.size() << " frames.";
// Because of possible truncation, we can't be confident that our
// packet size calculation worked correctly.
if (!possibly_truncated_by_length) {
@@ -411,15 +479,24 @@ SerializedPacket QuicPacketCreator::SerializePacket(
// Immediately encrypt the packet, to ensure we don't encrypt the same packet
// sequence number multiple times.
QuicEncryptedPacket* encrypted =
- framer_->EncryptPacket(encryption_level_, sequence_number_, *packet,
- encrypted_buffer, encrypted_buffer_len);
+ framer_->EncryptPayload(encryption_level_, sequence_number_, *packet,
+ encrypted_buffer, encrypted_buffer_len);
if (encrypted == nullptr) {
LOG(DFATAL) << "Failed to encrypt packet number " << sequence_number_;
return NoPacket();
}
+ // Update |needs_padding_| flag of |queued_retransmittable_frames_| here, and
+ // not in AddFrame, because when the first padded frame is added to the queue,
+ // it might not be retransmittable, and hence the flag would end up being not
+ // set.
+ if (queued_retransmittable_frames_.get() != nullptr) {
+ queued_retransmittable_frames_->set_needs_padding(needs_padding_);
+ }
+
packet_size_ = 0;
queued_frames_.clear();
+ needs_padding_ = false;
return SerializedPacket(header.packet_sequence_number,
header.public_header.sequence_number_length,
encrypted, QuicFramer::GetPacketEntropyHash(header),
@@ -448,7 +525,7 @@ SerializedPacket QuicPacketCreator::SerializeFec(char* buffer,
DCHECK_GE(max_packet_length_, packet->length());
// Immediately encrypt the packet, to ensure we don't encrypt the same packet
// sequence number multiple times.
- QuicEncryptedPacket* encrypted = framer_->EncryptPacket(
+ QuicEncryptedPacket* encrypted = framer_->EncryptPayload(
encryption_level_, sequence_number_, *packet, buffer, buffer_len);
if (encrypted == nullptr) {
LOG(DFATAL) << "Failed to encrypt packet number " << sequence_number_;
@@ -501,6 +578,7 @@ bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) {
case ACK_FRAME:
case PADDING_FRAME:
case STOP_WAITING_FRAME:
+ case MTU_DISCOVERY_FRAME:
return false;
default:
return true;
@@ -508,7 +586,9 @@ bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) {
}
bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
- bool save_retransmittable_frames) {
+ bool save_retransmittable_frames,
+ bool needs_padding,
+ char* buffer) {
DVLOG(1) << "Adding frame: " << frame;
InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec();
@@ -526,47 +606,31 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
queued_retransmittable_frames_.reset(
new RetransmittableFrames(encryption_level_));
}
- if (frame.type == STREAM_FRAME) {
- queued_frames_.push_back(
- queued_retransmittable_frames_->AddStreamFrame(frame.stream_frame));
- } else {
- queued_frames_.push_back(
- queued_retransmittable_frames_->AddNonStreamFrame(frame));
- }
+ queued_frames_.push_back(
+ queued_retransmittable_frames_->AddFrame(frame, buffer));
} else {
queued_frames_.push_back(frame);
}
+
+ if (needs_padding) {
+ needs_padding_ = true;
+ }
+
return true;
}
void QuicPacketCreator::MaybeAddPadding() {
- if (BytesFree() == 0) {
- // Don't pad full packets.
+ if (!needs_padding_) {
return;
}
- // Since ReserializeAllFrames does not populate queued_retransmittable_frames_
- // it's not sufficient to simply call
- // queued_retransmittable_frames_->HasCryptoHandshake().
- // TODO(rch): we should really make ReserializeAllFrames not be a special
- // case!
-
- // If any of the frames in the current packet are on the crypto stream
- // then they contain handshake messagses, and we should pad them.
- bool is_handshake = false;
- for (const QuicFrame& frame : queued_frames_) {
- if (frame.type == STREAM_FRAME &&
- frame.stream_frame->stream_id == kCryptoStreamId) {
- is_handshake = true;
- break;
- }
- }
- if (!is_handshake) {
+ if (BytesFree() == 0) {
+ // Don't pad full packets.
return;
}
QuicPaddingFrame padding;
- bool success = AddFrame(QuicFrame(&padding), false);
+ bool success = AddFrame(QuicFrame(&padding), false, false, nullptr);
DCHECK(success);
}
diff --git a/chromium/net/quic/quic_packet_creator.h b/chromium/net/quic/quic_packet_creator.h
index 190e5300dfe..493a47b9766 100644
--- a/chromium/net/quic/quic_packet_creator.h
+++ b/chromium/net/quic/quic_packet_creator.h
@@ -52,6 +52,10 @@ class NET_EXPORT_PRIVATE QuicPacketCreator {
// return true if an FEC group is open.
bool ShouldSendFec(bool force_close) const;
+ // Resets (closes) the FEC group. This method should only be called on a
+ // packet boundary.
+ void ResetFecGroup();
+
// Returns true if an FEC packet is under construction.
bool IsFecGroupOpen() const;
@@ -75,14 +79,18 @@ class NET_EXPORT_PRIVATE QuicPacketCreator {
bool HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset) const;
// Converts a raw payload to a frame which fits into the currently open
- // packet if there is one. Returns the number of bytes consumed from data.
+ // packet. The payload begins at |iov_offset| into the |iov|.
+ // Returns the number of bytes consumed from data.
// If data is empty and fin is true, the expected behavior is to consume the
- // fin but return 0.
+ // fin but return 0. If any data is consumed, it will be copied into a
+ // new buffer that |frame| will point to and will be stored in |buffer|.
size_t CreateStreamFrame(QuicStreamId id,
- const IOVector& data,
+ const QuicIOVector& iov,
+ size_t iov_offset,
QuicStreamOffset offset,
bool fin,
- QuicFrame* frame);
+ QuicFrame* frame,
+ scoped_ptr<char[]>* buffer);
// Serializes all frames into a single packet. All frames must fit into a
// single packet. Also, sets the entropy hash of the serialized packet to a
@@ -145,6 +153,14 @@ class NET_EXPORT_PRIVATE QuicPacketCreator {
// Returns false if the frame doesn't fit into the current packet.
bool AddSavedFrame(const QuicFrame& frame);
+ // Identical to AddSavedFrame, but takes ownership of the buffer if it returns
+ // true.
+ bool AddSavedFrame(const QuicFrame& frame, char* buffer);
+
+ // Identical to AddSavedFrame, but takes ownership of the buffer if it returns
+ // true, and allows to cause the packet to be padded.
+ bool AddPaddedSavedFrame(const QuicFrame& frame, char* buffer);
+
// Serializes all frames which have been added and adds any which should be
// retransmitted to |retransmittable_frames| if it's not nullptr. All frames
// must fit into a single packet. Sets the entropy hash of the serialized
@@ -198,6 +214,10 @@ class NET_EXPORT_PRIVATE QuicPacketCreator {
// plaintext size.
void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
+ // Indicates whether the packet creator is in a state where it can change
+ // current maximum packet length.
+ bool CanSetMaxPacketLength() const;
+
// Sets the maximum packet length.
void SetMaxPacketLength(QuicByteCount length);
@@ -222,6 +242,14 @@ class NET_EXPORT_PRIVATE QuicPacketCreator {
static bool ShouldRetransmit(const QuicFrame& frame);
+ // Copies |length| bytes from iov starting at offset |iov_offset| into buffer.
+ // |iov| must be at least iov_offset+length total length and buffer must be
+ // at least |length| long.
+ static void CopyToBuffer(const QuicIOVector& iov,
+ size_t iov_offset,
+ size_t length,
+ char* buffer);
+
// Updates lengths and also starts an FEC group if FEC protection is on and
// there is not already an FEC group open.
InFecGroup MaybeUpdateLengthsAndStartFec();
@@ -237,7 +265,10 @@ class NET_EXPORT_PRIVATE QuicPacketCreator {
// Allows a frame to be added without creating retransmittable frames.
// Particularly useful for retransmits using SerializeAllFrames().
- bool AddFrame(const QuicFrame& frame, bool save_retransmittable_frames);
+ bool AddFrame(const QuicFrame& frame,
+ bool save_retransmittable_frames,
+ bool needs_padding,
+ char* buffer);
// Adds a padding frame to the current packet only if the current packet
// contains a handshake message, and there is sufficient room to fit a
@@ -277,6 +308,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator {
mutable size_t max_plaintext_size_;
QuicFrames queued_frames_;
scoped_ptr<RetransmittableFrames> queued_retransmittable_frames_;
+ // If true, the packet will be padded up to |max_packet_length_|.
+ bool needs_padding_;
DISALLOW_COPY_AND_ASSIGN(QuicPacketCreator);
};
diff --git a/chromium/net/quic/quic_packet_creator_test.cc b/chromium/net/quic/quic_packet_creator_test.cc
index 8aecc8b24a3..46cf52818d8 100644
--- a/chromium/net/quic/quic_packet_creator_test.cc
+++ b/chromium/net/quic/quic_packet_creator_test.cc
@@ -4,6 +4,8 @@
#include "net/quic/quic_packet_creator.h"
+#include <stdint.h>
+
#include "base/stl_util.h"
#include "net/quic/crypto/null_encrypter.h"
#include "net/quic/crypto/quic_decrypter.h"
@@ -102,8 +104,7 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<TestParams> {
EXPECT_EQ(STREAM_FRAME, frame.type);
ASSERT_TRUE(frame.stream_frame);
EXPECT_EQ(stream_id, frame.stream_frame->stream_id);
- scoped_ptr<string> frame_data(frame.stream_frame->GetDataAsString());
- EXPECT_EQ(data, *frame_data);
+ EXPECT_EQ(data, frame.stream_frame->data);
EXPECT_EQ(offset, frame.stream_frame->offset);
EXPECT_EQ(fin, frame.stream_frame->fin);
}
@@ -138,6 +139,10 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<TestParams> {
return creator_.IsFecProtected();
}
+ QuicIOVector MakeIOVector(StringPiece s) {
+ return ::net::MakeIOVector(s, &iov_);
+ }
+
static const QuicStreamOffset kOffset = 1u;
QuicFrames frames_;
@@ -146,6 +151,7 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<TestParams> {
testing::StrictMock<MockFramerVisitor> framer_visitor_;
QuicConnectionId connection_id_;
string data_;
+ struct iovec iov_;
MockRandom mock_random_;
QuicPacketCreator creator_;
MockEntropyCalculator entropy_calculator_;
@@ -160,8 +166,10 @@ INSTANTIATE_TEST_CASE_P(QuicPacketCreatorTests,
TEST_P(QuicPacketCreatorTest, SerializeFrames) {
frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u))));
- frames_.push_back(QuicFrame(new QuicStreamFrame(0u, false, 0u, IOVector())));
- frames_.push_back(QuicFrame(new QuicStreamFrame(0u, true, 0u, IOVector())));
+ frames_.push_back(
+ QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
+ frames_.push_back(
+ QuicFrame(new QuicStreamFrame(0u, true, 0u, StringPiece())));
char buffer[kMaxPacketSize];
SerializedPacket serialized =
creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
@@ -192,7 +200,8 @@ TEST_P(QuicPacketCreatorTest, SerializeWithFEC) {
// trigger an FEC packet.
ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
- frames_.push_back(QuicFrame(new QuicStreamFrame(0u, false, 0u, IOVector())));
+ frames_.push_back(
+ QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
char buffer[kMaxPacketSize];
SerializedPacket serialized =
creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
@@ -453,9 +462,9 @@ TEST_P(QuicPacketCreatorTest, ReserializeFramesWithSequenceNumberLength) {
QuicPacketCreatorPeer::SetSequenceNumberLength(&creator_,
PACKET_2BYTE_SEQUENCE_NUMBER);
QuicStreamFrame* stream_frame =
- new QuicStreamFrame(kCryptoStreamId, /*fin=*/false, 0u, IOVector());
+ new QuicStreamFrame(kCryptoStreamId, /*fin=*/false, 0u, StringPiece());
RetransmittableFrames frames(ENCRYPTION_NONE);
- frames.AddStreamFrame(stream_frame);
+ frames.AddFrame(QuicFrame(stream_frame));
char buffer[kMaxPacketSize];
SerializedPacket serialized = creator_.ReserializeAllFrames(
frames, PACKET_1BYTE_SEQUENCE_NUMBER, buffer, kMaxPacketSize);
@@ -480,11 +489,14 @@ TEST_P(QuicPacketCreatorTest, ReserializeFramesWithSequenceNumberLength) {
}
TEST_P(QuicPacketCreatorTest, ReserializeFramesWithPadding) {
- QuicStreamFrame* stream_frame =
- new QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0,
- MakeIOVector("fake handshake message data"));
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("fake handshake message data"));
+ scoped_ptr<char[]> stream_buffer;
+ creator_.CreateStreamFrame(kCryptoStreamId, io_vector, 0u, 0u, false, &frame,
+ &stream_buffer);
RetransmittableFrames frames(ENCRYPTION_NONE);
- frames.AddStreamFrame(stream_frame);
+ frames.AddFrame(frame);
+ frames.set_needs_padding(true);
char buffer[kMaxPacketSize];
SerializedPacket serialized = creator_.ReserializeAllFrames(
frames, QuicPacketCreatorPeer::NextSequenceNumberLength(&creator_),
@@ -501,10 +513,14 @@ TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPacketAndPadding) {
string data(capacity + delta, 'A');
size_t bytes_free = 0 - delta;
- QuicStreamFrame* stream_frame = new QuicStreamFrame(
- kCryptoStreamId, /*fin=*/false, kOffset, MakeIOVector(data));
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector(data));
+ scoped_ptr<char[]> stream_buffer;
+ creator_.CreateStreamFrame(kCryptoStreamId, io_vector, 0, kOffset, false,
+ &frame, &stream_buffer);
RetransmittableFrames frames(ENCRYPTION_NONE);
- frames.AddStreamFrame(stream_frame);
+ frames.AddFrame(frame);
+ frames.set_needs_padding(true);
char buffer[kMaxPacketSize];
SerializedPacket serialized = creator_.ReserializeAllFrames(
frames, QuicPacketCreatorPeer::NextSequenceNumberLength(&creator_),
@@ -571,7 +587,8 @@ TEST_P(QuicPacketCreatorTest, SwitchFecOnOffWithNoGroup) {
TEST_P(QuicPacketCreatorTest, SwitchFecOnOffWithGroupInProgress) {
// Enable FEC protection, and send FEC packet every 6 packets.
EXPECT_TRUE(SwitchFecProtectionOn(6));
- frames_.push_back(QuicFrame(new QuicStreamFrame(0u, false, 0u, IOVector())));
+ frames_.push_back(
+ QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
char buffer[kMaxPacketSize];
SerializedPacket serialized =
creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
@@ -605,8 +622,10 @@ TEST_P(QuicPacketCreatorTest, SwitchFecOnOffWithGroupInProgress) {
TEST_P(QuicPacketCreatorTest, SwitchFecOnWithStreamFrameQueued) {
// Add a stream frame to the creator.
QuicFrame frame;
- size_t consumed = creator_.CreateStreamFrame(
- 1u, MakeIOVector("test"), 0u, false, &frame);
+ QuicIOVector io_vector(MakeIOVector("test"));
+ scoped_ptr<char[]> stream_buffer;
+ size_t consumed = creator_.CreateStreamFrame(1u, io_vector, 0u, 0u, false,
+ &frame, &stream_buffer);
EXPECT_EQ(4u, consumed);
ASSERT_TRUE(frame.stream_frame);
EXPECT_TRUE(creator_.AddSavedFrame(frame));
@@ -634,26 +653,34 @@ TEST_P(QuicPacketCreatorTest, SwitchFecOnWithStreamFrameQueued) {
TEST_P(QuicPacketCreatorTest, CreateStreamFrame) {
QuicFrame frame;
- size_t consumed = creator_.CreateStreamFrame(1u, MakeIOVector("test"), 0u,
- false, &frame);
+ QuicIOVector io_vector(MakeIOVector("test"));
+ scoped_ptr<char[]> stream_buffer;
+ size_t consumed = creator_.CreateStreamFrame(1u, io_vector, 0u, 0u, false,
+ &frame, &stream_buffer);
EXPECT_EQ(4u, consumed);
CheckStreamFrame(frame, 1u, "test", 0u, false);
- delete frame.stream_frame;
+ RetransmittableFrames cleanup_frames(ENCRYPTION_NONE);
+ cleanup_frames.AddFrame(frame);
}
TEST_P(QuicPacketCreatorTest, CreateStreamFrameFin) {
QuicFrame frame;
- size_t consumed = creator_.CreateStreamFrame(1u, MakeIOVector("test"), 10u,
- true, &frame);
+ QuicIOVector io_vector(MakeIOVector("test"));
+ scoped_ptr<char[]> stream_buffer;
+ size_t consumed = creator_.CreateStreamFrame(1u, io_vector, 0u, 10u, true,
+ &frame, &stream_buffer);
EXPECT_EQ(4u, consumed);
CheckStreamFrame(frame, 1u, "test", 10u, true);
- delete frame.stream_frame;
+ RetransmittableFrames cleanup_frames(ENCRYPTION_NONE);
+ cleanup_frames.AddFrame(frame);
}
TEST_P(QuicPacketCreatorTest, CreateStreamFrameFinOnly) {
QuicFrame frame;
- size_t consumed = creator_.CreateStreamFrame(1u, IOVector(), 0u, true,
- &frame);
+ QuicIOVector io_vector(nullptr, 0, 0);
+ scoped_ptr<char[]> stream_buffer;
+ size_t consumed = creator_.CreateStreamFrame(1u, io_vector, 0u, 0u, true,
+ &frame, &stream_buffer);
EXPECT_EQ(0u, consumed);
CheckStreamFrame(frame, 1u, string(), 0u, true);
delete frame.stream_frame;
@@ -670,9 +697,11 @@ TEST_P(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) {
kClientDataStreamId1, kOffset));
if (should_have_room) {
QuicFrame frame;
- size_t bytes_consumed = creator_.CreateStreamFrame(
- kClientDataStreamId1, MakeIOVector("testdata"), kOffset, false,
- &frame);
+ QuicIOVector io_vector(MakeIOVector("testdata"));
+ scoped_ptr<char[]> stream_buffer;
+ size_t bytes_consumed =
+ creator_.CreateStreamFrame(kClientDataStreamId1, io_vector, 0u,
+ kOffset, false, &frame, &stream_buffer);
EXPECT_LT(0u, bytes_consumed);
ASSERT_TRUE(creator_.AddSavedFrame(frame));
char buffer[kMaxPacketSize];
@@ -695,8 +724,11 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) {
string data(capacity + delta, 'A');
size_t bytes_free = delta > 0 ? 0 : 0 - delta;
QuicFrame frame;
- size_t bytes_consumed = creator_.CreateStreamFrame(
- kClientDataStreamId1, MakeIOVector(data), kOffset, false, &frame);
+ QuicIOVector io_vector(MakeIOVector(data));
+ scoped_ptr<char[]> stream_buffer;
+ size_t bytes_consumed =
+ creator_.CreateStreamFrame(kClientDataStreamId1, io_vector, 0u, kOffset,
+ false, &frame, &stream_buffer);
EXPECT_EQ(capacity - bytes_free, bytes_consumed);
ASSERT_TRUE(creator_.AddSavedFrame(frame));
@@ -726,8 +758,11 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumptionWithFec) {
string data(capacity + delta, 'A');
size_t bytes_free = delta > 0 ? 0 : 0 - delta;
QuicFrame frame;
- size_t bytes_consumed = creator_.CreateStreamFrame(
- kClientDataStreamId1, MakeIOVector(data), kOffset, false, &frame);
+ QuicIOVector io_vector(MakeIOVector(data));
+ scoped_ptr<char[]> stream_buffer;
+ size_t bytes_consumed =
+ creator_.CreateStreamFrame(kClientDataStreamId1, io_vector, 0u, kOffset,
+ false, &frame, &stream_buffer);
EXPECT_EQ(capacity - bytes_free, bytes_consumed);
ASSERT_TRUE(creator_.AddSavedFrame(frame));
@@ -758,10 +793,12 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
size_t bytes_free = delta > 0 ? 0 : 0 - delta;
QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector(data));
+ scoped_ptr<char[]> stream_buffer;
size_t bytes_consumed = creator_.CreateStreamFrame(
- kCryptoStreamId, MakeIOVector(data), kOffset, false, &frame);
+ kCryptoStreamId, io_vector, 0u, kOffset, false, &frame, &stream_buffer);
EXPECT_LT(0u, bytes_consumed);
- ASSERT_TRUE(creator_.AddSavedFrame(frame));
+ ASSERT_TRUE(creator_.AddPaddedSavedFrame(frame, nullptr));
char buffer[kMaxPacketSize];
SerializedPacket serialized_packet =
creator_.SerializePacket(buffer, kMaxPacketSize);
@@ -792,8 +829,11 @@ TEST_P(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) {
size_t bytes_free = delta > 0 ? 0 : 0 - delta;
QuicFrame frame;
- size_t bytes_consumed = creator_.CreateStreamFrame(
- kClientDataStreamId1, MakeIOVector(data), kOffset, false, &frame);
+ QuicIOVector io_vector(MakeIOVector(data));
+ scoped_ptr<char[]> stream_buffer;
+ size_t bytes_consumed =
+ creator_.CreateStreamFrame(kClientDataStreamId1, io_vector, 0u, kOffset,
+ false, &frame, &stream_buffer);
EXPECT_LT(0u, bytes_consumed);
ASSERT_TRUE(creator_.AddSavedFrame(frame));
char buffer[kMaxPacketSize];
@@ -854,7 +894,7 @@ TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
QuicPacketCreatorPeer::SetSequenceNumber(
&creator_,
- GG_UINT64_C(64) * 256 * 256 * 256 * 256 - max_packets_per_fec_group);
+ UINT64_C(64) * 256 * 256 * 256 * 256 - max_packets_per_fec_group);
creator_.UpdateSequenceNumberLength(2, 10000 / kDefaultMaxPacketSize);
EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
QuicPacketCreatorPeer::NextSequenceNumberLength(&creator_));
@@ -878,7 +918,7 @@ TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthBandwidth) {
QuicPacketCreatorPeer::NextSequenceNumberLength(&creator_));
creator_.UpdateSequenceNumberLength(
- 1, GG_UINT64_C(1000) * 256 * 256 * 256 * 256 / kDefaultMaxPacketSize);
+ 1, UINT64_C(1000) * 256 * 256 * 256 * 256 / kDefaultMaxPacketSize);
EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
QuicPacketCreatorPeer::NextSequenceNumberLength(&creator_));
}
@@ -887,7 +927,8 @@ TEST_P(QuicPacketCreatorTest, SerializeFrame) {
if (!GetParam().version_serialization) {
creator_.StopSendingVersion();
}
- frames_.push_back(QuicFrame(new QuicStreamFrame(0u, false, 0u, IOVector())));
+ frames_.push_back(
+ QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
char buffer[kMaxPacketSize];
SerializedPacket serialized =
creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
@@ -924,12 +965,15 @@ TEST_P(QuicPacketCreatorTest, CreateStreamFrameTooLarge) {
PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP, &payload_length));
QuicFrame frame;
const string too_long_payload(payload_length * 2, 'a');
- size_t consumed = creator_.CreateStreamFrame(
- 1u, MakeIOVector(too_long_payload), 0u, true, &frame);
+ QuicIOVector io_vector(MakeIOVector(too_long_payload));
+ scoped_ptr<char[]> stream_buffer;
+ size_t consumed = creator_.CreateStreamFrame(1u, io_vector, 0u, 0u, true,
+ &frame, &stream_buffer);
EXPECT_EQ(payload_length, consumed);
const string payload(payload_length, 'a');
CheckStreamFrame(frame, 1u, payload, 0u, false);
- delete frame.stream_frame;
+ RetransmittableFrames cleanup_frames(ENCRYPTION_NONE);
+ cleanup_frames.AddFrame(frame);
}
TEST_P(QuicPacketCreatorTest, AddFrameAndSerialize) {
@@ -952,8 +996,10 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndSerialize) {
EXPECT_TRUE(creator_.HasPendingFrames());
QuicFrame frame;
- size_t consumed = creator_.CreateStreamFrame(
- 1u, MakeIOVector("test"), 0u, false, &frame);
+ QuicIOVector io_vector(MakeIOVector("test"));
+ scoped_ptr<char[]> stream_buffer;
+ size_t consumed = creator_.CreateStreamFrame(1u, io_vector, 0u, 0u, false,
+ &frame, &stream_buffer);
EXPECT_EQ(4u, consumed);
ASSERT_TRUE(frame.stream_frame);
EXPECT_TRUE(creator_.AddSavedFrame(frame));
@@ -1012,8 +1058,10 @@ TEST_P(QuicPacketCreatorTest, SerializeTruncatedAckFrameWithLargePacketSize) {
// Make sure that an additional stream frame can be added to the packet.
QuicFrame stream_frame;
- size_t consumed = creator_.CreateStreamFrame(
- 2u, MakeIOVector("test"), 0u, false, &stream_frame);
+ QuicIOVector io_vector(MakeIOVector("test"));
+ scoped_ptr<char[]> stream_buffer;
+ size_t consumed = creator_.CreateStreamFrame(2u, io_vector, 0u, 0u, false,
+ &stream_frame, &stream_buffer);
EXPECT_EQ(4u, consumed);
ASSERT_TRUE(stream_frame.stream_frame);
EXPECT_TRUE(creator_.AddSavedFrame(stream_frame));
@@ -1075,7 +1123,8 @@ TEST_P(QuicPacketCreatorTest, SerializeTruncatedAckFrameWithSmallPacketSize) {
TEST_P(QuicPacketCreatorTest, EntropyFlag) {
- frames_.push_back(QuicFrame(new QuicStreamFrame(0u, false, 0u, IOVector())));
+ frames_.push_back(
+ QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
char buffer[kMaxPacketSize];
for (int i = 0; i < 2; ++i) {
@@ -1084,7 +1133,7 @@ TEST_P(QuicPacketCreatorTest, EntropyFlag) {
creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
// Verify both BoolSource and hash algorithm.
bool expected_rand_bool =
- (mock_random_.RandUint64() & (GG_UINT64_C(1) << j)) != 0;
+ (mock_random_.RandUint64() & (UINT64_C(1) << j)) != 0;
bool observed_rand_bool =
(serialized.entropy_hash & (1 << ((j+1) % 8))) != 0;
uint8 rest_of_hash = serialized.entropy_hash & ~(1 << ((j+1) % 8));
@@ -1099,6 +1148,86 @@ TEST_P(QuicPacketCreatorTest, EntropyFlag) {
delete frames_[0].stream_frame;
}
+TEST_P(QuicPacketCreatorTest, ResetFecGroup) {
+ // Enable FEC protection, and send FEC packet every 6 packets.
+ EXPECT_TRUE(SwitchFecProtectionOn(6));
+ frames_.push_back(
+ QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
+ char buffer[kMaxPacketSize];
+ SerializedPacket serialized =
+ creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
+ delete serialized.packet;
+
+ EXPECT_TRUE(creator_.IsFecProtected());
+ EXPECT_TRUE(creator_.IsFecGroupOpen());
+ // We do not have enough packets in the FEC group to trigger an FEC packet.
+ EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
+ // Should return true since there are packets in the FEC group.
+ EXPECT_TRUE(creator_.ShouldSendFec(/*force_close=*/true));
+
+ // Close the FEC Group.
+ creator_.ResetFecGroup();
+ EXPECT_TRUE(creator_.IsFecProtected());
+ EXPECT_FALSE(creator_.IsFecGroupOpen());
+ // We do not have enough packets in the FEC group to trigger an FEC packet.
+ EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
+ // Confirm that there is no FEC packet under construction.
+ EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/true));
+
+ EXPECT_DFATAL(serialized = creator_.SerializeFec(buffer, kMaxPacketSize),
+ "SerializeFEC called but no group or zero packets in group.");
+ delete serialized.packet;
+
+ // Start a new FEC packet.
+ serialized = creator_.SerializeAllFrames(frames_, buffer, kMaxPacketSize);
+ delete frames_[0].stream_frame;
+ delete serialized.packet;
+
+ EXPECT_TRUE(creator_.IsFecProtected());
+ EXPECT_TRUE(creator_.IsFecGroupOpen());
+ // We do not have enough packets in the FEC group to trigger an FEC packet.
+ EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
+ // Should return true since there are packets in the FEC group.
+ EXPECT_TRUE(creator_.ShouldSendFec(/*force_close=*/true));
+
+ // Should return false since we do not have enough packets in the FEC group to
+ // trigger an FEC packet.
+ ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
+ // Should return true since there are packets in the FEC group.
+ ASSERT_TRUE(creator_.ShouldSendFec(/*force_close=*/true));
+
+ serialized = creator_.SerializeFec(buffer, kMaxPacketSize);
+ ASSERT_EQ(3u, serialized.sequence_number);
+ delete serialized.packet;
+}
+
+TEST_P(QuicPacketCreatorTest, ResetFecGroupWithQueuedFrames) {
+ // Add a stream frame to the creator.
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("test"));
+ scoped_ptr<char[]> stream_buffer;
+ size_t consumed = creator_.CreateStreamFrame(1u, io_vector, 0u, 0u, false,
+ &frame, &stream_buffer);
+ EXPECT_EQ(4u, consumed);
+ ASSERT_TRUE(frame.stream_frame);
+ EXPECT_TRUE(creator_.AddSavedFrame(frame));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_DFATAL(creator_.ResetFecGroup(),
+ "Cannot reset FEC group with pending frames.");
+
+ // Serialize packet for transmission.
+ char buffer[kMaxPacketSize];
+ SerializedPacket serialized =
+ creator_.SerializePacket(buffer, kMaxPacketSize);
+ delete serialized.packet;
+ delete serialized.retransmittable_frames;
+ EXPECT_FALSE(creator_.HasPendingFrames());
+
+ // Close the FEC Group.
+ creator_.ResetFecGroup();
+ EXPECT_FALSE(creator_.IsFecGroupOpen());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/quic_packet_generator.cc b/chromium/net/quic/quic_packet_generator.cc
index 77f57759857..cc3a79331a1 100644
--- a/chromium/net/quic/quic_packet_generator.cc
+++ b/chromium/net/quic/quic_packet_generator.cc
@@ -45,10 +45,12 @@ QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId connection_id,
batch_mode_(false),
fec_timeout_(QuicTime::Delta::Zero()),
should_fec_protect_(false),
+ fec_send_policy_(FEC_ANY_TRIGGER),
should_send_ack_(false),
should_send_stop_waiting_(false),
ack_queued_(false),
- stop_waiting_queued_(false) {
+ stop_waiting_queued_(false),
+ max_packet_length_(kDefaultMaxPacketSize) {
}
QuicPacketGenerator::~QuicPacketGenerator() {
@@ -63,6 +65,9 @@ QuicPacketGenerator::~QuicPacketGenerator() {
case ACK_FRAME:
delete frame.ack_frame;
break;
+ case MTU_DISCOVERY_FRAME:
+ delete frame.mtu_discovery_frame;
+ break;
case RST_STREAM_FRAME:
delete frame.rst_stream_frame;
break;
@@ -114,17 +119,17 @@ void QuicPacketGenerator::SetShouldSendAck(bool also_send_stop_waiting) {
should_send_ack_ = true;
should_send_stop_waiting_ = also_send_stop_waiting;
- SendQueuedFrames(false);
+ SendQueuedFrames(/*flush=*/false, /*is_fec_timeout=*/false);
}
void QuicPacketGenerator::AddControlFrame(const QuicFrame& frame) {
queued_control_frames_.push_back(frame);
- SendQueuedFrames(false);
+ SendQueuedFrames(/*flush=*/false, /*is_fec_timeout=*/false);
}
QuicConsumedData QuicPacketGenerator::ConsumeData(
QuicStreamId id,
- const IOVector& data_to_write,
+ const QuicIOVector& iov,
QuicStreamOffset offset,
bool fin,
FecProtection fec_protection,
@@ -134,7 +139,7 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
// other retransmittable frames in a single packet.
const bool flush =
has_handshake && packet_creator_.HasPendingRetransmittableFrames();
- SendQueuedFrames(flush);
+ SendQueuedFrames(flush, /*is_fec_timeout=*/false);
size_t total_bytes_consumed = 0;
bool fin_consumed = false;
@@ -154,9 +159,7 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
notifier = new QuicAckNotifier(delegate);
}
- IOVector data = data_to_write;
- size_t data_size = data.TotalBufferSize();
- if (!fin && (data_size == 0)) {
+ if (!fin && (iov.total_length == 0)) {
LOG(DFATAL) << "Attempt to consume empty data without FIN.";
return QuicConsumedData(0, false);
}
@@ -165,8 +168,10 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
while (delegate_->ShouldGeneratePacket(
HAS_RETRANSMITTABLE_DATA, has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) {
QuicFrame frame;
+ scoped_ptr<char[]> buffer;
size_t bytes_consumed = packet_creator_.CreateStreamFrame(
- id, data, offset + total_bytes_consumed, fin, &frame);
+ id, iov, total_bytes_consumed, offset + total_bytes_consumed, fin,
+ &frame, &buffer);
++frames_created;
// We want to track which packet this stream frame ends up in.
@@ -174,7 +179,7 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
ack_notifiers_.push_back(notifier);
}
- if (!AddFrame(frame)) {
+ if (!AddFrame(frame, buffer.get(), has_handshake)) {
LOG(DFATAL) << "Failed to add stream frame.";
// Inability to add a STREAM frame creates an unrecoverable hole in a
// the stream, so it's best to close the connection.
@@ -182,18 +187,22 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
delete notifier;
return QuicConsumedData(0, false);
}
+ // When AddFrame succeeds, it takes ownership of the buffer.
+ ignore_result(buffer.release());
total_bytes_consumed += bytes_consumed;
- fin_consumed = fin && total_bytes_consumed == data_size;
- data.Consume(bytes_consumed);
- DCHECK(data.Empty() || packet_creator_.BytesFree() == 0u);
+ fin_consumed = fin && total_bytes_consumed == iov.total_length;
+ DCHECK(total_bytes_consumed == iov.total_length ||
+ packet_creator_.BytesFree() == 0u);
- // TODO(ianswett): Restore packet reordering.
if (!InBatchMode() || !packet_creator_.HasRoomForStreamFrame(id, offset)) {
+ // TODO(rtenneti): remove MaybeSendFecPacketAndCloseGroup() from inside
+ // SerializeAndSendPacket() and make it an explicit call here (and
+ // elsewhere where we call SerializeAndSendPacket?).
SerializeAndSendPacket();
}
- if (data.Empty()) {
+ if (total_bytes_consumed == iov.total_length) {
// We're done writing the data. Exit the loop.
// We don't make this a precondition because we could have 0 bytes of data
// if we're simply writing a fin.
@@ -213,17 +222,50 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
// Don't allow the handshake to be bundled with other retransmittable frames.
if (has_handshake) {
- SendQueuedFrames(true);
+ SendQueuedFrames(/*flush=*/true, /*is_fec_timeout=*/false);
}
// Try to close FEC group since we've either run out of data to send or we're
// blocked. If not in batch mode, force close the group.
- MaybeSendFecPacketAndCloseGroup(/*force=*/false);
+ MaybeSendFecPacketAndCloseGroup(/*force=*/false, /*is_fec_timeout=*/false);
DCHECK(InBatchMode() || !packet_creator_.HasPendingFrames());
return QuicConsumedData(total_bytes_consumed, fin_consumed);
}
+void QuicPacketGenerator::GenerateMtuDiscoveryPacket(
+ QuicByteCount target_mtu,
+ QuicAckNotifier::DelegateInterface* delegate) {
+ // MTU discovery frames must be sent by themselves.
+ DCHECK(!InBatchMode() && !packet_creator_.HasPendingFrames());
+
+ // If an ack notifier delegate is provided, register it.
+ if (delegate) {
+ QuicAckNotifier* ack_notifier = new QuicAckNotifier(delegate);
+ // The notifier manager will take the ownership of the notifier after the
+ // packet is sent.
+ ack_notifiers_.push_back(ack_notifier);
+ }
+
+ const QuicByteCount current_mtu = GetMaxPacketLength();
+
+ // The MTU discovery frame is allocated on the stack, since it is going to be
+ // serialized within this function.
+ QuicMtuDiscoveryFrame mtu_discovery_frame;
+ QuicFrame frame(&mtu_discovery_frame);
+
+ // Send the probe packet with the new length.
+ SetMaxPacketLength(target_mtu, /*force=*/true);
+ const bool success = AddFrame(frame, nullptr, /*needs_padding=*/true);
+ SerializeAndSendPacket();
+ // The only reason AddFrame can fail is that the packet is too full to fit in
+ // a ping. This is not possible for any sane MTU.
+ DCHECK(success);
+
+ // Reset the packet length back.
+ SetMaxPacketLength(current_mtu, /*force=*/true);
+}
+
bool QuicPacketGenerator::CanSendWithNextPendingFrameAddition() const {
DCHECK(HasPendingFrames());
HasRetransmittableData retransmittable =
@@ -236,7 +278,7 @@ bool QuicPacketGenerator::CanSendWithNextPendingFrameAddition() const {
return delegate_->ShouldGeneratePacket(retransmittable, NOT_HANDSHAKE);
}
-void QuicPacketGenerator::SendQueuedFrames(bool flush) {
+void QuicPacketGenerator::SendQueuedFrames(bool flush, bool is_fec_timeout) {
// Only add pending frames if we are SURE we can then send the whole packet.
while (HasPendingFrames() &&
(flush || CanSendWithNextPendingFrameAddition())) {
@@ -248,7 +290,7 @@ void QuicPacketGenerator::SendQueuedFrames(bool flush) {
if (packet_creator_.HasPendingFrames() && (flush || !InBatchMode())) {
SerializeAndSendPacket();
}
- MaybeSendFecPacketAndCloseGroup(flush);
+ MaybeSendFecPacketAndCloseGroup(flush, is_fec_timeout);
}
void QuicPacketGenerator::MaybeStartFecProtection() {
@@ -267,23 +309,31 @@ void QuicPacketGenerator::MaybeStartFecProtection() {
// converted to an FEC protected packet, do it. This will require the
// generator to check if the resulting expansion still allows the incoming
// frame to be added to the packet.
- SendQueuedFrames(true);
+ SendQueuedFrames(/*flush=*/true, /*is_fec_timeout=*/false);
}
packet_creator_.StartFecProtectingPackets();
DCHECK(packet_creator_.IsFecProtected());
}
-void QuicPacketGenerator::MaybeSendFecPacketAndCloseGroup(bool force) {
+void QuicPacketGenerator::MaybeSendFecPacketAndCloseGroup(bool force,
+ bool is_fec_timeout) {
if (!ShouldSendFecPacket(force)) {
return;
}
- // TODO(jri): SerializeFec can return a NULL packet, and this should
- // cause an early return, with a call to delegate_->OnPacketGenerationError.
- char buffer[kMaxPacketSize];
- SerializedPacket serialized_fec =
- packet_creator_.SerializeFec(buffer, kMaxPacketSize);
- DCHECK(serialized_fec.packet);
- delegate_->OnSerializedPacket(serialized_fec);
+
+ // If we want to send FEC packet only when FEC alaram goes off and if it is
+ // not a FEC timeout then close the group and dont send FEC packet.
+ if (fec_send_policy_ == FEC_ALARM_TRIGGER && !is_fec_timeout) {
+ ResetFecGroup();
+ } else {
+ // TODO(jri): SerializeFec can return a NULL packet, and this should
+ // cause an early return, with a call to delegate_->OnPacketGenerationError.
+ char buffer[kMaxPacketSize];
+ SerializedPacket serialized_fec =
+ packet_creator_.SerializeFec(buffer, kMaxPacketSize);
+ DCHECK(serialized_fec.packet);
+ delegate_->OnSerializedPacket(serialized_fec);
+ }
// Turn FEC protection off if creator's protection is on and the creator
// does not have an open FEC group.
// Note: We only wait until the frames queued in the creator are flushed;
@@ -300,6 +350,12 @@ bool QuicPacketGenerator::ShouldSendFecPacket(bool force) {
packet_creator_.ShouldSendFec(force);
}
+void QuicPacketGenerator::ResetFecGroup() {
+ DCHECK(packet_creator_.IsFecGroupOpen());
+ packet_creator_.ResetFecGroup();
+ delegate_->OnResetFecGroup();
+}
+
void QuicPacketGenerator::OnFecTimeout() {
DCHECK(!InBatchMode());
if (!ShouldSendFecPacket(true)) {
@@ -308,8 +364,8 @@ void QuicPacketGenerator::OnFecTimeout() {
}
// Flush out any pending frames in the generator and the creator, and then
// send out FEC packet.
- SendQueuedFrames(true);
- MaybeSendFecPacketAndCloseGroup(/*force=*/true);
+ SendQueuedFrames(/*flush=*/true, /*is_fec_timeout=*/true);
+ MaybeSendFecPacketAndCloseGroup(/*force=*/true, /*is_fec_timeout=*/true);
}
QuicTime::Delta QuicPacketGenerator::GetFecTimeout(
@@ -334,11 +390,11 @@ void QuicPacketGenerator::StartBatchOperations() {
void QuicPacketGenerator::FinishBatchOperations() {
batch_mode_ = false;
- SendQueuedFrames(false);
+ SendQueuedFrames(/*flush=*/false, /*is_fec_timeout=*/false);
}
void QuicPacketGenerator::FlushAllQueuedFrames() {
- SendQueuedFrames(true);
+ SendQueuedFrames(/*flush=*/true, /*is_fec_timeout=*/false);
}
bool QuicPacketGenerator::HasQueuedFrames() const {
@@ -355,7 +411,8 @@ bool QuicPacketGenerator::AddNextPendingFrame() {
delegate_->PopulateAckFrame(&pending_ack_frame_);
ack_queued_ = true;
// If we can't this add the frame now, then we still need to do so later.
- should_send_ack_ = !AddFrame(QuicFrame(&pending_ack_frame_));
+ should_send_ack_ = !AddFrame(QuicFrame(&pending_ack_frame_), nullptr,
+ /*needs_padding=*/false);
// Return success if we have cleared out this flag (i.e., added the frame).
// If we still need to send, then the frame is full, and we have failed.
return !should_send_ack_;
@@ -366,7 +423,8 @@ bool QuicPacketGenerator::AddNextPendingFrame() {
stop_waiting_queued_ = true;
// If we can't this add the frame now, then we still need to do so later.
should_send_stop_waiting_ =
- !AddFrame(QuicFrame(&pending_stop_waiting_frame_));
+ !AddFrame(QuicFrame(&pending_stop_waiting_frame_), nullptr,
+ /*needs_padding=*/false);
// Return success if we have cleared out this flag (i.e., added the frame).
// If we still need to send, then the frame is full, and we have failed.
return !should_send_stop_waiting_;
@@ -374,7 +432,8 @@ bool QuicPacketGenerator::AddNextPendingFrame() {
LOG_IF(DFATAL, queued_control_frames_.empty())
<< "AddNextPendingFrame called with no queued control frames.";
- if (!AddFrame(queued_control_frames_.back())) {
+ if (!AddFrame(queued_control_frames_.back(), nullptr,
+ /*needs_padding=*/false)) {
// Packet was full.
return false;
}
@@ -382,8 +441,12 @@ bool QuicPacketGenerator::AddNextPendingFrame() {
return true;
}
-bool QuicPacketGenerator::AddFrame(const QuicFrame& frame) {
- bool success = packet_creator_.AddSavedFrame(frame);
+bool QuicPacketGenerator::AddFrame(const QuicFrame& frame,
+ char* buffer,
+ bool needs_padding) {
+ bool success = needs_padding
+ ? packet_creator_.AddPaddedSavedFrame(frame, buffer)
+ : packet_creator_.AddSavedFrame(frame, buffer);
if (success && debug_delegate_) {
debug_delegate_->OnFrameAddedToPacket(frame);
}
@@ -394,14 +457,25 @@ void QuicPacketGenerator::SerializeAndSendPacket() {
char buffer[kMaxPacketSize];
SerializedPacket serialized_packet =
packet_creator_.SerializePacket(buffer, kMaxPacketSize);
- DCHECK(serialized_packet.packet);
+ if (serialized_packet.packet == nullptr) {
+ LOG(DFATAL) << "Failed to SerializePacket. fec_policy:" << fec_send_policy_
+ << " should_fec_protect_:" << should_fec_protect_;
+ delegate_->CloseConnection(QUIC_FAILED_TO_SERIALIZE_PACKET, false);
+ return;
+ }
// There may be AckNotifiers interested in this packet.
serialized_packet.notifiers.swap(ack_notifiers_);
ack_notifiers_.clear();
delegate_->OnSerializedPacket(serialized_packet);
- MaybeSendFecPacketAndCloseGroup(/*force=*/false);
+ MaybeSendFecPacketAndCloseGroup(/*force=*/false, /*is_fec_timeout=*/false);
+
+ // Maximum packet size may be only enacted while no packet is currently being
+ // constructed, so here we have a good opportunity to actually change it.
+ if (packet_creator_.CanSetMaxPacketLength()) {
+ packet_creator_.SetMaxPacketLength(max_packet_length_);
+ }
// The packet has now been serialized, so the frames are no longer queued.
ack_queued_ = false;
@@ -416,12 +490,28 @@ QuicPacketSequenceNumber QuicPacketGenerator::sequence_number() const {
return packet_creator_.sequence_number();
}
-QuicByteCount QuicPacketGenerator::max_packet_length() const {
+QuicByteCount QuicPacketGenerator::GetMaxPacketLength() const {
+ return max_packet_length_;
+}
+
+QuicByteCount QuicPacketGenerator::GetCurrentMaxPacketLength() const {
return packet_creator_.max_packet_length();
}
-void QuicPacketGenerator::set_max_packet_length(QuicByteCount length) {
- packet_creator_.SetMaxPacketLength(length);
+void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length, bool force) {
+ // If we cannot immediately set new maximum packet length, and the |force|
+ // flag is set, we have to flush the contents of the queue and close existing
+ // FEC group.
+ if (!packet_creator_.CanSetMaxPacketLength() && force) {
+ SendQueuedFrames(/*flush=*/true, /*is_fec_timeout=*/false);
+ MaybeSendFecPacketAndCloseGroup(/*force=*/true, /*is_fec_timeout=*/false);
+ DCHECK(packet_creator_.CanSetMaxPacketLength());
+ }
+
+ max_packet_length_ = length;
+ if (packet_creator_.CanSetMaxPacketLength()) {
+ packet_creator_.SetMaxPacketLength(length);
+ }
}
QuicEncryptedPacket* QuicPacketGenerator::SerializeVersionNegotiationPacket(
diff --git a/chromium/net/quic/quic_packet_generator.h b/chromium/net/quic/quic_packet_generator.h
index 5db862d07e3..9002b1a0988 100644
--- a/chromium/net/quic/quic_packet_generator.h
+++ b/chromium/net/quic/quic_packet_generator.h
@@ -79,6 +79,8 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
// Takes ownership of |packet.packet| and |packet.retransmittable_frames|.
virtual void OnSerializedPacket(const SerializedPacket& packet) = 0;
virtual void CloseConnection(QuicErrorCode error, bool from_peer) = 0;
+ // Called when a FEC Group is reset (closed).
+ virtual void OnResetFecGroup() = 0;
};
// Interface which gets callbacks from the QuicPacketGenerator at interesting
@@ -120,12 +122,16 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
// |delegate| (if not nullptr) will be informed once all packets sent as a
// result of this call are ACKed by the peer.
QuicConsumedData ConsumeData(QuicStreamId id,
- const IOVector& data,
+ const QuicIOVector& iov,
QuicStreamOffset offset,
bool fin,
FecProtection fec_protection,
QuicAckNotifier::DelegateInterface* delegate);
+ // Generates an MTU discovery packet of specified size.
+ void GenerateMtuDiscoveryPacket(QuicByteCount target_mtu,
+ QuicAckNotifier::DelegateInterface* delegate);
+
// Indicates whether batch mode is currently enabled.
bool InBatchMode();
// Disables flushing.
@@ -188,14 +194,28 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
// created.
QuicPacketSequenceNumber sequence_number() const;
- QuicByteCount max_packet_length() const;
+ // Returns the maximum packet length. Note that this is the long-term maximum
+ // packet length, and it may not be the maximum length of the current packet,
+ // if the generator is in the middle of the packet (in batch mode) or FEC
+ // group.
+ QuicByteCount GetMaxPacketLength() const;
+ // Returns the maximum length current packet can actually have.
+ QuicByteCount GetCurrentMaxPacketLength() const;
- void set_max_packet_length(QuicByteCount length);
+ // Set maximum packet length sent. If |force| is set to true, all pending
+ // unfinished packets and FEC groups are closed, and the change is enacted
+ // immediately. Otherwise, it is enacted at the next opportunity.
+ void SetMaxPacketLength(QuicByteCount length, bool force);
void set_debug_delegate(DebugDelegate* debug_delegate) {
debug_delegate_ = debug_delegate;
}
+ FecSendPolicy fec_send_policy() { return fec_send_policy_; }
+ void set_fec_send_policy(FecSendPolicy fec_send_policy) {
+ fec_send_policy_ = fec_send_policy;
+ }
+
private:
friend class test::QuicPacketGeneratorPeer;
@@ -211,13 +231,19 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
// creator being ready to send an FEC packet, otherwise FEC packet is sent
// as long as one is under construction in the creator. Also tries to turn
// off FEC protection in the creator if it's off in the generator.
- void MaybeSendFecPacketAndCloseGroup(bool force);
+ // When |fec_send_policy_| is FEC_SEND_QUIESCENCE, then send FEC
+ // packet if |is_fec_timeout| is true otherwise close the FEC group.
+ void MaybeSendFecPacketAndCloseGroup(bool force, bool is_fec_timeout);
// Returns true if an FEC packet should be generated based on |force| and
// current state of the generator and the creator.
bool ShouldSendFecPacket(bool force);
- void SendQueuedFrames(bool flush);
+ // Resets (closes) the FEC group and calls the Delegate's OnResetFecGroup.
+ // Asserts that FEC group is open.
+ void ResetFecGroup();
+
+ void SendQueuedFrames(bool flush, bool is_fec_timeout);
// Test to see if we have pending ack, or control frames.
bool HasPendingFrames() const;
@@ -226,8 +252,9 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
bool CanSendWithNextPendingFrameAddition() const;
// Add exactly one pending frame, preferring ack frames over control frames.
bool AddNextPendingFrame();
-
- bool AddFrame(const QuicFrame& frame);
+ // Adds a frame and takes ownership of the underlying buffer if the addition
+ // was successful.
+ bool AddFrame(const QuicFrame& frame, char* buffer, bool needs_padding);
void SerializeAndSendPacket();
@@ -248,13 +275,16 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
// if this variable is false.
bool should_fec_protect_;
+ // FEC policy that specifies when to send FEC packet.
+ FecSendPolicy fec_send_policy_;
+
// Flags to indicate the need for just-in-time construction of a frame.
bool should_send_ack_;
bool should_send_stop_waiting_;
- // If we put a non-retransmittable frame (ack frame) in this packet, then we
- // have to hold a reference to it until we flush (and serialize it).
- // Retransmittable frames are referenced elsewhere so that they
- // can later be (optionally) retransmitted.
+ // If we put a non-retransmittable frame in this packet, then we have to hold
+ // a reference to it until we flush (and serialize it). Retransmittable frames
+ // are referenced elsewhere so that they can later be (optionally)
+ // retransmitted.
QuicAckFrame pending_ack_frame_;
QuicStopWaitingFrame pending_stop_waiting_frame_;
// True if an ack or stop waiting frame is already queued, and should not be
@@ -265,6 +295,11 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
// Stores notifiers that should be attached to the next serialized packet.
std::list<QuicAckNotifier*> ack_notifiers_;
+ // Stores the maximum packet size we are allowed to send. This might not be
+ // the maximum size we are actually using now, if we are in the middle of the
+ // packet.
+ QuicByteCount max_packet_length_;
+
DISALLOW_COPY_AND_ASSIGN(QuicPacketGenerator);
};
diff --git a/chromium/net/quic/quic_packet_generator_test.cc b/chromium/net/quic/quic_packet_generator_test.cc
index 21e186def67..bd6a207715e 100644
--- a/chromium/net/quic/quic_packet_generator_test.cc
+++ b/chromium/net/quic/quic_packet_generator_test.cc
@@ -35,6 +35,11 @@ namespace {
const int64 kMinFecTimeoutMs = 5u;
+static const FecSendPolicy kFecSendPolicyList[] = {
+ FEC_ANY_TRIGGER,
+ FEC_ALARM_TRIGGER,
+};
+
class MockDelegate : public QuicPacketGenerator::DelegateInterface {
public:
MockDelegate() {}
@@ -47,6 +52,7 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface {
MOCK_METHOD1(PopulateStopWaitingFrame, void(QuicStopWaitingFrame*));
MOCK_METHOD1(OnSerializedPacket, void(const SerializedPacket& packet));
MOCK_METHOD2(CloseConnection, void(QuicErrorCode, bool));
+ MOCK_METHOD0(OnResetFecGroup, void());
void SetCanWriteAnything() {
EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true));
@@ -84,8 +90,9 @@ struct PacketContents {
num_rst_stream_frames(0),
num_stop_waiting_frames(0),
num_stream_frames(0),
- fec_group(0) {
- }
+ num_ping_frames(0),
+ num_mtu_discovery_frames(0),
+ fec_group(0) {}
size_t num_ack_frames;
size_t num_connection_close_frames;
@@ -93,20 +100,24 @@ struct PacketContents {
size_t num_rst_stream_frames;
size_t num_stop_waiting_frames;
size_t num_stream_frames;
+ size_t num_ping_frames;
+ size_t num_mtu_discovery_frames;
QuicFecGroupNumber fec_group;
};
} // namespace
-class QuicPacketGeneratorTest : public ::testing::Test {
+class QuicPacketGeneratorTest : public ::testing::TestWithParam<FecSendPolicy> {
public:
QuicPacketGeneratorTest()
: framer_(QuicSupportedVersions(),
QuicTime::Zero(),
Perspective::IS_CLIENT),
generator_(42, &framer_, &random_, &delegate_),
- creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) {}
+ creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) {
+ generator_.set_fec_send_policy(GetParam());
+ }
~QuicPacketGeneratorTest() override {
for (SerializedPacket& packet : packets_) {
@@ -135,12 +146,13 @@ class QuicPacketGeneratorTest : public ::testing::Test {
size_t packet_index) {
ASSERT_GT(packets_.size(), packet_index);
const SerializedPacket& packet = packets_[packet_index];
- size_t num_retransmittable_frames = contents.num_connection_close_frames +
- contents.num_goaway_frames + contents.num_rst_stream_frames +
- contents.num_stream_frames;
- size_t num_frames = contents.num_ack_frames +
- contents.num_stop_waiting_frames +
- num_retransmittable_frames;
+ size_t num_retransmittable_frames =
+ contents.num_connection_close_frames + contents.num_goaway_frames +
+ contents.num_rst_stream_frames + contents.num_stream_frames +
+ contents.num_ping_frames;
+ size_t num_frames =
+ contents.num_ack_frames + contents.num_stop_waiting_frames +
+ contents.num_mtu_discovery_frames + num_retransmittable_frames;
if (num_retransmittable_frames == 0) {
ASSERT_TRUE(packet.retransmittable_frames == nullptr);
@@ -165,6 +177,10 @@ class QuicPacketGeneratorTest : public ::testing::Test {
EXPECT_EQ(contents.num_stop_waiting_frames,
simple_framer_.stop_waiting_frames().size());
EXPECT_EQ(contents.fec_group, simple_framer_.header().fec_group);
+
+ // From the receiver's perspective, MTU discovery frames are ping frames.
+ EXPECT_EQ(contents.num_ping_frames + contents.num_mtu_discovery_frames,
+ simple_framer_.ping_frames().size());
}
void CheckPacketHasSingleStreamFrame(size_t packet_index) {
@@ -178,6 +194,12 @@ class QuicPacketGeneratorTest : public ::testing::Test {
EXPECT_EQ(1u, simple_framer_.stream_frames().size());
}
+ void CheckAllPacketsHaveSingleStreamFrame() {
+ for (size_t i = 0; i < packets_.size(); i++) {
+ CheckPacketHasSingleStreamFrame(i);
+ }
+ }
+
void CheckPacketIsFec(size_t packet_index,
QuicPacketSequenceNumber fec_group) {
ASSERT_GT(packets_.size(), packet_index);
@@ -189,12 +211,16 @@ class QuicPacketGeneratorTest : public ::testing::Test {
EXPECT_EQ(fec_group, simple_framer_.fec_data().fec_group);
}
- IOVector CreateData(size_t len) {
+ QuicIOVector CreateData(size_t len) {
data_array_.reset(new char[len]);
memset(data_array_.get(), '?', len);
- IOVector data;
- data.Append(data_array_.get(), len);
- return data;
+ iov_.iov_base = data_array_.get();
+ iov_.iov_len = len;
+ return QuicIOVector(&iov_, 1, len);
+ }
+
+ QuicIOVector MakeIOVector(StringPiece s) {
+ return ::net::MakeIOVector(s, &iov_);
}
QuicFramer framer_;
@@ -207,6 +233,7 @@ class QuicPacketGeneratorTest : public ::testing::Test {
private:
scoped_ptr<char[]> data_array_;
+ struct iovec iov_;
};
class MockDebugDelegate : public QuicPacketGenerator::DebugDelegate {
@@ -215,14 +242,19 @@ class MockDebugDelegate : public QuicPacketGenerator::DebugDelegate {
void(const QuicFrame&));
};
-TEST_F(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) {
+// Run all end to end tests with all supported FEC send polocies.
+INSTANTIATE_TEST_CASE_P(FecSendPolicy,
+ QuicPacketGeneratorTest,
+ ::testing::ValuesIn(kFecSendPolicyList));
+
+TEST_P(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) {
delegate_.SetCanNotWrite();
generator_.SetShouldSendAck(false);
EXPECT_TRUE(generator_.HasQueuedFrames());
}
-TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) {
+TEST_P(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) {
StrictMock<MockDebugDelegate> debug_delegate;
generator_.set_debug_delegate(&debug_delegate);
@@ -236,7 +268,7 @@ TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) {
EXPECT_TRUE(generator_.HasQueuedFrames());
}
-TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) {
+TEST_P(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) {
delegate_.SetCanWriteOnlyNonRetransmittable();
EXPECT_CALL(delegate_, PopulateAckFrame(_));
@@ -251,7 +283,7 @@ TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) {
CheckPacketContains(contents, 0);
}
-TEST_F(QuicPacketGeneratorTest, ShouldSendAck_MultipleCalls) {
+TEST_P(QuicPacketGeneratorTest, ShouldSendAck_MultipleCalls) {
// Make sure that calling SetShouldSendAck multiple times does not result in a
// crash. Previously this would result in multiple QuicFrames queued in the
// packet generator, with all but the last with internal pointers to freed
@@ -270,21 +302,21 @@ TEST_F(QuicPacketGeneratorTest, ShouldSendAck_MultipleCalls) {
generator_.FinishBatchOperations();
}
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) {
+TEST_P(QuicPacketGeneratorTest, AddControlFrame_NotWritable) {
delegate_.SetCanNotWrite();
generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
EXPECT_TRUE(generator_.HasQueuedFrames());
}
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) {
+TEST_P(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) {
delegate_.SetCanWriteOnlyNonRetransmittable();
generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
EXPECT_TRUE(generator_.HasQueuedFrames());
}
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) {
+TEST_P(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) {
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
@@ -292,7 +324,7 @@ TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) {
EXPECT_TRUE(generator_.HasQueuedFrames());
}
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) {
+TEST_P(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) {
delegate_.SetCanNotWrite();
generator_.StartBatchOperations();
@@ -311,7 +343,7 @@ TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) {
CheckPacketContains(contents, 0);
}
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) {
+TEST_P(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) {
delegate_.SetCanWriteAnything();
EXPECT_CALL(delegate_, OnSerializedPacket(_))
@@ -325,7 +357,7 @@ TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) {
CheckPacketContains(contents, 0);
}
-TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
+TEST_P(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
delegate_.SetCanNotWrite();
QuicConsumedData consumed = generator_.ConsumeData(
@@ -335,7 +367,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
EXPECT_FALSE(generator_.HasQueuedFrames());
}
-TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
+TEST_P(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
@@ -346,7 +378,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
EXPECT_TRUE(generator_.HasQueuedFrames());
}
-TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) {
+TEST_P(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) {
delegate_.SetCanWriteAnything();
EXPECT_CALL(delegate_, OnSerializedPacket(_))
@@ -362,13 +394,36 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) {
CheckPacketContains(contents, 0);
}
-TEST_F(QuicPacketGeneratorTest, ConsumeData_EmptyData) {
+// Test the behavior of ConsumeData when the data consumed is for the crypto
+// handshake stream. Ensure that the packet is always sent and padded even if
+// the generator operates in batch mode.
+TEST_P(QuicPacketGeneratorTest, ConsumeData_Handshake) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kCryptoStreamId, MakeIOVector("foo"), 0, false, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+
+ ASSERT_EQ(1u, packets_.size());
+ ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetMaxPacketLength());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].packet->length());
+}
+
+TEST_P(QuicPacketGeneratorTest, ConsumeData_EmptyData) {
EXPECT_DFATAL(generator_.ConsumeData(kHeadersStreamId, MakeIOVector(""), 0,
false, MAY_FEC_PROTECT, nullptr),
"Attempt to consume empty data without FIN.");
}
-TEST_F(QuicPacketGeneratorTest,
+TEST_P(QuicPacketGeneratorTest,
ConsumeDataMultipleTimes_WritableAndShouldNotFlush) {
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
@@ -382,7 +437,7 @@ TEST_F(QuicPacketGeneratorTest,
EXPECT_TRUE(generator_.HasQueuedFrames());
}
-TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) {
+TEST_P(QuicPacketGeneratorTest, ConsumeData_BatchOperations) {
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
@@ -405,7 +460,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) {
CheckPacketContains(contents, 0);
}
-TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecOnMaxGroupSize) {
+TEST_P(QuicPacketGeneratorTest, ConsumeDataFecOnMaxGroupSize) {
delegate_.SetCanWriteAnything();
// Send FEC every two packets.
@@ -417,8 +472,14 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecOnMaxGroupSize) {
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER, but FEC
+ // group is closed.
+ EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
}
@@ -434,30 +495,47 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecOnMaxGroupSize) {
CheckPacketHasSingleStreamFrame(0);
CheckPacketHasSingleStreamFrame(1);
- CheckPacketIsFec(2, 1);
- CheckPacketHasSingleStreamFrame(3);
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER.
+ CheckPacketHasSingleStreamFrame(2);
+ } else {
+ CheckPacketIsFec(2, 1);
+ CheckPacketHasSingleStreamFrame(3);
+ }
EXPECT_TRUE(creator_->IsFecProtected());
- // The FEC packet under construction will be sent when one more packet is sent
- // (since FEC group size is 2), or when OnFecTimeout is called. Send more data
- // with MAY_FEC_PROTECT. This packet should also be protected, and FEC packet
- // is sent since FEC group size is reached.
+ // If FEC send policy is FEC_ANY_TRIGGER, then the FEC packet under
+ // construction will be sent when one more packet is sent (since FEC group
+ // size is 2), or when OnFecTimeout is called. Send more data with
+ // MAY_FEC_PROTECT. This packet should also be protected, and FEC packet is
+ // sent since FEC group size is reached.
+ //
+ // If FEC send policy is FEC_ALARM_TRIGGER, FEC group is closed when the group
+ // size is reached. FEC packet is not sent.
{
InSequence dummy;
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
}
consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, MAY_FEC_PROTECT,
nullptr);
EXPECT_EQ(1u, consumed.bytes_consumed);
- CheckPacketHasSingleStreamFrame(4);
- CheckPacketIsFec(5, 4);
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ CheckPacketHasSingleStreamFrame(3);
+ } else {
+ CheckPacketHasSingleStreamFrame(4);
+ CheckPacketIsFec(5, 4);
+ }
EXPECT_FALSE(creator_->IsFecProtected());
}
-TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecOnTimeout) {
+TEST_P(QuicPacketGeneratorTest, ConsumeDataSendsFecOnTimeout) {
delegate_.SetCanWriteAnything();
creator_->set_max_packets_per_fec_group(1000);
@@ -515,7 +593,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecOnTimeout) {
EXPECT_FALSE(creator_->IsFecProtected());
}
-TEST_F(QuicPacketGeneratorTest, GetFecTimeoutFiniteOnlyOnFirstPacketInGroup) {
+TEST_P(QuicPacketGeneratorTest, GetFecTimeoutFiniteOnlyOnFirstPacketInGroup) {
delegate_.SetCanWriteAnything();
creator_->set_max_packets_per_fec_group(6);
@@ -608,7 +686,7 @@ TEST_F(QuicPacketGeneratorTest, GetFecTimeoutFiniteOnlyOnFirstPacketInGroup) {
generator_.GetFecTimeout(/*sequence_number=*/8u));
}
-TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
+TEST_P(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
// Set the packet size be enough for two stream frames with 0 stream offset,
// but not enough for a stream frame of 0 offset and one with non-zero offset.
size_t length =
@@ -621,7 +699,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
// than the GetMinStreamFrameSize.
QuicFramer::GetMinStreamFrameSize(1, 0, false, NOT_IN_FEC_GROUP) + 3 +
QuicFramer::GetMinStreamFrameSize(1, 0, true, NOT_IN_FEC_GROUP) + 1;
- creator_->SetMaxPacketLength(length);
+ generator_.SetMaxPacketLength(length, /*force=*/false);
delegate_.SetCanWriteAnything();
{
InSequence dummy;
@@ -655,7 +733,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
CheckPacketContains(contents, 1);
}
-TEST_F(QuicPacketGeneratorTest, NoFecPacketSentWhenBatchEnds) {
+TEST_P(QuicPacketGeneratorTest, NoFecPacketSentWhenBatchEnds) {
delegate_.SetCanWriteAnything();
creator_->set_max_packets_per_fec_group(6);
@@ -687,7 +765,7 @@ TEST_F(QuicPacketGeneratorTest, NoFecPacketSentWhenBatchEnds) {
CheckPacketIsFec(1, /*fec_group=*/1u);
}
-TEST_F(QuicPacketGeneratorTest, FecTimeoutOnRttChange) {
+TEST_P(QuicPacketGeneratorTest, FecTimeoutOnRttChange) {
EXPECT_EQ(QuicTime::Delta::Zero(),
QuicPacketGeneratorPeer::GetFecTimeout(&generator_));
generator_.OnRttChange(QuicTime::Delta::FromMilliseconds(300));
@@ -695,7 +773,7 @@ TEST_F(QuicPacketGeneratorTest, FecTimeoutOnRttChange) {
QuicPacketGeneratorPeer::GetFecTimeout(&generator_));
}
-TEST_F(QuicPacketGeneratorTest, FecGroupSizeOnCongestionWindowChange) {
+TEST_P(QuicPacketGeneratorTest, FecGroupSizeOnCongestionWindowChange) {
delegate_.SetCanWriteAnything();
creator_->set_max_packets_per_fec_group(50);
EXPECT_EQ(50u, creator_->max_packets_per_fec_group());
@@ -714,7 +792,7 @@ TEST_F(QuicPacketGeneratorTest, FecGroupSizeOnCongestionWindowChange) {
EXPECT_EQ(2u, creator_->max_packets_per_fec_group());
}
-TEST_F(QuicPacketGeneratorTest, FecGroupSizeChangeWithOpenGroup) {
+TEST_P(QuicPacketGeneratorTest, FecGroupSizeChangeWithOpenGroup) {
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
creator_->set_max_packets_per_fec_group(50);
@@ -742,25 +820,34 @@ TEST_F(QuicPacketGeneratorTest, FecGroupSizeChangeWithOpenGroup) {
generator_.OnCongestionWindowChange(2);
EXPECT_EQ(2u, creator_->max_packets_per_fec_group());
- // Send enough data to trigger one unprotected data packet, causing the FEC
- // packet to also be sent.
+ // If FEC send policy is FEC_ANY_TRIGGER, then send enough data to trigger one
+ // unprotected data packet, causing the FEC packet to also be sent.
+ //
+ // If FEC send policy is FEC_ALARM_TRIGGER, FEC group is closed and FEC packet
+ // is not sent.
{
InSequence dummy;
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
}
consumed = generator_.ConsumeData(7, CreateData(kDefaultMaxPacketSize), 0,
true, MAY_FEC_PROTECT, nullptr);
EXPECT_EQ(kDefaultMaxPacketSize, consumed.bytes_consumed);
- // Verify that one FEC packet was sent.
- CheckPacketIsFec(4, /*fec_group=*/1u);
+ if (generator_.fec_send_policy() == FEC_ANY_TRIGGER) {
+ // Verify that one FEC packet was sent.
+ CheckPacketIsFec(4, /*fec_group=*/1u);
+ }
EXPECT_FALSE(creator_->IsFecGroupOpen());
EXPECT_FALSE(creator_->IsFecProtected());
}
-TEST_F(QuicPacketGeneratorTest, SwitchFecOnOff) {
+TEST_P(QuicPacketGeneratorTest, SwitchFecOnOff) {
delegate_.SetCanWriteAnything();
creator_->set_max_packets_per_fec_group(2);
EXPECT_FALSE(creator_->IsFecProtected());
@@ -784,8 +871,13 @@ TEST_F(QuicPacketGeneratorTest, SwitchFecOnOff) {
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ // If FEC send policy is FEC_ALARM_TRIGGER, FEC group is closed.
+ EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
}
@@ -796,17 +888,29 @@ TEST_F(QuicPacketGeneratorTest, SwitchFecOnOff) {
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_FALSE(generator_.HasQueuedFrames());
- // Verify that packets sent were 3 data and 1 FEC.
+ // If FEC send policy is FEC_ANY_TRIGGER, verify that packets sent were 3 data
+ // and 1 FEC.
+ //
+ // If FEC send policy is FEC_ALARM_TRIGGER, verify that packets sent were 3
+ // data and FEC group is closed.
CheckPacketHasSingleStreamFrame(1);
CheckPacketHasSingleStreamFrame(2);
- CheckPacketIsFec(3, /*fec_group=*/2u);
- CheckPacketHasSingleStreamFrame(4);
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ CheckPacketHasSingleStreamFrame(3);
+ } else {
+ CheckPacketIsFec(3, /*fec_group=*/2u);
+ CheckPacketHasSingleStreamFrame(4);
+ }
// Calling OnFecTimeout should emit the pending FEC packet.
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
generator_.OnFecTimeout();
- CheckPacketIsFec(5, /*fec_group=*/5u);
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ CheckPacketIsFec(4, /*fec_group=*/4u);
+ } else {
+ CheckPacketIsFec(5, /*fec_group=*/5u);
+ }
// Send one unprotected data packet.
EXPECT_CALL(delegate_, OnSerializedPacket(_))
@@ -817,10 +921,14 @@ TEST_F(QuicPacketGeneratorTest, SwitchFecOnOff) {
EXPECT_FALSE(generator_.HasQueuedFrames());
EXPECT_FALSE(creator_->IsFecProtected());
// Verify that one unprotected data packet was sent.
- CheckPacketContains(contents, 6);
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ CheckPacketContains(contents, 5);
+ } else {
+ CheckPacketContains(contents, 6);
+ }
}
-TEST_F(QuicPacketGeneratorTest, SwitchFecOnWithPendingFrameInCreator) {
+TEST_P(QuicPacketGeneratorTest, SwitchFecOnWithPendingFrameInCreator) {
delegate_.SetCanWriteAnything();
// Enable FEC.
creator_->set_max_packets_per_fec_group(2);
@@ -848,7 +956,7 @@ TEST_F(QuicPacketGeneratorTest, SwitchFecOnWithPendingFrameInCreator) {
EXPECT_TRUE(creator_->HasPendingFrames());
}
-TEST_F(QuicPacketGeneratorTest, SwitchFecOnWithPendingFramesInGenerator) {
+TEST_P(QuicPacketGeneratorTest, SwitchFecOnWithPendingFramesInGenerator) {
// Enable FEC.
creator_->set_max_packets_per_fec_group(2);
@@ -882,7 +990,7 @@ TEST_F(QuicPacketGeneratorTest, SwitchFecOnWithPendingFramesInGenerator) {
EXPECT_TRUE(creator_->IsFecProtected());
}
-TEST_F(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentFramesProtected) {
+TEST_P(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentFramesProtected) {
delegate_.SetCanWriteAnything();
// Enable FEC.
@@ -914,7 +1022,7 @@ TEST_F(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentFramesProtected) {
EXPECT_TRUE(creator_->IsFecProtected());
}
-TEST_F(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentPacketsProtected) {
+TEST_P(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentPacketsProtected) {
delegate_.SetCanWriteAnything();
// Enable FEC.
@@ -942,21 +1050,28 @@ TEST_F(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentPacketsProtected) {
InSequence dummy;
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
}
consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, MAY_FEC_PROTECT,
nullptr);
EXPECT_EQ(1u, consumed.bytes_consumed);
contents.num_stream_frames = 1u;
CheckPacketContains(contents, 1);
- CheckPacketIsFec(2, /*fec_group=*/1u);
+ if (generator_.fec_send_policy() == FEC_ANY_TRIGGER) {
+ // FEC packet is sent when send policy is FEC_ANY_TRIGGER.
+ CheckPacketIsFec(2, /*fec_group=*/1u);
+ }
// FEC protection should be off in creator.
EXPECT_FALSE(creator_->IsFecProtected());
}
-TEST_F(QuicPacketGeneratorTest, SwitchFecOnOffThenOnWithCreatorProtectionOn) {
+TEST_P(QuicPacketGeneratorTest, SwitchFecOnOffThenOnWithCreatorProtectionOn) {
delegate_.SetCanWriteAnything();
generator_.StartBatchOperations();
@@ -990,20 +1105,154 @@ TEST_F(QuicPacketGeneratorTest, SwitchFecOnOffThenOnWithCreatorProtectionOn) {
InSequence dummy;
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
}
consumed = generator_.ConsumeData(5, CreateData(data_len), 0, true,
MUST_FEC_PROTECT, nullptr);
EXPECT_EQ(data_len, consumed.bytes_consumed);
CheckPacketContains(contents, 1);
- CheckPacketIsFec(2, /*fec_group=*/1u);
+ if (generator_.fec_send_policy() == FEC_ANY_TRIGGER) {
+ // FEC packet is sent when send policy is FEC_ANY_TRIGGER.
+ CheckPacketIsFec(2, /*fec_group=*/1u);
+ }
// FEC protection should remain on in creator.
EXPECT_TRUE(creator_->IsFecProtected());
}
-TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
+TEST_P(QuicPacketGeneratorTest, ResetFecGroupNoTimeout) {
+ delegate_.SetCanWriteAnything();
+ // Send FEC packet after 2 packets.
+ creator_->set_max_packets_per_fec_group(2);
+ EXPECT_FALSE(creator_->IsFecProtected());
+
+ // Send two packets so that when this data is consumed, two packets are sent
+ // out. In FEC_TRIGGER_ANY, this will cause an FEC packet to be sent out and
+ // with FEC_TRIGGER_ALARM, this will cause a Reset to be called. In both
+ // cases, the creator's fec protection will be turned off afterwards.
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER, but FEC
+ // group is closed.
+ EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
+ // Fin Packet.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
+ size_t data_len = 2 * kDefaultMaxPacketSize;
+ QuicConsumedData consumed = generator_.ConsumeData(
+ 5, CreateData(data_len), 0, true, MUST_FEC_PROTECT, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ CheckPacketHasSingleStreamFrame(0);
+ CheckPacketHasSingleStreamFrame(1);
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER.
+ CheckPacketHasSingleStreamFrame(2);
+ } else {
+ // FEC packet is sent after 2 packets and when send policy is
+ // FEC_ANY_TRIGGER.
+ CheckPacketIsFec(2, 1);
+ CheckPacketHasSingleStreamFrame(3);
+ }
+ EXPECT_TRUE(creator_->IsFecProtected());
+
+ // Do the same send (with MUST_FEC_PROTECT) on a different stream id.
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ // FEC packet is sent after 2 packets and when send policy is
+ // FEC_ANY_TRIGGER. When policy is FEC_ALARM_TRIGGER, FEC group is closed
+ // and FEC packet is not sent.
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ // FEC packet is sent after 2 packets and when send policy is
+ // FEC_ANY_TRIGGER. When policy is FEC_ALARM_TRIGGER, FEC group is closed
+ // and FEC packet is not sent.
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+ } else {
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
+ }
+ consumed = generator_.ConsumeData(7, CreateData(data_len), 0, true,
+ MUST_FEC_PROTECT, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) {
+ CheckPacketHasSingleStreamFrame(3);
+ CheckPacketHasSingleStreamFrame(4);
+ CheckPacketHasSingleStreamFrame(5);
+ } else {
+ CheckPacketHasSingleStreamFrame(4);
+ // FEC packet is sent after 2 packets and when send policy is
+ // FEC_ANY_TRIGGER.
+ CheckPacketIsFec(5, 4);
+ CheckPacketHasSingleStreamFrame(6);
+ CheckPacketHasSingleStreamFrame(7);
+ // FEC packet is sent after 2 packets and when send policy is
+ // FEC_ANY_TRIGGER.
+ CheckPacketIsFec(8, 7);
+ }
+ EXPECT_TRUE(creator_->IsFecProtected());
+}
+
+// 1. Create and send one packet with MUST_FEC_PROTECT.
+// 2. Call FecTimeout, expect FEC packet is sent.
+// 3. Do the same thing over again, with a different stream id.
+TEST_P(QuicPacketGeneratorTest, FecPacketSentOnFecTimeout) {
+ delegate_.SetCanWriteAnything();
+ creator_->set_max_packets_per_fec_group(1000);
+ EXPECT_FALSE(creator_->IsFecProtected());
+
+ for (int i = 1; i < 4; i = i + 2) {
+ // Send data with MUST_FEC_PROTECT flag. No FEC packet is emitted, but the
+ // creator FEC protects all data.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed = generator_.ConsumeData(
+ i + 2, CreateData(1u), 0, true, MUST_FEC_PROTECT, nullptr);
+ EXPECT_EQ(1u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ CheckPacketHasSingleStreamFrame(0);
+ EXPECT_TRUE(creator_->IsFecProtected());
+
+ // Calling OnFecTimeout should cause the FEC packet to be emitted.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ generator_.OnFecTimeout();
+ CheckPacketIsFec(i, i);
+ EXPECT_FALSE(creator_->IsFecProtected());
+ }
+}
+
+TEST_P(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
delegate_.SetCanNotWrite();
generator_.SetShouldSendAck(false);
@@ -1036,7 +1285,7 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
CheckPacketContains(contents, 0);
}
-TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) {
+TEST_P(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) {
delegate_.SetCanNotWrite();
generator_.SetShouldSendAck(false);
@@ -1084,7 +1333,7 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) {
CheckPacketContains(contents2, 1);
}
-TEST_F(QuicPacketGeneratorTest, TestConnectionIdLength) {
+TEST_P(QuicPacketGeneratorTest, TestConnectionIdLength) {
generator_.SetConnectionIdLength(0);
EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, creator_->connection_id_length());
generator_.SetConnectionIdLength(1);
@@ -1107,5 +1356,302 @@ TEST_F(QuicPacketGeneratorTest, TestConnectionIdLength) {
EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, creator_->connection_id_length());
}
+// Test whether SetMaxPacketLength() works in the situation when the queue is
+// empty, and we send three packets worth of data.
+TEST_P(QuicPacketGeneratorTest, SetMaxPacketLength_Initial) {
+ delegate_.SetCanWriteAnything();
+
+ // Send enough data for three packets.
+ size_t data_len = 3 * kDefaultMaxPacketSize + 1;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ ASSERT_LE(packet_len, kMaxPacketSize);
+ generator_.SetMaxPacketLength(packet_len, /*force=*/false);
+ EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength());
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(3)
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ /*offset=*/2,
+ /*fin=*/true, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // We expect three packets, and first two of them have to be of packet_len
+ // size. We check multiple packets (instead of just one) because we want to
+ // ensure that |max_packet_length_| does not get changed incorrectly by the
+ // generator after first packet is serialized.
+ ASSERT_EQ(3u, packets_.size());
+ EXPECT_EQ(packet_len, packets_[0].packet->length());
+ EXPECT_EQ(packet_len, packets_[1].packet->length());
+ CheckAllPacketsHaveSingleStreamFrame();
+}
+
+// Test whether SetMaxPacketLength() works in the situation when we first write
+// data, then change packet size, then write data again.
+TEST_P(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) {
+ delegate_.SetCanWriteAnything();
+
+ // We send enough data to overflow default packet length, but not the altered
+ // one.
+ size_t data_len = kDefaultMaxPacketSize;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ ASSERT_LE(packet_len, kMaxPacketSize);
+
+ // We expect to see three packets in total.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(3)
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ // Send two packets before packet size change.
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ /*offset=*/2,
+ /*fin=*/false, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // Make sure we already have two packets.
+ ASSERT_EQ(2u, packets_.size());
+
+ // Increase packet size.
+ generator_.SetMaxPacketLength(packet_len, /*force=*/false);
+ EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength());
+
+ // Send a packet after packet size change.
+ consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ 2 + data_len,
+ /*fin=*/true, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // We expect first data chunk to get fragmented, but the second one to fit
+ // into a single packet.
+ ASSERT_EQ(3u, packets_.size());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].packet->length());
+ EXPECT_LE(kDefaultMaxPacketSize, packets_[2].packet->length());
+ CheckAllPacketsHaveSingleStreamFrame();
+}
+
+// Test whether SetMaxPacketLength() works correctly when we change the packet
+// size in the middle of the batched packet.
+TEST_P(QuicPacketGeneratorTest, SetMaxPacketLength_Midpacket) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ size_t first_write_len = kDefaultMaxPacketSize / 2;
+ size_t second_write_len = kDefaultMaxPacketSize;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ ASSERT_LE(packet_len, kMaxPacketSize);
+
+ // First send half of the packet worth of data. We are in the batch mode, so
+ // should not cause packet serialization.
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(first_write_len),
+ /*offset=*/2,
+ /*fin=*/false, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(first_write_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ // Make sure we have no packets so far.
+ ASSERT_EQ(0u, packets_.size());
+
+ // Increase packet size. Ensure it's not immediately enacted.
+ generator_.SetMaxPacketLength(packet_len, /*force=*/false);
+ EXPECT_EQ(packet_len, generator_.GetMaxPacketLength());
+ EXPECT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength());
+
+ // We expect to see exactly one packet serialized after that, since we are in
+ // batch mode and we have sent approximately 3/2 of our MTU.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ // Send a packet worth of data to the same stream. This should trigger
+ // serialization of other packet.
+ consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(second_write_len),
+ /*offset=*/2 + first_write_len,
+ /*fin=*/true, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(second_write_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ // We expect the first packet to contain two frames, and to not reflect the
+ // packet size change.
+ ASSERT_EQ(1u, packets_.size());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].packet->length());
+
+ PacketContents contents;
+ contents.num_stream_frames = 2;
+ CheckPacketContains(contents, 0);
+}
+
+// Test whether SetMaxPacketLength() works correctly when we force the change of
+// the packet size in the middle of the batched packet.
+TEST_P(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ size_t first_write_len = kDefaultMaxPacketSize / 2;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ size_t second_write_len = packet_len + 1;
+ ASSERT_LE(packet_len, kMaxPacketSize);
+
+ // First send half of the packet worth of data. We are in the batch mode, so
+ // should not cause packet serialization.
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(first_write_len),
+ /*offset=*/2,
+ /*fin=*/false, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(first_write_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ // Make sure we have no packets so far.
+ ASSERT_EQ(0u, packets_.size());
+
+ // Expect a packet to be flushed.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ // Increase packet size. Ensure it's immediately enacted.
+ generator_.SetMaxPacketLength(packet_len, /*force=*/true);
+ EXPECT_EQ(packet_len, generator_.GetMaxPacketLength());
+ EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength());
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // We expect to see exactly one packet serialized after that, because we send
+ // a value somewhat exceeding new max packet size, and the tail data does not
+ // get serialized because we are still in the batch mode.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ // Send a more than a packet worth of data to the same stream. This should
+ // trigger serialization of one packet, and queue another one.
+ consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(second_write_len),
+ /*offset=*/2 + first_write_len,
+ /*fin=*/true, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(second_write_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ // We expect the first packet to be underfilled, and the second packet be up
+ // to the new max packet size.
+ ASSERT_EQ(2u, packets_.size());
+ EXPECT_GT(kDefaultMaxPacketSize, packets_[0].packet->length());
+ EXPECT_EQ(packet_len, packets_[1].packet->length());
+
+ CheckAllPacketsHaveSingleStreamFrame();
+}
+
+// Test sending an MTU probe, without any surrounding data.
+TEST_P(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_Simple) {
+ delegate_.SetCanWriteAnything();
+
+ const size_t target_mtu = kDefaultMaxPacketSize + 100;
+ static_assert(target_mtu < kMaxPacketSize,
+ "The MTU probe used by the test exceeds maximum packet size");
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ generator_.GenerateMtuDiscoveryPacket(target_mtu, nullptr);
+
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ ASSERT_EQ(1u, packets_.size());
+ EXPECT_EQ(target_mtu, packets_[0].packet->length());
+
+ PacketContents contents;
+ contents.num_mtu_discovery_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+// Test sending an MTU probe. Surround it with data, to ensure that it resets
+// the MTU to the value before the probe was sent.
+TEST_P(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) {
+ delegate_.SetCanWriteAnything();
+
+ const size_t target_mtu = kDefaultMaxPacketSize + 100;
+ static_assert(target_mtu < kMaxPacketSize,
+ "The MTU probe used by the test exceeds maximum packet size");
+
+ // Send enough data so it would always cause two packets to be sent.
+ const size_t data_len = target_mtu + 1;
+
+ // Send a total of five packets: two packets before the probe, the probe
+ // itself, and two packets after the probe.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(5)
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ // Send data before the MTU probe.
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ /*offset=*/2,
+ /*fin=*/false, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // Send the MTU probe.
+ generator_.GenerateMtuDiscoveryPacket(target_mtu, nullptr);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // Send data after the MTU probe.
+ consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ /*offset=*/2 + data_len,
+ /*fin=*/true, MAY_FEC_PROTECT, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ ASSERT_EQ(5u, packets_.size());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].packet->length());
+ EXPECT_EQ(target_mtu, packets_[2].packet->length());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[3].packet->length());
+
+ PacketContents probe_contents;
+ probe_contents.num_mtu_discovery_frames = 1;
+
+ CheckPacketHasSingleStreamFrame(0);
+ CheckPacketHasSingleStreamFrame(1);
+ CheckPacketContains(probe_contents, 2);
+ CheckPacketHasSingleStreamFrame(3);
+ CheckPacketHasSingleStreamFrame(4);
+}
+
+TEST_P(QuicPacketGeneratorTest, DontCrashOnInvalidStopWaiting) {
+ // Test added to ensure the generator does not crash when an invalid frame is
+ // added. Because this is an indication of internal programming errors,
+ // DFATALs are expected.
+ // A 1 byte sequence number length can't encode a gap of 1000.
+ QuicPacketCreatorPeer::SetSequenceNumber(creator_, 1000);
+
+ 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_, PopulateAckFrame(_));
+ EXPECT_CALL(delegate_, PopulateStopWaitingFrame(_));
+ // Generator should have queued control frames, and creator should be empty.
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(creator_->HasPendingFrames());
+
+ // This will not serialize any packets, because of the invalid frame.
+ EXPECT_CALL(delegate_,
+ CloseConnection(QUIC_FAILED_TO_SERIALIZE_PACKET, false));
+ EXPECT_DFATAL(generator_.FinishBatchOperations(),
+ "sequence_number_length 1 is too small "
+ "for least_unacked_delta: 1001");
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/quic_packet_reader.cc b/chromium/net/quic/quic_packet_reader.cc
index 93451daaaba..c58a51fa7f8 100644
--- a/chromium/net/quic/quic_packet_reader.cc
+++ b/chromium/net/quic/quic_packet_reader.cc
@@ -4,7 +4,10 @@
#include "net/quic/quic_packet_reader.h"
-#include "base/metrics/histogram.h"
+#include "base/location.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "net/base/net_errors.h"
namespace net {
@@ -44,7 +47,7 @@ void QuicPacketReader::StartReading() {
// Data was read, process it.
// Schedule the work through the message loop to 1) prevent infinite
// recursion and 2) avoid blocking the thread for too long.
- base::MessageLoop::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&QuicPacketReader::OnReadComplete,
weak_factory_.GetWeakPtr(), rv));
} else {
diff --git a/chromium/net/quic/quic_protocol.cc b/chromium/net/quic/quic_protocol.cc
index 7fa153d9c51..c110522bb20 100644
--- a/chromium/net/quic/quic_protocol.cc
+++ b/chromium/net/quic/quic_protocol.cc
@@ -73,20 +73,20 @@ QuicPacketPublicHeader::QuicPacketPublicHeader(
QuicPacketPublicHeader::~QuicPacketPublicHeader() {}
QuicPacketHeader::QuicPacketHeader()
- : fec_flag(false),
+ : packet_sequence_number(0),
+ fec_flag(false),
entropy_flag(false),
entropy_hash(0),
- packet_sequence_number(0),
is_in_fec_group(NOT_IN_FEC_GROUP),
fec_group(0) {
}
QuicPacketHeader::QuicPacketHeader(const QuicPacketPublicHeader& header)
: public_header(header),
+ packet_sequence_number(0),
fec_flag(false),
entropy_flag(false),
entropy_hash(0),
- packet_sequence_number(0),
is_in_fec_group(NOT_IN_FEC_GROUP),
fec_group(0) {
}
@@ -114,21 +114,10 @@ QuicStreamFrame::QuicStreamFrame(const QuicStreamFrame& frame)
QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
bool fin,
QuicStreamOffset offset,
- IOVector data)
+ StringPiece data)
: stream_id(stream_id), fin(fin), offset(offset), data(data) {
}
-string* QuicStreamFrame::GetDataAsString() const {
- string* data_string = new string();
- data_string->reserve(data.TotalBufferSize());
- for (size_t i = 0; i < data.Size(); ++i) {
- data_string->append(static_cast<char*>(data.iovec()[i].iov_base),
- data.iovec()[i].iov_len);
- }
- DCHECK_EQ(data_string->size(), data.TotalBufferSize());
- return data_string;
-}
-
uint32 MakeQuicTag(char a, char b, char c, char d) {
return static_cast<uint32>(a) |
static_cast<uint32>(b) << 8 |
@@ -300,6 +289,10 @@ QuicFrame::QuicFrame(QuicAckFrame* frame)
ack_frame(frame) {
}
+QuicFrame::QuicFrame(QuicMtuDiscoveryFrame* frame)
+ : type(MTU_DISCOVERY_FRAME), mtu_discovery_frame(frame) {
+}
+
QuicFrame::QuicFrame(QuicStopWaitingFrame* frame)
: type(STOP_WAITING_FRAME),
stop_waiting_frame(frame) {
@@ -412,6 +405,10 @@ ostream& operator<<(ostream& os, const QuicFrame& frame) {
os << "type { PING_FRAME } ";
break;
}
+ case MTU_DISCOVERY_FRAME: {
+ os << "type { MTU_DISCOVERY_FRAME } ";
+ break;
+ }
default: {
LOG(ERROR) << "Unknown frame type: " << frame.type;
break;
@@ -457,8 +454,7 @@ ostream& operator<<(ostream& os, const QuicStreamFrame& stream_frame) {
os << "stream_id { " << stream_frame.stream_id << " } "
<< "fin { " << stream_frame.fin << " } "
<< "offset { " << stream_frame.offset << " } "
- << "data { "
- << QuicUtils::StringToHexASCIIDump(*(stream_frame.GetDataAsString()))
+ << "data { " << QuicUtils::StringToHexASCIIDump(stream_frame.data)
<< " }\n";
return os;
}
@@ -559,7 +555,9 @@ StringPiece QuicPacket::Plaintext() const {
}
RetransmittableFrames::RetransmittableFrames(EncryptionLevel level)
- : encryption_level_(level), has_crypto_handshake_(NOT_HANDSHAKE) {
+ : encryption_level_(level),
+ has_crypto_handshake_(NOT_HANDSHAKE),
+ needs_padding_(false) {
}
RetransmittableFrames::~RetransmittableFrames() {
@@ -574,6 +572,9 @@ RetransmittableFrames::~RetransmittableFrames() {
case ACK_FRAME:
delete it->ack_frame;
break;
+ case MTU_DISCOVERY_FRAME:
+ delete it->mtu_discovery_frame;
+ break;
case STOP_WAITING_FRAME:
delete it->stop_waiting_frame;
break;
@@ -599,27 +600,24 @@ RetransmittableFrames::~RetransmittableFrames() {
DCHECK(false) << "Cannot delete type: " << it->type;
}
}
- STLDeleteElements(&stream_data_);
-}
-
-const QuicFrame& RetransmittableFrames::AddStreamFrame(
- QuicStreamFrame* stream_frame) {
- // Make an owned copy of the stream frame's data.
- stream_data_.push_back(stream_frame->GetDataAsString());
- // Ensure the stream frame's IOVector points to the owned copy of the data.
- stream_frame->data.Clear();
- stream_frame->data.Append(const_cast<char*>(stream_data_.back()->data()),
- stream_data_.back()->size());
- frames_.push_back(QuicFrame(stream_frame));
- if (stream_frame->stream_id == kCryptoStreamId) {
- has_crypto_handshake_ = IS_HANDSHAKE;
+ for (const char* buffer : stream_data_) {
+ delete[] buffer;
}
- return frames_.back();
}
-const QuicFrame& RetransmittableFrames::AddNonStreamFrame(
- const QuicFrame& frame) {
- DCHECK_NE(frame.type, STREAM_FRAME);
+const QuicFrame& RetransmittableFrames::AddFrame(const QuicFrame& frame) {
+ return AddFrame(frame, nullptr);
+}
+
+const QuicFrame& RetransmittableFrames::AddFrame(const QuicFrame& frame,
+ char* buffer) {
+ if (frame.type == STREAM_FRAME &&
+ frame.stream_frame->stream_id == kCryptoStreamId) {
+ has_crypto_handshake_ = IS_HANDSHAKE;
+ }
+ if (buffer != nullptr) {
+ stream_data_.push_back(buffer);
+ }
frames_.push_back(frame);
return frames_.back();
}
@@ -642,11 +640,11 @@ SerializedPacket::SerializedPacket(
QuicEncryptedPacket* packet,
QuicPacketEntropyHash entropy_hash,
RetransmittableFrames* retransmittable_frames)
- : sequence_number(sequence_number),
+ : packet(packet),
+ retransmittable_frames(retransmittable_frames),
+ sequence_number(sequence_number),
sequence_number_length(sequence_number_length),
- packet(packet),
entropy_hash(entropy_hash),
- retransmittable_frames(retransmittable_frames),
is_fec_packet(false) {
}
diff --git a/chromium/net/quic/quic_protocol.h b/chromium/net/quic/quic_protocol.h
index 8c2bca76bba..d68f300c505 100644
--- a/chromium/net/quic/quic_protocol.h
+++ b/chromium/net/quic/quic_protocol.h
@@ -6,6 +6,7 @@
#define NET_QUIC_QUIC_PROTOCOL_H_
#include <stddef.h>
+#include <stdint.h>
#include <limits>
#include <list>
#include <map>
@@ -20,11 +21,12 @@
#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "net/base/int128.h"
+#include "net/base/iovec.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
-#include "net/quic/iovector.h"
#include "net/quic/quic_bandwidth.h"
#include "net/quic/quic_time.h"
+#include "net/quic/quic_types.h"
namespace net {
@@ -72,8 +74,11 @@ const uint32 kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB
// Minimum size of the CWND, in packets, when doing bandwidth resumption.
const QuicPacketCount kMinCongestionWindowForBandwidthResumption = 10;
-// Maximum size of the CWND, in packets, for TCP congestion control algorithms.
-const QuicPacketCount kMaxTcpCongestionWindow = 200;
+// Maximum size of the CWND, in packets, for bandwidth resumption.
+const QuicPacketCount kMaxResumptionCwnd = 200;
+
+// Maximum number of tracked packets.
+const QuicPacketCount kMaxTrackedPackets = 5000;
// Default size of the socket receive buffer in bytes.
const QuicByteCount kDefaultSocketReceiveBuffer = 256 * 1024;
@@ -169,7 +174,7 @@ const int kUFloat16MaxExponent = (1 << kUFloat16ExponentBits) - 2; // 30
const int kUFloat16MantissaBits = 16 - kUFloat16ExponentBits; // 11
const int kUFloat16MantissaEffectiveBits = kUFloat16MantissaBits + 1; // 12
const uint64 kUFloat16MaxValue = // 0x3FFC0000000
- ((GG_UINT64_C(1) << kUFloat16MantissaEffectiveBits) - 1) <<
+ ((UINT64_C(1) << kUFloat16MantissaEffectiveBits) - 1) <<
kUFloat16MaxExponent;
enum TransmissionType {
@@ -211,6 +216,14 @@ enum FecPolicy {
FEC_PROTECT_OPTIONAL // Data in the stream does not need FEC protection.
};
+// Indicates FEC policy about when to send FEC packet.
+enum FecSendPolicy {
+ // Send FEC packet when FEC group is full or when FEC alarm goes off.
+ FEC_ANY_TRIGGER,
+ // Send FEC packet only when FEC alarm goes off.
+ FEC_ALARM_TRIGGER
+};
+
enum QuicFrameType {
// Regular frame types. The values set here cannot change without the
// introduction of a new QUIC version.
@@ -227,6 +240,8 @@ enum QuicFrameType {
// the wire and their values do not need to be stable.
STREAM_FRAME,
ACK_FRAME,
+ // The path MTU discovery frame is encoded as a PING frame on the wire.
+ MTU_DISCOVERY_FRAME,
NUM_FRAME_TYPES
};
@@ -527,6 +542,12 @@ enum QuicErrorCode {
QUIC_CONNECTION_CANCELLED = 70,
// Disabled QUIC because of high packet loss rate.
QUIC_BAD_PACKET_LOSS_RATE = 71,
+ // Disabled QUIC because of too many PUBLIC_RESETs post handshake.
+ QUIC_PUBLIC_RESETS_POST_HANDSHAKE = 73,
+ // Disabled QUIC because of too many timeouts with streams open.
+ QUIC_TIMEOUTS_WITH_OPEN_STREAMS = 74,
+ // Closed because we failed to serialize a packet.
+ QUIC_FAILED_TO_SERIALIZE_PACKET = 75,
// Crypto errors.
@@ -586,7 +607,7 @@ enum QuicErrorCode {
QUIC_VERSION_NEGOTIATION_MISMATCH = 55,
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 73,
+ QUIC_LAST_ERROR = 76,
};
struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
@@ -616,10 +637,10 @@ struct NET_EXPORT_PRIVATE QuicPacketHeader {
std::ostream& os, const QuicPacketHeader& s);
QuicPacketPublicHeader public_header;
+ QuicPacketSequenceNumber packet_sequence_number;
bool fec_flag;
bool entropy_flag;
QuicPacketEntropyHash entropy_hash;
- QuicPacketSequenceNumber packet_sequence_number;
InFecGroup is_in_fec_group;
QuicFecGroupNumber fec_group;
};
@@ -659,25 +680,25 @@ struct NET_EXPORT_PRIVATE QuicPaddingFrame {
struct NET_EXPORT_PRIVATE QuicPingFrame {
};
+// A path MTU discovery frame contains no payload and is serialized as a ping
+// frame.
+struct NET_EXPORT_PRIVATE QuicMtuDiscoveryFrame {};
+
struct NET_EXPORT_PRIVATE QuicStreamFrame {
QuicStreamFrame();
QuicStreamFrame(const QuicStreamFrame& frame);
QuicStreamFrame(QuicStreamId stream_id,
bool fin,
QuicStreamOffset offset,
- IOVector data);
+ base::StringPiece data);
NET_EXPORT_PRIVATE friend std::ostream& operator<<(
std::ostream& os, const QuicStreamFrame& s);
- // Returns a copy of the IOVector |data| as a heap-allocated string.
- // Caller must take ownership of the returned string.
- std::string* GetDataAsString() const;
-
QuicStreamId stream_id;
bool fin;
QuicStreamOffset offset; // Location of this data in the stream.
- IOVector data;
+ base::StringPiece data;
};
// TODO(ianswett): Re-evaluate the trade-offs of hash_set vs set when framing
@@ -871,6 +892,7 @@ struct NET_EXPORT_PRIVATE QuicFrame {
explicit QuicFrame(QuicPaddingFrame* padding_frame);
explicit QuicFrame(QuicStreamFrame* stream_frame);
explicit QuicFrame(QuicAckFrame* frame);
+ explicit QuicFrame(QuicMtuDiscoveryFrame* frame);
explicit QuicFrame(QuicRstStreamFrame* frame);
explicit QuicFrame(QuicConnectionCloseFrame* frame);
@@ -888,6 +910,7 @@ struct NET_EXPORT_PRIVATE QuicFrame {
QuicPaddingFrame* padding_frame;
QuicStreamFrame* stream_frame;
QuicAckFrame* ack_frame;
+ QuicMtuDiscoveryFrame* mtu_discovery_frame;
QuicStopWaitingFrame* stop_waiting_frame;
@@ -983,12 +1006,10 @@ class NET_EXPORT_PRIVATE RetransmittableFrames {
explicit RetransmittableFrames(EncryptionLevel level);
~RetransmittableFrames();
- // Allocates a local copy of the referenced StringPiece has QuicStreamFrame
- // use it.
- // Takes ownership of |stream_frame|.
- const QuicFrame& AddStreamFrame(QuicStreamFrame* stream_frame);
// Takes ownership of the frame inside |frame|.
- const QuicFrame& AddNonStreamFrame(const QuicFrame& frame);
+ const QuicFrame& AddFrame(const QuicFrame& frame);
+ // Takes ownership of the frame inside |frame| and |buffer|.
+ const QuicFrame& AddFrame(const QuicFrame& frame, char* buffer);
// Removes all stream frames associated with |stream_id|.
void RemoveFramesForStream(QuicStreamId stream_id);
@@ -1002,12 +1023,17 @@ class NET_EXPORT_PRIVATE RetransmittableFrames {
return encryption_level_;
}
+ bool needs_padding() const { return needs_padding_; }
+
+ void set_needs_padding(bool needs_padding) { needs_padding_ = needs_padding; }
+
private:
QuicFrames frames_;
const EncryptionLevel encryption_level_;
IsHandshake has_crypto_handshake_;
+ bool needs_padding_;
// Data referenced by the StringPiece of a QuicStreamFrame.
- std::vector<std::string*> stream_data_;
+ std::vector<const char*> stream_data_;
DISALLOW_COPY_AND_ASSIGN(RetransmittableFrames);
};
@@ -1020,11 +1046,11 @@ struct NET_EXPORT_PRIVATE SerializedPacket {
RetransmittableFrames* retransmittable_frames);
~SerializedPacket();
+ QuicEncryptedPacket* packet;
+ RetransmittableFrames* retransmittable_frames;
QuicPacketSequenceNumber sequence_number;
QuicSequenceNumberLength sequence_number_length;
- QuicEncryptedPacket* packet;
QuicPacketEntropyHash entropy_hash;
- RetransmittableFrames* retransmittable_frames;
bool is_fec_packet;
// Optional notifiers which will be informed when this packet has been ACKed.
@@ -1062,6 +1088,17 @@ struct NET_EXPORT_PRIVATE TransmissionInfo {
bool is_fec_packet;
};
+// Convenience wrapper to wrap an iovec array and the total length, which must
+// be less than or equal to the actual total length of the iovecs.
+struct NET_EXPORT_PRIVATE QuicIOVector {
+ QuicIOVector(const struct iovec* iov, int iov_count, size_t total_length)
+ : iov(iov), iov_count(iov_count), total_length(total_length) {}
+
+ const struct iovec* iov;
+ const int iov_count;
+ const size_t total_length;
+};
+
} // namespace net
#endif // NET_QUIC_QUIC_PROTOCOL_H_
diff --git a/chromium/net/quic/quic_reliable_client_stream.cc b/chromium/net/quic/quic_reliable_client_stream.cc
index 68651cb049c..b65acf95c37 100644
--- a/chromium/net/quic/quic_reliable_client_stream.cc
+++ b/chromium/net/quic/quic_reliable_client_stream.cc
@@ -6,17 +6,15 @@
#include "base/callback_helpers.h"
#include "net/base/net_errors.h"
-#include "net/quic/quic_session.h"
+#include "net/quic/quic_spdy_session.h"
#include "net/quic/quic_write_blocked_list.h"
namespace net {
QuicReliableClientStream::QuicReliableClientStream(QuicStreamId id,
- QuicSession* session,
+ QuicSpdySession* session,
const BoundNetLog& net_log)
- : QuicDataStream(id, session),
- net_log_(net_log),
- delegate_(nullptr) {
+ : QuicDataStream(id, session), net_log_(net_log), delegate_(nullptr) {
}
QuicReliableClientStream::~QuicReliableClientStream() {
@@ -24,6 +22,15 @@ QuicReliableClientStream::~QuicReliableClientStream() {
delegate_->OnClose(connection_error());
}
+void QuicReliableClientStream::OnStreamHeadersComplete(bool fin,
+ size_t frame_len) {
+ QuicDataStream::OnStreamHeadersComplete(fin, frame_len);
+ if (delegate_) {
+ delegate_->OnHeadersAvailable(decompressed_headers());
+ MarkHeadersConsumed(decompressed_headers().length());
+ }
+}
+
uint32 QuicReliableClientStream::ProcessData(const char* data,
uint32 data_len) {
// TODO(rch): buffer data if we don't have a delegate.
@@ -33,6 +40,11 @@ uint32 QuicReliableClientStream::ProcessData(const char* data,
return 0;
}
+ if (!FinishedReadingHeaders()) {
+ // Buffer the data in the sequencer until the headers have been read.
+ return 0;
+ }
+
int rv = delegate_->OnDataReceived(data, data_len);
if (rv != OK) {
DLOG(ERROR) << "Delegate refused data, rv: " << rv;
diff --git a/chromium/net/quic/quic_reliable_client_stream.h b/chromium/net/quic/quic_reliable_client_stream.h
index 48f5cc91ef7..fb2c51d1e58 100644
--- a/chromium/net/quic/quic_reliable_client_stream.h
+++ b/chromium/net/quic/quic_reliable_client_stream.h
@@ -16,7 +16,7 @@
namespace net {
-class QuicClientSession;
+class QuicSpdySession;
// A client-initiated ReliableQuicStream. Instances of this class
// are owned by the QuicClientSession which created them.
@@ -27,6 +27,9 @@ class NET_EXPORT_PRIVATE QuicReliableClientStream : public QuicDataStream {
public:
Delegate() {}
+ // Called when headers are available.
+ virtual void OnHeadersAvailable(StringPiece headers) = 0;
+
// Called when data is received.
// Returns network error code. OK when it successfully receives data.
virtual int OnDataReceived(const char* data, int length) = 0;
@@ -48,12 +51,13 @@ class NET_EXPORT_PRIVATE QuicReliableClientStream : public QuicDataStream {
};
QuicReliableClientStream(QuicStreamId id,
- QuicSession* session,
+ QuicSpdySession* session,
const BoundNetLog& net_log);
~QuicReliableClientStream() override;
// QuicDataStream
+ void OnStreamHeadersComplete(bool fin, size_t frame_len) override;
uint32 ProcessData(const char* data, uint32 data_len) override;
void OnClose() override;
void OnCanWrite() override;
diff --git a/chromium/net/quic/quic_reliable_client_stream_test.cc b/chromium/net/quic/quic_reliable_client_stream_test.cc
index b36e61046fb..c53e414018b 100644
--- a/chromium/net/quic/quic_reliable_client_stream_test.cc
+++ b/chromium/net/quic/quic_reliable_client_stream_test.cc
@@ -21,7 +21,7 @@ namespace net {
namespace test {
namespace {
-const QuicConnectionId kStreamId = 3;
+const QuicStreamId kTestStreamId = 5u;
class MockDelegate : public QuicReliableClientStream::Delegate {
public:
@@ -29,6 +29,7 @@ class MockDelegate : public QuicReliableClientStream::Delegate {
MOCK_METHOD0(OnSendData, int());
MOCK_METHOD2(OnSendDataComplete, int(int, bool*));
+ MOCK_METHOD1(OnHeadersAvailable, void(StringPiece));
MOCK_METHOD2(OnDataReceived, int(const char*, int));
MOCK_METHOD1(OnClose, void(QuicErrorCode));
MOCK_METHOD1(OnError, void(int));
@@ -44,7 +45,8 @@ class QuicReliableClientStreamTest
QuicReliableClientStreamTest()
: session_(new MockConnection(Perspective::IS_CLIENT,
SupportedVersions(GetParam()))) {
- stream_ = new QuicReliableClientStream(kStreamId, &session_, BoundNetLog());
+ stream_ =
+ new QuicReliableClientStream(kTestStreamId, &session_, BoundNetLog());
session_.ActivateStream(stream_);
stream_->SetDelegate(&delegate_);
}
@@ -80,7 +82,7 @@ class QuicReliableClientStreamTest
}
testing::StrictMock<MockDelegate> delegate_;
- MockSession session_;
+ MockQuicSpdySession session_;
QuicReliableClientStream* stream_;
QuicCryptoClientConfig crypto_config_;
SpdyHeaderBlock headers_;
@@ -93,19 +95,32 @@ TEST_P(QuicReliableClientStreamTest, OnFinRead) {
InitializeHeaders();
std::string uncompressed_headers =
SpdyUtils::SerializeUncompressedHeaders(headers_, GetParam());
- EXPECT_CALL(delegate_, OnDataReceived(StrEq(uncompressed_headers.data()),
- uncompressed_headers.size()));
+ EXPECT_CALL(delegate_, OnHeadersAvailable(StringPiece(uncompressed_headers)));
QuicStreamOffset offset = 0;
stream_->OnStreamHeaders(uncompressed_headers);
stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
+ EXPECT_TRUE(stream_->decompressed_headers().empty());
- IOVector iov;
- QuicStreamFrame frame2(kStreamId, true, offset, iov);
+ QuicStreamFrame frame2(kTestStreamId, true, offset, StringPiece());
EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR));
stream_->OnStreamFrame(frame2);
}
+TEST_P(QuicReliableClientStreamTest, ProcessDataBeforeHeaders) {
+ const char data[] = "hello world!";
+ EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR));
+
+ EXPECT_EQ(0u, stream_->ProcessData(data, arraysize(data)));
+}
+
TEST_P(QuicReliableClientStreamTest, ProcessData) {
+ InitializeHeaders();
+ std::string uncompressed_headers =
+ SpdyUtils::SerializeUncompressedHeaders(headers_, GetParam());
+ EXPECT_CALL(delegate_, OnHeadersAvailable(StringPiece(uncompressed_headers)));
+ stream_->OnStreamHeaders(uncompressed_headers);
+ stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
+
const char data[] = "hello world!";
EXPECT_CALL(delegate_, OnDataReceived(StrEq(data), arraysize(data)));
EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR));
@@ -114,6 +129,9 @@ TEST_P(QuicReliableClientStreamTest, ProcessData) {
}
TEST_P(QuicReliableClientStreamTest, ProcessDataWithError) {
+ EXPECT_CALL(delegate_, OnHeadersAvailable(StringPiece("")));
+ stream_->OnStreamHeadersComplete(false, 0); // Send empty headers.
+
const char data[] = "hello world!";
EXPECT_CALL(delegate_,
OnDataReceived(StrEq(data),
diff --git a/chromium/net/quic/quic_sent_packet_manager.cc b/chromium/net/quic/quic_sent_packet_manager.cc
index c81c93df8e3..039a43d990e 100644
--- a/chromium/net/quic/quic_sent_packet_manager.cc
+++ b/chromium/net/quic/quic_sent_packet_manager.cc
@@ -69,7 +69,7 @@ QuicSentPacketManager::QuicSentPacketManager(
CongestionControlType congestion_control_type,
LossDetectionType loss_type,
bool is_secure)
- : unacked_packets_(),
+ : unacked_packets_(&ack_notifier_manager_),
perspective_(perspective),
clock_(clock),
stats_(stats),
@@ -146,16 +146,16 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
}
EnablePacing();
- if (HasClientSentConnectionOption(config, k1CON)) {
+ if (config.HasClientSentConnectionOption(k1CON, perspective_)) {
send_algorithm_->SetNumEmulatedConnections(1);
}
- if (HasClientSentConnectionOption(config, kNCON)) {
+ if (config.HasClientSentConnectionOption(kNCON, perspective_)) {
n_connection_simulation_ = true;
}
- if (HasClientSentConnectionOption(config, kNTLP)) {
+ if (config.HasClientSentConnectionOption(kNTLP, perspective_)) {
max_tail_loss_probes_ = 0;
}
- if (HasClientSentConnectionOption(config, kNRTO)) {
+ if (config.HasClientSentConnectionOption(kNRTO, perspective_)) {
use_new_rto_ = true;
}
if (config.HasReceivedConnectionOptions() &&
@@ -198,20 +198,6 @@ void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) {
}
}
-bool QuicSentPacketManager::HasClientSentConnectionOption(
- const QuicConfig& config, QuicTag tag) const {
- if (perspective_ == Perspective::IS_SERVER) {
- if (config.HasReceivedConnectionOptions() &&
- ContainsQuicTag(config.ReceivedConnectionOptions(), tag)) {
- return true;
- }
- } else if (config.HasSendConnectionOptions() &&
- ContainsQuicTag(config.SendConnectionOptions(), tag)) {
- return true;
- }
- return false;
-}
-
void QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame,
QuicTime ack_receive_time) {
QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight();
diff --git a/chromium/net/quic/quic_sent_packet_manager.h b/chromium/net/quic/quic_sent_packet_manager.h
index bb65e5eb1b5..e0310c05743 100644
--- a/chromium/net/quic/quic_sent_packet_manager.h
+++ b/chromium/net/quic/quic_sent_packet_manager.h
@@ -337,11 +337,6 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
const SequenceNumberList& all_transmissions,
QuicPacketSequenceNumber acked_sequence_number);
- // Returns true if the client is sending or the server has received a
- // connection option.
- bool HasClientSentConnectionOption(const QuicConfig& config,
- QuicTag tag) const;
-
// Newly serialized retransmittable and fec packets are added to this map,
// which contains owning pointers to any contained frames. If a packet is
// retransmitted, this map will contain entries for both the old and the new
diff --git a/chromium/net/quic/quic_sent_packet_manager_test.cc b/chromium/net/quic/quic_sent_packet_manager_test.cc
index 2b55382fdd9..1c78779c547 100644
--- a/chromium/net/quic/quic_sent_packet_manager_test.cc
+++ b/chromium/net/quic/quic_sent_packet_manager_test.cc
@@ -183,8 +183,8 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
RetransmittableFrames* frames = nullptr;
if (retransmittable) {
frames = new RetransmittableFrames(ENCRYPTION_NONE);
- frames->AddStreamFrame(
- new QuicStreamFrame(kStreamId, false, 0, IOVector()));
+ frames->AddFrame(
+ QuicFrame(new QuicStreamFrame(kStreamId, false, 0, StringPiece())));
}
return SerializedPacket(sequence_number, PACKET_6BYTE_SEQUENCE_NUMBER,
packets_.back(), 0u, frames);
@@ -214,8 +214,8 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
kDefaultLength, HAS_RETRANSMITTABLE_DATA))
.Times(1).WillOnce(Return(true));
SerializedPacket packet(CreateDataPacket(sequence_number));
- packet.retransmittable_frames->AddStreamFrame(
- new QuicStreamFrame(1, false, 0, IOVector()));
+ packet.retransmittable_frames->AddFrame(
+ QuicFrame(new QuicStreamFrame(1, false, 0, StringPiece())));
manager_.OnPacketSent(&packet, 0, clock_.Now(),
packet.packet->length(), NOT_RETRANSMISSION,
HAS_RETRANSMITTABLE_DATA);
diff --git a/chromium/net/quic/quic_session.cc b/chromium/net/quic/quic_session.cc
index 570eab7eb17..00318f75757 100644
--- a/chromium/net/quic/quic_session.cc
+++ b/chromium/net/quic/quic_session.cc
@@ -8,7 +8,6 @@
#include "net/quic/crypto/proof_verifier.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_flow_controller.h"
-#include "net/quic/quic_headers_stream.h"
#include "net/ssl/ssl_info.h"
using base::StringPiece;
@@ -89,8 +88,8 @@ class VisitorShim : public QuicConnectionVisitorInterface {
return session_->HasPendingHandshake();
}
- bool HasOpenDataStreams() const override {
- return session_->HasOpenDataStreams();
+ bool HasOpenDynamicStreams() const override {
+ return session_->HasOpenDynamicStreams();
}
private:
@@ -102,29 +101,32 @@ QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
visitor_shim_(new VisitorShim(this)),
config_(config),
max_open_streams_(config_.MaxStreamsPerConnection()),
- next_stream_id_(perspective() == Perspective::IS_SERVER ? 2 : 5),
- largest_peer_created_stream_id_(0),
+ next_stream_id_(perspective() == Perspective::IS_SERVER ? 2 : 3),
+ largest_peer_created_stream_id_(
+ perspective() == Perspective::IS_SERVER ? 1 : 0),
error_(QUIC_NO_ERROR),
flow_controller_(connection_.get(),
0,
perspective(),
kMinimumFlowControlSendWindow,
config_.GetInitialSessionFlowControlWindowToSend(),
- config_.GetInitialSessionFlowControlWindowToSend()),
+ false),
goaway_received_(false),
goaway_sent_(false),
has_pending_handshake_(false) {
}
-void QuicSession::InitializeSession() {
+void QuicSession::Initialize() {
connection_->set_visitor(visitor_shim_.get());
connection_->SetFromConfig(config_);
- headers_stream_.reset(new QuicHeadersStream(this));
+
+ DCHECK_EQ(kCryptoStreamId, GetCryptoStream()->id());
+ static_stream_map_[kCryptoStreamId] = GetCryptoStream();
}
QuicSession::~QuicSession() {
STLDeleteElements(&closed_streams_);
- STLDeleteValues(&stream_map_);
+ STLDeleteValues(&dynamic_stream_map_);
DLOG_IF(WARNING,
locally_closed_streams_highest_offset_.size() > max_open_streams_)
@@ -143,8 +145,7 @@ void QuicSession::OnStreamFrames(const vector<QuicStreamFrame>& frames) {
// final stream byte offset sent by the peer. A frame with a FIN can give
// us this offset.
if (frame.fin) {
- QuicStreamOffset final_byte_offset =
- frame.offset + frame.data.TotalBufferSize();
+ QuicStreamOffset final_byte_offset = frame.offset + frame.data.size();
UpdateFlowControlOnFinalReceivedByteOffset(stream_id,
final_byte_offset);
}
@@ -152,58 +153,17 @@ void QuicSession::OnStreamFrames(const vector<QuicStreamFrame>& frames) {
continue;
}
stream->OnStreamFrame(frames[i]);
- if (!connection_->connected()) {
- return;
- }
- }
-}
-
-void QuicSession::OnStreamHeaders(QuicStreamId stream_id,
- StringPiece headers_data) {
- QuicDataStream* stream = GetDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
- }
- stream->OnStreamHeaders(headers_data);
-}
-
-void QuicSession::OnStreamHeadersPriority(QuicStreamId stream_id,
- QuicPriority priority) {
- QuicDataStream* stream = GetDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
}
- stream->OnStreamHeadersPriority(priority);
-}
-
-void QuicSession::OnStreamHeadersComplete(QuicStreamId stream_id,
- bool fin,
- size_t frame_len) {
- QuicDataStream* stream = GetDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
- }
- stream->OnStreamHeadersComplete(fin, frame_len);
}
void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
- if (frame.stream_id == kCryptoStreamId) {
+ if (ContainsKey(static_stream_map_, frame.stream_id)) {
connection()->SendConnectionCloseWithDetails(
- QUIC_INVALID_STREAM_ID,
- "Attempt to reset the crypto stream");
- return;
- }
- if (frame.stream_id == kHeadersStreamId) {
- connection()->SendConnectionCloseWithDetails(
- QUIC_INVALID_STREAM_ID,
- "Attempt to reset the headers stream");
+ QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream");
return;
}
- QuicDataStream* stream = GetDataStream(frame.stream_id);
+ ReliableQuicStream* stream = GetDynamicStream(frame.stream_id);
if (!stream) {
// The RST frame contains the final byte offset for the stream: we can now
// update the connection level flow controller if needed.
@@ -226,12 +186,12 @@ void QuicSession::OnConnectionClosed(QuicErrorCode error, bool from_peer) {
error_ = error;
}
- while (!stream_map_.empty()) {
- DataStreamMap::iterator it = stream_map_.begin();
+ while (!dynamic_stream_map_.empty()) {
+ StreamMap::iterator it = dynamic_stream_map_.begin();
QuicStreamId id = it->first;
it->second->OnConnectionClosed(error, from_peer);
// The stream should call CloseStream as part of OnConnectionClosed.
- if (stream_map_.find(id) != stream_map_.end()) {
+ if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) {
LOG(DFATAL) << ENDPOINT
<< "Stream failed to close under OnConnectionClosed";
CloseStream(id);
@@ -346,34 +306,29 @@ bool QuicSession::HasPendingHandshake() const {
return has_pending_handshake_;
}
-bool QuicSession::HasOpenDataStreams() const {
+bool QuicSession::HasOpenDynamicStreams() const {
return GetNumOpenStreams() > 0;
}
QuicConsumedData QuicSession::WritevData(
QuicStreamId id,
- const IOVector& data,
+ const QuicIOVector& iov,
QuicStreamOffset offset,
bool fin,
FecProtection fec_protection,
QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
- return connection_->SendStreamData(id, data, offset, fin, fec_protection,
+ return connection_->SendStreamData(id, iov, offset, fin, fec_protection,
ack_notifier_delegate);
}
-size_t QuicSession::WriteHeaders(
- QuicStreamId id,
- const SpdyHeaderBlock& headers,
- bool fin,
- QuicPriority priority,
- QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
- return headers_stream_->WriteHeaders(id, headers, fin, priority,
- ack_notifier_delegate);
-}
-
void QuicSession::SendRstStream(QuicStreamId id,
QuicRstStreamErrorCode error,
QuicStreamOffset bytes_written) {
+ if (ContainsKey(static_stream_map_, id)) {
+ LOG(DFATAL) << "Cannot send RST for a static stream with ID " << id;
+ return;
+ }
+
if (connection()->connected()) {
// Only send a RST_STREAM frame if still connected.
connection_->SendRstStream(id, error, bytes_written);
@@ -397,12 +352,15 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id,
bool locally_reset) {
DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
- DataStreamMap::iterator it = stream_map_.find(stream_id);
- if (it == stream_map_.end()) {
+ StreamMap::iterator it = dynamic_stream_map_.find(stream_id);
+ if (it == dynamic_stream_map_.end()) {
+ // When CloseStreamInner has been called recursively (via
+ // ReliableQuicStream::OnClose), the stream will already have been deleted
+ // from stream_map_, so return immediately.
DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
return;
}
- QuicDataStream* stream = it->second;
+ ReliableQuicStream* stream = it->second;
// Tell the stream that a RST has been sent.
if (locally_reset) {
@@ -419,10 +377,11 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id,
stream->flow_controller()->highest_received_byte_offset();
}
- stream_map_.erase(it);
+ dynamic_stream_map_.erase(it);
+ draining_streams_.erase(stream_id);
stream->OnClose();
// Decrease the number of streams being emulated when a new one is opened.
- connection_->SetNumOpenStreams(stream_map_.size());
+ connection_->SetNumOpenStreams(dynamic_stream_map_.size());
}
void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset(
@@ -471,6 +430,11 @@ void QuicSession::OnConfigNegotiated() {
max_streams =
max(max_streams + kMaxStreamsMinimumIncrement,
static_cast<uint32>(max_streams * kMaxStreamsMultiplier));
+
+ if (config_.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config_.ReceivedConnectionOptions(), kAFCW)) {
+ EnableAutoTuneReceiveWindow();
+ }
}
set_max_open_streams(max_streams);
@@ -486,6 +450,17 @@ void QuicSession::OnConfigNegotiated() {
}
}
+void QuicSession::EnableAutoTuneReceiveWindow() {
+ flow_controller_.set_auto_tune_receive_window(true);
+ // Inform all existing streams about the new window.
+ for (auto const& kv : static_stream_map_) {
+ kv.second->flow_controller()->set_auto_tune_receive_window(true);
+ }
+ for (auto const& kv : dynamic_stream_map_) {
+ kv.second->flow_controller()->set_auto_tune_receive_window(true);
+ }
+}
+
void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
if (new_window < kMinimumFlowControlSendWindow) {
LOG(ERROR) << "Peer sent us an invalid stream flow control send window: "
@@ -498,11 +473,11 @@ void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
}
// Inform all existing streams about the new window.
- GetCryptoStream()->UpdateSendWindowOffset(new_window);
- headers_stream_->UpdateSendWindowOffset(new_window);
- for (DataStreamMap::iterator it = stream_map_.begin();
- it != stream_map_.end(); ++it) {
- it->second->UpdateSendWindowOffset(new_window);
+ for (auto const& kv : static_stream_map_) {
+ kv.second->UpdateSendWindowOffset(new_window);
+ }
+ for (auto const& kv : dynamic_stream_map_) {
+ kv.second->UpdateSendWindowOffset(new_window);
}
}
@@ -558,13 +533,14 @@ QuicConfig* QuicSession::config() {
return &config_;
}
-void QuicSession::ActivateStream(QuicDataStream* stream) {
- DVLOG(1) << ENDPOINT << "num_streams: " << stream_map_.size()
+void QuicSession::ActivateStream(ReliableQuicStream* stream) {
+ DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size()
<< ". activating " << stream->id();
- DCHECK_EQ(stream_map_.count(stream->id()), 0u);
- stream_map_[stream->id()] = stream;
+ DCHECK(!ContainsKey(dynamic_stream_map_, stream->id()));
+ DCHECK(!ContainsKey(static_stream_map_, stream->id()));
+ dynamic_stream_map_[stream->id()] = stream;
// Increase the number of streams being emulated when a new one is opened.
- connection_->SetNumOpenStreams(stream_map_.size());
+ connection_->SetNumOpenStreams(dynamic_stream_map_.size());
}
QuicStreamId QuicSession::GetNextStreamId() {
@@ -574,27 +550,29 @@ QuicStreamId QuicSession::GetNextStreamId() {
}
ReliableQuicStream* QuicSession::GetStream(const QuicStreamId stream_id) {
- if (stream_id == kCryptoStreamId) {
- return GetCryptoStream();
- }
- if (stream_id == kHeadersStreamId) {
- return headers_stream_.get();
+ StreamMap::iterator it = static_stream_map_.find(stream_id);
+ if (it != static_stream_map_.end()) {
+ return it->second;
}
- return GetDataStream(stream_id);
+ return GetDynamicStream(stream_id);
}
-QuicDataStream* QuicSession::GetDataStream(const QuicStreamId stream_id) {
- if (stream_id == kCryptoStreamId) {
- DLOG(FATAL) << "Attempt to call GetDataStream with the crypto stream id";
- return nullptr;
+void QuicSession::StreamDraining(QuicStreamId stream_id) {
+ DCHECK(ContainsKey(dynamic_stream_map_, stream_id));
+ if (!ContainsKey(draining_streams_, stream_id)) {
+ draining_streams_.insert(stream_id);
}
- if (stream_id == kHeadersStreamId) {
- DLOG(FATAL) << "Attempt to call GetDataStream with the headers stream id";
+}
+
+ReliableQuicStream* QuicSession::GetDynamicStream(
+ const QuicStreamId stream_id) {
+ if (static_stream_map_.find(stream_id) != static_stream_map_.end()) {
+ DLOG(FATAL) << "Attempt to call GetDynamicStream for a static stream";
return nullptr;
}
- DataStreamMap::iterator it = stream_map_.find(stream_id);
- if (it != stream_map_.end()) {
+ StreamMap::iterator it = dynamic_stream_map_.find(stream_id);
+ if (it != dynamic_stream_map_.end()) {
return it->second;
}
@@ -611,10 +589,11 @@ QuicDataStream* QuicSession::GetDataStream(const QuicStreamId stream_id) {
return nullptr;
}
- return GetIncomingDataStream(stream_id);
+ return GetIncomingDynamicStream(stream_id);
}
-QuicDataStream* QuicSession::GetIncomingDataStream(QuicStreamId stream_id) {
+ReliableQuicStream* QuicSession::GetIncomingDynamicStream(
+ QuicStreamId stream_id) {
if (IsClosedStream(stream_id)) {
return nullptr;
}
@@ -633,13 +612,6 @@ QuicDataStream* QuicSession::GetIncomingDataStream(QuicStreamId stream_id) {
}
return nullptr;
}
- if (largest_peer_created_stream_id_ == 0) {
- if (perspective() == Perspective::IS_SERVER) {
- largest_peer_created_stream_id_ = 3;
- } else {
- largest_peer_created_stream_id_ = 1;
- }
- }
for (QuicStreamId id = largest_peer_created_stream_id_ + 2;
id < stream_id;
id += 2) {
@@ -647,7 +619,7 @@ QuicDataStream* QuicSession::GetIncomingDataStream(QuicStreamId stream_id) {
}
largest_peer_created_stream_id_ = stream_id;
}
- QuicDataStream* stream = CreateIncomingDataStream(stream_id);
+ ReliableQuicStream* stream = CreateIncomingDynamicStream(stream_id);
if (stream == nullptr) {
return nullptr;
}
@@ -662,13 +634,8 @@ void QuicSession::set_max_open_streams(size_t max_open_streams) {
bool QuicSession::IsClosedStream(QuicStreamId id) {
DCHECK_NE(0u, id);
- if (id == kCryptoStreamId) {
- return false;
- }
- if (id == kHeadersStreamId) {
- return false;
- }
- if (ContainsKey(stream_map_, id)) {
+ if (ContainsKey(static_stream_map_, id) ||
+ ContainsKey(dynamic_stream_map_, id)) {
// Stream is active
return false;
}
@@ -684,7 +651,8 @@ bool QuicSession::IsClosedStream(QuicStreamId id) {
}
size_t QuicSession::GetNumOpenStreams() const {
- return stream_map_.size() + implicitly_created_streams_.size();
+ return dynamic_stream_map_.size() + implicitly_created_streams_.size() -
+ draining_streams_.size();
}
void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) {
@@ -732,13 +700,13 @@ bool QuicSession::IsConnectionFlowControlBlocked() const {
}
bool QuicSession::IsStreamFlowControlBlocked() {
- if (headers_stream_->flow_controller()->IsBlocked() ||
- GetCryptoStream()->flow_controller()->IsBlocked()) {
- return true;
+ for (auto const& kv : static_stream_map_) {
+ if (kv.second->flow_controller()->IsBlocked()) {
+ return true;
+ }
}
- for (DataStreamMap::iterator it = stream_map_.begin();
- it != stream_map_.end(); ++it) {
- if (it->second->flow_controller()->IsBlocked()) {
+ for (auto const& kv : dynamic_stream_map_) {
+ if (kv.second->flow_controller()->IsBlocked()) {
return true;
}
}
diff --git a/chromium/net/quic/quic_session.h b/chromium/net/quic/quic_session.h
index 4a401bf2b48..275a00e0628 100644
--- a/chromium/net/quic/quic_session.h
+++ b/chromium/net/quic/quic_session.h
@@ -18,8 +18,6 @@
#include "net/base/ip_endpoint.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_data_stream.h"
-#include "net/quic/quic_headers_stream.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_write_blocked_list.h"
@@ -56,10 +54,11 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
};
QuicSession(QuicConnection* connection, const QuicConfig& config);
- void InitializeSession();
~QuicSession() override;
+ virtual void Initialize();
+
// QuicConnectionVisitorInterface methods:
void OnStreamFrames(const std::vector<QuicStreamFrame>& frames) override;
void OnRstStream(const QuicRstStreamFrame& frame) override;
@@ -74,22 +73,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
void OnCongestionWindowChange(QuicTime now) override {}
bool WillingAndAbleToWrite() const override;
bool HasPendingHandshake() const override;
- bool HasOpenDataStreams() const override;
-
- // Called by the headers stream when headers have been received for a stream.
- virtual void OnStreamHeaders(QuicStreamId stream_id,
- base::StringPiece headers_data);
- // Called by the headers stream when headers with a priority have been
- // received for this stream. This method will only be called for server
- // streams.
- virtual void OnStreamHeadersPriority(QuicStreamId stream_id,
- QuicPriority priority);
- // Called by the headers stream when headers have been completely received
- // for a stream. |fin| will be true if the fin flag was set in the headers
- // frame.
- virtual void OnStreamHeadersComplete(QuicStreamId stream_id,
- bool fin,
- size_t frame_len);
+ bool HasOpenDynamicStreams() const override;
// Called by streams when they want to write data to the peer.
// Returns a pair with the number of bytes consumed from data, and a boolean
@@ -103,23 +87,12 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// we have seen ACKs for all packets resulting from this call.
virtual QuicConsumedData WritevData(
QuicStreamId id,
- const IOVector& data,
+ const QuicIOVector& iov,
QuicStreamOffset offset,
bool fin,
FecProtection fec_protection,
QuicAckNotifier::DelegateInterface* ack_notifier_delegate);
- // Writes |headers| for the stream |id| to the dedicated headers stream.
- // If |fin| is true, then no more data will be sent for the stream |id|.
- // If provided, |ack_notifier_delegate| will be registered to be notified when
- // we have seen ACKs for all packets resulting from this call.
- size_t WriteHeaders(
- QuicStreamId id,
- const SpdyHeaderBlock& headers,
- bool fin,
- QuicPriority priority,
- QuicAckNotifier::DelegateInterface* ack_notifier_delegate);
-
// Called by streams when they want to close the stream in both directions.
virtual void SendRstStream(QuicStreamId id,
QuicRstStreamErrorCode error,
@@ -171,7 +144,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
QuicConnection* connection() { return connection_.get(); }
const QuicConnection* connection() const { return connection_.get(); }
- size_t num_active_requests() const { return stream_map_.size(); }
+ size_t num_active_requests() const { return dynamic_stream_map_.size(); }
const IPEndPoint& peer_address() const {
return connection_->peer_address();
}
@@ -211,35 +184,35 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
size_t get_max_open_streams() const { return max_open_streams_; }
- // Used in Chrome.
- const QuicHeadersStream* headers_stream() { return headers_stream_.get(); }
+ ReliableQuicStream* GetStream(const QuicStreamId stream_id);
+
+ // Mark a stream as draining.
+ void StreamDraining(QuicStreamId id);
protected:
- typedef base::hash_map<QuicStreamId, QuicDataStream*> DataStreamMap;
+ typedef base::hash_map<QuicStreamId, ReliableQuicStream*> StreamMap;
// Creates a new stream, owned by the caller, to handle a peer-initiated
// stream. Returns nullptr and does error handling if the stream can not be
// created.
- virtual QuicDataStream* CreateIncomingDataStream(QuicStreamId id) = 0;
+ virtual ReliableQuicStream* CreateIncomingDynamicStream(QuicStreamId id) = 0;
// Create a new stream, owned by the caller, to handle a locally-initiated
// stream. Returns nullptr if max streams have already been opened.
- virtual QuicDataStream* CreateOutgoingDataStream() = 0;
+ virtual ReliableQuicStream* CreateOutgoingDynamicStream() = 0;
// Return the reserved crypto stream.
virtual QuicCryptoStream* GetCryptoStream() = 0;
// Adds 'stream' to the active stream map.
- virtual void ActivateStream(QuicDataStream* stream);
+ virtual void ActivateStream(ReliableQuicStream* stream);
// Returns the stream id for a new stream.
QuicStreamId GetNextStreamId();
- QuicDataStream* GetIncomingDataStream(QuicStreamId stream_id);
-
- QuicDataStream* GetDataStream(const QuicStreamId stream_id);
+ ReliableQuicStream* GetIncomingDynamicStream(QuicStreamId stream_id);
- ReliableQuicStream* GetStream(const QuicStreamId stream_id);
+ ReliableQuicStream* GetDynamicStream(const QuicStreamId stream_id);
// This is called after every call other than OnConnectionClose from the
// QuicConnectionVisitor to allow post-processing once the work has been done.
@@ -247,19 +220,22 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// operations are being done on the streams at this time)
virtual void PostProcessAfterData();
- base::hash_map<QuicStreamId, QuicDataStream*>* streams() {
- return &stream_map_;
- }
+ StreamMap& static_streams() { return static_stream_map_; }
+ const StreamMap& static_streams() const { return static_stream_map_; }
- const base::hash_map<QuicStreamId, QuicDataStream*>* streams() const {
- return &stream_map_;
- }
+ StreamMap& dynamic_streams() { return dynamic_stream_map_; }
+ const StreamMap& dynamic_streams() const { return dynamic_stream_map_; }
- std::vector<QuicDataStream*>* closed_streams() { return &closed_streams_; }
+ std::vector<ReliableQuicStream*>* closed_streams() {
+ return &closed_streams_;
+ }
void set_max_open_streams(size_t max_open_streams);
- scoped_ptr<QuicHeadersStream> headers_stream_;
+ void set_largest_peer_created_stream_id(
+ QuicStreamId largest_peer_created_stream_id) {
+ largest_peer_created_stream_id_ = largest_peer_created_stream_id;
+ }
private:
friend class test::QuicSessionPeer;
@@ -280,10 +256,14 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// control window in a negotiated config. Closes the connection if invalid.
void OnNewStreamFlowControlWindow(QuicStreamOffset new_window);
- // Called in OnConfigNegotiated when we receive a new session level flow
+ // Called in OnConfigNegotiated when we receive a new connection level flow
// control window in a negotiated config. Closes the connection if invalid.
void OnNewSessionFlowControlWindow(QuicStreamOffset new_window);
+ // Called in OnConfigNegotiated when auto-tuning is enabled for flow
+ // control receive windows.
+ void EnableAutoTuneReceiveWindow();
+
// Keep track of highest received byte offset of locally closed streams, while
// waiting for a definitive final highest offset from the peer.
std::map<QuicStreamId, QuicStreamOffset>
@@ -295,21 +275,30 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// deletions.
scoped_ptr<VisitorShim> visitor_shim_;
- std::vector<QuicDataStream*> closed_streams_;
+ std::vector<ReliableQuicStream*> closed_streams_;
QuicConfig config_;
// Returns the maximum number of streams this connection can open.
size_t max_open_streams_;
+ // Static streams, such as crypto and header streams. Owned by child classes
+ // that create these streams.
+ StreamMap static_stream_map_;
+
// Map from StreamId to pointers to streams that are owned by the caller.
- DataStreamMap stream_map_;
+ StreamMap dynamic_stream_map_;
QuicStreamId next_stream_id_;
// Set of stream ids that have been "implicitly created" by receipt
// of a stream id larger than the next expected stream id.
base::hash_set<QuicStreamId> implicitly_created_streams_;
+ // Set of stream ids that are "draining" -- a FIN has been sent and received,
+ // but the stream object still exists because not all the received data has
+ // been consumed.
+ base::hash_set<QuicStreamId> draining_streams_;
+
// A list of streams which need to write more data.
QuicWriteBlockedList write_blocked_streams_;
@@ -318,7 +307,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// The latched error with which the connection was closed.
QuicErrorCode error_;
- // Used for session level flow control.
+ // Used for connection-level flow control.
QuicFlowController flow_controller_;
// Whether a GoAway has been received.
diff --git a/chromium/net/quic/quic_session_test.cc b/chromium/net/quic/quic_session_test.cc
index c3f49070201..672ecf800f4 100644
--- a/chromium/net/quic/quic_session_test.cc
+++ b/chromium/net/quic/quic_session_test.cc
@@ -22,6 +22,7 @@
#include "net/quic/test_tools/quic_data_stream_peer.h"
#include "net/quic/test_tools/quic_flow_controller_peer.h"
#include "net/quic/test_tools/quic_session_peer.h"
+#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
#include "net/spdy/spdy_framer.h"
@@ -76,18 +77,16 @@ class TestCryptoStream : public QuicCryptoStream {
class TestHeadersStream : public QuicHeadersStream {
public:
- explicit TestHeadersStream(QuicSession* session)
- : QuicHeadersStream(session) {
- }
+ explicit TestHeadersStream(QuicSpdySession* session)
+ : QuicHeadersStream(session) {}
MOCK_METHOD0(OnCanWrite, void());
};
class TestStream : public QuicDataStream {
public:
- TestStream(QuicStreamId id, QuicSession* session)
- : QuicDataStream(id, session) {
- }
+ TestStream(QuicStreamId id, QuicSpdySession* session)
+ : QuicDataStream(id, session) {}
using ReliableQuicStream::CloseWriteSide;
@@ -119,24 +118,24 @@ class StreamBlocker {
const QuicStreamId stream_id_;
};
-class TestSession : public QuicSession {
+class TestSession : public QuicSpdySession {
public:
explicit TestSession(QuicConnection* connection)
- : QuicSession(connection, DefaultQuicConfig()),
+ : QuicSpdySession(connection, DefaultQuicConfig()),
crypto_stream_(this),
writev_consumes_all_data_(false) {
- InitializeSession();
+ Initialize();
}
TestCryptoStream* GetCryptoStream() override { return &crypto_stream_; }
- TestStream* CreateOutgoingDataStream() override {
+ TestStream* CreateOutgoingDynamicStream() override {
TestStream* stream = new TestStream(GetNextStreamId(), this);
ActivateStream(stream);
return stream;
}
- TestStream* CreateIncomingDataStream(QuicStreamId id) override {
+ TestStream* CreateIncomingDynamicStream(QuicStreamId id) override {
return new TestStream(id, this);
}
@@ -144,20 +143,20 @@ class TestSession : public QuicSession {
return QuicSession::IsClosedStream(id);
}
- QuicDataStream* GetIncomingDataStream(QuicStreamId stream_id) {
- return QuicSession::GetIncomingDataStream(stream_id);
+ ReliableQuicStream* GetIncomingDynamicStream(QuicStreamId stream_id) {
+ return QuicSpdySession::GetIncomingDynamicStream(stream_id);
}
QuicConsumedData WritevData(
QuicStreamId id,
- const IOVector& data,
+ const QuicIOVector& data,
QuicStreamOffset offset,
bool fin,
FecProtection fec_protection,
QuicAckNotifier::DelegateInterface* ack_notifier_delegate) override {
// Always consumes everything.
if (writev_consumes_all_data_) {
- return QuicConsumedData(data.TotalBufferSize(), fin);
+ return QuicConsumedData(data.total_length, fin);
} else {
return QuicSession::WritevData(id, data, offset, fin, fec_protection,
ack_notifier_delegate);
@@ -169,8 +168,9 @@ class TestSession : public QuicSession {
}
QuicConsumedData SendStreamData(QuicStreamId id) {
- return WritevData(id, MakeIOVector("not empty"), 0, true, MAY_FEC_PROTECT,
- nullptr);
+ struct iovec iov;
+ return WritevData(id, MakeIOVector("not empty", &iov), 0, true,
+ MAY_FEC_PROTECT, nullptr);
}
using QuicSession::PostProcessAfterData;
@@ -181,11 +181,11 @@ class TestSession : public QuicSession {
bool writev_consumes_all_data_;
};
-class QuicSessionTest : public ::testing::TestWithParam<QuicVersion> {
+class QuicSessionTestBase : public ::testing::TestWithParam<QuicVersion> {
protected:
- QuicSessionTest()
+ explicit QuicSessionTestBase(Perspective perspective)
: connection_(
- new StrictMock<MockConnection>(Perspective::IS_SERVER,
+ new StrictMock<MockConnection>(perspective,
SupportedVersions(GetParam()))),
session_(connection_) {
session_.config()->SetInitialStreamFlowControlWindowToSend(
@@ -223,7 +223,7 @@ class QuicSessionTest : public ::testing::TestWithParam<QuicVersion> {
}
void CheckClosedStreams() {
- for (int i = kCryptoStreamId; i < 100; i++) {
+ for (QuicStreamId i = kCryptoStreamId; i < 100; i++) {
if (!ContainsKey(closed_streams_, i)) {
EXPECT_FALSE(session_.IsClosedStream(i)) << " stream id: " << i;
} else {
@@ -246,40 +246,46 @@ class QuicSessionTest : public ::testing::TestWithParam<QuicVersion> {
SpdyHeaderBlock headers_;
};
-INSTANTIATE_TEST_CASE_P(Tests, QuicSessionTest,
+class QuicSessionTestServer : public QuicSessionTestBase {
+ protected:
+ QuicSessionTestServer() : QuicSessionTestBase(Perspective::IS_SERVER) {}
+};
+
+INSTANTIATE_TEST_CASE_P(Tests,
+ QuicSessionTestServer,
::testing::ValuesIn(QuicSupportedVersions()));
-TEST_P(QuicSessionTest, PeerAddress) {
+TEST_P(QuicSessionTestServer, PeerAddress) {
EXPECT_EQ(IPEndPoint(Loopback4(), kTestPort), session_.peer_address());
}
-TEST_P(QuicSessionTest, IsCryptoHandshakeConfirmed) {
+TEST_P(QuicSessionTestServer, IsCryptoHandshakeConfirmed) {
EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
CryptoHandshakeMessage message;
session_.GetCryptoStream()->OnHandshakeMessage(message);
EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed());
}
-TEST_P(QuicSessionTest, IsClosedStreamDefault) {
+TEST_P(QuicSessionTestServer, IsClosedStreamDefault) {
// Ensure that no streams are initially closed.
- for (int i = kCryptoStreamId; i < 100; i++) {
+ for (QuicStreamId i = kCryptoStreamId; i < 100; i++) {
EXPECT_FALSE(session_.IsClosedStream(i)) << "stream id: " << i;
}
}
-TEST_P(QuicSessionTest, ImplicitlyCreatedStreams) {
- ASSERT_TRUE(session_.GetIncomingDataStream(7) != nullptr);
- // Both 3 and 5 should be implicitly created.
- EXPECT_FALSE(session_.IsClosedStream(3));
- EXPECT_FALSE(session_.IsClosedStream(5));
- ASSERT_TRUE(session_.GetIncomingDataStream(5) != nullptr);
- ASSERT_TRUE(session_.GetIncomingDataStream(3) != nullptr);
+TEST_P(QuicSessionTestServer, ImplicitlyCreatedStreams) {
+ ASSERT_TRUE(session_.GetIncomingDynamicStream(9) != nullptr);
+ // Both 5 and 7 should be implicitly created.
+ EXPECT_TRUE(QuicSessionPeer::IsStreamImplicitlyCreated(&session_, 5));
+ EXPECT_TRUE(QuicSessionPeer::IsStreamImplicitlyCreated(&session_, 7));
+ ASSERT_TRUE(session_.GetIncomingDynamicStream(7) != nullptr);
+ ASSERT_TRUE(session_.GetIncomingDynamicStream(5) != nullptr);
}
-TEST_P(QuicSessionTest, IsClosedStreamLocallyCreated) {
- TestStream* stream2 = session_.CreateOutgoingDataStream();
+TEST_P(QuicSessionTestServer, IsClosedStreamLocallyCreated) {
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream();
EXPECT_EQ(2u, stream2->id());
- TestStream* stream4 = session_.CreateOutgoingDataStream();
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream();
EXPECT_EQ(4u, stream4->id());
CheckClosedStreams();
@@ -289,36 +295,34 @@ TEST_P(QuicSessionTest, IsClosedStreamLocallyCreated) {
CheckClosedStreams();
}
-TEST_P(QuicSessionTest, IsClosedStreamPeerCreated) {
+TEST_P(QuicSessionTestServer, IsClosedStreamPeerCreated) {
QuicStreamId stream_id1 = kClientDataStreamId1;
QuicStreamId stream_id2 = kClientDataStreamId2;
- QuicDataStream* stream1 = session_.GetIncomingDataStream(stream_id1);
- QuicDataStreamPeer::SetHeadersDecompressed(stream1, true);
- QuicDataStream* stream2 = session_.GetIncomingDataStream(stream_id2);
- QuicDataStreamPeer::SetHeadersDecompressed(stream2, true);
+ session_.GetIncomingDynamicStream(stream_id1);
+ session_.GetIncomingDynamicStream(stream_id2);
CheckClosedStreams();
CloseStream(stream_id1);
CheckClosedStreams();
CloseStream(stream_id2);
// Create a stream explicitly, and another implicitly.
- QuicDataStream* stream3 = session_.GetIncomingDataStream(stream_id2 + 4);
- QuicDataStreamPeer::SetHeadersDecompressed(stream3, true);
+ ReliableQuicStream* stream3 =
+ session_.GetIncomingDynamicStream(stream_id2 + 4);
CheckClosedStreams();
// Close one, but make sure the other is still not closed
CloseStream(stream3->id());
CheckClosedStreams();
}
-TEST_P(QuicSessionTest, StreamIdTooLarge) {
+TEST_P(QuicSessionTestServer, StreamIdTooLarge) {
QuicStreamId stream_id = kClientDataStreamId1;
- session_.GetIncomingDataStream(stream_id);
+ session_.GetIncomingDynamicStream(stream_id);
EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID));
- session_.GetIncomingDataStream(stream_id + kMaxStreamIdDelta + 2);
+ session_.GetIncomingDynamicStream(stream_id + kMaxStreamIdDelta + 2);
}
-TEST_P(QuicSessionTest, DebugDFatalIfMarkingClosedStreamWriteBlocked) {
- TestStream* stream2 = session_.CreateOutgoingDataStream();
+TEST_P(QuicSessionTestServer, DebugDFatalIfMarkingClosedStreamWriteBlocked) {
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream();
QuicStreamId kClosedStreamId = stream2->id();
// Close the stream.
EXPECT_CALL(*connection_, SendRstStream(kClosedStreamId, _, _));
@@ -328,20 +332,21 @@ TEST_P(QuicSessionTest, DebugDFatalIfMarkingClosedStreamWriteBlocked) {
"Marking unknown stream 2 blocked.");
}
-TEST_P(QuicSessionTest, DebugDFatalIfMarkWriteBlockedCalledWithWrongPriority) {
+TEST_P(QuicSessionTestServer,
+ DebugDFatalIfMarkWriteBlockedCalledWithWrongPriority) {
const QuicPriority kDifferentPriority = 0;
- TestStream* stream2 = session_.CreateOutgoingDataStream();
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream();
EXPECT_NE(kDifferentPriority, stream2->EffectivePriority());
EXPECT_DEBUG_DFATAL(
session_.MarkWriteBlocked(stream2->id(), kDifferentPriority),
"Priorities do not match. Got: 0 Expected: 3");
}
-TEST_P(QuicSessionTest, OnCanWrite) {
- TestStream* stream2 = session_.CreateOutgoingDataStream();
- TestStream* stream4 = session_.CreateOutgoingDataStream();
- TestStream* stream6 = session_.CreateOutgoingDataStream();
+TEST_P(QuicSessionTestServer, OnCanWrite) {
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream();
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream();
+ TestStream* stream6 = session_.CreateOutgoingDynamicStream();
session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority);
session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority);
@@ -358,14 +363,14 @@ TEST_P(QuicSessionTest, OnCanWrite) {
EXPECT_TRUE(session_.WillingAndAbleToWrite());
}
-TEST_P(QuicSessionTest, OnCanWriteBundlesStreams) {
+TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) {
// Drive congestion control manually.
MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm);
- TestStream* stream2 = session_.CreateOutgoingDataStream();
- TestStream* stream4 = session_.CreateOutgoingDataStream();
- TestStream* stream6 = session_.CreateOutgoingDataStream();
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream();
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream();
+ TestStream* stream6 = session_.CreateOutgoingDynamicStream();
session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority);
session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority);
@@ -376,13 +381,13 @@ TEST_P(QuicSessionTest, OnCanWriteBundlesStreams) {
EXPECT_CALL(*send_algorithm, GetCongestionWindow())
.WillRepeatedly(Return(kMaxPacketSize * 10));
EXPECT_CALL(*stream2, OnCanWrite())
- .WillOnce(IgnoreResult(Invoke(CreateFunctor(
+ .WillOnce(testing::IgnoreResult(Invoke(CreateFunctor(
&session_, &TestSession::SendStreamData, stream2->id()))));
EXPECT_CALL(*stream4, OnCanWrite())
- .WillOnce(IgnoreResult(Invoke(CreateFunctor(
+ .WillOnce(testing::IgnoreResult(Invoke(CreateFunctor(
&session_, &TestSession::SendStreamData, stream4->id()))));
EXPECT_CALL(*stream6, OnCanWrite())
- .WillOnce(IgnoreResult(Invoke(CreateFunctor(
+ .WillOnce(testing::IgnoreResult(Invoke(CreateFunctor(
&session_, &TestSession::SendStreamData, stream6->id()))));
// Expect that we only send one packet, the writes from different streams
@@ -397,16 +402,16 @@ TEST_P(QuicSessionTest, OnCanWriteBundlesStreams) {
EXPECT_FALSE(session_.WillingAndAbleToWrite());
}
-TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) {
+TEST_P(QuicSessionTestServer, OnCanWriteCongestionControlBlocks) {
InSequence s;
// Drive congestion control manually.
MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm);
- TestStream* stream2 = session_.CreateOutgoingDataStream();
- TestStream* stream4 = session_.CreateOutgoingDataStream();
- TestStream* stream6 = session_.CreateOutgoingDataStream();
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream();
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream();
+ TestStream* stream6 = session_.CreateOutgoingDynamicStream();
session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority);
session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority);
@@ -441,16 +446,16 @@ TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) {
EXPECT_FALSE(session_.WillingAndAbleToWrite());
}
-TEST_P(QuicSessionTest, BufferedHandshake) {
+TEST_P(QuicSessionTestServer, BufferedHandshake) {
EXPECT_FALSE(session_.HasPendingHandshake()); // Default value.
// Test that blocking other streams does not change our status.
- TestStream* stream2 = session_.CreateOutgoingDataStream();
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream();
StreamBlocker stream2_blocker(&session_, stream2->id());
stream2_blocker.MarkWriteBlocked();
EXPECT_FALSE(session_.HasPendingHandshake());
- TestStream* stream3 = session_.CreateOutgoingDataStream();
+ TestStream* stream3 = session_.CreateOutgoingDynamicStream();
StreamBlocker stream3_blocker(&session_, stream3->id());
stream3_blocker.MarkWriteBlocked();
EXPECT_FALSE(session_.HasPendingHandshake());
@@ -459,7 +464,7 @@ TEST_P(QuicSessionTest, BufferedHandshake) {
session_.MarkWriteBlocked(kCryptoStreamId, kHighestPriority);
EXPECT_TRUE(session_.HasPendingHandshake());
- TestStream* stream4 = session_.CreateOutgoingDataStream();
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream();
StreamBlocker stream4_blocker(&session_, stream4->id());
stream4_blocker.MarkWriteBlocked();
EXPECT_TRUE(session_.HasPendingHandshake());
@@ -487,10 +492,10 @@ TEST_P(QuicSessionTest, BufferedHandshake) {
EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote.
}
-TEST_P(QuicSessionTest, OnCanWriteWithClosedStream) {
- TestStream* stream2 = session_.CreateOutgoingDataStream();
- TestStream* stream4 = session_.CreateOutgoingDataStream();
- TestStream* stream6 = session_.CreateOutgoingDataStream();
+TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) {
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream();
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream();
+ TestStream* stream6 = session_.CreateOutgoingDynamicStream();
session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority);
session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority);
@@ -504,7 +509,7 @@ TEST_P(QuicSessionTest, OnCanWriteWithClosedStream) {
EXPECT_FALSE(session_.WillingAndAbleToWrite());
}
-TEST_P(QuicSessionTest, OnCanWriteLimitsNumWritesIfFlowControlBlocked) {
+TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) {
// Ensure connection level flow control blockage.
QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0);
EXPECT_TRUE(session_.flow_controller()->IsBlocked());
@@ -518,7 +523,7 @@ TEST_P(QuicSessionTest, OnCanWriteLimitsNumWritesIfFlowControlBlocked) {
// Create a data stream, and although it is write blocked we never expect it
// to be allowed to write as we are connection level flow control blocked.
- TestStream* stream = session_.CreateOutgoingDataStream();
+ TestStream* stream = session_.CreateOutgoingDynamicStream();
session_.MarkWriteBlocked(stream->id(), kSomeMiddlePriority);
EXPECT_CALL(*stream, OnCanWrite()).Times(0);
@@ -527,33 +532,35 @@ TEST_P(QuicSessionTest, OnCanWriteLimitsNumWritesIfFlowControlBlocked) {
TestCryptoStream* crypto_stream = session_.GetCryptoStream();
EXPECT_CALL(*crypto_stream, OnCanWrite()).Times(1);
TestHeadersStream* headers_stream = new TestHeadersStream(&session_);
- QuicSessionPeer::SetHeadersStream(&session_, headers_stream);
+ QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream);
EXPECT_CALL(*headers_stream, OnCanWrite()).Times(1);
session_.OnCanWrite();
EXPECT_FALSE(session_.WillingAndAbleToWrite());
}
-TEST_P(QuicSessionTest, SendGoAway) {
- EXPECT_CALL(*connection_,
- SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away."));
+TEST_P(QuicSessionTestServer, SendGoAway) {
+ EXPECT_CALL(*connection_, SendGoAway(QUIC_PEER_GOING_AWAY, kHeadersStreamId,
+ "Going Away."));
session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
EXPECT_TRUE(session_.goaway_sent());
+ const QuicStreamId kTestStreamId = 5u;
EXPECT_CALL(*connection_,
- SendRstStream(3u, QUIC_STREAM_PEER_GOING_AWAY, 0)).Times(0);
- EXPECT_TRUE(session_.GetIncomingDataStream(3u));
+ SendRstStream(kTestStreamId, QUIC_STREAM_PEER_GOING_AWAY, 0))
+ .Times(0);
+ EXPECT_TRUE(session_.GetIncomingDynamicStream(kTestStreamId));
}
-TEST_P(QuicSessionTest, DoNotSendGoAwayTwice) {
- EXPECT_CALL(*connection_,
- SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away.")).Times(1);
+TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) {
+ EXPECT_CALL(*connection_, SendGoAway(QUIC_PEER_GOING_AWAY, kHeadersStreamId,
+ "Going Away.")).Times(1);
session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
EXPECT_TRUE(session_.goaway_sent());
session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
}
-TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
+TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) {
EXPECT_EQ(kInitialIdleTimeoutSecs + 3,
QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
CryptoHandshakeMessage msg;
@@ -562,9 +569,9 @@ TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
}
-TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) {
+TEST_P(QuicSessionTestServer, RstStreamBeforeHeadersDecompressed) {
// Send two bytes of payload.
- QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT"));
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT"));
vector<QuicStreamFrame> frames;
frames.push_back(data1);
session_.OnStreamFrames(frames);
@@ -578,13 +585,13 @@ TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) {
EXPECT_TRUE(connection_->connected());
}
-TEST_P(QuicSessionTest, MultipleRstStreamsCauseSingleConnectionClose) {
+TEST_P(QuicSessionTestServer, MultipleRstStreamsCauseSingleConnectionClose) {
// If multiple invalid reset stream frames arrive in a single packet, this
// should trigger a connection close. However there is no need to send
// multiple connection close frames.
// Create valid stream.
- QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT"));
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT"));
vector<QuicStreamFrame> frames;
frames.push_back(data1);
session_.OnStreamFrames(frames);
@@ -594,7 +601,7 @@ TEST_P(QuicSessionTest, MultipleRstStreamsCauseSingleConnectionClose) {
// closed.
EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID))
.Times(1);
- QuicStreamId kLargeInvalidStreamId = 99999999;
+ const QuicStreamId kLargeInvalidStreamId = 99999999;
QuicRstStreamFrame rst1(kLargeInvalidStreamId, QUIC_STREAM_NO_ERROR, 0);
session_.OnRstStream(rst1);
QuicConnectionPeer::CloseConnection(connection_);
@@ -605,7 +612,7 @@ TEST_P(QuicSessionTest, MultipleRstStreamsCauseSingleConnectionClose) {
session_.OnRstStream(rst2);
}
-TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedStream) {
+TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedStream) {
// Test that if a stream is flow control blocked, then on receipt of the SHLO
// containing a suitable send window offset, the stream becomes unblocked.
@@ -614,7 +621,7 @@ TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedStream) {
session_.set_writev_consumes_all_data(true);
// Create a stream, and send enough data to make it flow control blocked.
- TestStream* stream2 = session_.CreateOutgoingDataStream();
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream();
string body(kMinimumFlowControlSendWindow, '.');
EXPECT_FALSE(stream2->flow_controller()->IsBlocked());
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
@@ -640,7 +647,7 @@ TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedStream) {
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
}
-TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedCryptoStream) {
+TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) {
// Test that if the crypto stream is flow control blocked, then if the SHLO
// contains a larger send window offset, the stream becomes unblocked.
session_.set_writev_consumes_all_data(true);
@@ -649,21 +656,20 @@ TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedCryptoStream) {
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
QuicHeadersStream* headers_stream =
- QuicSessionPeer::GetHeadersStream(&session_);
+ QuicSpdySessionPeer::GetHeadersStream(&session_);
EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
// Write until the crypto stream is flow control blocked.
EXPECT_CALL(*connection_, SendBlocked(kCryptoStreamId));
- int i = 0;
- while (!crypto_stream->flow_controller()->IsBlocked() && i < 1000) {
+ for (QuicStreamId i = 0;
+ !crypto_stream->flow_controller()->IsBlocked() && i < 1000u; i++) {
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
QuicConfig config;
CryptoHandshakeMessage crypto_message;
config.ToHandshakeMessage(&crypto_message);
crypto_stream->SendHandshakeMessage(crypto_message);
- ++i;
}
EXPECT_TRUE(crypto_stream->flow_controller()->IsBlocked());
EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
@@ -686,7 +692,8 @@ TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedCryptoStream) {
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
}
-TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedHeadersStream) {
+TEST_P(QuicSessionTestServer,
+ HandshakeUnblocksFlowControlBlockedHeadersStream) {
// Test that if the header stream is flow control blocked, then if the SHLO
// contains a larger send window offset, the stream becomes unblocked.
session_.set_writev_consumes_all_data(true);
@@ -695,7 +702,7 @@ TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedHeadersStream) {
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
QuicHeadersStream* headers_stream =
- QuicSessionPeer::GetHeadersStream(&session_);
+ QuicSpdySessionPeer::GetHeadersStream(&session_);
EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
@@ -735,12 +742,12 @@ TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedHeadersStream) {
EXPECT_FALSE(headers_stream->HasBufferedData());
}
-TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstOutOfOrder) {
+TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstOutOfOrder) {
// Test that when we receive an out of order stream RST we correctly adjust
// our connection level flow control receive window.
// On close, the stream should mark as consumed all bytes between the highest
// byte consumed so far and the final byte offset from the RST frame.
- TestStream* stream = session_.CreateOutgoingDataStream();
+ TestStream* stream = session_.CreateOutgoingDynamicStream();
const QuicStreamOffset kByteOffset =
1 + kInitialSessionFlowControlWindowForTest / 2;
@@ -760,17 +767,17 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstOutOfOrder) {
EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
}
-TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAndLocalReset) {
+TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAndLocalReset) {
// Test the situation where we receive a FIN on a stream, and before we fully
// consume all the data from the sequencer buffer we locally RST the stream.
// The bytes between highest consumed byte, and the final byte offset that we
// determined when the FIN arrived, should be marked as consumed at the
// connection level flow controller when the stream is reset.
- TestStream* stream = session_.CreateOutgoingDataStream();
+ TestStream* stream = session_.CreateOutgoingDynamicStream();
const QuicStreamOffset kByteOffset =
kInitialSessionFlowControlWindowForTest / 2;
- QuicStreamFrame frame(stream->id(), true, kByteOffset, IOVector());
+ QuicStreamFrame frame(stream->id(), true, kByteOffset, StringPiece());
vector<QuicStreamFrame> frames;
frames.push_back(frame);
session_.OnStreamFrames(frames);
@@ -787,7 +794,7 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAndLocalReset) {
EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
}
-TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAfterRst) {
+TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAfterRst) {
// Test that when we RST the stream (and tear down stream state), and then
// receive a FIN from the peer, we correctly adjust our connection level flow
// control receive window.
@@ -803,7 +810,7 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAfterRst) {
session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed);
// Reset our stream: this results in the stream being closed locally.
- TestStream* stream = session_.CreateOutgoingDataStream();
+ TestStream* stream = session_.CreateOutgoingDynamicStream();
EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
stream->Reset(QUIC_STREAM_CANCELLED);
@@ -812,8 +819,7 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAfterRst) {
// account the total number of bytes sent by the peer.
const QuicStreamOffset kByteOffset = 5678;
string body = "hello";
- IOVector data = MakeIOVector(body);
- QuicStreamFrame frame(stream->id(), true, kByteOffset, data);
+ QuicStreamFrame frame(stream->id(), true, kByteOffset, StringPiece(body));
vector<QuicStreamFrame> frames;
frames.push_back(frame);
session_.OnStreamFrames(frames);
@@ -827,7 +833,7 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAfterRst) {
session_.flow_controller()->highest_received_byte_offset());
}
-TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstAfterRst) {
+TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstAfterRst) {
// Test that when we RST the stream (and tear down stream state), and then
// receive a RST from the peer, we correctly adjust our connection level flow
// control receive window.
@@ -843,7 +849,7 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstAfterRst) {
session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed);
// Reset our stream: this results in the stream being closed locally.
- TestStream* stream = session_.CreateOutgoingDataStream();
+ TestStream* stream = session_.CreateOutgoingDynamicStream();
EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
stream->Reset(QUIC_STREAM_CANCELLED);
@@ -861,10 +867,10 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstAfterRst) {
session_.flow_controller()->highest_received_byte_offset());
}
-TEST_P(QuicSessionTest, InvalidStreamFlowControlWindowInHandshake) {
+TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) {
// Test that receipt of an invalid (< default) stream flow control window from
// the peer results in the connection being torn down.
- uint32 kInvalidWindow = kMinimumFlowControlSendWindow - 1;
+ const uint32 kInvalidWindow = kMinimumFlowControlSendWindow - 1;
QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(session_.config(),
kInvalidWindow);
@@ -873,10 +879,10 @@ TEST_P(QuicSessionTest, InvalidStreamFlowControlWindowInHandshake) {
session_.OnConfigNegotiated();
}
-TEST_P(QuicSessionTest, InvalidSessionFlowControlWindowInHandshake) {
+TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) {
// Test that receipt of an invalid (< default) session flow control window
// from the peer results in the connection being torn down.
- uint32 kInvalidWindow = kMinimumFlowControlSendWindow - 1;
+ const uint32 kInvalidWindow = kMinimumFlowControlSendWindow - 1;
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(),
kInvalidWindow);
@@ -885,7 +891,7 @@ TEST_P(QuicSessionTest, InvalidSessionFlowControlWindowInHandshake) {
session_.OnConfigNegotiated();
}
-TEST_P(QuicSessionTest, FlowControlWithInvalidFinalOffset) {
+TEST_P(QuicSessionTestServer, FlowControlWithInvalidFinalOffset) {
// Test that if we receive a stream RST with a highest byte offset that
// violates flow control, that we close the connection.
const uint64 kLargeOffset = kInitialSessionFlowControlWindowForTest + 1;
@@ -894,10 +900,10 @@ TEST_P(QuicSessionTest, FlowControlWithInvalidFinalOffset) {
.Times(2);
// Check that stream frame + FIN results in connection close.
- TestStream* stream = session_.CreateOutgoingDataStream();
+ TestStream* stream = session_.CreateOutgoingDynamicStream();
EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
stream->Reset(QUIC_STREAM_CANCELLED);
- QuicStreamFrame frame(stream->id(), true, kLargeOffset, IOVector());
+ QuicStreamFrame frame(stream->id(), true, kLargeOffset, StringPiece());
vector<QuicStreamFrame> frames;
frames.push_back(frame);
session_.OnStreamFrames(frames);
@@ -908,13 +914,13 @@ TEST_P(QuicSessionTest, FlowControlWithInvalidFinalOffset) {
session_.OnRstStream(rst_frame);
}
-TEST_P(QuicSessionTest, WindowUpdateUnblocksHeadersStream) {
+TEST_P(QuicSessionTestServer, WindowUpdateUnblocksHeadersStream) {
// Test that a flow control blocked headers stream gets unblocked on recipt of
- // a WINDOW_UPDATE frame. Regression test for b/17413860.
+ // a WINDOW_UPDATE frame.
// Set the headers stream to be flow control blocked.
QuicHeadersStream* headers_stream =
- QuicSessionPeer::GetHeadersStream(&session_);
+ QuicSpdySessionPeer::GetHeadersStream(&session_);
QuicFlowControllerPeer::SetSendWindowOffset(headers_stream->flow_controller(),
0);
EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked());
@@ -932,21 +938,22 @@ TEST_P(QuicSessionTest, WindowUpdateUnblocksHeadersStream) {
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
}
-TEST_P(QuicSessionTest, TooManyUnfinishedStreamsCauseConnectionClose) {
+TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseConnectionClose) {
// If a buggy/malicious peer creates too many streams that are not ended with
// a FIN or RST then we send a connection close.
EXPECT_CALL(*connection_,
SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS)).Times(1);
- const int kMaxStreams = 5;
+ const QuicStreamId kMaxStreams = 5;
QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams);
// Create kMaxStreams + 1 data streams, and close them all without receiving a
- // FIN or a RST from the client.
- const int kFirstStreamId = kClientDataStreamId1;
- const int kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams + 1;
- for (int i = kFirstStreamId; i < kFinalStreamId; i += 2) {
- QuicStreamFrame data1(i, false, 0, MakeIOVector("HT"));
+ // FIN or a RST_STREAM from the client.
+ const QuicStreamId kFirstStreamId = kClientDataStreamId1;
+ const QuicStreamId kFinalStreamId =
+ kClientDataStreamId1 + 2 * kMaxStreams + 1;
+ for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) {
+ QuicStreamFrame data1(i, false, 0, StringPiece("HT"));
vector<QuicStreamFrame> frames;
frames.push_back(data1);
session_.OnStreamFrames(frames);
@@ -960,6 +967,55 @@ TEST_P(QuicSessionTest, TooManyUnfinishedStreamsCauseConnectionClose) {
session_.PostProcessAfterData();
}
+TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) {
+ // Verify that a draining stream (which has received a FIN but not consumed
+ // it) does not count against the open quota (because it is closed from the
+ // protocol point of view).
+ EXPECT_CALL(*connection_,
+ SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS)).Times(0);
+
+ const QuicStreamId kMaxStreams = 5;
+ QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams);
+
+ // Create kMaxStreams + 1 data streams, and mark them draining.
+ const QuicStreamId kFirstStreamId = kClientDataStreamId1;
+ const QuicStreamId kFinalStreamId =
+ kClientDataStreamId1 + 2 * kMaxStreams + 1;
+ for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) {
+ QuicStreamFrame data1(i, true, 0, StringPiece("HT"));
+ vector<QuicStreamFrame> frames;
+ frames.push_back(data1);
+ session_.OnStreamFrames(frames);
+ EXPECT_EQ(1u, session_.GetNumOpenStreams());
+ session_.StreamDraining(i);
+ EXPECT_EQ(0u, session_.GetNumOpenStreams());
+ }
+
+ // Called after any new data is received by the session, and triggers the call
+ // to close the connection.
+ session_.PostProcessAfterData();
+}
+
+class QuicSessionTestClient : public QuicSessionTestBase {
+ protected:
+ QuicSessionTestClient() : QuicSessionTestBase(Perspective::IS_CLIENT) {}
+};
+
+INSTANTIATE_TEST_CASE_P(Tests,
+ QuicSessionTestClient,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicSessionTestClient, ImplicitlyCreatedStreamsClient) {
+ ASSERT_TRUE(session_.GetIncomingDynamicStream(6) != nullptr);
+ // Both 2 and 4 should be implicitly created.
+ EXPECT_TRUE(QuicSessionPeer::IsStreamImplicitlyCreated(&session_, 2));
+ EXPECT_TRUE(QuicSessionPeer::IsStreamImplicitlyCreated(&session_, 4));
+ ASSERT_TRUE(session_.GetIncomingDynamicStream(2) != nullptr);
+ ASSERT_TRUE(session_.GetIncomingDynamicStream(4) != nullptr);
+ // And 5 should be not implicitly created.
+ EXPECT_FALSE(QuicSessionPeer::IsStreamImplicitlyCreated(&session_, 5));
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/quic_socket_address_coder.cc b/chromium/net/quic/quic_socket_address_coder.cc
index 77e595f2d65..5dba82107f5 100644
--- a/chromium/net/quic/quic_socket_address_coder.cc
+++ b/chromium/net/quic/quic_socket_address_coder.cc
@@ -4,6 +4,8 @@
#include "net/quic/quic_socket_address_coder.h"
+#include "net/base/sys_addrinfo.h"
+
using std::string;
namespace net {
diff --git a/chromium/net/quic/quic_socket_address_coder_test.cc b/chromium/net/quic/quic_socket_address_coder_test.cc
index cbfac2b12d8..6a94550d8e0 100644
--- a/chromium/net/quic/quic_socket_address_coder_test.cc
+++ b/chromium/net/quic/quic_socket_address_coder_test.cc
@@ -4,6 +4,8 @@
#include "net/quic/quic_socket_address_coder.h"
+#include "net/base/net_util.h"
+#include "net/base/sys_addrinfo.h"
#include "testing/gtest/include/gtest/gtest.h"
using std::string;
diff --git a/chromium/net/quic/quic_spdy_session.cc b/chromium/net/quic/quic_spdy_session.cc
new file mode 100644
index 00000000000..0a8dda6929e
--- /dev/null
+++ b/chromium/net/quic/quic_spdy_session.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2015 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/quic_spdy_session.h"
+
+#include "net/quic/quic_headers_stream.h"
+
+namespace net {
+
+QuicSpdySession::QuicSpdySession(QuicConnection* connection,
+ const QuicConfig& config)
+ : QuicSession(connection, config) {
+}
+
+QuicSpdySession::~QuicSpdySession() {
+}
+
+void QuicSpdySession::Initialize() {
+ QuicSession::Initialize();
+
+ if (perspective() == Perspective::IS_SERVER) {
+ set_largest_peer_created_stream_id(kHeadersStreamId);
+ } else {
+ QuicStreamId headers_stream_id = GetNextStreamId();
+ DCHECK_EQ(headers_stream_id, kHeadersStreamId);
+ }
+
+ headers_stream_.reset(new QuicHeadersStream(this));
+ DCHECK_EQ(kHeadersStreamId, headers_stream_->id());
+ static_streams()[kHeadersStreamId] = headers_stream_.get();
+}
+
+void QuicSpdySession::OnStreamHeaders(QuicStreamId stream_id,
+ StringPiece headers_data) {
+ QuicDataStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnStreamHeaders(headers_data);
+}
+
+void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
+ QuicPriority priority) {
+ QuicDataStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnStreamHeadersPriority(priority);
+}
+
+void QuicSpdySession::OnStreamHeadersComplete(QuicStreamId stream_id,
+ bool fin,
+ size_t frame_len) {
+ QuicDataStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnStreamHeadersComplete(fin, frame_len);
+}
+
+size_t QuicSpdySession::WriteHeaders(
+ QuicStreamId id,
+ const SpdyHeaderBlock& headers,
+ bool fin,
+ QuicPriority priority,
+ QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
+ return headers_stream_->WriteHeaders(id, headers, fin, priority,
+ ack_notifier_delegate);
+}
+
+QuicDataStream* QuicSpdySession::GetSpdyDataStream(
+ const QuicStreamId stream_id) {
+ return static_cast<QuicDataStream*>(GetDynamicStream(stream_id));
+}
+
+} // namespace net
diff --git a/chromium/net/quic/quic_spdy_session.h b/chromium/net/quic/quic_spdy_session.h
new file mode 100644
index 00000000000..b59eb63aa0e
--- /dev/null
+++ b/chromium/net/quic/quic_spdy_session.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2015 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_QUIC_SPDY_SESSION_H_
+#define NET_QUIC_QUIC_SPDY_SESSION_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/quic_data_stream.h"
+#include "net/quic/quic_headers_stream.h"
+#include "net/quic/quic_session.h"
+
+namespace net {
+
+namespace test {
+class QuicSpdySessionPeer;
+} // namespace test
+
+// A QUIC session with a headers stream.
+class NET_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
+ public:
+ QuicSpdySession(QuicConnection* connection, const QuicConfig& config);
+
+ ~QuicSpdySession() override;
+
+ void Initialize() override;
+
+ // Called by |headers_stream_| when headers have been received for a stream.
+ virtual void OnStreamHeaders(QuicStreamId stream_id,
+ StringPiece headers_data);
+ // Called by |headers_stream_| when headers with a priority have been
+ // received for this stream. This method will only be called for server
+ // streams.
+ virtual void OnStreamHeadersPriority(QuicStreamId stream_id,
+ QuicPriority priority);
+ // Called by |headers_stream_| when headers have been completely received
+ // for a stream. |fin| will be true if the fin flag was set in the headers
+ // frame.
+ virtual void OnStreamHeadersComplete(QuicStreamId stream_id,
+ bool fin,
+ size_t frame_len);
+
+ // Writes |headers| for the stream |id| to the dedicated headers stream.
+ // If |fin| is true, then no more data will be sent for the stream |id|.
+ // If provided, |ack_notifier_delegate| will be registered to be notified when
+ // we have seen ACKs for all packets resulting from this call.
+ size_t WriteHeaders(
+ QuicStreamId id,
+ const SpdyHeaderBlock& headers,
+ bool fin,
+ QuicPriority priority,
+ QuicAckNotifier::DelegateInterface* ack_notifier_delegate);
+
+ QuicHeadersStream* headers_stream() { return headers_stream_.get(); }
+
+ protected:
+ // Override CreateIncomingDynamicStream() and CreateOutgoingDynamicStream()
+ // with QuicDataStream return type to make sure that all data streams are
+ // QuicDataStreams.
+ QuicDataStream* CreateIncomingDynamicStream(QuicStreamId id) override = 0;
+ QuicDataStream* CreateOutgoingDynamicStream() override = 0;
+
+ QuicDataStream* GetSpdyDataStream(const QuicStreamId stream_id);
+
+ private:
+ friend class test::QuicSpdySessionPeer;
+
+ scoped_ptr<QuicHeadersStream> headers_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSpdySession);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_SPDY_SESSION_H_
diff --git a/chromium/net/quic/quic_stream_factory.cc b/chromium/net/quic/quic_stream_factory.cc
index 76ab6563c68..6ad16be7d2b 100644
--- a/chromium/net/quic/quic_stream_factory.cc
+++ b/chromium/net/quic/quic_stream_factory.cc
@@ -4,17 +4,19 @@
#include "net/quic/quic_stream_factory.h"
+#include <algorithm>
#include <set>
-#include "base/cpu.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
#include "base/values.h"
#include "net/base/net_errors.h"
#include "net/cert/cert_verifier.h"
@@ -43,6 +45,13 @@
#include "base/win/windows_version.h"
#endif
+#if defined(USE_OPENSSL)
+#include <openssl/aead.h>
+#include "crypto/openssl_util.h"
+#else
+#include "base/cpu.h"
+#endif
+
namespace net {
namespace {
@@ -57,8 +66,9 @@ enum CreateSessionFailure {
// When a connection is idle for 30 seconds it will be closed.
const int kIdleConnectionTimeoutSeconds = 30;
-// The initial receive window size for both streams and sessions.
-const int32 kInitialReceiveWindowSize = 10 * 1024 * 1024; // 10MB
+// The maximum receive window sizes for QUIC sessions and streams.
+const int32 kQuicSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
+const int32 kQuicStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
// Set the maximum number of undecryptable packets the connection will store.
const int32 kMaxUndecryptablePackets = 100;
@@ -138,8 +148,9 @@ class QuicStreamFactory::Job {
Job(QuicStreamFactory* factory,
HostResolver* host_resolver,
const HostPortPair& host_port_pair,
+ bool server_and_origin_have_same_host,
bool is_https,
- bool was_alternate_protocol_recently_broken,
+ bool was_alternative_service_recently_broken,
PrivacyMode privacy_mode,
int cert_verify_flags,
bool is_post,
@@ -195,8 +206,10 @@ class QuicStreamFactory::Job {
SingleRequestHostResolver host_resolver_;
QuicServerId server_id_;
int cert_verify_flags_;
+ // True if and only if server and origin have the same hostname.
+ bool server_and_origin_have_same_host_;
bool is_post_;
- bool was_alternate_protocol_recently_broken_;
+ bool was_alternative_service_recently_broken_;
scoped_ptr<QuicServerInfo> server_info_;
bool started_another_job_;
const BoundNetLog net_log_;
@@ -212,8 +225,9 @@ class QuicStreamFactory::Job {
QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
HostResolver* host_resolver,
const HostPortPair& host_port_pair,
+ bool server_and_origin_have_same_host,
bool is_https,
- bool was_alternate_protocol_recently_broken,
+ bool was_alternative_service_recently_broken,
PrivacyMode privacy_mode,
int cert_verify_flags,
bool is_post,
@@ -224,9 +238,10 @@ QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
host_resolver_(host_resolver),
server_id_(host_port_pair, is_https, privacy_mode),
cert_verify_flags_(cert_verify_flags),
+ server_and_origin_have_same_host_(server_and_origin_have_same_host),
is_post_(is_post),
- was_alternate_protocol_recently_broken_(
- was_alternate_protocol_recently_broken),
+ was_alternative_service_recently_broken_(
+ was_alternative_service_recently_broken),
server_info_(server_info),
started_another_job_(false),
net_log_(net_log),
@@ -242,11 +257,12 @@ QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
factory_(factory),
host_resolver_(host_resolver), // unused
server_id_(server_id),
- cert_verify_flags_(0), // unused
- is_post_(false), // unused
- was_alternate_protocol_recently_broken_(false), // unused
- started_another_job_(false), // unused
- net_log_(session->net_log()), // unused
+ cert_verify_flags_(0), // unused
+ server_and_origin_have_same_host_(false), // unused
+ is_post_(false), // unused
+ was_alternative_service_recently_broken_(false), // unused
+ started_another_job_(false), // unused
+ net_log_(session->net_log()), // unused
session_(session),
weak_factory_(this) {
}
@@ -395,7 +411,8 @@ int QuicStreamFactory::Job::DoLoadServerInfo() {
// If we are waiting to load server config from the disk cache, then start
// another job.
started_another_job_ = true;
- factory_->CreateAuxilaryJob(server_id_, cert_verify_flags_, is_post_,
+ factory_->CreateAuxilaryJob(server_id_, cert_verify_flags_,
+ server_and_origin_have_same_host_, is_post_,
net_log_);
}
return rv;
@@ -442,9 +459,9 @@ int QuicStreamFactory::Job::DoConnect() {
if (!session_->connection()->connected()) {
return ERR_QUIC_PROTOCOL_ERROR;
}
- bool require_confirmation =
- factory_->require_confirmation() || is_post_ ||
- was_alternate_protocol_recently_broken_;
+ bool require_confirmation = factory_->require_confirmation() ||
+ !server_and_origin_have_same_host_ || is_post_ ||
+ was_alternative_service_recently_broken_;
rv = session_->CryptoConnect(
require_confirmation,
@@ -492,14 +509,18 @@ int QuicStreamRequest::Request(const HostPortPair& host_port_pair,
bool is_https,
PrivacyMode privacy_mode,
int cert_verify_flags,
+ base::StringPiece origin_host,
base::StringPiece method,
const BoundNetLog& net_log,
const CompletionCallback& callback) {
DCHECK(!stream_);
DCHECK(callback_.is_null());
DCHECK(factory_);
- int rv = factory_->Create(host_port_pair, is_https, privacy_mode,
- cert_verify_flags, method, net_log, this);
+ origin_host_ = origin_host.as_string();
+ privacy_mode_ = privacy_mode;
+ int rv =
+ factory_->Create(host_port_pair, is_https, privacy_mode,
+ cert_verify_flags, origin_host, method, net_log, this);
if (rv == ERR_IO_PENDING) {
host_port_pair_ = host_port_pair;
net_log_ = net_log;
@@ -547,8 +568,12 @@ QuicStreamFactory::QuicStreamFactory(
bool enable_connection_racing,
bool enable_non_blocking_io,
bool disable_disk_cache,
+ bool prefer_aes,
int max_number_of_lossy_connections,
float packet_loss_threshold,
+ int max_disabled_reasons,
+ int threshold_public_resets_post_handshake,
+ int threshold_timeouts_with_open_streams,
int socket_receive_buffer_size,
const QuicTagVector& connection_options)
: require_confirmation_(true),
@@ -572,8 +597,18 @@ QuicStreamFactory::QuicStreamFactory(
enable_connection_racing_(enable_connection_racing),
enable_non_blocking_io_(enable_non_blocking_io),
disable_disk_cache_(disable_disk_cache),
+ prefer_aes_(prefer_aes),
max_number_of_lossy_connections_(max_number_of_lossy_connections),
packet_loss_threshold_(packet_loss_threshold),
+ max_disabled_reasons_(max_disabled_reasons),
+ num_public_resets_post_handshake_(0),
+ num_timeouts_with_open_streams_(0),
+ max_public_resets_post_handshake_(0),
+ max_timeouts_with_open_streams_(0),
+ threshold_timeouts_with_open_streams_(
+ threshold_timeouts_with_open_streams),
+ threshold_public_resets_post_handshake_(
+ threshold_public_resets_post_handshake),
socket_receive_buffer_size_(socket_receive_buffer_size),
port_seed_(random_generator_->RandUint64()),
check_persisted_supports_quic_(true),
@@ -583,6 +618,7 @@ QuicStreamFactory::QuicStreamFactory(
crypto_config_.set_user_agent_id(user_agent_id);
crypto_config_.AddCanonicalSuffix(".c.youtube.com");
crypto_config_.AddCanonicalSuffix(".googlevideo.com");
+ crypto_config_.AddCanonicalSuffix(".googleusercontent.com");
crypto_config_.SetProofVerifier(
new ProofVerifierChromium(cert_verifier, transport_security_state));
// TODO(rtenneti): http://crbug.com/487355. Temporary fix for b/20760730 until
@@ -591,8 +627,16 @@ QuicStreamFactory::QuicStreamFactory(
crypto_config_.SetChannelIDSource(
new ChannelIDSourceChromium(channel_id_service));
}
+#if defined(USE_OPENSSL)
+ crypto::EnsureOpenSSLInit();
+ bool has_aes_hardware_support = !!EVP_has_aes_hardware();
+#else
base::CPU cpu;
- if (cpu.has_aesni() && cpu.has_avx())
+ bool has_aes_hardware_support = cpu.has_aesni() && cpu.has_avx();
+#endif
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm",
+ has_aes_hardware_support);
+ if (has_aes_hardware_support || prefer_aes_)
crypto_config_.PreferAesGcm();
if (!IsEcdsaSupported())
crypto_config_.DisableEcdsa();
@@ -623,12 +667,17 @@ int QuicStreamFactory::Create(const HostPortPair& host_port_pair,
bool is_https,
PrivacyMode privacy_mode,
int cert_verify_flags,
+ base::StringPiece origin_host,
base::StringPiece method,
const BoundNetLog& net_log,
QuicStreamRequest* request) {
QuicServerId server_id(host_port_pair, is_https, privacy_mode);
- if (HasActiveSession(server_id)) {
- request->set_stream(CreateIfSessionExists(server_id, net_log));
+ SessionMap::iterator it = active_sessions_.find(server_id);
+ if (it != active_sessions_.end()) {
+ QuicClientSession* session = it->second;
+ if (!session->CanPool(origin_host.as_string(), privacy_mode))
+ return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN;
+ request->set_stream(CreateFromSession(session));
return OK;
}
@@ -641,7 +690,7 @@ int QuicStreamFactory::Create(const HostPortPair& host_port_pair,
// TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
// in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
if (!task_runner_)
- task_runner_ = base::MessageLoop::current()->message_loop_proxy().get();
+ task_runner_ = base::ThreadTaskRunnerHandle::Get().get();
QuicServerInfo* quic_server_info = nullptr;
if (quic_server_info_factory_) {
@@ -649,13 +698,21 @@ int QuicStreamFactory::Create(const HostPortPair& host_port_pair,
if (http_server_properties_) {
const AlternativeServiceMap& alternative_service_map =
http_server_properties_->alternative_service_map();
- AlternativeServiceMap::const_iterator it =
+ AlternativeServiceMap::const_iterator map_it =
alternative_service_map.Peek(server_id.host_port_pair());
- if (it == alternative_service_map.end() ||
- it->second.alternative_service.protocol != QUIC) {
+ if (map_it != alternative_service_map.end()) {
+ const AlternativeServiceInfoVector& alternative_service_info_vector =
+ map_it->second;
+ AlternativeServiceInfoVector::const_iterator it;
+ for (it = alternative_service_info_vector.begin();
+ it != alternative_service_info_vector.end(); ++it) {
+ if (it->alternative_service.protocol == QUIC)
+ break;
+ }
// If there is no entry for QUIC, consider that as a new server and
// don't wait for Cache thread to load the data for that server.
- load_from_disk_cache = false;
+ if (it == alternative_service_info_vector.end())
+ load_from_disk_cache = false;
}
}
if (load_from_disk_cache && CryptoConfigCacheIsEmpty(server_id)) {
@@ -663,7 +720,9 @@ int QuicStreamFactory::Create(const HostPortPair& host_port_pair,
}
}
- scoped_ptr<Job> job(new Job(this, host_resolver_, host_port_pair, is_https,
+ bool server_and_origin_have_same_host = host_port_pair.host() == origin_host;
+ scoped_ptr<Job> job(new Job(this, host_resolver_, host_port_pair,
+ server_and_origin_have_same_host, is_https,
WasQuicRecentlyBroken(server_id), privacy_mode,
cert_verify_flags, method == "POST" /* is_post */,
quic_server_info, net_log));
@@ -676,20 +735,26 @@ int QuicStreamFactory::Create(const HostPortPair& host_port_pair,
return rv;
}
if (rv == OK) {
- DCHECK(HasActiveSession(server_id));
- request->set_stream(CreateIfSessionExists(server_id, net_log));
+ it = active_sessions_.find(server_id);
+ DCHECK(it != active_sessions_.end());
+ QuicClientSession* session = it->second;
+ if (!session->CanPool(origin_host.as_string(), privacy_mode))
+ return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN;
+ request->set_stream(CreateFromSession(session));
}
return rv;
}
void QuicStreamFactory::CreateAuxilaryJob(const QuicServerId server_id,
int cert_verify_flags,
+ bool server_and_origin_have_same_host,
bool is_post,
const BoundNetLog& net_log) {
- Job* aux_job = new Job(this, host_resolver_, server_id.host_port_pair(),
- server_id.is_https(), WasQuicRecentlyBroken(server_id),
- server_id.privacy_mode(), cert_verify_flags, is_post,
- nullptr, net_log);
+ Job* aux_job =
+ new Job(this, host_resolver_, server_id.host_port_pair(),
+ server_and_origin_have_same_host, server_id.is_https(),
+ WasQuicRecentlyBroken(server_id), server_id.privacy_mode(),
+ cert_verify_flags, is_post, nullptr, net_log);
active_jobs_[server_id].insert(aux_job);
task_runner_->PostTask(FROM_HERE,
base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob,
@@ -739,9 +804,25 @@ void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
set_require_confirmation(false);
// Create all the streams, but do not notify them yet.
- for (QuicStreamRequest* request : job_requests_map_[server_id]) {
- DCHECK(HasActiveSession(server_id));
- request->set_stream(CreateIfSessionExists(server_id, request->net_log()));
+ SessionMap::iterator session_it = active_sessions_.find(server_id);
+ for (RequestSet::iterator request_it = job_requests_map_[server_id].begin();
+ request_it != job_requests_map_[server_id].end();) {
+ DCHECK(session_it != active_sessions_.end());
+ QuicClientSession* session = session_it->second;
+ QuicStreamRequest* request = *request_it;
+ if (!session->CanPool(request->origin_host(), request->privacy_mode())) {
+ RequestSet::iterator old_request_it = request_it;
+ ++request_it;
+ // Remove request from containers so that OnRequestComplete() is not
+ // called later again on the same request.
+ job_requests_map_[server_id].erase(old_request_it);
+ active_requests_.erase(request);
+ // Notify request of certificate error.
+ request->OnRequestComplete(ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN);
+ continue;
+ }
+ request->set_stream(CreateFromSession(session));
+ ++request_it;
}
}
@@ -766,25 +847,50 @@ void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
job_requests_map_.erase(server_id);
}
-// Returns a newly created QuicHttpStream owned by the caller, if a
-// matching session already exists. Returns nullptr otherwise.
-scoped_ptr<QuicHttpStream> QuicStreamFactory::CreateIfSessionExists(
- const QuicServerId& server_id,
- const BoundNetLog& net_log) {
- if (!HasActiveSession(server_id)) {
- DVLOG(1) << "No active session";
- return scoped_ptr<QuicHttpStream>();
+scoped_ptr<QuicHttpStream> QuicStreamFactory::CreateFromSession(
+ QuicClientSession* session) {
+ return scoped_ptr<QuicHttpStream>(new QuicHttpStream(session->GetWeakPtr()));
+}
+
+QuicClientSession::QuicDisabledReason QuicStreamFactory::QuicDisabledReason(
+ uint16 port) const {
+ if (max_number_of_lossy_connections_ > 0 &&
+ number_of_lossy_connections_.find(port) !=
+ number_of_lossy_connections_.end() &&
+ number_of_lossy_connections_.at(port) >=
+ max_number_of_lossy_connections_) {
+ return QuicClientSession::QUIC_DISABLED_BAD_PACKET_LOSS_RATE;
+ }
+ if (threshold_public_resets_post_handshake_ > 0 &&
+ num_public_resets_post_handshake_ >=
+ threshold_public_resets_post_handshake_) {
+ return QuicClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE;
}
+ if (threshold_timeouts_with_open_streams_ > 0 &&
+ num_timeouts_with_open_streams_ >=
+ threshold_timeouts_with_open_streams_) {
+ return QuicClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS;
+ }
+ return QuicClientSession::QUIC_DISABLED_NOT;
+}
- QuicClientSession* session = active_sessions_[server_id];
- DCHECK(session);
- return scoped_ptr<QuicHttpStream>(
- new QuicHttpStream(session->GetWeakPtr()));
+const char* QuicStreamFactory::QuicDisabledReasonString() const {
+ // TODO(ckrasic) - better solution for port/lossy connections?
+ const uint16 port = 443;
+ switch (QuicDisabledReason(port)) {
+ case QuicClientSession::QUIC_DISABLED_BAD_PACKET_LOSS_RATE:
+ return "Bad packet loss rate.";
+ case QuicClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE:
+ return "Public resets after successful handshakes.";
+ case QuicClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS:
+ return "Connection timeouts with streams open.";
+ default:
+ return "";
+ }
}
bool QuicStreamFactory::IsQuicDisabled(uint16 port) {
- return max_number_of_lossy_connections_ > 0 &&
- number_of_lossy_connections_[port] >= max_number_of_lossy_connections_;
+ return QuicDisabledReason(port) != QuicClientSession::QUIC_DISABLED_NOT;
}
bool QuicStreamFactory::OnHandshakeConfirmed(QuicClientSession* session,
@@ -803,19 +909,29 @@ bool QuicStreamFactory::OnHandshakeConfirmed(QuicClientSession* session,
AlternativeService(QUIC, session->server_id().host(), port));
}
- // We abandon the connection if packet loss rate is too bad.
- session->CloseSessionOnErrorAndNotifyFactoryLater(ERR_ABORTED,
- QUIC_BAD_PACKET_LOSS_RATE);
-
- if (IsQuicDisabled(port))
- return true; // Exit if Quic is already disabled for this port.
+ bool was_quic_disabled = IsQuicDisabled(port);
+ ++number_of_lossy_connections_[port];
- if (++number_of_lossy_connections_[port] >=
- max_number_of_lossy_connections_) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicStreamFactory.QuicIsDisabled", port);
+ // Collect data for port 443 for packet loss events.
+ if (port == 443 && max_number_of_lossy_connections_ > 0) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ base::StringPrintf("Net.QuicStreamFactory.BadPacketLossEvents%d",
+ max_number_of_lossy_connections_),
+ std::min(number_of_lossy_connections_[port],
+ max_number_of_lossy_connections_));
}
- return true;
+ bool is_quic_disabled = IsQuicDisabled(port);
+ if (is_quic_disabled) {
+ // Close QUIC connection if Quic is disabled for this port.
+ session->CloseSessionOnErrorAndNotifyFactoryLater(
+ ERR_ABORTED, QUIC_BAD_PACKET_LOSS_RATE);
+
+ // If this bad packet loss rate disabled the QUIC, then record it.
+ if (!was_quic_disabled)
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicStreamFactory.QuicIsDisabled", port);
+ }
+ return is_quic_disabled;
}
void QuicStreamFactory::OnIdleSession(QuicClientSession* session) {
@@ -848,8 +964,67 @@ void QuicStreamFactory::OnSessionGoingAway(QuicClientSession* session) {
session_aliases_.erase(session);
}
+void QuicStreamFactory::MaybeDisableQuic(QuicClientSession* session) {
+ DCHECK(session);
+ uint16 port = session->server_id().port();
+ if (IsQuicDisabled(port))
+ return;
+
+ // Expire the oldest disabled_reason if appropriate. This enforces that we
+ // only consider the max_disabled_reasons_ most recent sessions.
+ QuicClientSession::QuicDisabledReason disabled_reason;
+ if (static_cast<int>(disabled_reasons_.size()) == max_disabled_reasons_) {
+ disabled_reason = disabled_reasons_.front();
+ disabled_reasons_.pop_front();
+ if (disabled_reason ==
+ QuicClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE) {
+ --num_public_resets_post_handshake_;
+ } else if (disabled_reason ==
+ QuicClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
+ --num_timeouts_with_open_streams_;
+ }
+ }
+ disabled_reason = session->disabled_reason();
+ disabled_reasons_.push_back(disabled_reason);
+ if (disabled_reason ==
+ QuicClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE) {
+ ++num_public_resets_post_handshake_;
+ } else if (disabled_reason ==
+ QuicClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
+ ++num_timeouts_with_open_streams_;
+ }
+ if (num_timeouts_with_open_streams_ > max_timeouts_with_open_streams_) {
+ max_timeouts_with_open_streams_ = num_timeouts_with_open_streams_;
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicStreamFactory.TimeoutsWithOpenStreams",
+ num_timeouts_with_open_streams_, 0, 20, 10);
+ }
+
+ if (num_public_resets_post_handshake_ > max_public_resets_post_handshake_) {
+ max_public_resets_post_handshake_ = num_public_resets_post_handshake_;
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Net.QuicStreamFactory.PublicResetsPostHandshake",
+ num_public_resets_post_handshake_, 0, 20, 10);
+ }
+
+ if (IsQuicDisabled(port)) {
+ if (disabled_reason ==
+ QuicClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE) {
+ session->CloseSessionOnErrorAndNotifyFactoryLater(
+ ERR_ABORTED, QUIC_PUBLIC_RESETS_POST_HANDSHAKE);
+ } else if (disabled_reason ==
+ QuicClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
+ session->CloseSessionOnErrorAndNotifyFactoryLater(
+ ERR_ABORTED, QUIC_TIMEOUTS_WITH_OPEN_STREAMS);
+ }
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicStreamFactory.DisabledReasons",
+ disabled_reason,
+ QuicClientSession::QUIC_DISABLED_MAX);
+ }
+}
+
void QuicStreamFactory::OnSessionClosed(QuicClientSession* session) {
DCHECK_EQ(0u, session->GetNumOpenStreams());
+ MaybeDisableQuic(session);
OnSessionGoingAway(session);
delete session;
all_sessions_.erase(session);
@@ -907,8 +1082,9 @@ void QuicStreamFactory::CloseAllSessions(int error) {
DCHECK(all_sessions_.empty());
}
-base::Value* QuicStreamFactory::QuicStreamFactoryInfoToValue() const {
- base::ListValue* list = new base::ListValue();
+scoped_ptr<base::Value> QuicStreamFactory::QuicStreamFactoryInfoToValue()
+ const {
+ scoped_ptr<base::ListValue> list(new base::ListValue());
for (SessionMap::const_iterator it = active_sessions_.begin();
it != active_sessions_.end(); ++it) {
@@ -925,7 +1101,7 @@ base::Value* QuicStreamFactory::QuicStreamFactoryInfoToValue() const {
list->Append(session->GetInfoAsValue(hosts));
}
}
- return list;
+ return list.Pass();
}
void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
@@ -1041,9 +1217,9 @@ int QuicStreamFactory::CreateSession(const QuicServerId& server_id,
DefaultPacketWriterFactory packet_writer_factory(socket.get());
if (!helper_.get()) {
- helper_.reset(new QuicConnectionHelper(
- base::MessageLoop::current()->message_loop_proxy().get(),
- clock_.get(), random_generator_));
+ helper_.reset(
+ new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
+ clock_.get(), random_generator_));
}
QuicConnection* connection = new QuicConnection(
@@ -1057,8 +1233,9 @@ int QuicStreamFactory::CreateSession(const QuicServerId& server_id,
QuicConfig config = config_;
config.SetSocketReceiveBufferToSend(socket_receive_buffer_size_);
config.set_max_undecryptable_packets(kMaxUndecryptablePackets);
- config.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize);
- config.SetInitialSessionFlowControlWindowToSend(kInitialReceiveWindowSize);
+ config.SetInitialSessionFlowControlWindowToSend(
+ kQuicSessionMaxRecvWindowSize);
+ config.SetInitialStreamFlowControlWindowToSend(kQuicStreamMaxRecvWindowSize);
int64 srtt = GetServerNetworkStatsSmoothedRttInMicroseconds(server_id);
if (srtt > 0)
config.SetInitialRoundTripTimeUsToSend(static_cast<uint32>(srtt));
@@ -1073,16 +1250,15 @@ int QuicStreamFactory::CreateSession(const QuicServerId& server_id,
}
*session = new QuicClientSession(
- connection, socket.Pass(), this, transport_security_state_,
- server_info.Pass(), cert_verify_flags, config,
+ connection, socket.Pass(), this, quic_crypto_client_stream_factory_,
+ transport_security_state_, server_info.Pass(), server_id,
+ cert_verify_flags, config, &crypto_config_,
network_connection_.GetDescription(), dns_resolution_end_time,
- base::MessageLoop::current()->message_loop_proxy().get(),
- net_log.net_log());
+ base::ThreadTaskRunnerHandle::Get().get(), net_log.net_log());
all_sessions_[*session] = server_id; // owning pointer
- (*session)->InitializeSession(server_id, &crypto_config_,
- quic_crypto_client_stream_factory_);
+ (*session)->Initialize();
bool closed_during_initialize =
!ContainsKey(all_sessions_, *session) ||
!(*session)->connection()->connected();
@@ -1153,10 +1329,14 @@ void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
if (http_server_properties_) {
if (quic_supported_servers_at_startup_.empty()) {
- for (const std::pair<const HostPortPair, AlternativeServiceInfo>&
+ for (const std::pair<const HostPortPair, AlternativeServiceInfoVector>&
key_value : http_server_properties_->alternative_service_map()) {
- if (key_value.second.alternative_service.protocol == QUIC) {
- quic_supported_servers_at_startup_.insert(key_value.first);
+ for (const AlternativeServiceInfo& alternative_service_info :
+ key_value.second) {
+ if (alternative_service_info.alternative_service.protocol == QUIC) {
+ quic_supported_servers_at_startup_.insert(key_value.first);
+ break;
+ }
}
}
}
diff --git a/chromium/net/quic/quic_stream_factory.h b/chromium/net/quic/quic_stream_factory.h
index f7400a3355b..2e39387df42 100644
--- a/chromium/net/quic/quic_stream_factory.h
+++ b/chromium/net/quic/quic_stream_factory.h
@@ -20,6 +20,7 @@
#include "net/log/net_log.h"
#include "net/proxy/proxy_server.h"
#include "net/quic/network_connection.h"
+#include "net/quic/quic_client_session.h"
#include "net/quic/quic_config.h"
#include "net/quic/quic_crypto_stream.h"
#include "net/quic/quic_http_stream.h"
@@ -61,6 +62,7 @@ class NET_EXPORT_PRIVATE QuicStreamRequest {
bool is_https,
PrivacyMode privacy_mode,
int cert_verify_flags,
+ base::StringPiece origin_host,
base::StringPiece method,
const BoundNetLog& net_log,
const CompletionCallback& callback);
@@ -71,6 +73,10 @@ class NET_EXPORT_PRIVATE QuicStreamRequest {
void set_stream(scoped_ptr<QuicHttpStream> stream);
+ const std::string origin_host() const { return origin_host_; }
+
+ PrivacyMode privacy_mode() const { return privacy_mode_; }
+
const BoundNetLog& net_log() const{
return net_log_;
}
@@ -78,6 +84,8 @@ class NET_EXPORT_PRIVATE QuicStreamRequest {
private:
QuicStreamFactory* factory_;
HostPortPair host_port_pair_;
+ std::string origin_host_;
+ PrivacyMode privacy_mode_;
BoundNetLog net_log_;
CompletionCallback callback_;
scoped_ptr<QuicHttpStream> stream_;
@@ -111,8 +119,12 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
bool enable_connection_racing,
bool enable_non_blocking_io,
bool disable_disk_cache,
+ bool prefer_aes,
int max_number_of_lossy_connections,
float packet_loss_threshold,
+ int max_recent_disabled_reasons,
+ int threshold_timeouts_with_streams_open,
+ int threshold_public_resets_post_handshake,
int socket_receive_buffer_size,
const QuicTagVector& connection_options);
~QuicStreamFactory() override;
@@ -126,19 +138,30 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
bool is_https,
PrivacyMode privacy_mode,
int cert_verify_flags,
+ base::StringPiece origin_host,
base::StringPiece method,
const BoundNetLog& net_log,
QuicStreamRequest* request);
- // Returns false if |packet_loss_rate| is less than |packet_loss_threshold_|
- // otherwise it returns true and closes the session and marks QUIC as recently
- // broken for the port of the session. Increments
- // |number_of_lossy_connections_| by port.
+ // If |packet_loss_rate| is greater than or equal to |packet_loss_threshold_|
+ // it marks QUIC as recently broken for the port of the session. Increments
+ // |number_of_lossy_connections_| by port. If |number_of_lossy_connections_|
+ // is greater than or equal to |max_number_of_lossy_connections_| then it
+ // disables QUIC. If QUIC is disabled then it closes the connection.
+ //
+ // Returns true if QUIC is disabled for the port of the session.
bool OnHandshakeConfirmed(QuicClientSession* session, float packet_loss_rate);
// Returns true if QUIC is disabled for this port.
bool IsQuicDisabled(uint16 port);
+ // Returns reason QUIC is disabled for this port, or QUIC_DISABLED_NOT if not.
+ QuicClientSession::QuicDisabledReason QuicDisabledReason(uint16 port) const;
+
+ // Returns reason QUIC is disabled as string for net-internals, or
+ // returns empty string if QUIC is not disabled.
+ const char* QuicDisabledReasonString() const;
+
// Called by a session when it becomes idle.
void OnIdleSession(QuicClientSession* session);
@@ -158,7 +181,7 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
// Closes all current sessions.
void CloseAllSessions(int error);
- base::Value* QuicStreamFactoryInfoToValue() const;
+ scoped_ptr<base::Value> QuicStreamFactoryInfoToValue() const;
// Delete all cached state objects in |crypto_config_|.
void ClearCachedStatesInCryptoConfig();
@@ -200,9 +223,12 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
enable_connection_racing_ = enable_connection_racing;
}
+ int socket_receive_buffer_size() const { return socket_receive_buffer_size_; }
+
private:
class Job;
friend class test::QuicStreamFactoryPeer;
+ FRIEND_TEST_ALL_PREFIXES(HttpStreamFactoryTest, QuicLossyProxyMarkedAsBad);
// The key used to find session by ip. Includes
// the ip address, port, and scheme.
@@ -231,18 +257,19 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
typedef std::map<QuicStreamRequest*, QuicServerId> RequestMap;
typedef std::set<QuicStreamRequest*> RequestSet;
typedef std::map<QuicServerId, RequestSet> ServerIDRequestsMap;
+ typedef std::deque<enum QuicClientSession::QuicDisabledReason>
+ DisabledReasonsQueue;
// Creates a job which doesn't wait for server config to be loaded from the
// disk cache. This job is started via a PostTask.
void CreateAuxilaryJob(const QuicServerId server_id,
int cert_verify_flags,
+ bool server_and_origin_have_same_host,
bool is_post,
const BoundNetLog& net_log);
- // Returns a newly created QuicHttpStream owned by the caller, if a
- // matching session already exists. Returns NULL otherwise.
- scoped_ptr<QuicHttpStream> CreateIfSessionExists(const QuicServerId& key,
- const BoundNetLog& net_log);
+ // Returns a newly created QuicHttpStream owned by the caller.
+ scoped_ptr<QuicHttpStream> CreateFromSession(QuicClientSession*);
bool OnResolution(const QuicServerId& server_id,
const AddressList& address_list);
@@ -279,6 +306,9 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
const QuicServerId& server_id,
bool was_session_active);
+ // Collect stats from recent connections, possibly disabling Quic.
+ void MaybeDisableQuic(QuicClientSession* session);
+
bool require_confirmation_;
HostResolver* host_resolver_;
ClientSocketFactory* client_socket_factory_;
@@ -344,6 +374,9 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
// Set if we do not want to load server config from the disk cache.
bool disable_disk_cache_;
+ // Set if AES-GCM should be preferred, even if there is no hardware support.
+ bool prefer_aes_;
+
// Set if we want to disable QUIC when there is high packet loss rate.
// Specifies the maximum number of connections with high packet loss in a row
// after which QUIC will be disabled.
@@ -354,6 +387,21 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
// Count number of lossy connections by port.
std::map<uint16, int> number_of_lossy_connections_;
+ // Keep track of stats for recently closed connections, using a
+ // bounded queue.
+ int max_disabled_reasons_;
+ DisabledReasonsQueue disabled_reasons_;
+ // Events that can trigger disabling QUIC
+ int num_public_resets_post_handshake_;
+ int num_timeouts_with_open_streams_;
+ // Keep track the largest values for UMA histograms, that will help
+ // determine good threshold values.
+ int max_public_resets_post_handshake_;
+ int max_timeouts_with_open_streams_;
+ // Thresholds if greater than zero, determine when to
+ int threshold_timeouts_with_open_streams_;
+ int threshold_public_resets_post_handshake_;
+
// Size of the UDP receive buffer.
int socket_receive_buffer_size_;
diff --git a/chromium/net/quic/quic_stream_factory_test.cc b/chromium/net/quic/quic_stream_factory_test.cc
index 456a8da56d2..b4044558b36 100644
--- a/chromium/net/quic/quic_stream_factory_test.cc
+++ b/chromium/net/quic/quic_stream_factory_test.cc
@@ -6,6 +6,7 @@
#include "base/run_loop.h"
#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
#include "net/base/test_data_directory.h"
#include "net/cert/cert_verifier.h"
#include "net/dns/mock_host_resolver.h"
@@ -96,13 +97,10 @@ class QuicStreamFactoryPeer {
return factory->active_sessions_[server_id];
}
- static scoped_ptr<QuicHttpStream> CreateIfSessionExists(
+ static scoped_ptr<QuicHttpStream> CreateFromSession(
QuicStreamFactory* factory,
- const HostPortPair& host_port_pair,
- bool is_https,
- const BoundNetLog& net_log) {
- QuicServerId server_id(host_port_pair, is_https, PRIVACY_MODE_DISABLED);
- return factory->CreateIfSessionExists(server_id, net_log);
+ QuicClientSession* session) {
+ return factory->CreateFromSession(session);
}
static bool IsLiveSession(QuicStreamFactory* factory,
@@ -154,6 +152,28 @@ class QuicStreamFactoryPeer {
const QuicServerId& server_id) {
return (factory->active_jobs_[server_id]).size();
}
+
+ static void SetThresholdTimeoutsWithOpenStreams(
+ QuicStreamFactory* factory,
+ int threshold_timeouts_with_open_streams) {
+ factory->threshold_timeouts_with_open_streams_ =
+ threshold_timeouts_with_open_streams;
+ }
+
+ static int GetNumTimeoutsWithOpenStreams(QuicStreamFactory* factory) {
+ return factory->num_timeouts_with_open_streams_;
+ }
+
+ static void SetThresholdPublicResetsPostHandshake(
+ QuicStreamFactory* factory,
+ int threshold_public_resets_post_handshake) {
+ factory->threshold_public_resets_post_handshake_ =
+ threshold_public_resets_post_handshake;
+ }
+
+ static int GetNumPublicResetsPostHandshake(QuicStreamFactory* factory) {
+ return factory->num_public_resets_post_handshake_;
+ }
};
class MockQuicServerInfo : public QuicServerInfo {
@@ -201,7 +221,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
cert_verifier_(CertVerifier::CreateDefault()),
channel_id_service_(
new ChannelIDService(new DefaultChannelIDStore(nullptr),
- base::MessageLoopProxy::current())),
+ base::ThreadTaskRunnerHandle::Get())),
factory_(&host_resolver_,
&socket_factory_,
base::WeakPtr<HttpServerProperties>(),
@@ -221,8 +241,12 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
/*enable_connection_racing=*/false,
/*enable_non_blocking_io=*/true,
/*disable_disk_cache=*/false,
+ /*prefer_aes=*/false,
/*max_number_of_lossy_connections=*/0,
/*packet_loss_threshold=*/1.0f,
+ /*max_disabled_reasons=*/3,
+ /*threshold_timeouts_with_open_streams=*/2,
+ /*threshold_pulic_resets_post_handshake=*/2,
/*receive_buffer_size=*/0,
QuicTagVector()),
host_port_pair_(kDefaultServerHostName, kDefaultServerPort),
@@ -234,11 +258,16 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
&factory_, GetParam().enable_connection_racing);
}
- scoped_ptr<QuicHttpStream> CreateIfSessionExists(
- const HostPortPair& host_port_pair,
- const BoundNetLog& net_log) {
- return QuicStreamFactoryPeer::CreateIfSessionExists(
- &factory_, host_port_pair, false, net_log_);
+ bool HasActiveSession(const HostPortPair& host_port_pair) {
+ return QuicStreamFactoryPeer::HasActiveSession(&factory_, host_port_pair,
+ /*is_https_=*/false);
+ }
+
+ scoped_ptr<QuicHttpStream> CreateFromSession(
+ const HostPortPair& host_port_pair) {
+ QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
+ &factory_, host_port_pair, /*is_https=*/false);
+ return QuicStreamFactoryPeer::CreateFromSession(&factory_, session);
}
int GetSourcePortForNewSession(const HostPortPair& destination) {
@@ -253,7 +282,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
int GetSourcePortForNewSessionInner(const HostPortPair& destination,
bool goaway_received) {
// Should only be called if there is no active session for this destination.
- EXPECT_EQ(nullptr, CreateIfSessionExists(destination, net_log_).get());
+ EXPECT_FALSE(HasActiveSession(destination));
size_t socket_count = socket_factory_.udp_client_sockets().size();
MockRead reads[] = {
@@ -266,8 +295,8 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(destination, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, destination.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
@@ -292,9 +321,9 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
}
factory_.OnSessionClosed(session);
- EXPECT_EQ(nullptr, CreateIfSessionExists(destination, net_log_).get());
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_FALSE(HasActiveSession(destination));
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
return port;
}
@@ -305,6 +334,18 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, GetParam().version));
}
+ static ProofVerifyDetailsChromium DefaultProofVerifyDetails() {
+ // Load a certificate that is valid for www.example.org, mail.example.org,
+ // and mail.example.com.
+ scoped_refptr<X509Certificate> test_cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
+ EXPECT_TRUE(test_cert.get());
+ ProofVerifyDetailsChromium verify_details;
+ verify_details.cert_verify_result.verified_cert = test_cert;
+ verify_details.cert_verify_result.is_issued_by_known_root = true;
+ return verify_details;
+ }
+
MockQuicServerInfoFactory quic_server_info_factory_;
MockHostResolver host_resolver_;
DeterministicMockClientSocketFactory socket_factory_;
@@ -328,10 +369,6 @@ INSTANTIATE_TEST_CASE_P(Version,
QuicStreamFactoryTest,
::testing::ValuesIn(GetTestParams()));
-TEST_P(QuicStreamFactoryTest, CreateIfSessionExists) {
- EXPECT_EQ(nullptr, CreateIfSessionExists(host_port_pair_, net_log_).get());
-}
-
TEST_P(QuicStreamFactoryTest, Create) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
@@ -343,28 +380,29 @@ TEST_P(QuicStreamFactoryTest, Create) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
// Will reset stream 3.
- stream = CreateIfSessionExists(host_port_pair_, net_log_);
+ stream = CreateFromSession(host_port_pair_);
EXPECT_TRUE(stream.get());
// TODO(rtenneti): We should probably have a tests that HTTP and HTTPS result
// in streams on different sessions.
QuicStreamRequest request2(&factory_);
- EXPECT_EQ(OK, request2.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ EXPECT_EQ(OK,
+ request2.Request(host_port_pair_, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
stream = request2.ReleaseStream(); // Will reset stream 5.
stream.reset(); // Will reset stream 7.
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, CreateZeroRtt) {
@@ -383,13 +421,13 @@ TEST_P(QuicStreamFactoryTest, CreateZeroRtt) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, CreateZeroRttPost) {
@@ -410,8 +448,8 @@ TEST_P(QuicStreamFactoryTest, CreateZeroRttPost) {
// Posts require handshake confirmation, so this will return asynchronously.
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "POST", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "POST", net_log_, callback_.callback()));
// Confirm the handshake and verify that the stream is created.
crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
@@ -420,8 +458,40 @@ TEST_P(QuicStreamFactoryTest, CreateZeroRttPost) {
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, NoZeroRttForDifferentHost) {
+ MockRead reads[] = {
+ MockRead(ASYNC, OK, 0),
+ };
+ DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+ socket_data.StopAfter(1);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::ZERO_RTT);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ QuicStreamRequest request(&factory_);
+ int rv = request.Request(
+ host_port_pair_, is_https_, privacy_mode_, /*cert_verify_flags=*/0,
+ "different.host.example.com", "GET", net_log_, callback_.callback());
+ // If server and origin have different hostnames, then handshake confirmation
+ // should be required, so Request will return asynchronously.
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ // Confirm handshake.
+ crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+ QuicSession::HANDSHAKE_CONFIRMED);
+ EXPECT_EQ(OK, callback_.WaitForResult());
+
+ scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+ EXPECT_TRUE(stream.get());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, CreateHttpVsHttps) {
@@ -438,8 +508,8 @@ TEST_P(QuicStreamFactoryTest, CreateHttpVsHttps) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
@@ -448,8 +518,8 @@ TEST_P(QuicStreamFactoryTest, CreateHttpVsHttps) {
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, !is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.ReleaseStream();
EXPECT_TRUE(stream.get());
@@ -460,10 +530,10 @@ TEST_P(QuicStreamFactoryTest, CreateHttpVsHttps) {
QuicStreamFactoryPeer::GetActiveSession(
&factory_, host_port_pair_, !is_https_));
- EXPECT_TRUE(socket_data1.at_read_eof());
- EXPECT_TRUE(socket_data1.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, Pooling) {
@@ -483,16 +553,16 @@ TEST_P(QuicStreamFactoryTest, Pooling) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
@@ -501,8 +571,8 @@ TEST_P(QuicStreamFactoryTest, Pooling) {
&factory_, host_port_pair_, is_https_),
QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_));
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoPoolingIfDisabled) {
@@ -528,16 +598,16 @@ TEST_P(QuicStreamFactoryTest, NoPoolingIfDisabled) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
@@ -546,10 +616,10 @@ TEST_P(QuicStreamFactoryTest, NoPoolingIfDisabled) {
&factory_, host_port_pair_, is_https_),
QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_));
- EXPECT_TRUE(socket_data1.at_read_eof());
- EXPECT_TRUE(socket_data1.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
@@ -572,16 +642,16 @@ TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
@@ -595,18 +665,18 @@ TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
TestCompletionCallback callback3;
QuicStreamRequest request3(&factory_);
EXPECT_EQ(OK, request3.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback3.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback3.callback()));
scoped_ptr<QuicHttpStream> stream3 = request3.ReleaseStream();
EXPECT_TRUE(stream3.get());
EXPECT_TRUE(QuicStreamFactoryPeer::HasActiveSession(
&factory_, server2, is_https_));
- EXPECT_TRUE(socket_data1.at_read_eof());
- EXPECT_TRUE(socket_data1.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, HttpsPooling) {
@@ -620,17 +690,7 @@ TEST_P(QuicStreamFactoryTest, HttpsPooling) {
HostPortPair server1("www.example.org", 443);
HostPortPair server2("mail.example.org", 443);
- // Load a cert that is valid for:
- // www.example.org (server1)
- // mail.example.org (server2)
- // www.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
- ProofVerifyDetailsChromium verify_details;
- verify_details.cert_verify_result.verified_cert = test_cert;
- verify_details.cert_verify_result.is_issued_by_known_root = true;
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
host_resolver_.set_synchronous_mode(true);
@@ -640,16 +700,16 @@ TEST_P(QuicStreamFactoryTest, HttpsPooling) {
QuicStreamRequest request(&factory_);
is_https_ = true;
EXPECT_EQ(OK, request.Request(server1, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server1.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
@@ -658,8 +718,8 @@ TEST_P(QuicStreamFactoryTest, HttpsPooling) {
QuicStreamFactoryPeer::GetActiveSession(
&factory_, server2, is_https_));
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoHttpsPoolingIfDisabled) {
@@ -676,17 +736,7 @@ TEST_P(QuicStreamFactoryTest, NoHttpsPoolingIfDisabled) {
HostPortPair server1("www.example.org", 443);
HostPortPair server2("mail.example.org", 443);
- // Load a cert that is valid for:
- // www.example.org (server1)
- // mail.example.org (server2)
- // www.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
- ProofVerifyDetailsChromium verify_details;
- verify_details.cert_verify_result.verified_cert = test_cert;
- verify_details.cert_verify_result.is_issued_by_known_root = true;
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
host_resolver_.set_synchronous_mode(true);
@@ -699,16 +749,16 @@ TEST_P(QuicStreamFactoryTest, NoHttpsPoolingIfDisabled) {
QuicStreamRequest request(&factory_);
is_https_ = true;
EXPECT_EQ(OK, request.Request(server1, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server1.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
@@ -717,68 +767,83 @@ TEST_P(QuicStreamFactoryTest, NoHttpsPoolingIfDisabled) {
QuicStreamFactoryPeer::GetActiveSession(
&factory_, server2, is_https_));
- EXPECT_TRUE(socket_data1.at_read_eof());
- EXPECT_TRUE(socket_data1.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
-TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithCertMismatch) {
- MockRead reads[] = {
- MockRead(ASYNC, OK, 0) // EOF
- };
- DeterministicSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
- DeterministicSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data1);
- socket_factory_.AddSocketDataProvider(&socket_data2);
- socket_data1.StopAfter(1);
- socket_data2.StopAfter(1);
-
- HostPortPair server1("www.example.org", 443);
- HostPortPair server2("mail.google.com", 443);
-
- // Load a cert that is valid for:
- // www.example.org (server1)
- // mail.example.org
- // www.example.com
- // But is not valid for mail.google.com (server2).
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
- ProofVerifyDetailsChromium verify_details;
- verify_details.cert_verify_result.verified_cert = test_cert;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+class QuicAlternativeServiceCertificateValidationPooling
+ : public QuicStreamFactoryTest {
+ public:
+ void Run(bool valid) {
+ MockRead reads[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+ DeterministicSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data1);
+ socket_data1.StopAfter(1);
+
+ HostPortPair server1("www.example.org", 443);
+ HostPortPair server2("mail.example.org", 443);
+
+ std::string origin_host(valid ? "mail.example.org" : "invalid.example.org");
+ HostPortPair alternative("www.example.org", 443);
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ bool common_name_fallback_used;
+ EXPECT_EQ(valid,
+ verify_details.cert_verify_result.verified_cert->VerifyNameMatch(
+ origin_host, &common_name_fallback_used));
+ EXPECT_TRUE(
+ verify_details.cert_verify_result.verified_cert->VerifyNameMatch(
+ alternative.host(), &common_name_fallback_used));
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(alternative.host(), "192.168.0.1",
+ "");
+
+ // Open first stream to alternative.
+ QuicStreamRequest request1(&factory_);
+ is_https_ = true;
+ EXPECT_EQ(OK, request1.Request(alternative, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, alternative.host(),
+ "GET", net_log_, callback_.callback()));
+ scoped_ptr<QuicHttpStream> stream1 = request1.ReleaseStream();
+ EXPECT_TRUE(stream1.get());
+
+ QuicStreamRequest request2(&factory_);
+ int rv = request2.Request(alternative, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, origin_host, "GET",
+ net_log_, callback_.callback());
+ if (valid) {
+ // Alternative service of origin to |alternative| should pool to session
+ // of |stream1| even if origin is different. Since only one
+ // SocketDataProvider is set up, the second request succeeding means that
+ // it pooled to the session opened by the first one.
+ EXPECT_EQ(OK, rv);
+ scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+ EXPECT_TRUE(stream2.get());
+ } else {
+ EXPECT_EQ(ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN, rv);
+ }
- QuicStreamRequest request(&factory_);
- is_https_ = true;
- EXPECT_EQ(OK, request.Request(server1, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
- scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
- EXPECT_TRUE(stream.get());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ }
+};
- TestCompletionCallback callback;
- QuicStreamRequest request2(&factory_);
- EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
- scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
- EXPECT_TRUE(stream2.get());
+INSTANTIATE_TEST_CASE_P(Version,
+ QuicAlternativeServiceCertificateValidationPooling,
+ ::testing::ValuesIn(GetTestParams()));
- EXPECT_NE(QuicStreamFactoryPeer::GetActiveSession(
- &factory_, server1, is_https_),
- QuicStreamFactoryPeer::GetActiveSession(
- &factory_, server2, is_https_));
+TEST_P(QuicAlternativeServiceCertificateValidationPooling, Valid) {
+ Run(true);
+}
- EXPECT_TRUE(socket_data1.at_read_eof());
- EXPECT_TRUE(socket_data1.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+TEST_P(QuicAlternativeServiceCertificateValidationPooling, Invalid) {
+ Run(false);
}
TEST_P(QuicStreamFactoryTest, HttpsPoolingWithMatchingPins) {
@@ -796,16 +861,7 @@ TEST_P(QuicStreamFactoryTest, HttpsPoolingWithMatchingPins) {
test::AddPin(&transport_security_state_, "mail.example.org", primary_pin,
backup_pin);
- // Load a cert that is valid for:
- // www.example.org (server1)
- // mail.example.org (server2)
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
- ProofVerifyDetailsChromium verify_details;
- verify_details.cert_verify_result.verified_cert = test_cert;
- verify_details.cert_verify_result.is_issued_by_known_root = true;
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
verify_details.cert_verify_result.public_key_hashes.push_back(
test::GetTestHashValue(primary_pin));
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
@@ -817,16 +873,16 @@ TEST_P(QuicStreamFactoryTest, HttpsPoolingWithMatchingPins) {
QuicStreamRequest request(&factory_);
is_https_ = true;
EXPECT_EQ(OK, request.Request(server1, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server1.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
@@ -835,8 +891,8 @@ TEST_P(QuicStreamFactoryTest, HttpsPoolingWithMatchingPins) {
QuicStreamFactoryPeer::GetActiveSession(
&factory_, server2, is_https_));
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithMatchingPinsIfDisabled) {
@@ -857,16 +913,7 @@ TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithMatchingPinsIfDisabled) {
test::AddPin(&transport_security_state_, "mail.example.org", primary_pin,
backup_pin);
- // Load a cert that is valid for:
- // www.example.org (server1)
- // mail.example.org (server2)
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
- ProofVerifyDetailsChromium verify_details;
- verify_details.cert_verify_result.verified_cert = test_cert;
- verify_details.cert_verify_result.is_issued_by_known_root = true;
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
verify_details.cert_verify_result.public_key_hashes.push_back(
test::GetTestHashValue(primary_pin));
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
@@ -881,16 +928,16 @@ TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithMatchingPinsIfDisabled) {
QuicStreamRequest request(&factory_);
is_https_ = true;
EXPECT_EQ(OK, request.Request(server1, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server1.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
@@ -899,10 +946,10 @@ TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithMatchingPinsIfDisabled) {
QuicStreamFactoryPeer::GetActiveSession(
&factory_, server2, is_https_));
- EXPECT_TRUE(socket_data1.at_read_eof());
- EXPECT_TRUE(socket_data1.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithDifferentPins) {
@@ -924,24 +971,12 @@ TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithDifferentPins) {
test::AddPin(&transport_security_state_, "mail.example.org", primary_pin,
backup_pin);
- // Load a cert that is valid for:
- // www.example.org (server1)
- // mail.example.org (server2)
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
-
- ProofVerifyDetailsChromium verify_details1;
- verify_details1.cert_verify_result.verified_cert = test_cert;
- verify_details1.cert_verify_result.is_issued_by_known_root = true;
+ ProofVerifyDetailsChromium verify_details1 = DefaultProofVerifyDetails();
verify_details1.cert_verify_result.public_key_hashes.push_back(
test::GetTestHashValue(bad_pin));
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
- ProofVerifyDetailsChromium verify_details2;
- verify_details2.cert_verify_result.verified_cert = test_cert;
- verify_details2.cert_verify_result.is_issued_by_known_root = true;
+ ProofVerifyDetailsChromium verify_details2 = DefaultProofVerifyDetails();
verify_details2.cert_verify_result.public_key_hashes.push_back(
test::GetTestHashValue(primary_pin));
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
@@ -953,16 +988,16 @@ TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithDifferentPins) {
QuicStreamRequest request(&factory_);
is_https_ = true;
EXPECT_EQ(OK, request.Request(server1, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server1.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback_.callback()));
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
@@ -971,10 +1006,10 @@ TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithDifferentPins) {
QuicStreamFactoryPeer::GetActiveSession(
&factory_, server2, is_https_));
- EXPECT_TRUE(socket_data1.at_read_eof());
- EXPECT_TRUE(socket_data1.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, Goaway) {
@@ -991,8 +1026,8 @@ TEST_P(QuicStreamFactoryTest, Goaway) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
@@ -1006,15 +1041,15 @@ TEST_P(QuicStreamFactoryTest, Goaway) {
EXPECT_EQ(true, QuicStreamFactoryPeer::IsLiveSession(&factory_, session));
EXPECT_FALSE(QuicStreamFactoryPeer::HasActiveSession(
&factory_, host_port_pair_, is_https_));
- EXPECT_EQ(nullptr, CreateIfSessionExists(host_port_pair_, net_log_).get());
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
// Create a new request for the same destination and verify that a
// new session is created.
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
@@ -1030,10 +1065,10 @@ TEST_P(QuicStreamFactoryTest, Goaway) {
stream2.reset();
stream.reset();
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
@@ -1058,8 +1093,8 @@ TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
for (size_t i = 0; i < kDefaultMaxStreamsPerConnection / 2; i++) {
QuicStreamRequest request(&factory_);
int rv = request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback());
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback());
if (i == 0) {
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_EQ(OK, callback_.WaitForResult());
@@ -1075,8 +1110,8 @@ TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- CompletionCallback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, CompletionCallback()));
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream);
EXPECT_EQ(ERR_IO_PENDING, stream->InitializeStream(
@@ -1089,8 +1124,8 @@ TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
EXPECT_EQ(OK, callback_.WaitForResult());
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
STLDeleteElements(&streams);
}
@@ -1103,13 +1138,13 @@ TEST_P(QuicStreamFactoryTest, ResolutionErrorInCreate) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult());
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, ConnectErrorInCreate) {
@@ -1122,13 +1157,13 @@ TEST_P(QuicStreamFactoryTest, ConnectErrorInCreate) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(ERR_ADDRESS_IN_USE, callback_.WaitForResult());
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, CancelCreate) {
@@ -1141,21 +1176,20 @@ TEST_P(QuicStreamFactoryTest, CancelCreate) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
}
socket_data.StopAfter(1);
base::RunLoop run_loop;
run_loop.RunUntilIdle();
- scoped_ptr<QuicHttpStream> stream(
- CreateIfSessionExists(host_port_pair_, net_log_));
+ scoped_ptr<QuicHttpStream> stream(CreateFromSession(host_port_pair_));
EXPECT_TRUE(stream.get());
stream.reset();
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, CreateConsistentEphemeralPort) {
@@ -1205,8 +1239,8 @@ TEST_P(QuicStreamFactoryTest, CloseAllSessions) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
@@ -1226,17 +1260,17 @@ TEST_P(QuicStreamFactoryTest, CloseAllSessions) {
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.ReleaseStream();
stream.reset(); // Will reset stream 3.
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) {
@@ -1262,8 +1296,8 @@ TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
@@ -1284,17 +1318,17 @@ TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) {
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.ReleaseStream();
stream.reset(); // Will reset stream 3.
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnCertAdded) {
@@ -1320,8 +1354,8 @@ TEST_P(QuicStreamFactoryTest, OnCertAdded) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
@@ -1342,17 +1376,17 @@ TEST_P(QuicStreamFactoryTest, OnCertAdded) {
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.ReleaseStream();
stream.reset(); // Will reset stream 3.
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnCACertChanged) {
@@ -1378,8 +1412,8 @@ TEST_P(QuicStreamFactoryTest, OnCACertChanged) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
@@ -1400,17 +1434,17 @@ TEST_P(QuicStreamFactoryTest, OnCACertChanged) {
QuicStreamRequest request2(&factory_);
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.ReleaseStream();
stream.reset(); // Will reset stream 3.
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, SharedCryptoConfig) {
@@ -1511,8 +1545,8 @@ TEST_P(QuicStreamFactoryTest, RacingConnections) {
QuicServerId server_id(host_port_pair_, is_https_, privacy_mode_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
EXPECT_EQ(2u,
QuicStreamFactoryPeer::GetNumberOfActiveJobs(&factory_, server_id));
@@ -1520,8 +1554,8 @@ TEST_P(QuicStreamFactoryTest, RacingConnections) {
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_EQ(0u,
QuicStreamFactoryPeer::GetNumberOfActiveJobs(&factory_, server_id));
}
@@ -1546,8 +1580,8 @@ TEST_P(QuicStreamFactoryTest, EnableNotLoadFromDiskCache) {
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
// If we are waiting for disk cache, we would have posted a task. Verify that
// the CancelWaitForDataReady task hasn't been posted.
@@ -1555,8 +1589,8 @@ TEST_P(QuicStreamFactoryTest, EnableNotLoadFromDiskCache) {
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, BadPacketLoss) {
@@ -1576,16 +1610,21 @@ TEST_P(QuicStreamFactoryTest, BadPacketLoss) {
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
- DeterministicSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
+ DeterministicSocketData socket_data2(nullptr, 0, nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
socket_data2.StopAfter(1);
- DeterministicSocketData socket_data3(reads, arraysize(reads), nullptr, 0);
+ DeterministicSocketData socket_data3(nullptr, 0, nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data3);
socket_data3.StopAfter(1);
+ DeterministicSocketData socket_data4(nullptr, 0, nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data4);
+ socket_data4.StopAfter(1);
+
HostPortPair server2("mail.example.org", kDefaultServerPort);
HostPortPair server3("docs.example.org", kDefaultServerPort);
+ HostPortPair server4("images.example.org", kDefaultServerPort);
crypto_client_stream_factory_.set_handshake_mode(
MockCryptoClientStream::ZERO_RTT);
@@ -1594,11 +1633,12 @@ TEST_P(QuicStreamFactoryTest, BadPacketLoss) {
"192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server4.host(), "192.168.0.1", "");
QuicStreamRequest request(&factory_);
EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback_.callback()));
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
&factory_, host_port_pair_, is_https_);
@@ -1617,16 +1657,16 @@ TEST_P(QuicStreamFactoryTest, BadPacketLoss) {
&factory_, host_port_pair_.port()));
// Set packet_loss_rate to a higher value than packet_loss_threshold only once
- // and that should close the session, but shouldn't disable QUIC.
- EXPECT_TRUE(
+ // and that shouldn't close the session and it shouldn't disable QUIC.
+ EXPECT_FALSE(
factory_.OnHandshakeConfirmed(session, /*packet_loss_rate=*/1.0f));
EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
&factory_, host_port_pair_.port()));
+ EXPECT_TRUE(session->connection()->connected());
EXPECT_FALSE(
QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
- EXPECT_FALSE(QuicStreamFactoryPeer::HasActiveSession(
+ EXPECT_TRUE(QuicStreamFactoryPeer::HasActiveSession(
&factory_, host_port_pair_, is_https_));
- EXPECT_EQ(nullptr, CreateIfSessionExists(host_port_pair_, net_log_).get());
// Test N-in-a-row high packet loss connections.
@@ -1635,8 +1675,8 @@ TEST_P(QuicStreamFactoryTest, BadPacketLoss) {
TestCompletionCallback callback2;
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback2.callback()));
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback2.callback()));
QuicClientSession* session2 =
QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_);
@@ -1652,52 +1692,760 @@ TEST_P(QuicStreamFactoryTest, BadPacketLoss) {
QuicStreamFactoryPeer::IsQuicDisabled(&factory_, server2.port()));
// Set packet_loss_rate to a higher value than packet_loss_threshold only once
- // and that should close the session, but shouldn't disable QUIC.
- EXPECT_TRUE(
+ // and that shouldn't close the session and it shouldn't disable QUIC.
+ EXPECT_FALSE(
factory_.OnHandshakeConfirmed(session2, /*packet_loss_rate=*/1.0f));
EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
&factory_, server2.port()));
- EXPECT_FALSE(session2->connection()->connected());
+ EXPECT_TRUE(session2->connection()->connected());
EXPECT_FALSE(
QuicStreamFactoryPeer::IsQuicDisabled(&factory_, server2.port()));
- EXPECT_FALSE(
+ EXPECT_TRUE(
QuicStreamFactoryPeer::HasActiveSession(&factory_, server2, is_https_));
- EXPECT_EQ(nullptr, CreateIfSessionExists(server2, net_log_).get());
DVLOG(1) << "Create 3rd session which also has packet loss";
TestCompletionCallback callback3;
QuicStreamRequest request3(&factory_);
EXPECT_EQ(OK, request3.Request(server3, is_https_, privacy_mode_,
- /*cert_verify_flags=*/0, "GET", net_log_,
- callback3.callback()));
+ /*cert_verify_flags=*/0, server3.host(), "GET",
+ net_log_, callback3.callback()));
QuicClientSession* session3 =
QuicStreamFactoryPeer::GetActiveSession(&factory_, server3, is_https_);
+ DVLOG(1) << "Create 4th session with packet loss and test IsQuicDisabled()";
+ TestCompletionCallback callback4;
+ QuicStreamRequest request4(&factory_);
+ EXPECT_EQ(OK, request4.Request(server4, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server4.host(), "GET",
+ net_log_, callback4.callback()));
+ QuicClientSession* session4 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server4, is_https_);
+
// Set packet_loss_rate to higher value than packet_loss_threshold 2nd time in
// a row and that should close the session and disable QUIC.
EXPECT_TRUE(
factory_.OnHandshakeConfirmed(session3, /*packet_loss_rate=*/1.0f));
EXPECT_EQ(2, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
&factory_, server3.port()));
- EXPECT_FALSE(session2->connection()->connected());
+ EXPECT_FALSE(session3->connection()->connected());
EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(&factory_, server3.port()));
EXPECT_FALSE(
QuicStreamFactoryPeer::HasActiveSession(&factory_, server3, is_https_));
- EXPECT_EQ(nullptr, CreateIfSessionExists(server3, net_log_).get());
+ EXPECT_FALSE(HasActiveSession(server3));
+
+ // Set packet_loss_rate to higher value than packet_loss_threshold 3rd time in
+ // a row and IsQuicDisabled() should close the session.
+ EXPECT_TRUE(
+ factory_.OnHandshakeConfirmed(session4, /*packet_loss_rate=*/1.0f));
+ EXPECT_EQ(3, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
+ &factory_, server4.port()));
+ EXPECT_FALSE(session4->connection()->connected());
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(&factory_, server4.port()));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::HasActiveSession(&factory_, server4, is_https_));
+ EXPECT_FALSE(HasActiveSession(server4));
+
+ scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+ EXPECT_TRUE(stream.get());
+ scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+ EXPECT_TRUE(stream2.get());
+ scoped_ptr<QuicHttpStream> stream3 = request3.ReleaseStream();
+ EXPECT_TRUE(stream3.get());
+ scoped_ptr<QuicHttpStream> stream4 = request4.ReleaseStream();
+ EXPECT_TRUE(stream4.get());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data3.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data4.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data4.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, PublicResetPostHandshakeTwoOfTwo) {
+ factory_.set_quic_server_info_factory(&quic_server_info_factory_);
+ QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get());
+ QuicStreamFactoryPeer::SetDisableDiskCache(&factory_, true);
+ QuicStreamFactoryPeer::SetThresholdPublicResetsPostHandshake(&factory_, 2);
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
+ &factory_, host_port_pair_.port()));
+
+ MockRead reads[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+ DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+ socket_data.StopAfter(1);
+
+ DeterministicSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data2);
+ socket_data2.StopAfter(1);
+
+ HostPortPair server2("mail.example.org", kDefaultServerPort);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(&factory_);
+ EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
+
+ QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
+ &factory_, host_port_pair_, is_https_);
+
+ DVLOG(1) << "Created 1st session. Now trigger public reset post handshake";
+ session->connection()->CloseConnection(QUIC_PUBLIC_RESET, true);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_EQ(1,
+ QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ // Test two-in-a-row public reset post handshakes..
+ DVLOG(1) << "Create 2nd session and trigger public reset post handshake";
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(&factory_);
+ EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback2.callback()));
+ QuicClientSession* session2 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_);
+
+ session2->connection()->CloseConnection(QUIC_PUBLIC_RESET, true);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop2;
+ run_loop2.RunUntilIdle();
+ EXPECT_EQ(2,
+ QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(&factory_));
+ EXPECT_TRUE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(QuicClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE,
+ factory_.QuicDisabledReason(host_port_pair_.port()));
+
+ scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+ EXPECT_TRUE(stream.get());
+ scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+ EXPECT_TRUE(stream2.get());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, TimeoutsWithOpenStreamsTwoOfTwo) {
+ factory_.set_quic_server_info_factory(&quic_server_info_factory_);
+ QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get());
+ QuicStreamFactoryPeer::SetDisableDiskCache(&factory_, true);
+ QuicStreamFactoryPeer::SetThresholdTimeoutsWithOpenStreams(&factory_, 2);
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
+ &factory_, host_port_pair_.port()));
+
+ MockRead reads[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+ DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+ socket_data.StopAfter(1);
+
+ DeterministicSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data2);
+ socket_data2.StopAfter(1);
+
+ HostPortPair server2("mail.example.org", kDefaultServerPort);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(&factory_);
+ EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
+
+ QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
+ &factory_, host_port_pair_, is_https_);
+
+ scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+ EXPECT_TRUE(stream.get());
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ DVLOG(1)
+ << "Created 1st session and initialized a stream. Now trigger timeout";
+ session->connection()->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ // Test two-in-a-row timeouts with open streams.
+ DVLOG(1) << "Create 2nd session and timeout with open stream";
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(&factory_);
+ EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback2.callback()));
+ QuicClientSession* session2 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_);
+
+ scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+ EXPECT_TRUE(stream2.get());
+ EXPECT_EQ(OK, stream2->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ session2->connection()->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop2;
+ run_loop2.RunUntilIdle();
+ EXPECT_EQ(2, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(&factory_));
+ EXPECT_TRUE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(QuicClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS,
+ factory_.QuicDisabledReason(host_port_pair_.port()));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, PublicResetPostHandshakeTwoOfThree) {
+ factory_.set_quic_server_info_factory(&quic_server_info_factory_);
+ QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get());
+ QuicStreamFactoryPeer::SetDisableDiskCache(&factory_, true);
+ QuicStreamFactoryPeer::SetThresholdPublicResetsPostHandshake(&factory_, 2);
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
+ &factory_, host_port_pair_.port()));
+
+ MockRead reads[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+ DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+ socket_data.StopAfter(1);
+
+ DeterministicSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data2);
+ socket_data2.StopAfter(1);
+
+ DeterministicSocketData socket_data3(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data3);
+ socket_data3.StopAfter(1);
+
+ HostPortPair server2("mail.example.org", kDefaultServerPort);
+ HostPortPair server3("docs.example.org", kDefaultServerPort);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
+
+ // Test first and third out of three public reset post handshakes.
+ QuicStreamRequest request(&factory_);
+ EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
+
+ QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
+ &factory_, host_port_pair_, is_https_);
+
+ DVLOG(1) << "Created 1st session. Now trigger public reset post handshake";
+ session->connection()->CloseConnection(QUIC_PUBLIC_RESET, true);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_EQ(1,
+ QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ DVLOG(1) << "Create 2nd session without disable trigger";
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(&factory_);
+ EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback2.callback()));
+ QuicClientSession* session2 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_);
+
+ session2->connection()->CloseConnection(QUIC_NO_ERROR, false);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop2;
+ run_loop2.RunUntilIdle();
+ EXPECT_EQ(1,
+ QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ DVLOG(1) << "Create 3rd session with public reset post handshake,"
+ << " will disable QUIC";
+ TestCompletionCallback callback3;
+ QuicStreamRequest request3(&factory_);
+ EXPECT_EQ(OK, request3.Request(server3, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server3.host(), "GET",
+ net_log_, callback3.callback()));
+ QuicClientSession* session3 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server3, is_https_);
+
+ session3->connection()->CloseConnection(QUIC_PUBLIC_RESET, true);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop3;
+ run_loop3.RunUntilIdle();
+ EXPECT_EQ(2,
+ QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(&factory_));
+ EXPECT_TRUE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(QuicClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE,
+ factory_.QuicDisabledReason(host_port_pair_.port()));
+
+ scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+ EXPECT_TRUE(stream.get());
+ scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+ EXPECT_TRUE(stream2.get());
+ scoped_ptr<QuicHttpStream> stream3 = request3.ReleaseStream();
+ EXPECT_TRUE(stream3.get());
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data3.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, TimeoutsWithOpenStreamsTwoOfThree) {
+ factory_.set_quic_server_info_factory(&quic_server_info_factory_);
+ QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get());
+ QuicStreamFactoryPeer::SetDisableDiskCache(&factory_, true);
+ QuicStreamFactoryPeer::SetThresholdTimeoutsWithOpenStreams(&factory_, 2);
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
+ &factory_, host_port_pair_.port()));
+
+ MockRead reads[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+ DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+ socket_data.StopAfter(1);
+
+ // DeterministicSocketData socket_data2(nullptr, 0, nullptr, 0);
+ DeterministicSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data2);
+ socket_data2.StopAfter(1);
+
+ DeterministicSocketData socket_data3(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data3);
+ socket_data3.StopAfter(1);
+
+ HostPortPair server2("mail.example.org", kDefaultServerPort);
+ HostPortPair server3("docs.example.org", kDefaultServerPort);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
+
+ // Test first and third out of three timeouts with open streams.
+ QuicStreamRequest request(&factory_);
+ EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
+
+ QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
+ &factory_, host_port_pair_, is_https_);
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ DVLOG(1)
+ << "Created 1st session and initialized a stream. Now trigger timeout";
+ session->connection()->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ // Test two-in-a-row timeouts with open streams.
+ DVLOG(1) << "Create 2nd session without timeout";
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(&factory_);
+ EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback2.callback()));
+ QuicClientSession* session2 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_);
+
+ session2->connection()->CloseConnection(QUIC_NO_ERROR, true);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop2;
+ run_loop2.RunUntilIdle();
+ EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ DVLOG(1) << "Create 3rd session with timeout with open streams,"
+ << " will disable QUIC";
+
+ TestCompletionCallback callback3;
+ QuicStreamRequest request3(&factory_);
+ EXPECT_EQ(OK, request3.Request(server3, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server3.host(), "GET",
+ net_log_, callback3.callback()));
+ QuicClientSession* session3 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server3, is_https_);
+
+ scoped_ptr<QuicHttpStream> stream3 = request3.ReleaseStream();
+ EXPECT_TRUE(stream3.get());
+ EXPECT_EQ(OK, stream3->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+ session3->connection()->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop3;
+ run_loop3.RunUntilIdle();
+ EXPECT_EQ(2, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(&factory_));
+ EXPECT_TRUE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(QuicClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS,
+ factory_.QuicDisabledReason(host_port_pair_.port()));
+
+ scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+ EXPECT_TRUE(stream2.get());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data3.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, PublicResetPostHandshakeTwoOfFour) {
+ factory_.set_quic_server_info_factory(&quic_server_info_factory_);
+ QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get());
+ QuicStreamFactoryPeer::SetDisableDiskCache(&factory_, true);
+ QuicStreamFactoryPeer::SetThresholdPublicResetsPostHandshake(&factory_, 2);
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
+ &factory_, host_port_pair_.port()));
+
+ MockRead reads[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+ DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+ socket_data.StopAfter(1);
+
+ DeterministicSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data2);
+ socket_data2.StopAfter(1);
+
+ DeterministicSocketData socket_data3(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data3);
+ socket_data3.StopAfter(1);
+
+ DeterministicSocketData socket_data4(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data4);
+ socket_data4.StopAfter(1);
+
+ HostPortPair server2("mail.example.org", kDefaultServerPort);
+ HostPortPair server3("docs.example.org", kDefaultServerPort);
+ HostPortPair server4("images.example.org", kDefaultServerPort);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server4.host(), "192.168.0.1", "");
+
+ // Test first and fourth out of four public reset post handshakes.
+ QuicStreamRequest request(&factory_);
+ EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
+
+ QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
+ &factory_, host_port_pair_, is_https_);
+
+ DVLOG(1) << "Created 1st session. Now trigger public reset post handshake";
+ session->connection()->CloseConnection(QUIC_PUBLIC_RESET, true);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_EQ(1,
+ QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ DVLOG(1) << "Create 2nd and 3rd sessions without disable trigger";
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(&factory_);
+ EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback2.callback()));
+ QuicClientSession* session2 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_);
+
+ session2->connection()->CloseConnection(QUIC_NO_ERROR, false);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop2;
+ run_loop2.RunUntilIdle();
+ EXPECT_EQ(1,
+ QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ TestCompletionCallback callback3;
+ QuicStreamRequest request3(&factory_);
+ EXPECT_EQ(OK, request3.Request(server3, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server3.host(), "GET",
+ net_log_, callback3.callback()));
+ QuicClientSession* session3 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server3, is_https_);
+
+ session3->connection()->CloseConnection(QUIC_NO_ERROR, false);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop3;
+ run_loop3.RunUntilIdle();
+ EXPECT_EQ(1,
+ QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ DVLOG(1) << "Create 4rd session with public reset post handshake,"
+ << " will not disable QUIC";
+ TestCompletionCallback callback4;
+ QuicStreamRequest request4(&factory_);
+ EXPECT_EQ(OK, request4.Request(server4, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server4.host(), "GET",
+ net_log_, callback4.callback()));
+ QuicClientSession* session4 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server4, is_https_);
+
+ session4->connection()->CloseConnection(QUIC_PUBLIC_RESET, true);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop4;
+ run_loop4.RunUntilIdle();
+ EXPECT_EQ(1,
+ QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+ EXPECT_TRUE(stream.get());
+ scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+ EXPECT_TRUE(stream2.get());
+ scoped_ptr<QuicHttpStream> stream3 = request3.ReleaseStream();
+ EXPECT_TRUE(stream3.get());
+ scoped_ptr<QuicHttpStream> stream4 = request4.ReleaseStream();
+ EXPECT_TRUE(stream4.get());
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data3.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data4.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data4.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, TimeoutsWithOpenStreamsTwoOfFour) {
+ factory_.set_quic_server_info_factory(&quic_server_info_factory_);
+ QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get());
+ QuicStreamFactoryPeer::SetDisableDiskCache(&factory_, true);
+ QuicStreamFactoryPeer::SetThresholdTimeoutsWithOpenStreams(&factory_, 2);
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
+ &factory_, host_port_pair_.port()));
+
+ MockRead reads[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+ DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+ socket_data.StopAfter(1);
+
+ // DeterministicSocketData socket_data2(nullptr, 0, nullptr, 0);
+ DeterministicSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data2);
+ socket_data2.StopAfter(1);
+
+ DeterministicSocketData socket_data3(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data3);
+ socket_data3.StopAfter(1);
+
+ DeterministicSocketData socket_data4(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data4);
+ socket_data4.StopAfter(1);
+
+ HostPortPair server2("mail.example.org", kDefaultServerPort);
+ HostPortPair server3("docs.example.org", kDefaultServerPort);
+ HostPortPair server4("images.example.org", kDefaultServerPort);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server4.host(), "192.168.0.1", "");
+
+ // Test first and fourth out of three timeouts with open streams.
+ QuicStreamRequest request(&factory_);
+ EXPECT_EQ(OK, request.Request(host_port_pair_, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
+
+ QuicClientSession* session = QuicStreamFactoryPeer::GetActiveSession(
+ &factory_, host_port_pair_, is_https_);
+
+ scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+ EXPECT_TRUE(stream.get());
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ DVLOG(1)
+ << "Created 1st session and initialized a stream. Now trigger timeout";
+ session->connection()->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ DVLOG(1) << "Create 2nd and 3rd sessions without timeout";
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(&factory_);
+ EXPECT_EQ(OK, request2.Request(server2, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server2.host(), "GET",
+ net_log_, callback2.callback()));
+ QuicClientSession* session2 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_);
+
+ session2->connection()->CloseConnection(QUIC_NO_ERROR, true);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop2;
+ run_loop2.RunUntilIdle();
+ EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ TestCompletionCallback callback3;
+ QuicStreamRequest request3(&factory_);
+ EXPECT_EQ(OK, request3.Request(server3, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server3.host(), "GET",
+ net_log_, callback3.callback()));
+ QuicClientSession* session3 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server3, is_https_);
+
+ session3->connection()->CloseConnection(QUIC_NO_ERROR, true);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop3;
+ run_loop3.RunUntilIdle();
+ EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
+ DVLOG(1) << "Create 4th session with timeout with open streams,"
+ << " will not disable QUIC";
+
+ TestCompletionCallback callback4;
+ QuicStreamRequest request4(&factory_);
+ EXPECT_EQ(OK, request4.Request(server4, is_https_, privacy_mode_,
+ /*cert_verify_flags=*/0, server4.host(), "GET",
+ net_log_, callback4.callback()));
+ QuicClientSession* session4 =
+ QuicStreamFactoryPeer::GetActiveSession(&factory_, server4, is_https_);
+
+ scoped_ptr<QuicHttpStream> stream4 = request4.ReleaseStream();
+ EXPECT_TRUE(stream4.get());
+ EXPECT_EQ(OK, stream4->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+ session4->connection()->CloseConnection(QUIC_CONNECTION_TIMED_OUT, false);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop4;
+ run_loop4.RunUntilIdle();
+ EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(&factory_));
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsQuicDisabled(&factory_, host_port_pair_.port()));
+
scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
EXPECT_TRUE(stream2.get());
scoped_ptr<QuicHttpStream> stream3 = request3.ReleaseStream();
EXPECT_TRUE(stream3.get());
- EXPECT_TRUE(socket_data.at_read_eof());
- EXPECT_TRUE(socket_data.at_write_eof());
- EXPECT_TRUE(socket_data2.at_read_eof());
- EXPECT_TRUE(socket_data2.at_write_eof());
- EXPECT_TRUE(socket_data3.at_read_eof());
- EXPECT_TRUE(socket_data3.at_write_eof());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data3.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data4.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data4.AllWriteDataConsumed());
}
} // namespace test
diff --git a/chromium/net/quic/quic_stream_sequencer.cc b/chromium/net/quic/quic_stream_sequencer.cc
index 6ca6352f4d5..b9b7ad32700 100644
--- a/chromium/net/quic/quic_stream_sequencer.cc
+++ b/chromium/net/quic/quic_stream_sequencer.cc
@@ -45,8 +45,8 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
return;
}
- QuicStreamOffset byte_offset = frame.offset;
- size_t data_len = frame.data.TotalBufferSize();
+ const QuicStreamOffset byte_offset = frame.offset;
+ const size_t data_len = frame.data.length();
if (data_len == 0 && !frame.fin) {
// Stream frames must have data or a fin flag.
stream_->CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME,
@@ -61,23 +61,17 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
}
}
- IOVector data;
- data.AppendIovec(frame.data.iovec(), frame.data.Size());
-
if (byte_offset > num_bytes_consumed_) {
++num_early_frames_received_;
}
// If the frame has arrived in-order then we can process it immediately, only
// buffering if the stream is unable to process it.
+ size_t bytes_consumed = 0;
if (!blocked_ && byte_offset == num_bytes_consumed_) {
DVLOG(1) << "Processing byte offset " << byte_offset;
- size_t bytes_consumed = 0;
- for (size_t i = 0; i < data.Size(); ++i) {
- bytes_consumed += stream_->ProcessRawData(
- static_cast<char*>(data.iovec()[i].iov_base),
- data.iovec()[i].iov_len);
- }
+ bytes_consumed =
+ stream_->ProcessRawData(frame.data.data(), frame.data.length());
num_bytes_consumed_ += bytes_consumed;
stream_->AddBytesConsumed(bytes_consumed);
@@ -90,24 +84,18 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
} else if (bytes_consumed == data_len) {
FlushBufferedFrames();
return; // it's safe to ack this frame.
- } else {
- // Set ourselves up to buffer what's left.
- data_len -= bytes_consumed;
- data.Consume(bytes_consumed);
- byte_offset += bytes_consumed;
}
}
// Buffer any remaining data to be consumed by the stream when ready.
- for (size_t i = 0; i < data.Size(); ++i) {
+ if (bytes_consumed < data_len) {
DVLOG(1) << "Buffering stream data at offset " << byte_offset;
- const iovec& iov = data.iovec()[i];
+ const size_t remaining_length = data_len - bytes_consumed;
buffered_frames_.insert(std::make_pair(
- byte_offset, string(static_cast<char*>(iov.iov_base), iov.iov_len)));
- byte_offset += iov.iov_len;
- num_bytes_buffered_ += iov.iov_len;
+ byte_offset + bytes_consumed,
+ string(frame.data.data() + bytes_consumed, remaining_length)));
+ num_bytes_buffered_ += remaining_length;
}
- return;
}
void QuicStreamSequencer::CloseStreamAtOffset(QuicStreamOffset offset) {
@@ -140,9 +128,9 @@ bool QuicStreamSequencer::MaybeCloseStream() {
return false;
}
-int QuicStreamSequencer::GetReadableRegions(iovec* iov, size_t iov_len) {
+int QuicStreamSequencer::GetReadableRegions(iovec* iov, size_t iov_len) const {
DCHECK(!blocked_);
- FrameMap::iterator it = buffered_frames_.begin();
+ FrameMap::const_iterator it = buffered_frames_.begin();
size_t index = 0;
QuicStreamOffset offset = num_bytes_consumed_;
while (it != buffered_frames_.end() && index < iov_len) {
@@ -227,9 +215,9 @@ bool QuicStreamSequencer::FrameOverlapsBufferedData(
// If there is a buffered frame with a higher starting offset, then we check
// to see if the new frame runs into the higher frame.
if (next_frame != buffered_frames_.end() &&
- (frame.offset + frame.data.TotalBufferSize()) > next_frame->first) {
+ (frame.offset + frame.data.size()) > next_frame->first) {
DVLOG(1) << "New frame overlaps next frame: " << frame.offset << " + "
- << frame.data.TotalBufferSize() << " > " << next_frame->first;
+ << frame.data.size() << " > " << next_frame->first;
return true;
}
@@ -248,6 +236,37 @@ bool QuicStreamSequencer::FrameOverlapsBufferedData(
return false;
}
+void QuicStreamSequencer::MarkConsumed(size_t num_bytes_consumed) {
+ DCHECK(!blocked_);
+ size_t end_offset = num_bytes_consumed_ + num_bytes_consumed;
+ while (!buffered_frames_.empty() && end_offset != num_bytes_consumed_) {
+ FrameMap::iterator it = buffered_frames_.begin();
+ if (it->first != num_bytes_consumed_) {
+ LOG(DFATAL) << "Invalid argument to MarkConsumed. "
+ << " num_bytes_consumed_: " << num_bytes_consumed_
+ << " end_offset: " << end_offset << " offset: " << it->first
+ << " length: " << it->second.length();
+ stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
+ return;
+ }
+
+ if (it->first + it->second.length() <= end_offset) {
+ num_bytes_consumed_ += it->second.length();
+ num_bytes_buffered_ -= it->second.length();
+ // This chunk is entirely consumed.
+ buffered_frames_.erase(it);
+ continue;
+ }
+
+ // Partially consume this frame.
+ size_t delta = end_offset - it->first;
+ RecordBytesConsumed(delta);
+ buffered_frames_.insert(make_pair(end_offset, it->second.substr(delta)));
+ buffered_frames_.erase(it);
+ break;
+ }
+}
+
bool QuicStreamSequencer::IsDuplicate(const QuicStreamFrame& frame) const {
// A frame is duplicate if the frame offset is smaller than our bytes consumed
// or we have stored the frame in our map.
diff --git a/chromium/net/quic/quic_stream_sequencer.h b/chromium/net/quic/quic_stream_sequencer.h
index 3570d3b86cc..87eff0d8aa9 100644
--- a/chromium/net/quic/quic_stream_sequencer.h
+++ b/chromium/net/quic/quic_stream_sequencer.h
@@ -40,25 +40,22 @@ class NET_EXPORT_PRIVATE QuicStreamSequencer {
// Fills in up to iov_len iovecs with the next readable regions. Returns the
// number of iovs used. Non-destructive of the underlying data.
- int GetReadableRegions(iovec* iov, size_t iov_len);
+ int GetReadableRegions(iovec* iov, size_t iov_len) const;
// Copies the data into the iov_len buffers provided. Returns the number of
// bytes read. Any buffered data no longer in use will be released.
int Readv(const struct iovec* iov, size_t iov_len);
+ // Consumes |num_bytes| data. Used in conjunction with |GetReadableRegions|
+ // to do zero-copy reads.
+ void MarkConsumed(size_t num_bytes);
+
// Returns true if the sequncer has bytes available for reading.
bool HasBytesToRead() const;
// Returns true if the sequencer has delivered the fin.
bool IsClosed() const;
- // Returns true if the sequencer has received this frame before.
- bool IsDuplicate(const QuicStreamFrame& frame) const;
-
- // Returns true if |frame| contains data which overlaps buffered data
- // (indicating an invalid stream frame has been received).
- bool FrameOverlapsBufferedData(const QuicStreamFrame& frame) const;
-
// Calls |ProcessRawData| on |stream_| for each buffered frame that may
// be processed.
void FlushBufferedFrames();
@@ -80,6 +77,13 @@ class NET_EXPORT_PRIVATE QuicStreamSequencer {
private:
friend class test::QuicStreamSequencerPeer;
+ // Returns true if |frame| contains data which overlaps buffered data
+ // (indicating an invalid stream frame has been received).
+ bool FrameOverlapsBufferedData(const QuicStreamFrame& frame) const;
+
+ // Returns true if the sequencer has received this frame before.
+ bool IsDuplicate(const QuicStreamFrame& frame) const;
+
// Wait until we've seen 'offset' bytes, and then terminate the stream.
void CloseStreamAtOffset(QuicStreamOffset offset);
@@ -104,7 +108,7 @@ class NET_EXPORT_PRIVATE QuicStreamSequencer {
// bytes, and gaps.
typedef std::map<QuicStreamOffset, std::string> FrameMap;
- // Stores buffered frames (maps from sequence number -> frame data as string).
+ // Stores buffered frames (maps from byte offset -> frame data as string).
FrameMap buffered_frames_;
// The offset, if any, we got a stream termination for. When this many bytes
diff --git a/chromium/net/quic/quic_stream_sequencer_test.cc b/chromium/net/quic/quic_stream_sequencer_test.cc
index e15f3d3e67d..ed0e780b5cd 100644
--- a/chromium/net/quic/quic_stream_sequencer_test.cc
+++ b/chromium/net/quic/quic_stream_sequencer_test.cc
@@ -64,9 +64,31 @@ class QuicStreamSequencerTest : public ::testing::Test {
: connection_(new MockConnection(Perspective::IS_CLIENT)),
session_(connection_),
stream_(&session_, 1),
- sequencer_(new QuicStreamSequencer(&stream_)),
- buffered_frames_(
- QuicStreamSequencerPeer::GetBufferedFrames(sequencer_.get())) {}
+ sequencer_(new QuicStreamSequencer(&stream_)) {}
+
+ bool VerifyReadableRegions(const char** expected, size_t num_expected) {
+ iovec iovecs[5];
+ size_t num_iovecs =
+ sequencer_->GetReadableRegions(iovecs, arraysize(iovecs));
+ return VerifyIovecs(iovecs, num_iovecs, expected, num_expected);
+ }
+
+ bool VerifyIovecs(iovec* iovecs,
+ size_t num_iovecs,
+ const char** expected,
+ size_t num_expected) {
+ if (num_expected != num_iovecs) {
+ LOG(ERROR) << "Incorrect number of iovecs. Expected: " << num_expected
+ << " Actual: " << num_iovecs;
+ return false;
+ }
+ for (size_t i = 0; i < num_expected; ++i) {
+ if (!VerifyIovec(iovecs[i], expected[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
bool VerifyIovec(const iovec& iovec, StringPiece expected) {
if (iovec.iov_len != expected.length()) {
@@ -86,7 +108,7 @@ class QuicStreamSequencerTest : public ::testing::Test {
QuicStreamFrame frame;
frame.stream_id = 1;
frame.offset = byte_offset;
- frame.data.Append(const_cast<char*>(data), strlen(data));
+ frame.data = StringPiece(data);
frame.fin = true;
sequencer_->OnStreamFrame(frame);
}
@@ -95,47 +117,55 @@ class QuicStreamSequencerTest : public ::testing::Test {
QuicStreamFrame frame;
frame.stream_id = 1;
frame.offset = byte_offset;
- frame.data.Append(const_cast<char*>(data), strlen(data));
+ frame.data = StringPiece(data);
frame.fin = false;
sequencer_->OnStreamFrame(frame);
}
+ size_t NumBufferedFrames() {
+ return QuicStreamSequencerPeer::GetNumBufferedFrames(sequencer_.get());
+ }
+
+ bool FrameOverlapsBufferedData(const QuicStreamFrame& frame) {
+ return QuicStreamSequencerPeer::FrameOverlapsBufferedData(sequencer_.get(),
+ frame);
+ }
+
MockConnection* connection_;
- MockSession session_;
+ MockQuicSpdySession session_;
testing::StrictMock<MockStream> stream_;
scoped_ptr<QuicStreamSequencer> sequencer_;
- map<QuicStreamOffset, string>* buffered_frames_;
};
TEST_F(QuicStreamSequencerTest, RejectOldFrame) {
EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(3));
OnFrame(0, "abc");
- EXPECT_EQ(0u, buffered_frames_->size());
+ EXPECT_EQ(0u, NumBufferedFrames());
EXPECT_EQ(3u, sequencer_->num_bytes_consumed());
// Ignore this - it matches a past sequence number and we should not see it
// again.
OnFrame(0, "def");
- EXPECT_EQ(0u, buffered_frames_->size());
+ EXPECT_EQ(0u, NumBufferedFrames());
}
TEST_F(QuicStreamSequencerTest, RejectBufferedFrame) {
EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3));
OnFrame(0, "abc");
- EXPECT_EQ(1u, buffered_frames_->size());
+ EXPECT_EQ(1u, NumBufferedFrames());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
// Ignore this - it matches a buffered frame.
// Right now there's no checking that the payload is consistent.
OnFrame(0, "def");
- EXPECT_EQ(1u, buffered_frames_->size());
+ EXPECT_EQ(1u, NumBufferedFrames());
}
TEST_F(QuicStreamSequencerTest, FullFrameConsumed) {
EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(3));
OnFrame(0, "abc");
- EXPECT_EQ(0u, buffered_frames_->size());
+ EXPECT_EQ(0u, NumBufferedFrames());
EXPECT_EQ(3u, sequencer_->num_bytes_consumed());
}
@@ -143,12 +173,12 @@ TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameConsumed) {
sequencer_->SetBlockedUntilFlush();
OnFrame(0, "abc");
- EXPECT_EQ(1u, buffered_frames_->size());
+ EXPECT_EQ(1u, NumBufferedFrames());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(3));
sequencer_->FlushBufferedFrames();
- EXPECT_EQ(0u, buffered_frames_->size());
+ EXPECT_EQ(0u, NumBufferedFrames());
EXPECT_EQ(3u, sequencer_->num_bytes_consumed());
EXPECT_CALL(stream_, ProcessRawData(StrEq("def"), 3)).WillOnce(Return(3));
@@ -160,13 +190,13 @@ TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameAndFinConsumed) {
sequencer_->SetBlockedUntilFlush();
OnFinFrame(0, "abc");
- EXPECT_EQ(1u, buffered_frames_->size());
+ EXPECT_EQ(1u, NumBufferedFrames());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(3));
EXPECT_CALL(stream_, OnFinRead());
sequencer_->FlushBufferedFrames();
- EXPECT_EQ(0u, buffered_frames_->size());
+ EXPECT_EQ(0u, NumBufferedFrames());
EXPECT_EQ(3u, sequencer_->num_bytes_consumed());
}
@@ -174,14 +204,14 @@ TEST_F(QuicStreamSequencerTest, EmptyFrame) {
EXPECT_CALL(stream_,
CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME, _));
OnFrame(0, "");
- EXPECT_EQ(0u, buffered_frames_->size());
+ EXPECT_EQ(0u, NumBufferedFrames());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
}
TEST_F(QuicStreamSequencerTest, EmptyFinFrame) {
EXPECT_CALL(stream_, OnFinRead());
OnFinFrame(0, "");
- EXPECT_EQ(0u, buffered_frames_->size());
+ EXPECT_EQ(0u, NumBufferedFrames());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
}
@@ -189,38 +219,35 @@ TEST_F(QuicStreamSequencerTest, PartialFrameConsumed) {
EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(2));
OnFrame(0, "abc");
- EXPECT_EQ(1u, buffered_frames_->size());
+ EXPECT_EQ(1u, NumBufferedFrames());
EXPECT_EQ(2u, sequencer_->num_bytes_consumed());
- EXPECT_EQ("c", buffered_frames_->find(2)->second);
}
TEST_F(QuicStreamSequencerTest, NextxFrameNotConsumed) {
EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(0));
OnFrame(0, "abc");
- EXPECT_EQ(1u, buffered_frames_->size());
+ EXPECT_EQ(1u, NumBufferedFrames());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
- EXPECT_EQ("abc", buffered_frames_->find(0)->second);
EXPECT_EQ(0, sequencer_->num_early_frames_received());
}
TEST_F(QuicStreamSequencerTest, FutureFrameNotProcessed) {
OnFrame(3, "abc");
- EXPECT_EQ(1u, buffered_frames_->size());
+ EXPECT_EQ(1u, NumBufferedFrames());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
- EXPECT_EQ("abc", buffered_frames_->find(3)->second);
EXPECT_EQ(1, sequencer_->num_early_frames_received());
}
TEST_F(QuicStreamSequencerTest, OutOfOrderFrameProcessed) {
// Buffer the first
OnFrame(6, "ghi");
- EXPECT_EQ(1u, buffered_frames_->size());
+ EXPECT_EQ(1u, NumBufferedFrames());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
EXPECT_EQ(3u, sequencer_->num_bytes_buffered());
// Buffer the second
OnFrame(3, "def");
- EXPECT_EQ(2u, buffered_frames_->size());
+ EXPECT_EQ(2u, NumBufferedFrames());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
EXPECT_EQ(6u, sequencer_->num_bytes_buffered());
@@ -234,7 +261,7 @@ TEST_F(QuicStreamSequencerTest, OutOfOrderFrameProcessed) {
EXPECT_EQ(9u, sequencer_->num_bytes_consumed());
EXPECT_EQ(0u, sequencer_->num_bytes_buffered());
- EXPECT_EQ(0u, buffered_frames_->size());
+ EXPECT_EQ(0u, NumBufferedFrames());
}
TEST_F(QuicStreamSequencerTest, BasicHalfCloseOrdered) {
@@ -358,61 +385,126 @@ TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingNoBackup) {
}
}
+// Same as above, just using a different method for reading.
+TEST_F(QuicStreamSequencerTest, MarkConsumed) {
+ InSequence s;
+ EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(0));
+
+ OnFrame(0, "abc");
+ OnFrame(3, "def");
+ OnFrame(6, "ghi");
+
+ // abcdefghi buffered.
+ EXPECT_EQ(9u, sequencer_->num_bytes_buffered());
+
+ // Peek into the data.
+ const char* expected[] = {"abc", "def", "ghi"};
+ ASSERT_TRUE(VerifyReadableRegions(expected, arraysize(expected)));
+
+ // Consume 1 byte.
+ sequencer_->MarkConsumed(1);
+ // Verify data.
+ const char* expected2[] = {"bc", "def", "ghi"};
+ ASSERT_TRUE(VerifyReadableRegions(expected2, arraysize(expected2)));
+ EXPECT_EQ(8u, sequencer_->num_bytes_buffered());
+
+ // Consume 2 bytes.
+ sequencer_->MarkConsumed(2);
+ // Verify data.
+ const char* expected3[] = {"def", "ghi"};
+ ASSERT_TRUE(VerifyReadableRegions(expected3, arraysize(expected3)));
+ EXPECT_EQ(6u, sequencer_->num_bytes_buffered());
+
+ // Consume 5 bytes.
+ sequencer_->MarkConsumed(5);
+ // Verify data.
+ const char* expected4[] = {"i"};
+ ASSERT_TRUE(VerifyReadableRegions(expected4, arraysize(expected4)));
+ EXPECT_EQ(1u, sequencer_->num_bytes_buffered());
+}
+
+TEST_F(QuicStreamSequencerTest, MarkConsumedError) {
+ EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(0));
+
+ OnFrame(0, "abc");
+ OnFrame(9, "jklmnopqrstuvwxyz");
+
+ // Peek into the data. Only the first chunk should be readable because of the
+ // missing data.
+ const char* expected[] = {"abc"};
+ ASSERT_TRUE(VerifyReadableRegions(expected, arraysize(expected)));
+
+ // Now, attempt to mark consumed more data than was readable and expect the
+ // stream to be closed.
+ EXPECT_CALL(stream_, Reset(QUIC_ERROR_PROCESSING_STREAM));
+ EXPECT_DFATAL(sequencer_->MarkConsumed(4),
+ "Invalid argument to MarkConsumed. num_bytes_consumed_: 3 "
+ "end_offset: 4 offset: 9 length: 17");
+}
+
+TEST_F(QuicStreamSequencerTest, MarkConsumedWithMissingPacket) {
+ InSequence s;
+ EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(0));
+
+ OnFrame(0, "abc");
+ OnFrame(3, "def");
+ // Missing packet: 6, ghi.
+ OnFrame(9, "jkl");
+
+ const char* expected[] = {"abc", "def"};
+ ASSERT_TRUE(VerifyReadableRegions(expected, arraysize(expected)));
+
+ sequencer_->MarkConsumed(6);
+}
+
TEST_F(QuicStreamSequencerTest, FrameOverlapsBufferedData) {
// Ensure that FrameOverlapsBufferedData returns appropriate responses when
// there is existing data buffered.
-
- map<QuicStreamOffset, string>* buffered_frames =
- QuicStreamSequencerPeer::GetBufferedFrames(sequencer_.get());
-
const int kBufferedOffset = 10;
const int kBufferedDataLength = 3;
const int kNewDataLength = 3;
- IOVector data = MakeIOVector(string(kNewDataLength, '.'));
+ string data(kNewDataLength, '.');
// No overlap if no buffered frames.
- EXPECT_TRUE(buffered_frames_->empty());
- EXPECT_FALSE(sequencer_->FrameOverlapsBufferedData(
- QuicStreamFrame(1, false, kBufferedOffset - 1, data)));
-
+ EXPECT_EQ(0u, NumBufferedFrames());
// Add a buffered frame.
- buffered_frames->insert(
- std::make_pair(kBufferedOffset, string(kBufferedDataLength, '.')));
+ sequencer_->OnStreamFrame(QuicStreamFrame(1, false, kBufferedOffset,
+ string(kBufferedDataLength, '.')));
// New byte range partially overlaps with buffered frame, start offset
- // preceeding buffered frame.
- EXPECT_TRUE(sequencer_->FrameOverlapsBufferedData(
+ // preceding buffered frame.
+ EXPECT_TRUE(FrameOverlapsBufferedData(
QuicStreamFrame(1, false, kBufferedOffset - 1, data)));
- EXPECT_TRUE(sequencer_->FrameOverlapsBufferedData(
+ EXPECT_TRUE(FrameOverlapsBufferedData(
QuicStreamFrame(1, false, kBufferedOffset - kNewDataLength + 1, data)));
- // New byte range partially overlaps with buffered frame, start offset
- // inside existing buffered frame.
- EXPECT_TRUE(sequencer_->FrameOverlapsBufferedData(
+ // New byte range partially overlaps with buffered frame, start offset inside
+ // existing buffered frame.
+ EXPECT_TRUE(FrameOverlapsBufferedData(
QuicStreamFrame(1, false, kBufferedOffset + 1, data)));
- EXPECT_TRUE(sequencer_->FrameOverlapsBufferedData(QuicStreamFrame(
+ EXPECT_TRUE(FrameOverlapsBufferedData(QuicStreamFrame(
1, false, kBufferedOffset + kBufferedDataLength - 1, data)));
// New byte range entirely outside of buffered frames, start offset preceeding
// buffered frame.
- EXPECT_FALSE(sequencer_->FrameOverlapsBufferedData(
+ EXPECT_FALSE(FrameOverlapsBufferedData(
QuicStreamFrame(1, false, kBufferedOffset - kNewDataLength, data)));
// New byte range entirely outside of buffered frames, start offset later than
// buffered frame.
- EXPECT_FALSE(sequencer_->FrameOverlapsBufferedData(QuicStreamFrame(
- 1, false, kBufferedOffset + kBufferedDataLength, data)));
+ EXPECT_FALSE(FrameOverlapsBufferedData(
+ QuicStreamFrame(1, false, kBufferedOffset + kBufferedDataLength, data)));
}
TEST_F(QuicStreamSequencerTest, DontAcceptOverlappingFrames) {
// The peer should never send us non-identical stream frames which contain
// overlapping byte ranges - if they do, we close the connection.
- QuicStreamFrame frame1(kClientDataStreamId1, false, 1, MakeIOVector("hello"));
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 1, StringPiece("hello"));
sequencer_->OnStreamFrame(frame1);
- QuicStreamFrame frame2(kClientDataStreamId1, false, 2, MakeIOVector("hello"));
- EXPECT_TRUE(sequencer_->FrameOverlapsBufferedData(frame2));
+ QuicStreamFrame frame2(kClientDataStreamId1, false, 2, StringPiece("hello"));
+ EXPECT_TRUE(FrameOverlapsBufferedData(frame2));
EXPECT_CALL(stream_, CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME, _))
.Times(1);
sequencer_->OnStreamFrame(frame2);
diff --git a/chromium/net/quic/quic_time.cc b/chromium/net/quic/quic_time.cc
index 6d3155746fe..7da849ebc01 100644
--- a/chromium/net/quic/quic_time.cc
+++ b/chromium/net/quic/quic_time.cc
@@ -4,12 +4,14 @@
#include "net/quic/quic_time.h"
+#include <stdint.h>
+
#include "base/logging.h"
namespace net {
// Highest number of microseconds that DateTimeOffset can hold.
-const int64 kQuicInfiniteTimeUs = GG_INT64_C(0x7fffffffffffffff) / 10;
+const int64 kQuicInfiniteTimeUs = INT64_C(0x7fffffffffffffff) / 10;
QuicTime::Delta::Delta(base::TimeDelta delta)
: delta_(delta) {
diff --git a/chromium/net/quic/quic_unacked_packet_map.cc b/chromium/net/quic/quic_unacked_packet_map.cc
index 87a733bbd3a..fb5a892af06 100644
--- a/chromium/net/quic/quic_unacked_packet_map.cc
+++ b/chromium/net/quic/quic_unacked_packet_map.cc
@@ -6,19 +6,23 @@
#include "base/logging.h"
#include "base/stl_util.h"
+#include "net/quic/quic_ack_notifier_manager.h"
#include "net/quic/quic_connection_stats.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils_chromium.h"
using std::max;
namespace net {
-QuicUnackedPacketMap::QuicUnackedPacketMap()
+QuicUnackedPacketMap::QuicUnackedPacketMap(
+ AckNotifierManager* ack_notifier_manager)
: largest_sent_packet_(0),
largest_observed_(0),
least_unacked_(1),
bytes_in_flight_(0),
- pending_crypto_packet_count_(0) {
+ pending_crypto_packet_count_(0),
+ ack_notifier_manager_(ack_notifier_manager) {
}
QuicUnackedPacketMap::~QuicUnackedPacketMap() {
@@ -72,11 +76,15 @@ void QuicUnackedPacketMap::AddSentPacket(
void QuicUnackedPacketMap::RemoveObsoletePackets() {
while (!unacked_packets_.empty()) {
- if (!IsPacketRemovable(least_unacked_, unacked_packets_.front())) {
+ if (FLAGS_quic_use_is_useless_packet &&
+ !IsPacketUseless(least_unacked_, unacked_packets_.front())) {
break;
}
- unacked_packets_.pop_front();
- ++least_unacked_;
+ if (!FLAGS_quic_use_is_useless_packet &&
+ !IsPacketRemovable(least_unacked_, unacked_packets_.front())) {
+ break;
+ }
+ PopLeastUnacked();
}
}
@@ -162,8 +170,7 @@ void QuicUnackedPacketMap::ClearAllPreviousRetransmissions() {
}
}
}
- unacked_packets_.pop_front();
- ++least_unacked_;
+ PopLeastUnacked();
}
}
@@ -273,7 +280,7 @@ bool QuicUnackedPacketMap::IsPacketRemovable(
QuicPacketSequenceNumber sequence_number,
const TransmissionInfo& info) const {
return (!IsPacketUsefulForMeasuringRtt(sequence_number, info) ||
- unacked_packets_.size() > kMaxTcpCongestionWindow) &&
+ unacked_packets_.size() > 200) &&
!IsPacketUsefulForCongestionControl(info) &&
!IsPacketUsefulForRetransmittableData(info);
}
@@ -302,10 +309,6 @@ void QuicUnackedPacketMap::RemoveFromInFlight(
void QuicUnackedPacketMap::CancelRetransmissionsForStream(
QuicStreamId stream_id) {
- if (stream_id == kCryptoStreamId || stream_id == kHeadersStreamId) {
- LOG(DFATAL) << "Special streams must always retransmit data: " << stream_id;
- return;
- }
QuicPacketSequenceNumber sequence_number = least_unacked_;
for (UnackedPacketMap::const_iterator it = unacked_packets_.begin();
it != unacked_packets_.end(); ++it, ++sequence_number) {
@@ -391,4 +394,11 @@ QuicPacketSequenceNumber QuicUnackedPacketMap::GetLeastUnacked() const {
return least_unacked_;
}
+void QuicUnackedPacketMap::PopLeastUnacked() {
+ ack_notifier_manager_->OnPacketRemoved(least_unacked_);
+
+ unacked_packets_.pop_front();
+ ++least_unacked_;
+}
+
} // namespace net
diff --git a/chromium/net/quic/quic_unacked_packet_map.h b/chromium/net/quic/quic_unacked_packet_map.h
index 24abfeff11d..106c4cbcf8b 100644
--- a/chromium/net/quic/quic_unacked_packet_map.h
+++ b/chromium/net/quic/quic_unacked_packet_map.h
@@ -11,13 +11,18 @@
namespace net {
+class AckNotifierManager;
+
// Class which tracks unacked packets for three purposes:
// 1) Track retransmittable data, including multiple transmissions of frames.
// 2) Track packets and bytes in flight for congestion control.
// 3) Track sent time of packets to provide RTT measurements from acks.
class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
public:
- QuicUnackedPacketMap();
+ // Initialize an instance of UnackedPacketMap. The AckNotifierManager
+ // provided to the constructor will be notified whenever a packet is removed
+ // from the map.
+ explicit QuicUnackedPacketMap(AckNotifierManager* ack_notifier_manager);
~QuicUnackedPacketMap();
// Adds |serialized_packet| to the map and marks it as sent at |sent_time|.
@@ -158,6 +163,9 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
bool IsPacketRemovable(QuicPacketSequenceNumber sequence_number,
const TransmissionInfo& info) const;
+ // Removes the packet with lowest sequence number from the map.
+ void PopLeastUnacked();
+
QuicPacketSequenceNumber largest_sent_packet_;
QuicPacketSequenceNumber largest_observed_;
@@ -177,6 +185,10 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
// Number of retransmittable crypto handshake packets.
size_t pending_crypto_packet_count_;
+ // Notifier manager for ACK packets. We notify it every time we abandon a
+ // packet.
+ AckNotifierManager* ack_notifier_manager_;
+
DISALLOW_COPY_AND_ASSIGN(QuicUnackedPacketMap);
};
diff --git a/chromium/net/quic/quic_unacked_packet_map_test.cc b/chromium/net/quic/quic_unacked_packet_map_test.cc
index 150bebca4c2..f99e8b1ffba 100644
--- a/chromium/net/quic/quic_unacked_packet_map_test.cc
+++ b/chromium/net/quic/quic_unacked_packet_map_test.cc
@@ -4,6 +4,9 @@
#include "net/quic/quic_unacked_packet_map.h"
+#include "net/quic/quic_ack_notifier_manager.h"
+#include "net/quic/quic_flags.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,8 +24,8 @@ const uint32 kDefaultLength = 1000;
class QuicUnackedPacketMapTest : public ::testing::Test {
protected:
QuicUnackedPacketMapTest()
- : now_(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1000))) {
- }
+ : unacked_packets_(&ack_notifier_manager_),
+ now_(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1000))) {}
~QuicUnackedPacketMapTest() override {
STLDeleteElements(&packets_);
@@ -43,7 +46,7 @@ class QuicUnackedPacketMapTest : public ::testing::Test {
RetransmittableFrames* frames = new RetransmittableFrames(ENCRYPTION_NONE);
QuicStreamFrame* frame = new QuicStreamFrame();
frame->stream_id = stream_id;
- frames->AddStreamFrame(frame);
+ frames->AddFrame(QuicFrame(frame));
return SerializedPacket(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
packets_.back(), 0, frames);
}
@@ -115,6 +118,7 @@ class QuicUnackedPacketMapTest : public ::testing::Test {
}
}
vector<QuicEncryptedPacket*> packets_;
+ AckNotifierManager ack_notifier_manager_;
QuicUnackedPacketMap unacked_packets_;
QuicTime now_;
};
@@ -137,6 +141,7 @@ TEST_F(QuicUnackedPacketMapTest, RttOnly) {
}
TEST_F(QuicUnackedPacketMapTest, DiscardOldRttOnly) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_use_is_useless_packet, false);
// Acks are only tracked for RTT measurement purposes, and are discarded
// when more than 200 accumulate.
const size_t kNumUnackedPackets = 200;
@@ -440,7 +445,6 @@ TEST_F(QuicUnackedPacketMapTest, SendWithGap) {
EXPECT_EQ(5u, unacked_packets_.largest_sent_packet());
}
-
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/quic_utils.cc b/chromium/net/quic/quic_utils.cc
index 9f8b99371d6..32f8c09ce4c 100644
--- a/chromium/net/quic/quic_utils.cc
+++ b/chromium/net/quic/quic_utils.cc
@@ -5,6 +5,7 @@
#include "net/quic/quic_utils.h"
#include <ctype.h>
+#include <stdint.h>
#include <algorithm>
#include <vector>
@@ -12,7 +13,6 @@
#include "base/basictypes.h"
#include "base/containers/adapters.h"
#include "base/logging.h"
-#include "base/port.h"
#include "base/strings/stringprintf.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -25,8 +25,8 @@ namespace net {
// static
uint64 QuicUtils::FNV1a_64_Hash(const char* data, int len) {
- static const uint64 kOffset = GG_UINT64_C(14695981039346656037);
- static const uint64 kPrime = GG_UINT64_C(1099511628211);
+ static const uint64 kOffset = UINT64_C(14695981039346656037);
+ static const uint64 kPrime = UINT64_C(1099511628211);
const uint8* octets = reinterpret_cast<const uint8*>(data);
@@ -53,8 +53,8 @@ uint128 QuicUtils::FNV1a_128_Hash_Two(const char* data1,
// The two constants are defined as part of the hash algorithm.
// see http://www.isthe.com/chongo/tech/comp/fnv/
// 144066263297769815596495629667062367629
- const uint128 kOffset(GG_UINT64_C(7809847782465536322),
- GG_UINT64_C(7113472399480571277));
+ const uint128 kOffset(UINT64_C(7809847782465536322),
+ UINT64_C(7113472399480571277));
uint128 hash = IncrementalHash(kOffset, data1, len1);
if (data2 == nullptr) {
@@ -228,6 +228,9 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS);
RETURN_STRING_LITERAL(QUIC_CONNECTION_CANCELLED);
RETURN_STRING_LITERAL(QUIC_BAD_PACKET_LOSS_RATE);
+ RETURN_STRING_LITERAL(QUIC_PUBLIC_RESETS_POST_HANDSHAKE);
+ RETURN_STRING_LITERAL(QUIC_TIMEOUTS_WITH_OPEN_STREAMS);
+ RETURN_STRING_LITERAL(QUIC_FAILED_TO_SERIALIZE_PACKET);
RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build
// if we add errors and don't put them here.
@@ -292,11 +295,11 @@ string QuicUtils::TagToString(QuicTag tag) {
QuicTagVector QuicUtils::ParseQuicConnectionOptions(
const std::string& connection_options) {
QuicTagVector options;
- std::vector<std::string> tokens;
- base::SplitString(connection_options, ',', &tokens);
// Tokens are expected to be no more than 4 characters long, but we
// handle overflow gracefully.
- for (const std::string& token : tokens) {
+ for (const base::StringPiece& token :
+ base::SplitStringPiece(connection_options, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL)) {
uint32 option = 0;
for (char token_char : base::Reversed(token)) {
option <<= 8;
diff --git a/chromium/net/quic/quic_utils.h b/chromium/net/quic/quic_utils.h
index 46652f20103..fb379e66e71 100644
--- a/chromium/net/quic/quic_utils.h
+++ b/chromium/net/quic/quic_utils.h
@@ -9,6 +9,7 @@
#include <string>
+#include "base/strings/string_piece.h"
#include "net/base/int128.h"
#include "net/base/net_export.h"
#include "net/quic/quic_protocol.h"
@@ -100,11 +101,13 @@ class NET_EXPORT_PRIVATE QuicUtils {
DISALLOW_COPY_AND_ASSIGN(QuicUtils);
};
-// Utility function that returns an IOVector object wrapped around |str|.
-inline IOVector MakeIOVector(base::StringPiece str) {
- IOVector iov;
- iov.Append(const_cast<char*>(str.data()), str.size());
- return iov;
+// Utility function that returns an QuicIOVector object wrapped around |str|.
+// |str|'s data is stored in |iov|.
+inline QuicIOVector MakeIOVector(base::StringPiece str, struct iovec* iov) {
+ iov->iov_base = const_cast<char*>(str.data());
+ iov->iov_len = static_cast<size_t>(str.size());
+ QuicIOVector quic_iov(iov, 1, str.size());
+ return quic_iov;
}
} // namespace net
diff --git a/chromium/net/quic/reliable_quic_stream.cc b/chromium/net/quic/reliable_quic_stream.cc
index 33f14d4a236..924211f8a46 100644
--- a/chromium/net/quic/reliable_quic_stream.cc
+++ b/chromium/net/quic/reliable_quic_stream.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "net/quic/iovector.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_flow_controller.h"
#include "net/quic/quic_session.h"
#include "net/quic/quic_write_blocked_list.h"
@@ -133,18 +134,26 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session)
perspective_,
GetReceivedFlowControlWindow(session),
GetInitialStreamFlowControlWindowToSend(session),
- GetInitialStreamFlowControlWindowToSend(session)),
+ session_->flow_controller()->auto_tune_receive_window()),
connection_flow_controller_(session_->flow_controller()),
stream_contributes_to_connection_flow_control_(true) {
+ SetFromConfig();
}
ReliableQuicStream::~ReliableQuicStream() {
}
+void ReliableQuicStream::SetFromConfig() {
+ if (FLAGS_quic_send_fec_packet_only_on_fec_alarm &&
+ session_->config()->HasClientSentConnectionOption(kFSTR, perspective_)) {
+ fec_policy_ = FEC_PROTECT_ALWAYS;
+ }
+}
+
void ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
if (read_side_closed_) {
DVLOG(1) << ENDPOINT << "Ignoring frame " << frame.stream_id;
- // We don't want to be reading: blackhole the data.
+ // The subclass does not want read data: blackhole the data.
return;
}
@@ -155,16 +164,19 @@ void ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
if (frame.fin) {
fin_received_ = true;
+ if (fin_sent_) {
+ session_->StreamDraining(id_);
+ }
}
- // This count include duplicate data received.
- size_t frame_payload_size = frame.data.TotalBufferSize();
+ // This count includes duplicate data received.
+ size_t frame_payload_size = frame.data.size();
stream_bytes_read_ += frame_payload_size;
// Flow control is interested in tracking highest received offset.
if (MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size)) {
- // As the highest received offset has changed, we should check to see if
- // this is a violation of flow control.
+ // As the highest received offset has changed, check to see if this is a
+ // violation of flow control.
if (flow_controller_.FlowControlViolation() ||
connection_flow_controller_->FlowControlViolation()) {
session_->connection()->SendConnectionClose(
@@ -213,7 +225,12 @@ void ReliableQuicStream::OnConnectionClosed(QuicErrorCode error,
void ReliableQuicStream::OnFinRead() {
DCHECK(sequencer_.IsClosed());
+ // OnFinRead can be called due to a FIN flag in a headers block, so there may
+ // have been no OnStreamFrame call with a FIN in the frame.
fin_received_ = true;
+ // If fin_sent_ is true, then CloseWriteSide has already been called, and the
+ // stream will be destroyed by CloseReadSide, so don't need to call
+ // StreamDraining.
CloseReadSide();
}
@@ -247,6 +264,10 @@ void ReliableQuicStream::WriteOrBufferData(
LOG(DFATAL) << "Fin already buffered";
return;
}
+ if (write_side_closed_) {
+ DLOG(ERROR) << ENDPOINT << "Attempt to write when the write side is closed";
+ return;
+ }
scoped_refptr<ProxyAckNotifierDelegate> proxy_delegate;
if (ack_notifier_delegate != nullptr) {
@@ -325,9 +346,10 @@ void ReliableQuicStream::MaybeSendBlocked() {
return;
}
connection_flow_controller_->MaybeSendBlocked();
- // If we are connection level flow control blocked, then add the stream
- // to the write blocked list. It will be given a chance to write when a
- // connection level WINDOW_UPDATE arrives.
+ // If the stream is blocked by connection-level flow control but not by
+ // stream-level flow control, add the stream to the write blocked list so that
+ // the stream will be given a chance to write when a connection-level
+ // WINDOW_UPDATE arrives.
if (connection_flow_controller_->IsBlocked() &&
!flow_controller_.IsBlocked()) {
session_->MarkWriteBlocked(id(), EffectivePriority());
@@ -344,13 +366,13 @@ QuicConsumedData ReliableQuicStream::WritevData(
return QuicConsumedData(0, false);
}
- // How much data we want to write.
+ // How much data was provided.
size_t write_length = TotalIovecLength(iov, iov_count);
// A FIN with zero data payload should not be flow control blocked.
bool fin_with_zero_data = (fin && write_length == 0);
- // How much data we are allowed to write from flow control.
+ // How much data flow control permits to be written.
QuicByteCount send_window = flow_controller_.SendWindowSize();
if (stream_contributes_to_connection_flow_control_) {
send_window =
@@ -358,26 +380,22 @@ QuicConsumedData ReliableQuicStream::WritevData(
}
if (send_window == 0 && !fin_with_zero_data) {
- // Quick return if we can't send anything.
+ // Quick return if nothing can be sent.
MaybeSendBlocked();
return QuicConsumedData(0, false);
}
if (write_length > send_window) {
- // Don't send the FIN if we aren't going to send all the data.
+ // 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);
}
- // Fill an IOVector with bytes from the iovec.
- IOVector data;
- data.AppendIovecAtMostBytes(iov, iov_count, write_length);
-
QuicConsumedData consumed_data = session()->WritevData(
- id(), data, stream_bytes_written_, fin, GetFecProtection(),
- ack_notifier_delegate);
+ id(), QuicIOVector(iov, iov_count, write_length), stream_bytes_written_,
+ fin, GetFecProtection(), ack_notifier_delegate);
stream_bytes_written_ += consumed_data.bytes_consumed;
AddBytesSent(consumed_data.bytes_consumed);
@@ -388,6 +406,9 @@ QuicConsumedData ReliableQuicStream::WritevData(
}
if (fin && consumed_data.fin_consumed) {
fin_sent_ = true;
+ if (fin_received_) {
+ session_->StreamDraining(id_);
+ }
CloseWriteSide();
} else if (fin && !consumed_data.fin_consumed) {
session_->MarkWriteBlocked(id(), EffectivePriority());
@@ -441,19 +462,19 @@ void ReliableQuicStream::OnClose() {
CloseWriteSide();
if (!fin_sent_ && !rst_sent_) {
- // For flow control accounting, we must tell the peer how many bytes we have
+ // For flow control accounting, tell the peer how many bytes have been
// written on this stream before termination. Done here if needed, using a
- // RST frame.
- DVLOG(1) << ENDPOINT << "Sending RST in OnClose: " << id();
+ // RST_STREAM frame.
+ DVLOG(1) << ENDPOINT << "Sending RST_STREAM in OnClose: " << id();
session_->SendRstStream(id(), QUIC_RST_ACKNOWLEDGEMENT,
stream_bytes_written_);
rst_sent_ = true;
}
- // We are closing the stream and will not process any further incoming bytes.
- // As there may be more bytes in flight and we need to ensure that both
- // endpoints have the same connection level flow control state, mark all
- // unreceived or buffered bytes as consumed.
+ // The stream is being closed and will not process any further incoming bytes.
+ // As there may be more bytes in flight, to ensure that both endpoints have
+ // the same connection level flow control state, mark all unreceived or
+ // buffered bytes as consumed.
QuicByteCount bytes_to_consume =
flow_controller_.highest_received_byte_offset() -
flow_controller_.bytes_consumed();
@@ -463,11 +484,11 @@ void ReliableQuicStream::OnClose() {
void ReliableQuicStream::OnWindowUpdateFrame(
const QuicWindowUpdateFrame& frame) {
if (flow_controller_.UpdateSendWindowOffset(frame.byte_offset)) {
- // We can write again!
+ // Writing can be done again!
// TODO(rjshade): This does not respect priorities (e.g. multiple
// outstanding POSTs are unblocked on arrival of
// SHLO with initial window).
- // As long as the connection is not flow control blocked, we can write!
+ // As long as the connection is not flow control blocked, write on!
OnCanWrite();
}
}
@@ -481,8 +502,8 @@ bool ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(
}
// If |new_offset| increased the stream flow controller's highest received
- // offset, then we need to increase the connection flow controller's value
- // by the incremental difference.
+ // offset, increase the connection flow controller's value by the incremental
+ // difference.
if (stream_contributes_to_connection_flow_control_) {
connection_flow_controller_->UpdateHighestReceivedOffset(
connection_flow_controller_->highest_received_byte_offset() +
@@ -499,7 +520,7 @@ void ReliableQuicStream::AddBytesSent(QuicByteCount bytes) {
}
void ReliableQuicStream::AddBytesConsumed(QuicByteCount bytes) {
- // Only adjust stream level flow controller if we are still reading.
+ // Only adjust stream level flow controller if still reading.
if (!read_side_closed_) {
flow_controller_.AddBytesConsumed(bytes);
}
diff --git a/chromium/net/quic/reliable_quic_stream.h b/chromium/net/quic/reliable_quic_stream.h
index 7a954673685..265e4795a78 100644
--- a/chromium/net/quic/reliable_quic_stream.h
+++ b/chromium/net/quic/reliable_quic_stream.h
@@ -4,6 +4,16 @@
//
// The base class for client/server reliable streams.
+// It does not contain the entire interface needed by an application to interact
+// with a QUIC stream. Some parts of the interface must be obtained by
+// accessing the owning session object. A subclass of ReliableQuicStream
+// connects the object and the application that generates and consumes the data
+// of the stream.
+
+// The ReliableQuicStream object has a dependent QuicStreamSequencer object,
+// which is given the stream frames as they arrive, and provides stream data in
+// order by invoking ProcessRawData().
+
#ifndef NET_QUIC_RELIABLE_QUIC_STREAM_H_
#define NET_QUIC_RELIABLE_QUIC_STREAM_H_
@@ -38,34 +48,53 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
virtual ~ReliableQuicStream();
- // Called when a (potentially duplicate) stream frame has been received
- // for this stream.
+ // Sets |fec_policy_| parameter from |session_|'s config.
+ void SetFromConfig();
+
+ // Called by the session when a (potentially duplicate) stream frame has been
+ // received for this stream.
virtual void OnStreamFrame(const QuicStreamFrame& frame);
- // Called when the connection becomes writeable to allow the stream
- // to write any pending data.
+ // Called by the session when the connection becomes writeable to allow the
+ // stream to write any pending data.
virtual void OnCanWrite();
- // Called by the session just before the stream is deleted.
+ // Called by the session just before the object is destroyed.
+ // The object should not be accessed after OnClose is called.
+ // Sends a RST_STREAM with code QUIC_RST_ACKNOWLEDGEMENT if neither a FIN nor
+ // a RST_STREAM has been sent.
virtual void OnClose();
- // Called when we get a stream reset from the peer.
+ // Called by the session when the endpoint receives a RST_STREAM from the
+ // peer.
virtual void OnStreamReset(const QuicRstStreamFrame& frame);
- // Called when we get or send a connection close, and should immediately
- // close the stream. This is not passed through the sequencer,
- // but is handled immediately.
+ // Called by the session when the endpoint receives or sends a connection
+ // close, and should immediately close the stream.
virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer);
- // Called when the final data has been read.
+ // Called by the sequencer after ProcessRawData has accepted the final
+ // incoming data.
virtual void OnFinRead();
+ // Called by the sequencer to deliver to the subclass blocks of the stream's
+ // data in sequential order.
+ // ProcessRawData is called when the next sequential block of data becomes
+ // available, unless the subclass has left the next block of data in the
+ // sequencer. In that case, the subclass must actively retrieve the data
+ // using the sequencer's Readv() or FlushBufferedFrames().
+ // Return value is the number of data bytes accepted by the callee, i.e.,
+ // the first (return value) bytes of data are removed from the sequencer,
+ // and the final data_len-(return value) bytes of data are retained by the
+ // sequencer.
virtual uint32 ProcessRawData(const char* data, uint32 data_len) = 0;
- // Called to reset the stream from this end.
+ // Called by the subclass or the sequencer to reset the stream from this
+ // end.
virtual void Reset(QuicRstStreamErrorCode error);
- // Called to close the entire connection from this end.
+ // Called by the subclass or the sequencer to close the entire connection from
+ // this end.
virtual void CloseConnection(QuicErrorCode error);
virtual void CloseConnectionWithDetails(QuicErrorCode error,
const std::string& details);
@@ -91,7 +120,7 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
void set_fec_policy(FecPolicy fec_policy) { fec_policy_ = fec_policy; }
FecPolicy fec_policy() const { return fec_policy_; }
- // Adjust our flow control windows according to new offset in |frame|.
+ // Adjust the flow control window according to new offset in |frame|.
virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame);
// Used in Chrome.
@@ -101,13 +130,14 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
QuicFlowController* flow_controller() { return &flow_controller_; }
- // Called when we see a frame which could increase the highest offset.
+ // Called when endpoint receives a frame which could increase the highest
+ // offset.
// Returns true if the highest offset did increase.
bool MaybeIncreaseHighestReceivedOffset(QuicStreamOffset new_offset);
- // Called when bytese are sent to the peer.
+ // Called when bytes are sent to the peer.
void AddBytesSent(QuicByteCount bytes);
// Called by the stream sequencer as bytes are consumed from the buffer.
- // If our receive window has dropped below the threshold, then send a
+ // If the receive window has dropped below the threshold, then send a
// WINDOW_UPDATE frame.
void AddBytesConsumed(QuicByteCount bytes);
@@ -115,10 +145,11 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
// it was blocked before.
void UpdateSendWindowOffset(QuicStreamOffset new_offset);
- // Returns true if we have received either a RST or a FIN - either of which
- // gives a definitive number of bytes which the peer has sent. If this is not
- // true on stream termination the session must keep track of the stream's byte
- // offset until a definitive final value arrives.
+ // Returns true if the stream have received either a RST_STREAM or a FIN -
+ // either of which gives a definitive number of bytes which the peer has
+ // sent. If this is not true on deletion of the stream object, the session
+ // must keep track of the stream's byte offset until a definitive final value
+ // arrives.
bool HasFinalReceivedByteOffset() const {
return fin_received_ || rst_received_;
}
@@ -129,9 +160,13 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
// Returns the version of QUIC being used for this stream.
QuicVersion version() const;
+ bool fin_received() const { return fin_received_; }
+
protected:
// Sends as much of 'data' to the connection as the connection will consume,
// and then buffers any remaining data in queued_data_.
+ // If fin is true: if it is immediately passed on to the session,
+ // write_side_closed() becomes true, otherwise fin_buffered_ becomes true.
void WriteOrBufferData(
base::StringPiece data,
bool fin,
@@ -148,15 +183,19 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
bool fin,
QuicAckNotifier::DelegateInterface* ack_notifier_delegate);
- // Helper method that returns FecProtection to use for writes to the session.
- FecProtection GetFecProtection();
-
- // Close the read side of the socket. Further frames will not be accepted.
+ // Close the read side of the stream. Further incoming stream frames will be
+ // discarded. Can be called by the subclass or internally.
+ // May cause the stream to be closed.
virtual void CloseReadSide();
// Close the write side of the socket. Further writes will fail.
+ // Can be called by the subclass or internally.
+ // Does not send a FIN. May cause the stream to be closed.
void CloseWriteSide();
+ // Helper method that returns FecProtection to use when writing.
+ FecProtection GetFecProtection();
+
bool fin_buffered() const { return fin_buffered_; }
const QuicSession* session() const { return session_; }
@@ -188,15 +227,17 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
scoped_refptr<ProxyAckNotifierDelegate> delegate;
};
- // Calls MaybeSendBlocked on our flow controller, and connection level flow
- // controller. If we are flow control blocked, marks this stream as write
- // blocked.
+ // Calls MaybeSendBlocked on the stream's flow controller and the connection
+ // level flow controller. If the stream is flow control blocked by the
+ // connection-level flow controller but not by the stream-level flow
+ // controller, marks this stream as connection-level write blocked.
void MaybeSendBlocked();
std::list<PendingData> queued_data_;
QuicStreamSequencer sequencer_;
QuicStreamId id_;
+ // Pointer to the owning QuicSession object.
QuicSession* session_;
// Bytes read and written refer to payload bytes only: they do not include
// framing, encryption overhead etc.
@@ -216,18 +257,22 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
// True if the write side is closed, and further writes should fail.
bool write_side_closed_;
+ // True if the subclass has written a FIN with WriteOrBufferData, but it was
+ // buffered in queued_data_ rather than being sent to the session.
bool fin_buffered_;
+ // True if a FIN has been sent to the session.
bool fin_sent_;
// True if this stream has received (and the sequencer has accepted) a
// StreamFrame with the FIN set.
bool fin_received_;
- // In combination with fin_sent_, used to ensure that a FIN and/or a RST is
- // always sent before stream termination.
+ // True if an RST_STREAM has been sent to the session.
+ // In combination with fin_sent_, used to ensure that a FIN and/or a
+ // RST_STREAM is always sent to terminate the stream.
bool rst_sent_;
- // True if this stream has received a RST stream frame.
+ // True if this stream has received a RST_STREAM frame.
bool rst_received_;
// FEC policy to be used for this stream.
diff --git a/chromium/net/quic/reliable_quic_stream_test.cc b/chromium/net/quic/reliable_quic_stream_test.cc
index b17def0d1b4..dbdb7b5d176 100644
--- a/chromium/net/quic/reliable_quic_stream_test.cc
+++ b/chromium/net/quic/reliable_quic_stream_test.cc
@@ -6,6 +6,7 @@
#include "net/quic/quic_ack_notifier.h"
#include "net/quic/quic_connection.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils.h"
#include "net/quic/quic_write_blocked_list.h"
#include "net/quic/spdy_utils.h"
@@ -22,6 +23,7 @@
using base::StringPiece;
using std::min;
using std::string;
+using testing::AnyNumber;
using testing::CreateFunctor;
using testing::InSequence;
using testing::Invoke;
@@ -39,6 +41,7 @@ const char kData1[] = "FooAndBar";
const char kData2[] = "EepAndBaz";
const size_t kDataLen = 9;
const bool kShouldProcessData = true;
+const bool kShouldNotProcessData = false;
class TestStream : public ReliableQuicStream {
public:
@@ -107,21 +110,26 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
void Initialize(bool stream_should_process_data) {
connection_ = new StrictMock<MockConnection>(Perspective::IS_SERVER,
supported_versions_);
- session_.reset(new StrictMock<MockSession>(connection_));
+ session_.reset(new StrictMock<MockQuicSpdySession>(connection_));
// New streams rely on having the peer's flow control receive window
// negotiated in the config.
QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(
session_->config(), initial_flow_control_window_bytes_);
- stream_.reset(new TestStream(kHeadersStreamId, session_.get(),
- stream_should_process_data));
+ stream_ = new TestStream(kTestStreamId, session_.get(),
+ stream_should_process_data);
+ // session_ now owns stream_.
+ session_->ActivateStream(stream_);
+ // Ignore resetting when session_ is terminated.
+ EXPECT_CALL(*session_, SendRstStream(kTestStreamId, _, _))
+ .Times(AnyNumber());
write_blocked_list_ =
QuicSessionPeer::GetWriteBlockedStreams(session_.get());
}
- bool fin_sent() { return ReliableQuicStreamPeer::FinSent(stream_.get()); }
- bool rst_sent() { return ReliableQuicStreamPeer::RstSent(stream_.get()); }
+ bool fin_sent() { return ReliableQuicStreamPeer::FinSent(stream_); }
+ bool rst_sent() { return ReliableQuicStreamPeer::RstSent(stream_); }
void set_initial_flow_control_window_bytes(uint32 val) {
initial_flow_control_window_bytes_ = val;
@@ -134,13 +142,14 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
protected:
MockConnection* connection_;
- scoped_ptr<MockSession> session_;
- scoped_ptr<TestStream> stream_;
+ scoped_ptr<MockQuicSpdySession> session_;
+ TestStream* stream_;
SpdyHeaderBlock headers_;
QuicWriteBlockedList* write_blocked_list_;
uint32 initial_flow_control_window_bytes_;
QuicTime::Delta zero_;
QuicVersionVector supported_versions_;
+ const QuicStreamId kTestStreamId = 5u;
};
TEST_F(ReliableQuicStreamTest, WriteAllData) {
@@ -149,10 +158,10 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) {
size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead(
PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, 0u, NOT_IN_FEC_GROUP);
- QuicConnectionPeer::GetPacketCreator(connection_)->SetMaxPacketLength(length);
+ connection_->set_max_packet_length(length);
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(kDataLen, true)));
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kDataLen, true)));
stream_->WriteOrBufferData(kData1, false, nullptr);
EXPECT_FALSE(HasWriteBlockedStreams());
}
@@ -171,7 +180,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfOnlySomeDataConsumed) {
// Write some data and no fin. If we consume some but not all of the data,
// we should be write blocked a not all the data was consumed.
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(1, false)));
stream_->WriteOrBufferData(StringPiece(kData1, 2), false, nullptr);
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
@@ -184,7 +193,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfFinNotConsumedWithData) {
// we should be write blocked because the fin was not consumed.
// (This should never actually happen as the fin should be sent out with the
// last data)
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(2, false)));
stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr);
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
@@ -195,7 +204,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfSoloFinNotConsumed) {
// Write no data and a fin. If we consume nothing we should be write blocked,
// as the fin was not consumed.
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(0, false)));
stream_->WriteOrBufferData(StringPiece(), true, nullptr);
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
@@ -208,7 +217,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferData) {
size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead(
PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, 0u, NOT_IN_FEC_GROUP);
- QuicConnectionPeer::GetPacketCreator(connection_)->SetMaxPacketLength(length);
+ connection_->set_max_packet_length(length);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen - 1, false)));
@@ -236,13 +245,13 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithFecProtectAlways) {
Initialize(kShouldProcessData);
// Set FEC policy on stream.
- ReliableQuicStreamPeer::SetFecPolicy(stream_.get(), FEC_PROTECT_ALWAYS);
+ ReliableQuicStreamPeer::SetFecPolicy(stream_, FEC_PROTECT_ALWAYS);
EXPECT_FALSE(HasWriteBlockedStreams());
size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead(
PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, 0u, IN_FEC_GROUP);
- QuicConnectionPeer::GetPacketCreator(connection_)->SetMaxPacketLength(length);
+ connection_->set_max_packet_length(length);
// Write first data onto stream, which will cause one session write.
EXPECT_CALL(*session_, WritevData(_, _, _, _, MUST_FEC_PROTECT, _)).WillOnce(
@@ -271,14 +280,13 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithFecProtectOptional) {
Initialize(kShouldProcessData);
// Set FEC policy on stream.
- ReliableQuicStreamPeer::SetFecPolicy(stream_.get(), FEC_PROTECT_OPTIONAL);
+ ReliableQuicStreamPeer::SetFecPolicy(stream_, FEC_PROTECT_OPTIONAL);
EXPECT_FALSE(HasWriteBlockedStreams());
size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead(
PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, 0u, NOT_IN_FEC_GROUP);
- QuicConnectionPeer::GetPacketCreator(connection_)->SetMaxPacketLength(
- length);
+ connection_->set_max_packet_length(length);
// Write first data onto stream, which will cause one session write.
EXPECT_CALL(*session_, WritevData(_, _, _, _, MAY_FEC_PROTECT, _)).WillOnce(
@@ -325,7 +333,7 @@ TEST_F(ReliableQuicStreamTest, RstAlwaysSentIfNoFinSent) {
EXPECT_FALSE(rst_sent());
// Write some data, with no FIN.
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(1, false)));
stream_->WriteOrBufferData(StringPiece(kData1, 1), false, nullptr);
EXPECT_FALSE(fin_sent());
@@ -348,7 +356,7 @@ TEST_F(ReliableQuicStreamTest, RstNotSentIfFinSent) {
EXPECT_FALSE(rst_sent());
// Write some data, with FIN.
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(1, true)));
stream_->WriteOrBufferData(StringPiece(kData1, 1), true, nullptr);
EXPECT_TRUE(fin_sent());
@@ -442,7 +450,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(DoAll(WithArgs<5>(Invoke(CreateFunctor(
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(kFirstWriteSize, false))));
@@ -450,23 +458,23 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) {
EXPECT_TRUE(HasWriteBlockedStreams());
EXPECT_CALL(*session_,
- WritevData(kHeadersStreamId, _, _, _, _, proxy_delegate.get()))
+ WritevData(kTestStreamId, _, _, _, _, proxy_delegate.get()))
.WillOnce(Return(QuicConsumedData(kSecondWriteSize, false)));
stream_->OnCanWrite();
// No ack expected for an empty write.
EXPECT_CALL(*session_,
- WritevData(kHeadersStreamId, _, _, _, _, proxy_delegate.get()))
+ WritevData(kTestStreamId, _, _, _, _, proxy_delegate.get()))
.WillOnce(Return(QuicConsumedData(0, false)));
stream_->OnCanWrite();
EXPECT_CALL(*session_,
- WritevData(kHeadersStreamId, _, _, _, _, proxy_delegate.get()))
+ WritevData(kTestStreamId, _, _, _, _, proxy_delegate.get()))
.WillOnce(Return(QuicConsumedData(kLastWriteSize, false)));
stream_->OnCanWrite();
- // There were two writes, so OnAckNotification is not propagated
- // until the third Ack arrives.
+ // There were two writes, so OnAckNotification is not propagated until the
+ // third Ack arrives.
proxy_delegate->OnAckNotification(3, 4, zero_);
proxy_delegate->OnAckNotification(30, 40, zero_);
@@ -476,8 +484,8 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) {
proxy_delegate->OnAckNotification(300, 400, zero_);
}
-// Verify delegate behavior when packets are acked before the
-// WritevData call that sends out the last byte.
+// Verify delegate behavior when packets are acked before the WritevData call
+// that sends out the last byte.
TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) {
Initialize(kShouldProcessData);
@@ -495,7 +503,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(DoAll(WithArgs<5>(Invoke(CreateFunctor(
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(kInitialWriteSize, false))));
@@ -506,10 +514,11 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) {
proxy_delegate->OnAckNotification(3, 4, zero_);
proxy_delegate = nullptr;
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _)).WillOnce(
- DoAll(WithArgs<5>(Invoke(CreateFunctor(
- &SaveProxyAckNotifierDelegate, &proxy_delegate))),
- Return(QuicConsumedData(kDataSize - kInitialWriteSize, false))));
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
+ .WillOnce(DoAll(
+ WithArgs<5>(Invoke(
+ CreateFunctor(&SaveProxyAckNotifierDelegate, &proxy_delegate))),
+ Return(QuicConsumedData(kDataSize - kInitialWriteSize, false))));
stream_->OnCanWrite();
// Handle the ack for the second write.
@@ -526,7 +535,7 @@ TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferNoBuffer) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(DoAll(WithArgs<5>(Invoke(CreateFunctor(
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(kDataLen, true))));
@@ -547,12 +556,12 @@ TEST_F(ReliableQuicStreamTest, BufferOnWriteAndBufferDataWithAckNotifer) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(0, false)));
stream_->WriteOrBufferData(kData1, true, delegate.get());
EXPECT_TRUE(HasWriteBlockedStreams());
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(DoAll(WithArgs<5>(Invoke(CreateFunctor(
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(kDataLen, true))));
@@ -573,14 +582,14 @@ TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferOnlyFinRemains) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(DoAll(WithArgs<5>(Invoke(CreateFunctor(
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(kDataLen, false))));
stream_->WriteOrBufferData(kData1, true, delegate.get());
EXPECT_TRUE(HasWriteBlockedStreams());
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _, _))
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
.WillOnce(DoAll(WithArgs<5>(Invoke(CreateFunctor(
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(0, true))));
@@ -603,7 +612,7 @@ TEST_F(ReliableQuicStreamTest,
// higher than the receive window offset.
QuicStreamFrame frame(stream_->id(), false,
kInitialSessionFlowControlWindowForTest + 1,
- MakeIOVector("."));
+ StringPiece("."));
EXPECT_GT(frame.offset, QuicFlowControllerPeer::ReceiveWindowOffset(
stream_->flow_controller()));
@@ -619,12 +628,12 @@ TEST_F(ReliableQuicStreamTest, FinalByteOffsetFromFin) {
EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
QuicStreamFrame stream_frame_no_fin(stream_->id(), false, 1234,
- MakeIOVector("."));
+ StringPiece("."));
stream_->OnStreamFrame(stream_frame_no_fin);
EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234,
- MakeIOVector("."));
+ StringPiece("."));
stream_->OnStreamFrame(stream_frame_with_fin);
EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
}
@@ -638,6 +647,71 @@ TEST_F(ReliableQuicStreamTest, FinalByteOffsetFromRst) {
EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
}
+TEST_F(ReliableQuicStreamTest, SetDrainingIncomingOutgoing) {
+ // Don't have incoming data consumed.
+ Initialize(kShouldNotProcessData);
+
+ // Incoming data with FIN.
+ QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234,
+ StringPiece("."));
+ stream_->OnStreamFrame(stream_frame_with_fin);
+ // The FIN has been received but not consumed.
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+ EXPECT_FALSE(stream_->read_side_closed());
+
+ EXPECT_EQ(1u, session_->GetNumOpenStreams());
+
+ // Outgoing data with FIN.
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(2, true)));
+ stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr);
+ EXPECT_TRUE(stream_->write_side_closed());
+
+ EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get())
+ ->count(kTestStreamId));
+ EXPECT_EQ(0u, session_->GetNumOpenStreams());
+}
+
+TEST_F(ReliableQuicStreamTest, SetDrainingOutgoingIncoming) {
+ // Don't have incoming data consumed.
+ Initialize(kShouldNotProcessData);
+
+ // Outgoing data with FIN.
+ EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(2, true)));
+ stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr);
+ EXPECT_TRUE(stream_->write_side_closed());
+
+ EXPECT_EQ(1u, session_->GetNumOpenStreams());
+
+ // Incoming data with FIN.
+ QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234,
+ StringPiece("."));
+ stream_->OnStreamFrame(stream_frame_with_fin);
+ // The FIN has been received but not consumed.
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+ EXPECT_FALSE(stream_->read_side_closed());
+
+ EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get())
+ ->count(kTestStreamId));
+ EXPECT_EQ(0u, session_->GetNumOpenStreams());
+}
+
+TEST_F(ReliableQuicStreamTest, FecSendPolicyReceivedConnectionOption) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_send_fec_packet_only_on_fec_alarm,
+ true);
+ Initialize(kShouldProcessData);
+
+ // Test ReceivedConnectionOptions.
+ QuicConfig* config = session_->config();
+ QuicTagVector copt;
+ copt.push_back(kFSTR);
+ QuicConfigPeer::SetReceivedConnectionOptions(config, copt);
+ EXPECT_EQ(FEC_PROTECT_OPTIONAL, stream_->fec_policy());
+ stream_->SetFromConfig();
+ EXPECT_EQ(FEC_PROTECT_ALWAYS, stream_->fec_policy());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/spdy_utils.cc b/chromium/net/quic/spdy_utils.cc
index 4ebae318f55..c03d5887cfe 100644
--- a/chromium/net/quic/spdy_utils.cc
+++ b/chromium/net/quic/spdy_utils.cc
@@ -17,7 +17,7 @@ namespace net {
SpdyMajorVersion SpdyUtils::GetSpdyVersionForQuicVersion(
QuicVersion quic_version) {
if (quic_version > QUIC_VERSION_24) {
- return SPDY4;
+ return HTTP2;
}
return SPDY3;
}
@@ -39,7 +39,7 @@ string SpdyUtils::SerializeUncompressedHeaders(const SpdyHeaderBlock& headers,
QuicVersion quic_version) {
SpdyMajorVersion spdy_version = GetSpdyVersionForQuicVersion(quic_version);
- int length = SpdyFramer::GetSerializedLength(spdy_version, &headers);
+ size_t length = SpdyFramer::GetSerializedLength(spdy_version, &headers);
SpdyFrameBuilder builder(length, spdy_version);
SpdyFramer::WriteHeaderBlock(&builder, spdy_version, &headers);
scoped_ptr<SpdyFrame> block(builder.take());
diff --git a/chromium/net/quic/test_tools/crypto_test_utils.cc b/chromium/net/quic/test_tools/crypto_test_utils.cc
index f402256e112..811da803f1a 100644
--- a/chromium/net/quic/test_tools/crypto_test_utils.cc
+++ b/chromium/net/quic/test_tools/crypto_test_utils.cc
@@ -90,11 +90,8 @@ void MovePackets(PacketSavingConnection* source_conn,
break;
}
- for (vector<QuicStreamFrame>::const_iterator
- i = framer.stream_frames().begin();
- i != framer.stream_frames().end(); ++i) {
- scoped_ptr<string> frame_data(i->GetDataAsString());
- ASSERT_TRUE(crypto_framer.ProcessInput(*frame_data));
+ for (const QuicStreamFrame& stream_frame : framer.stream_frames()) {
+ ASSERT_TRUE(crypto_framer.ProcessInput(stream_frame.data));
ASSERT_FALSE(crypto_visitor.error());
}
}
@@ -104,10 +101,8 @@ void MovePackets(PacketSavingConnection* source_conn,
ASSERT_EQ(0u, crypto_framer.InputBytesRemaining());
- for (vector<CryptoHandshakeMessage>::const_iterator
- i = crypto_visitor.messages().begin();
- i != crypto_visitor.messages().end(); ++i) {
- dest_stream->OnHandshakeMessage(*i);
+ for (const CryptoHandshakeMessage& message : crypto_visitor.messages()) {
+ dest_stream->OnHandshakeMessage(message);
}
}
@@ -186,25 +181,23 @@ int CryptoTestUtils::HandshakeWithFakeServer(
QuicCryptoClientStream* client) {
PacketSavingConnection* server_conn = new PacketSavingConnection(
Perspective::IS_SERVER, client_conn->supported_versions());
- TestSession server_session(server_conn, DefaultQuicConfig());
- server_session.InitializeSession();
+
+ QuicConfig config = DefaultQuicConfig();
QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING,
QuicRandom::GetInstance());
+ SetupCryptoServerConfigForTest(server_conn->clock(),
+ server_conn->random_generator(), &config,
+ &crypto_config);
- SetupCryptoServerConfigForTest(
- server_session.connection()->clock(),
- server_session.connection()->random_generator(),
- server_session.config(), &crypto_config);
-
- QuicCryptoServerStream server(&crypto_config, &server_session);
- server_session.SetCryptoStream(&server);
+ TestQuicSpdyServerSession server_session(server_conn, config, &crypto_config);
// The client's handshake must have been started already.
CHECK_NE(0u, client_conn->encrypted_packets_.size());
- CommunicateHandshakeMessages(client_conn, client, server_conn, &server);
+ CommunicateHandshakeMessages(client_conn, client, server_conn,
+ server_session.GetCryptoStream());
- CompareClientAndServerKeys(client, &server);
+ CompareClientAndServerKeys(client, server_session.GetCryptoStream());
return client->num_sent_client_hellos();
}
@@ -218,14 +211,8 @@ int CryptoTestUtils::HandshakeWithFakeClient(
new PacketSavingConnection(Perspective::IS_CLIENT);
// Advance the time, because timers do not like uninitialized times.
client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
- TestClientSession client_session(client_conn, DefaultQuicConfig());
- QuicCryptoClientConfig crypto_config;
- if (!options.dont_verify_certs) {
- // TODO(wtc): replace this with ProofVerifierForTesting() when we have
- // a working ProofSourceForTesting().
- crypto_config.SetProofVerifier(FakeProofVerifierForTesting());
- }
+ QuicCryptoClientConfig crypto_config;
bool is_https = false;
AsyncTestChannelIDSource* async_channel_id_source = nullptr;
if (options.channel_id_enabled) {
@@ -240,18 +227,22 @@ int CryptoTestUtils::HandshakeWithFakeClient(
}
QuicServerId server_id(kServerHostname, kServerPort, is_https,
PRIVACY_MODE_DISABLED);
- QuicCryptoClientStream client(server_id, &client_session,
- ProofVerifyContextForTesting(),
- &crypto_config);
- client_session.SetCryptoStream(&client);
+ if (!options.dont_verify_certs) {
+ // TODO(wtc): replace this with ProofVerifierForTesting() when we have
+ // a working ProofSourceForTesting().
+ crypto_config.SetProofVerifier(FakeProofVerifierForTesting());
+ }
+ TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
+ server_id, &crypto_config);
- client.CryptoConnect();
+ client_session.GetCryptoStream()->CryptoConnect();
CHECK_EQ(1u, client_conn->encrypted_packets_.size());
CommunicateHandshakeMessagesAndRunCallbacks(
- client_conn, &client, server_conn, server, async_channel_id_source);
+ client_conn, client_session.GetCryptoStream(), server_conn, server,
+ async_channel_id_source);
- CompareClientAndServerKeys(&client, server);
+ CompareClientAndServerKeys(client_session.GetCryptoStream(), server);
if (options.channel_id_enabled) {
scoped_ptr<ChannelIDKey> channel_id_key;
@@ -260,11 +251,12 @@ int CryptoTestUtils::HandshakeWithFakeClient(
EXPECT_EQ(QUIC_SUCCESS, status);
EXPECT_EQ(channel_id_key->SerializeKey(),
server->crypto_negotiated_params().channel_id);
- EXPECT_EQ(options.channel_id_source_async,
- client.WasChannelIDSourceCallbackRun());
+ EXPECT_EQ(
+ options.channel_id_source_async,
+ client_session.GetCryptoStream()->WasChannelIDSourceCallbackRun());
}
- return client.num_sent_client_hellos();
+ return client_session.GetCryptoStream()->num_sent_client_hellos();
}
// static
diff --git a/chromium/net/quic/test_tools/crypto_test_utils_nss.cc b/chromium/net/quic/test_tools/crypto_test_utils_nss.cc
index f42775003fa..946b0531824 100644
--- a/chromium/net/quic/test_tools/crypto_test_utils_nss.cc
+++ b/chromium/net/quic/test_tools/crypto_test_utils_nss.cc
@@ -35,10 +35,10 @@ class TestChannelIDSource : public ChannelIDSource {
private:
typedef std::map<string, crypto::ECPrivateKey*> HostnameToKeyMap;
- crypto::ECPrivateKey* HostnameToKey(const string& hostname) {
+ scoped_ptr<crypto::ECPrivateKey> HostnameToKey(const string& hostname) {
HostnameToKeyMap::const_iterator it = hostname_to_key_.find(hostname);
if (it != hostname_to_key_.end()) {
- return it->second->Copy();
+ return make_scoped_ptr(it->second->Copy());
}
crypto::ECPrivateKey* keypair = crypto::ECPrivateKey::Create();
@@ -46,7 +46,7 @@ class TestChannelIDSource : public ChannelIDSource {
return nullptr;
}
hostname_to_key_[hostname] = keypair;
- return keypair->Copy();
+ return make_scoped_ptr(keypair->Copy());
}
HostnameToKeyMap hostname_to_key_;
diff --git a/chromium/net/quic/test_tools/mock_crypto_client_stream.cc b/chromium/net/quic/test_tools/mock_crypto_client_stream.cc
index 0018e91eb9c..290693933fd 100644
--- a/chromium/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/chromium/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -38,8 +38,8 @@ void MockCryptoClientStream::CryptoConnect() {
case ZERO_RTT: {
encryption_established_ = true;
handshake_confirmed_ = false;
- session()->connection()->SetDecrypter(QuicDecrypter::Create(kNULL),
- ENCRYPTION_INITIAL);
+ session()->connection()->SetDecrypter(ENCRYPTION_INITIAL,
+ QuicDecrypter::Create(kNULL));
session()->OnCryptoHandshakeEvent(
QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
break;
@@ -54,8 +54,8 @@ void MockCryptoClientStream::CryptoConnect() {
client_session()->OnProofVerifyDetailsAvailable(*proof_verify_details_);
}
SetConfigNegotiated();
- session()->connection()->SetDecrypter(QuicDecrypter::Create(kNULL),
- ENCRYPTION_FORWARD_SECURE);
+ session()->connection()->SetDecrypter(ENCRYPTION_FORWARD_SECURE,
+ QuicDecrypter::Create(kNULL));
session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
break;
}
diff --git a/chromium/net/quic/test_tools/quic_ack_notifier_manager_peer.cc b/chromium/net/quic/test_tools/quic_ack_notifier_manager_peer.cc
new file mode 100644
index 00000000000..3e7f90cb652
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_ack_notifier_manager_peer.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2015 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/test_tools/quic_ack_notifier_manager_peer.h"
+
+#include "net/quic/quic_ack_notifier_manager.h"
+
+namespace net {
+namespace test {
+
+size_t AckNotifierManagerPeer::GetNumberOfRegisteredPackets(
+ const AckNotifierManager* manager) {
+ return manager->ack_notifier_map_.size();
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_ack_notifier_manager_peer.h b/chromium/net/quic/test_tools/quic_ack_notifier_manager_peer.h
new file mode 100644
index 00000000000..ea128d3af24
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_ack_notifier_manager_peer.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2015 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_TEST_TOOLS_QUIC_ACK_NOTIFIER_MANAGER_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_ACK_NOTIFIER_MANAGER_PEER_H_
+
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+class AckNotifierManager;
+
+namespace test {
+
+// Exposes the internal fields of AckNotifierManager for tests.
+class AckNotifierManagerPeer {
+ public:
+ // Returns total number of packets known to the map.
+ static size_t GetNumberOfRegisteredPackets(const AckNotifierManager* manager);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AckNotifierManagerPeer);
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_ACK_NOTIFIER_MANAGER_PEER_H_
diff --git a/chromium/net/quic/test_tools/quic_connection_peer.cc b/chromium/net/quic/test_tools/quic_connection_peer.cc
index 3525a3247ef..df7d9e78e27 100644
--- a/chromium/net/quic/test_tools/quic_connection_peer.cc
+++ b/chromium/net/quic/test_tools/quic_connection_peer.cc
@@ -185,6 +185,12 @@ QuicAlarm* QuicConnectionPeer::GetTimeoutAlarm(QuicConnection* connection) {
}
// static
+QuicAlarm* QuicConnectionPeer::GetMtuDiscoveryAlarm(
+ QuicConnection* connection) {
+ return connection->mtu_discovery_alarm_.get();
+}
+
+// static
QuicPacketWriter* QuicConnectionPeer::GetWriter(QuicConnection* connection) {
return connection->writer_;
}
diff --git a/chromium/net/quic/test_tools/quic_connection_peer.h b/chromium/net/quic/test_tools/quic_connection_peer.h
index 88b05f034e7..56762757234 100644
--- a/chromium/net/quic/test_tools/quic_connection_peer.h
+++ b/chromium/net/quic/test_tools/quic_connection_peer.h
@@ -94,6 +94,7 @@ class QuicConnectionPeer {
static QuicAlarm* GetRetransmissionAlarm(QuicConnection* connection);
static QuicAlarm* GetSendAlarm(QuicConnection* connection);
static QuicAlarm* GetTimeoutAlarm(QuicConnection* connection);
+ static QuicAlarm* GetMtuDiscoveryAlarm(QuicConnection* connection);
static QuicPacketWriter* GetWriter(QuicConnection* connection);
// If |owns_writer| is true, takes ownership of |writer|.
diff --git a/chromium/net/quic/test_tools/quic_flow_controller_peer.cc b/chromium/net/quic/test_tools/quic_flow_controller_peer.cc
index d6a10987773..602aaf83808 100644
--- a/chromium/net/quic/test_tools/quic_flow_controller_peer.cc
+++ b/chromium/net/quic/test_tools/quic_flow_controller_peer.cc
@@ -30,7 +30,7 @@ void QuicFlowControllerPeer::SetReceiveWindowOffset(
void QuicFlowControllerPeer::SetMaxReceiveWindow(
QuicFlowController* flow_controller,
QuicByteCount window_size) {
- flow_controller->max_receive_window_ = window_size;
+ flow_controller->receive_window_size_ = window_size;
}
// static
@@ -58,5 +58,11 @@ QuicByteCount QuicFlowControllerPeer::ReceiveWindowSize(
flow_controller->highest_received_byte_offset_;
}
+// static
+QuicByteCount QuicFlowControllerPeer::WindowUpdateThreshold(
+ QuicFlowController* flow_controller) {
+ return flow_controller->WindowUpdateThreshold();
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_flow_controller_peer.h b/chromium/net/quic/test_tools/quic_flow_controller_peer.h
index 4270d96f1e3..3d7c9d00d30 100644
--- a/chromium/net/quic/test_tools/quic_flow_controller_peer.h
+++ b/chromium/net/quic/test_tools/quic_flow_controller_peer.h
@@ -33,6 +33,9 @@ class QuicFlowControllerPeer {
static QuicByteCount ReceiveWindowSize(QuicFlowController* flow_controller);
+ static QuicByteCount WindowUpdateThreshold(
+ QuicFlowController* flow_controller);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicFlowControllerPeer);
};
diff --git a/chromium/net/quic/test_tools/quic_framer_peer.cc b/chromium/net/quic/test_tools/quic_framer_peer.cc
index d477a808e6f..577a71ce475 100644
--- a/chromium/net/quic/test_tools/quic_framer_peer.cc
+++ b/chromium/net/quic/test_tools/quic_framer_peer.cc
@@ -25,17 +25,20 @@ void QuicFramerPeer::SetLastSerializedConnectionId(
framer->last_serialized_connection_id_ = connection_id;
}
+// static
void QuicFramerPeer::SetLastSequenceNumber(
QuicFramer* framer,
QuicPacketSequenceNumber packet_sequence_number) {
framer->last_sequence_number_ = packet_sequence_number;
}
+// static
void QuicFramerPeer::SetPerspective(QuicFramer* framer,
Perspective perspective) {
framer->perspective_ = perspective;
}
+// static
void QuicFramerPeer::SwapCrypters(QuicFramer* framer1, QuicFramer* framer2) {
for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; i++) {
framer1->encrypter_[i].swap(framer2->encrypter_[i]);
@@ -57,7 +60,7 @@ void QuicFramerPeer::SwapCrypters(QuicFramer* framer1, QuicFramer* framer2) {
framer1->alternative_decrypter_latch_ = framer2_latch;
}
-// static.
+// static
QuicEncrypter* QuicFramerPeer::GetEncrypter(QuicFramer* framer,
EncryptionLevel level) {
return framer->encrypter_[level].get();
diff --git a/chromium/net/quic/test_tools/quic_framer_peer.h b/chromium/net/quic/test_tools/quic_framer_peer.h
index 57818701cf9..2896e770563 100644
--- a/chromium/net/quic/test_tools/quic_framer_peer.h
+++ b/chromium/net/quic/test_tools/quic_framer_peer.h
@@ -6,12 +6,11 @@
#define NET_QUIC_TEST_TOOLS_QUIC_FRAMER_PEER_H_
#include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/quic_framer.h"
#include "net/quic/quic_protocol.h"
namespace net {
-class QuicFramer;
-
namespace test {
class QuicFramerPeer {
diff --git a/chromium/net/quic/test_tools/quic_session_peer.cc b/chromium/net/quic/test_tools/quic_session_peer.cc
index 7dd7b66df9d..c1f86198c02 100644
--- a/chromium/net/quic/test_tools/quic_session_peer.cc
+++ b/chromium/net/quic/test_tools/quic_session_peer.cc
@@ -4,6 +4,7 @@
#include "net/quic/test_tools/quic_session_peer.h"
+#include "base/stl_util.h"
#include "net/quic/quic_session.h"
#include "net/quic/reliable_quic_stream.h"
@@ -29,27 +30,16 @@ QuicCryptoStream* QuicSessionPeer::GetCryptoStream(QuicSession* session) {
}
// static
-QuicHeadersStream* QuicSessionPeer::GetHeadersStream(QuicSession* session) {
- return session->headers_stream_.get();
-}
-
-// static
-void QuicSessionPeer::SetHeadersStream(QuicSession* session,
- QuicHeadersStream* headers_stream) {
- session->headers_stream_.reset(headers_stream);
-}
-
-// static
QuicWriteBlockedList* QuicSessionPeer::GetWriteBlockedStreams(
QuicSession* session) {
return &session->write_blocked_streams_;
}
// static
-QuicDataStream* QuicSessionPeer::GetIncomingDataStream(
+ReliableQuicStream* QuicSessionPeer::GetIncomingDynamicStream(
QuicSession* session,
QuicStreamId stream_id) {
- return session->GetIncomingDataStream(stream_id);
+ return session->GetIncomingDynamicStream(stream_id);
}
// static
@@ -58,5 +48,42 @@ QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(QuicSession* session) {
return session->locally_closed_streams_highest_offset_;
}
+// static
+base::hash_set<QuicStreamId>* QuicSessionPeer::GetDrainingStreams(
+ QuicSession* session) {
+ return &session->draining_streams_;
+}
+
+// static
+bool QuicSessionPeer::IsStreamClosed(QuicSession* session, QuicStreamId id) {
+ DCHECK_NE(0u, id);
+ return session->IsClosedStream(id);
+}
+
+// static
+bool QuicSessionPeer::IsStreamCreated(QuicSession* session, QuicStreamId id) {
+ DCHECK_NE(0u, id);
+ return ContainsKey(session->dynamic_streams(), id);
+}
+
+// static
+bool QuicSessionPeer::IsStreamImplicitlyCreated(QuicSession* session,
+ QuicStreamId id) {
+ DCHECK_NE(0u, id);
+ return ContainsKey(session->implicitly_created_streams_, id);
+}
+
+// static
+bool QuicSessionPeer::IsStreamUncreated(QuicSession* session, QuicStreamId id) {
+ DCHECK_NE(0u, id);
+ if (id % 2 == session->next_stream_id_ % 2) {
+ // locally-created stream.
+ return id >= session->next_stream_id_;
+ } else {
+ // peer-created stream.
+ return id > session->largest_peer_created_stream_id_;
+ }
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_session_peer.h b/chromium/net/quic/test_tools/quic_session_peer.h
index 4a88c88fba0..9f4f0110901 100644
--- a/chromium/net/quic/test_tools/quic_session_peer.h
+++ b/chromium/net/quic/test_tools/quic_session_peer.h
@@ -7,6 +7,7 @@
#include <map>
+#include "base/containers/hash_tables.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_write_blocked_list.h"
@@ -16,6 +17,7 @@ class QuicCryptoStream;
class QuicDataStream;
class QuicHeadersStream;
class QuicSession;
+class ReliableQuicStream;
namespace test {
@@ -24,20 +26,26 @@ class QuicSessionPeer {
static void SetNextStreamId(QuicSession* session, QuicStreamId id);
static void SetMaxOpenStreams(QuicSession* session, uint32 max_streams);
static QuicCryptoStream* GetCryptoStream(QuicSession* session);
- static QuicHeadersStream* GetHeadersStream(QuicSession* session);
- static void SetHeadersStream(QuicSession* session,
- QuicHeadersStream* headers_stream);
static QuicWriteBlockedList* GetWriteBlockedStreams(QuicSession* session);
- static QuicDataStream* GetIncomingDataStream(QuicSession* session,
- QuicStreamId stream_id);
+ static ReliableQuicStream* GetIncomingDynamicStream(QuicSession* session,
+ QuicStreamId stream_id);
static std::map<QuicStreamId, QuicStreamOffset>&
GetLocallyClosedStreamsHighestOffset(QuicSession* session);
+ static base::hash_set<QuicStreamId>* GetDrainingStreams(QuicSession* session);
+
+ // Discern the state of a stream. Exactly one of these should be true at a
+ // time for any stream id > 0 (other than the special streams 1 and 3).
+ static bool IsStreamClosed(QuicSession* session, QuicStreamId id);
+ static bool IsStreamCreated(QuicSession* session, QuicStreamId id);
+ static bool IsStreamImplicitlyCreated(QuicSession* session, QuicStreamId id);
+ static bool IsStreamUncreated(QuicSession* session, QuicStreamId id);
private:
DISALLOW_COPY_AND_ASSIGN(QuicSessionPeer);
};
} // namespace test
+
} // namespace net
#endif // NET_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_
diff --git a/chromium/net/quic/test_tools/quic_spdy_session_peer.cc b/chromium/net/quic/test_tools/quic_spdy_session_peer.cc
new file mode 100644
index 00000000000..e13e477b05c
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_spdy_session_peer.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2015 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/test_tools/quic_spdy_session_peer.h"
+
+#include "net/quic/quic_spdy_session.h"
+
+namespace net {
+namespace test {
+
+// static
+QuicHeadersStream* QuicSpdySessionPeer::GetHeadersStream(
+ QuicSpdySession* session) {
+ return session->headers_stream_.get();
+}
+
+// static
+void QuicSpdySessionPeer::SetHeadersStream(QuicSpdySession* session,
+ QuicHeadersStream* headers_stream) {
+ session->headers_stream_.reset(headers_stream);
+ session->static_streams()[headers_stream->id()] = headers_stream;
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_spdy_session_peer.h b/chromium/net/quic/test_tools/quic_spdy_session_peer.h
new file mode 100644
index 00000000000..840f3dcb2c2
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_spdy_session_peer.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 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_TEST_TOOLS_QUIC_SPDY_SESSION_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_SPDY_SESSION_PEER_H_
+
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_write_blocked_list.h"
+
+namespace net {
+
+class QuicHeadersStream;
+class QuicSpdySession;
+
+namespace test {
+
+class QuicSpdySessionPeer {
+ public:
+ static QuicHeadersStream* GetHeadersStream(QuicSpdySession* session);
+ static void SetHeadersStream(QuicSpdySession* session,
+ QuicHeadersStream* headers_stream);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicSpdySessionPeer);
+};
+
+} // namespace test
+
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_SPDY_SESSION_PEER_H_
diff --git a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc
index 08a5c5b0720..43db645e6de 100644
--- a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc
+++ b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc
@@ -13,9 +13,16 @@ namespace net {
namespace test {
// static
-map<QuicStreamOffset, string>* QuicStreamSequencerPeer::GetBufferedFrames(
+size_t QuicStreamSequencerPeer::GetNumBufferedFrames(
QuicStreamSequencer* sequencer) {
- return &(sequencer->buffered_frames_);
+ return sequencer->buffered_frames_.size();
+}
+
+// static
+bool QuicStreamSequencerPeer::FrameOverlapsBufferedData(
+ QuicStreamSequencer* sequencer,
+ const QuicStreamFrame& frame) {
+ return sequencer->FrameOverlapsBufferedData(frame);
}
// static
diff --git a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h
index 7b2b28aad46..22e3a9908b7 100644
--- a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h
+++ b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h
@@ -16,8 +16,10 @@ namespace test {
class QuicStreamSequencerPeer {
public:
- static std::map<QuicStreamOffset, std::string>* GetBufferedFrames(
- QuicStreamSequencer* sequencer);
+ static size_t GetNumBufferedFrames(QuicStreamSequencer* sequencer);
+
+ static bool FrameOverlapsBufferedData(QuicStreamSequencer* sequencer,
+ const QuicStreamFrame& frame);
static QuicStreamOffset GetCloseOffset(QuicStreamSequencer* sequencer);
diff --git a/chromium/net/quic/test_tools/quic_test_packet_maker.cc b/chromium/net/quic/test_tools/quic_test_packet_maker.cc
index 2ac6b405d27..63c9ac6761f 100644
--- a/chromium/net/quic/test_tools/quic_test_packet_maker.cc
+++ b/chromium/net/quic/test_tools/quic_test_packet_maker.cc
@@ -24,8 +24,8 @@ QuicTestPacketMaker::QuicTestPacketMaker(QuicVersion version,
connection_id_(connection_id),
clock_(clock),
host_(host),
- spdy_request_framer_(SPDY4),
- spdy_response_framer_(SPDY4) {
+ spdy_request_framer_(HTTP2),
+ spdy_response_framer_(HTTP2) {
}
QuicTestPacketMaker::~QuicTestPacketMaker() {
@@ -94,8 +94,8 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket(
BuildUnsizedDataPacket(&framer, header, frames));
char buffer[kMaxPacketSize];
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
- *packet, buffer, kMaxPacketSize));
+ framer.EncryptPayload(ENCRYPTION_NONE, header.packet_sequence_number,
+ *packet, buffer, kMaxPacketSize));
EXPECT_TRUE(encrypted != nullptr);
return scoped_ptr<QuicEncryptedPacket>(encrypted->Clone());
}
@@ -152,8 +152,8 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket(
BuildUnsizedDataPacket(&framer, header, frames));
char buffer[kMaxPacketSize];
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
- *packet, buffer, kMaxPacketSize));
+ framer.EncryptPayload(ENCRYPTION_NONE, header.packet_sequence_number,
+ *packet, buffer, kMaxPacketSize));
EXPECT_TRUE(encrypted != nullptr);
return scoped_ptr<QuicEncryptedPacket>(encrypted->Clone());
}
@@ -167,7 +167,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeDataPacket(
QuicStreamOffset offset,
base::StringPiece data) {
InitializeHeader(sequence_number, should_include_version);
- QuicStreamFrame frame(stream_id, fin, offset, MakeIOVector(data));
+ QuicStreamFrame frame(stream_id, fin, offset, data);
return MakePacket(header_, QuicFrame(&frame));
}
@@ -194,9 +194,9 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket(
headers_frame.set_has_priority(true);
spdy_frame.reset(spdy_request_framer_.SerializeFrame(headers_frame));
}
- QuicStreamFrame frame(kHeadersStreamId, false, 0,
- MakeIOVector(base::StringPiece(spdy_frame->data(),
- spdy_frame->size())));
+ QuicStreamFrame frame(
+ kHeadersStreamId, false, 0,
+ base::StringPiece(spdy_frame->data(), spdy_frame->size()));
return MakePacket(header_, QuicFrame(&frame));
}
@@ -219,9 +219,9 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket(
headers_frame.set_fin(fin);
spdy_frame.reset(spdy_request_framer_.SerializeFrame(headers_frame));
}
- QuicStreamFrame frame(kHeadersStreamId, false, 0,
- MakeIOVector(base::StringPiece(spdy_frame->data(),
- spdy_frame->size())));
+ QuicStreamFrame frame(
+ kHeadersStreamId, false, 0,
+ base::StringPiece(spdy_frame->data(), spdy_frame->size()));
return MakePacket(header_, QuicFrame(&frame));
}
@@ -266,8 +266,8 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakePacket(
BuildUnsizedDataPacket(&framer, header, frames));
char buffer[kMaxPacketSize];
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
- *packet, buffer, kMaxPacketSize));
+ framer.EncryptPayload(ENCRYPTION_NONE, header.packet_sequence_number,
+ *packet, buffer, kMaxPacketSize));
EXPECT_TRUE(encrypted != nullptr);
return scoped_ptr<QuicEncryptedPacket>(encrypted->Clone());
}
diff --git a/chromium/net/quic/test_tools/quic_test_utils.cc b/chromium/net/quic/test_tools/quic_test_utils.cc
index 676a37dcac8..db45d15ab1d 100644
--- a/chromium/net/quic/test_tools/quic_test_utils.cc
+++ b/chromium/net/quic/test_tools/quic_test_utils.cc
@@ -17,6 +17,7 @@
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/spdy/spdy_frame_builder.h"
#include "net/tools/quic/quic_per_connection_packet_writer.h"
@@ -337,56 +338,50 @@ void PacketSavingConnection::SendOrQueuePacket(QueuedPacket packet) {
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
}
-MockSession::MockSession(QuicConnection* connection)
- : QuicSession(connection, DefaultQuicConfig()) {
- InitializeSession();
+MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection)
+ : QuicSpdySession(connection, DefaultQuicConfig()) {
+ crypto_stream_.reset(new QuicCryptoStream(this));
+ Initialize();
ON_CALL(*this, WritevData(_, _, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
-MockSession::~MockSession() {
+MockQuicSpdySession::~MockQuicSpdySession() {
}
-TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
- : QuicSession(connection, config),
- crypto_stream_(nullptr) {
- InitializeSession();
+TestQuicSpdyServerSession::TestQuicSpdyServerSession(
+ QuicConnection* connection,
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* crypto_config)
+ : QuicSpdySession(connection, config) {
+ crypto_stream_.reset(new QuicCryptoServerStream(crypto_config, this));
+ Initialize();
}
-TestSession::~TestSession() {}
-
-void TestSession::SetCryptoStream(QuicCryptoStream* stream) {
- crypto_stream_ = stream;
-}
-
-QuicCryptoStream* TestSession::GetCryptoStream() {
- return crypto_stream_;
+TestQuicSpdyServerSession::~TestQuicSpdyServerSession() {
}
-TestClientSession::TestClientSession(QuicConnection* connection,
- const QuicConfig& config)
- : QuicClientSessionBase(connection, config),
- crypto_stream_(nullptr) {
- EXPECT_CALL(*this, OnProofValid(_)).Times(AnyNumber());
- InitializeSession();
-}
-
-TestClientSession::~TestClientSession() {}
-
-void TestClientSession::SetCryptoStream(QuicCryptoStream* stream) {
- crypto_stream_ = stream;
+QuicCryptoServerStream* TestQuicSpdyServerSession::GetCryptoStream() {
+ return crypto_stream_.get();
}
-QuicCryptoStream* TestClientSession::GetCryptoStream() {
- return crypto_stream_;
+TestQuicSpdyClientSession::TestQuicSpdyClientSession(
+ QuicConnection* connection,
+ const QuicConfig& config,
+ const QuicServerId& server_id,
+ QuicCryptoClientConfig* crypto_config)
+ : QuicClientSessionBase(connection, config) {
+ crypto_stream_.reset(new QuicCryptoClientStream(
+ server_id, this, CryptoTestUtils::ProofVerifyContextForTesting(),
+ crypto_config));
+ Initialize();
}
-TestServerSession::TestServerSession(const QuicConfig& config,
- QuicConnection* connection)
- : QuicServerSession(config, connection, nullptr) {
+TestQuicSpdyClientSession::~TestQuicSpdyClientSession() {
}
-TestServerSession::~TestServerSession() {
+QuicCryptoClientStream* TestQuicSpdyClientSession::GetCryptoStream() {
+ return crypto_stream_.get();
}
MockPacketWriter::MockPacketWriter() {
@@ -538,7 +533,7 @@ QuicEncryptedPacket* ConstructEncryptedPacket(
header.fec_flag = false;
header.is_in_fec_group = NOT_IN_FEC_GROUP;
header.fec_group = 0;
- QuicStreamFrame stream_frame(1, false, 0, MakeIOVector(data));
+ QuicStreamFrame stream_frame(1, false, 0, StringPiece(data));
QuicFrame frame(&stream_frame);
QuicFrames frames;
frames.push_back(frame);
@@ -549,7 +544,7 @@ QuicEncryptedPacket* ConstructEncryptedPacket(
BuildUnsizedDataPacket(&framer, header, frames));
EXPECT_TRUE(packet != nullptr);
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer.EncryptPayload(
ENCRYPTION_NONE, sequence_number, *packet, buffer, kMaxPacketSize));
EXPECT_TRUE(encrypted != nullptr);
return encrypted->Clone();
@@ -576,15 +571,24 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket(
header.fec_flag = false;
header.is_in_fec_group = NOT_IN_FEC_GROUP;
header.fec_group = 0;
+ QuicStreamFrame stream_frame(1, false, 0, StringPiece(data));
+ QuicFrame frame(&stream_frame);
QuicFrames frames;
- QuicFramer framer(versions ? *versions : QuicSupportedVersions(),
+ frames.push_back(frame);
+ QuicFramer framer(versions != nullptr ? *versions : QuicSupportedVersions(),
QuicTime::Zero(), Perspective::IS_CLIENT);
- // Build a packet with zero frames, which is an error.
+
scoped_ptr<QuicPacket> packet(
BuildUnsizedDataPacket(&framer, header, frames));
EXPECT_TRUE(packet != nullptr);
+
+ // Now set the packet's private flags byte to 0xFF, which is an invalid value.
+ reinterpret_cast<unsigned char*>(
+ packet->mutable_data())[GetStartOfEncryptedData(
+ connection_id_length, version_flag, sequence_number_length)] = 0xFF;
+
char buffer[kMaxPacketSize];
- scoped_ptr<QuicEncryptedPacket> encrypted(framer.EncryptPacket(
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer.EncryptPayload(
ENCRYPTION_NONE, sequence_number, *packet, buffer, kMaxPacketSize));
EXPECT_TRUE(encrypted != nullptr);
return encrypted->Clone();
@@ -654,7 +658,7 @@ static QuicPacket* ConstructPacketFromHandshakeMessage(
header.fec_group = 0;
QuicStreamFrame stream_frame(kCryptoStreamId, false, 0,
- MakeIOVector(data->AsStringPiece()));
+ data->AsStringPiece());
QuicFrame frame(&stream_frame);
QuicFrames frames;
@@ -682,9 +686,9 @@ size_t GetPacketLengthForOneStream(
QuicPacketCreator::StreamFramePacketOverhead(
PACKET_8BYTE_CONNECTION_ID, include_version,
sequence_number_length, 0u, is_in_fec_group);
- const size_t ack_length = NullEncrypter().GetCiphertextSize(
- QuicFramer::GetMinAckFrameSize(
- sequence_number_length, PACKET_1BYTE_SEQUENCE_NUMBER)) +
+ const size_t ack_length =
+ NullEncrypter().GetCiphertextSize(
+ QuicFramer::GetMinAckFrameSize(PACKET_1BYTE_SEQUENCE_NUMBER)) +
GetPacketHeaderSize(connection_id_length, include_version,
sequence_number_length, is_in_fec_group);
if (stream_length < ack_length) {
@@ -786,18 +790,15 @@ MockQuicConnectionDebugVisitor::MockQuicConnectionDebugVisitor() {
MockQuicConnectionDebugVisitor::~MockQuicConnectionDebugVisitor() {
}
-void SetupCryptoClientStreamForTest(
- QuicServerId server_id,
- bool supports_stateless_rejects,
- QuicTime::Delta connection_start_time,
- QuicCryptoClientConfig* crypto_client_config,
- PacketSavingConnection** client_connection,
- TestClientSession** client_session,
- QuicCryptoClientStream** client_stream) {
+void CreateClientSessionForTest(QuicServerId server_id,
+ bool supports_stateless_rejects,
+ QuicTime::Delta connection_start_time,
+ QuicCryptoClientConfig* crypto_client_config,
+ PacketSavingConnection** client_connection,
+ TestQuicSpdyClientSession** client_session) {
CHECK(crypto_client_config);
CHECK(client_connection);
CHECK(client_session);
- CHECK(client_stream);
CHECK(!connection_start_time.IsZero())
<< "Connections must start at non-zero times, otherwise the "
<< "strike-register will be unhappy.";
@@ -806,35 +807,26 @@ void SetupCryptoClientStreamForTest(
? DefaultQuicConfigStatelessRejects()
: DefaultQuicConfig();
*client_connection = new PacketSavingConnection(Perspective::IS_CLIENT);
- *client_session = new TestClientSession(*client_connection, config);
- *client_stream = new QuicCryptoClientStream(server_id, *client_session,
- nullptr, crypto_client_config);
- (*client_session)->SetCryptoStream(*client_stream);
+ *client_session = new TestQuicSpdyClientSession(
+ *client_connection, config, server_id, crypto_client_config);
(*client_connection)->AdvanceTime(connection_start_time);
}
-// Setup or create?
-void SetupCryptoServerStreamForTest(
- QuicServerId server_id,
- QuicTime::Delta connection_start_time,
- QuicCryptoServerConfig* server_crypto_config,
- PacketSavingConnection** server_connection,
- TestServerSession** server_session,
- QuicCryptoServerStream** server_stream) {
+void CreateServerSessionForTest(QuicServerId server_id,
+ QuicTime::Delta connection_start_time,
+ QuicCryptoServerConfig* server_crypto_config,
+ PacketSavingConnection** server_connection,
+ TestQuicSpdyServerSession** server_session) {
CHECK(server_crypto_config);
CHECK(server_connection);
CHECK(server_session);
- CHECK(server_stream);
CHECK(!connection_start_time.IsZero())
<< "Connections must start at non-zero times, otherwise the "
<< "strike-register will be unhappy.";
*server_connection = new PacketSavingConnection(Perspective::IS_SERVER);
- *server_session =
- new TestServerSession(DefaultQuicConfig(), *server_connection);
- *server_stream =
- new QuicCryptoServerStream(server_crypto_config, *server_session);
- (*server_session)->InitializeSession(server_crypto_config);
+ *server_session = new TestQuicSpdyServerSession(
+ *server_connection, DefaultQuicConfig(), server_crypto_config);
// We advance the clock initially because the default time is zero and the
// strike register worries that we've just overflowed a uint32 time.
diff --git a/chromium/net/quic/test_tools/quic_test_utils.h b/chromium/net/quic/test_tools/quic_test_utils.h
index facdcbf6118..874bce5e124 100644
--- a/chromium/net/quic/test_tools/quic_test_utils.h
+++ b/chromium/net/quic/test_tools/quic_test_utils.h
@@ -66,6 +66,8 @@ void GenerateBody(std::string* body, int length);
// Create an encrypted packet for testing.
// If versions == nullptr, uses &QuicSupportedVersions().
+// Note that the packet is encrypted with NullEncrypter, so to decrypt the
+// constructed packet, the framer must be set to use NullDecrypter.
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId connection_id,
bool version_flag,
@@ -96,8 +98,11 @@ QuicEncryptedPacket* ConstructEncryptedPacket(
QuicPacketSequenceNumber sequence_number,
const std::string& data);
-// Create an encrypted packet for testing whose data portion contains
-// a framing error.
+// Create an encrypted packet for testing whose data portion erroneous.
+// The specific way the data portion is erroneous is not specified, but
+// it is an error that QuicFramer detects.
+// Note that the packet is encrypted with NullEncrypter, so to decrypt the
+// constructed packet, the framer must be set to use NullDecrypter.
QuicEncryptedPacket* ConstructMisFramedEncryptedPacket(
QuicConnectionId connection_id,
bool version_flag,
@@ -284,7 +289,7 @@ class MockConnectionVisitor : public QuicConnectionVisitorInterface {
MOCK_METHOD1(OnCongestionWindowChange, void(QuicTime now));
MOCK_CONST_METHOD0(WillingAndAbleToWrite, bool());
MOCK_CONST_METHOD0(HasPendingHandshake, bool());
- MOCK_CONST_METHOD0(HasOpenDataStreams, bool());
+ MOCK_CONST_METHOD0(HasOpenDynamicStreams, bool());
MOCK_METHOD1(OnSuccessfulVersionNegotiation,
void(const QuicVersion& version));
MOCK_METHOD0(OnConfigNegotiated, void());
@@ -417,17 +422,19 @@ class PacketSavingConnection : public MockConnection {
DISALLOW_COPY_AND_ASSIGN(PacketSavingConnection);
};
-class MockSession : public QuicSession {
+class MockQuicSpdySession : public QuicSpdySession {
public:
- explicit MockSession(QuicConnection* connection);
- ~MockSession() override;
+ explicit MockQuicSpdySession(QuicConnection* connection);
+ ~MockQuicSpdySession() override;
+
+ QuicCryptoStream* GetCryptoStream() override { return crypto_stream_.get(); }
+
MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer));
- MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
- MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*());
- MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
+ MOCK_METHOD1(CreateIncomingDynamicStream, QuicDataStream*(QuicStreamId id));
+ MOCK_METHOD0(CreateOutgoingDynamicStream, QuicDataStream*());
MOCK_METHOD6(WritevData,
QuicConsumedData(QuicStreamId id,
- const IOVector& data,
+ const QuicIOVector& data,
QuicStreamOffset offset,
bool fin,
FecProtection fec_protection,
@@ -447,31 +454,36 @@ class MockSession : public QuicSession {
using QuicSession::ActivateStream;
private:
- DISALLOW_COPY_AND_ASSIGN(MockSession);
+ scoped_ptr<QuicCryptoStream> crypto_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockQuicSpdySession);
};
-class TestSession : public QuicSession {
+class TestQuicSpdyServerSession : public QuicSpdySession {
public:
- TestSession(QuicConnection* connection, const QuicConfig& config);
- ~TestSession() override;
+ TestQuicSpdyServerSession(QuicConnection* connection,
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* crypto_config);
+ ~TestQuicSpdyServerSession() override;
- MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
- MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
+ MOCK_METHOD1(CreateIncomingDynamicStream, QuicDataStream*(QuicStreamId id));
+ MOCK_METHOD0(CreateOutgoingDynamicStream, QuicDataStream*());
- void SetCryptoStream(QuicCryptoStream* stream);
-
- QuicCryptoStream* GetCryptoStream() override;
+ QuicCryptoServerStream* GetCryptoStream() override;
private:
- QuicCryptoStream* crypto_stream_;
+ scoped_ptr<QuicCryptoServerStream> crypto_stream_;
- DISALLOW_COPY_AND_ASSIGN(TestSession);
+ DISALLOW_COPY_AND_ASSIGN(TestQuicSpdyServerSession);
};
-class TestClientSession : public QuicClientSessionBase {
+class TestQuicSpdyClientSession : public QuicClientSessionBase {
public:
- TestClientSession(QuicConnection* connection, const QuicConfig& config);
- ~TestClientSession() override;
+ TestQuicSpdyClientSession(QuicConnection* connection,
+ const QuicConfig& config,
+ const QuicServerId& server_id,
+ QuicCryptoClientConfig* crypto_config);
+ ~TestQuicSpdyClientSession() override;
// QuicClientSessionBase
MOCK_METHOD1(OnProofValid,
@@ -479,18 +491,16 @@ class TestClientSession : public QuicClientSessionBase {
MOCK_METHOD1(OnProofVerifyDetailsAvailable,
void(const ProofVerifyDetails& verify_details));
- // TestClientSession
- MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
- MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
-
- void SetCryptoStream(QuicCryptoStream* stream);
+ // TestQuicSpdyClientSession
+ MOCK_METHOD1(CreateIncomingDynamicStream, QuicDataStream*(QuicStreamId id));
+ MOCK_METHOD0(CreateOutgoingDynamicStream, QuicDataStream*());
- QuicCryptoStream* GetCryptoStream() override;
+ QuicCryptoClientStream* GetCryptoStream() override;
private:
- QuicCryptoStream* crypto_stream_;
+ scoped_ptr<QuicCryptoClientStream> crypto_stream_;
- DISALLOW_COPY_AND_ASSIGN(TestClientSession);
+ DISALLOW_COPY_AND_ASSIGN(TestQuicSpdyClientSession);
};
class MockPacketWriter : public QuicPacketWriter {
@@ -710,17 +720,7 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor {
void(const QuicPacketHeader&, StringPiece payload));
};
-class TestServerSession : public tools::QuicServerSession {
- public:
- TestServerSession(const QuicConfig& config, QuicConnection* connection);
- ~TestServerSession() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestServerSession);
-};
-
-// Creates and sets up a QuicCryptoClientStream for testing, and all
-// its associated state.
+// Creates a client session for testing.
//
// server_id: The server id associated with this stream.
// supports_stateless_rejects: Does this client support stateless rejects.
@@ -734,19 +734,14 @@ class TestServerSession : public tools::QuicServerSession {
// client_session.
// client_session: Pointer reference for the newly created client
// session. The new object will be owned by the caller.
-// client_stream: Pointer reference for the newly created crypto
-// client stream. The new object will be owned by the caller.
-void SetupCryptoClientStreamForTest(
- QuicServerId server_id,
- bool supports_stateless_rejects,
- QuicTime::Delta connection_start_time,
- QuicCryptoClientConfig* crypto_client_config,
- PacketSavingConnection** client_connection,
- TestClientSession** client_session,
- QuicCryptoClientStream** client_stream);
-
-// Creates and sets up a QuicCryptoServerStream for testing, and all
-// its associated state.
+void CreateClientSessionForTest(QuicServerId server_id,
+ bool supports_stateless_rejects,
+ QuicTime::Delta connection_start_time,
+ QuicCryptoClientConfig* crypto_client_config,
+ PacketSavingConnection** client_connection,
+ TestQuicSpdyClientSession** client_session);
+
+// Creates a server session for testing.
//
// server_id: The server id associated with this stream.
// connection_start_time: The time to set for the connection clock.
@@ -759,15 +754,11 @@ void SetupCryptoClientStreamForTest(
// server_session.
// server_session: Pointer reference for the newly created server
// session. The new object will be owned by the caller.
-// server_stream: Pointer reference for the newly created crypto
-// server stream. The new object will be owned by the caller.
-void SetupCryptoServerStreamForTest(
- QuicServerId server_id,
- QuicTime::Delta connection_start_time,
- QuicCryptoServerConfig* crypto_server_config,
- PacketSavingConnection** server_connection,
- TestServerSession** server_session,
- QuicCryptoServerStream** server_stream);
+void CreateServerSessionForTest(QuicServerId server_id,
+ QuicTime::Delta connection_start_time,
+ QuicCryptoServerConfig* crypto_server_config,
+ PacketSavingConnection** server_connection,
+ TestQuicSpdyServerSession** server_session);
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/test_tools/simple_quic_framer.cc b/chromium/net/quic/test_tools/simple_quic_framer.cc
index 639a2f6c40d..7784695d035 100644
--- a/chromium/net/quic/test_tools/simple_quic_framer.cc
+++ b/chromium/net/quic/test_tools/simple_quic_framer.cc
@@ -56,12 +56,12 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
bool OnStreamFrame(const QuicStreamFrame& frame) override {
// Save a copy of the data so it is valid after the packet is processed.
- stream_data_.push_back(frame.GetDataAsString());
+ string* string_data = new string();
+ frame.data.AppendToString(string_data);
+ stream_data_.push_back(string_data);
QuicStreamFrame stream_frame(frame);
// Make sure that the stream frame points to this data.
- stream_frame.data.Clear();
- stream_frame.data.Append(const_cast<char*>(stream_data_.back()->data()),
- stream_data_.back()->size());
+ stream_frame.data = StringPiece(*string_data);
stream_frames_.push_back(stream_frame);
return true;
}