summaryrefslogtreecommitdiff
path: root/chromium/net/tools/quic
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/tools/quic')
-rw-r--r--chromium/net/tools/quic/chlo_extractor.cc19
-rw-r--r--chromium/net/tools/quic/chlo_extractor.h6
-rw-r--r--chromium/net/tools/quic/chlo_extractor_test.cc12
-rw-r--r--chromium/net/tools/quic/crypto_message_printer_bin.cc4
-rw-r--r--chromium/net/tools/quic/end_to_end_test.cc504
-rw-r--r--chromium/net/tools/quic/quic_client.cc367
-rw-r--r--chromium/net/tools/quic/quic_client.h211
-rw-r--r--chromium/net/tools/quic/quic_client_base.cc343
-rw-r--r--chromium/net/tools/quic/quic_client_base.h248
-rw-r--r--chromium/net/tools/quic/quic_client_bin.cc39
-rw-r--r--chromium/net/tools/quic/quic_client_session.cc12
-rw-r--r--chromium/net/tools/quic/quic_client_session.h9
-rw-r--r--chromium/net/tools/quic/quic_client_session_test.cc9
-rw-r--r--chromium/net/tools/quic/quic_client_test.cc6
-rw-r--r--chromium/net/tools/quic/quic_default_packet_writer.h5
-rw-r--r--chromium/net/tools/quic/quic_dispatcher.cc366
-rw-r--r--chromium/net/tools/quic/quic_dispatcher.h122
-rw-r--r--chromium/net/tools/quic/quic_dispatcher_test.cc931
-rw-r--r--chromium/net/tools/quic/quic_epoll_alarm_factory.cc3
-rw-r--r--chromium/net/tools/quic/quic_epoll_alarm_factory.h4
-rw-r--r--chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc35
-rw-r--r--chromium/net/tools/quic/quic_epoll_clock.cc14
-rw-r--r--chromium/net/tools/quic/quic_epoll_clock.h4
-rw-r--r--chromium/net/tools/quic/quic_epoll_clock_test.cc8
-rw-r--r--chromium/net/tools/quic/quic_epoll_connection_helper.cc2
-rw-r--r--chromium/net/tools/quic/quic_epoll_connection_helper.h10
-rw-r--r--chromium/net/tools/quic/quic_epoll_connection_helper_test.cc4
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache.cc40
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache.h6
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache_test.cc18
-rw-r--r--chromium/net/tools/quic/quic_packet_printer_bin.cc6
-rw-r--r--chromium/net/tools/quic/quic_packet_reader.cc71
-rw-r--r--chromium/net/tools/quic/quic_packet_reader.h9
-rw-r--r--chromium/net/tools/quic/quic_packet_writer_wrapper.cc2
-rw-r--r--chromium/net/tools/quic/quic_packet_writer_wrapper.h2
-rw-r--r--chromium/net/tools/quic/quic_per_connection_packet_writer.h6
-rw-r--r--chromium/net/tools/quic/quic_process_packet_interface.h2
-rw-r--r--chromium/net/tools/quic/quic_reject_reason_decoder_bin.cc47
-rw-r--r--chromium/net/tools/quic/quic_server.cc52
-rw-r--r--chromium/net/tools/quic/quic_server.h24
-rw-r--r--chromium/net/tools/quic/quic_server_bin.cc16
-rw-r--r--chromium/net/tools/quic/quic_server_test.cc130
-rw-r--r--chromium/net/tools/quic/quic_simple_client.cc347
-rw-r--r--chromium/net/tools/quic/quic_simple_client.h191
-rw-r--r--chromium/net/tools/quic/quic_simple_client_bin.cc37
-rw-r--r--chromium/net/tools/quic/quic_simple_client_test.cc2
-rw-r--r--chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.cc28
-rw-r--r--chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.h35
-rw-r--r--chromium/net/tools/quic/quic_simple_dispatcher.cc43
-rw-r--r--chromium/net/tools/quic/quic_simple_dispatcher.h32
-rw-r--r--chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h4
-rw-r--r--chromium/net/tools/quic/quic_simple_server.cc86
-rw-r--r--chromium/net/tools/quic/quic_simple_server.h31
-rw-r--r--chromium/net/tools/quic/quic_simple_server_bin.cc17
-rw-r--r--chromium/net/tools/quic/quic_simple_server_packet_writer.cc5
-rw-r--r--chromium/net/tools/quic/quic_simple_server_packet_writer.h36
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session.cc20
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session.h11
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session_helper.h6
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session_helper_test.cc8
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session_test.cc124
-rw-r--r--chromium/net/tools/quic/quic_simple_server_stream.cc18
-rw-r--r--chromium/net/tools/quic/quic_simple_server_stream.h4
-rw-r--r--chromium/net/tools/quic/quic_simple_server_stream_test.cc35
-rw-r--r--chromium/net/tools/quic/quic_simple_server_test.cc10
-rw-r--r--chromium/net/tools/quic/quic_socket_utils.cc46
-rw-r--r--chromium/net/tools/quic/quic_socket_utils.h21
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream.cc18
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream.h4
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream_test.cc5
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager.cc34
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager.h14
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager_test.cc36
-rw-r--r--chromium/net/tools/quic/spdy_balsa_utils.cc28
-rw-r--r--chromium/net/tools/quic/spdy_balsa_utils.h2
-rw-r--r--chromium/net/tools/quic/spdy_balsa_utils_test.cc4
-rw-r--r--chromium/net/tools/quic/stateless_rejector.cc116
-rw-r--r--chromium/net/tools/quic/stateless_rejector.h49
-rw-r--r--chromium/net/tools/quic/stateless_rejector_test.cc126
-rw-r--r--chromium/net/tools/quic/synchronous_host_resolver.cc17
-rw-r--r--chromium/net/tools/quic/synchronous_host_resolver.h1
-rw-r--r--chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h2
-rw-r--r--chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc4
-rw-r--r--chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h13
-rw-r--r--chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc8
-rw-r--r--chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h9
-rw-r--r--chromium/net/tools/quic/test_tools/packet_reordering_writer.cc50
-rw-r--r--chromium/net/tools/quic/test_tools/packet_reordering_writer.h45
-rw-r--r--chromium/net/tools/quic/test_tools/quic_client_peer.cc4
-rw-r--r--chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc25
-rw-r--r--chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h13
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_client.cc222
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_client.h56
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_server.cc58
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_server.h10
-rw-r--r--chromium/net/tools/quic/test_tools/server_thread.h2
-rw-r--r--chromium/net/tools/quic/test_tools/simple_client.cc14
-rw-r--r--chromium/net/tools/quic/test_tools/simple_client.h6
98 files changed, 3683 insertions, 2237 deletions
diff --git a/chromium/net/tools/quic/chlo_extractor.cc b/chromium/net/tools/quic/chlo_extractor.cc
index 55e68a09ccf..3e5ce787f7a 100644
--- a/chromium/net/tools/quic/chlo_extractor.cc
+++ b/chromium/net/tools/quic/chlo_extractor.cc
@@ -4,12 +4,13 @@
#include "net/tools/quic/chlo_extractor.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/crypto_handshake_message.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/quic_framer.h"
+#include "base/strings/string_util.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_framer.h"
using base::StringPiece;
@@ -92,7 +93,7 @@ bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) {
bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) {
StringPiece data(frame.data_buffer, frame.data_length);
if (frame.stream_id == kCryptoStreamId && frame.offset == 0 &&
- data.starts_with("CHLO")) {
+ base::StartsWith(data, "CHLO", base::CompareCase::INSENSITIVE_ASCII)) {
CryptoFramer crypto_framer;
crypto_framer.set_visitor(this);
if (!crypto_framer.ProcessInput(data)) {
@@ -148,7 +149,9 @@ void ChloFramerVisitor::OnError(CryptoFramer* framer) {}
void ChloFramerVisitor::OnHandshakeMessage(
const CryptoHandshakeMessage& message) {
- delegate_->OnChlo(framer_->version(), connection_id_, message);
+ if (delegate_ != nullptr) {
+ delegate_->OnChlo(framer_->version(), connection_id_, message);
+ }
found_chlo_ = true;
}
diff --git a/chromium/net/tools/quic/chlo_extractor.h b/chromium/net/tools/quic/chlo_extractor.h
index eefaae3f51d..7820bb596ca 100644
--- a/chromium/net/tools/quic/chlo_extractor.h
+++ b/chromium/net/tools/quic/chlo_extractor.h
@@ -5,8 +5,8 @@
#ifndef NET_TOOLS_QUIC_CHLO_EXTRACTOR_H_
#define NET_TOOLS_QUIC_CHLO_EXTRACTOR_H_
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -31,7 +31,7 @@ class ChloExtractor {
const QuicVersionVector& versions,
Delegate* delegate);
- ChloExtractor(ChloExtractor&) = delete;
+ ChloExtractor(const ChloExtractor&) = delete;
ChloExtractor operator=(const ChloExtractor&) = delete;
};
diff --git a/chromium/net/tools/quic/chlo_extractor_test.cc b/chromium/net/tools/quic/chlo_extractor_test.cc
index 320df5ae390..1be18208c91 100644
--- a/chromium/net/tools/quic/chlo_extractor_test.cc
+++ b/chromium/net/tools/quic/chlo_extractor_test.cc
@@ -4,7 +4,7 @@
#include "net/tools/quic/chlo_extractor.h"
-#include "net/quic/quic_framer.h"
+#include "net/quic/core/quic_framer.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -48,7 +48,7 @@ class ChloExtractorTest : public ::testing::Test {
header_.public_header.connection_id_length = PACKET_8BYTE_CONNECTION_ID;
header_.public_header.version_flag = true;
header_.public_header.versions =
- SupportedVersions(QuicSupportedVersions().front());
+ SupportedVersions(AllSupportedVersions().front());
header_.public_header.reset_flag = false;
header_.public_header.packet_number_length = PACKET_6BYTE_PACKET_NUMBER;
header_.packet_number = 1;
@@ -88,7 +88,7 @@ TEST_F(ChloExtractorTest, FindsValidChlo) {
string client_hello_str(
client_hello.GetSerialized().AsStringPiece().as_string());
// Construct a CHLO with each supported version
- for (QuicVersion version : QuicSupportedVersions()) {
+ for (QuicVersion version : AllSupportedVersions()) {
QuicVersionVector versions(SupportedVersions(version));
header_.public_header.versions = versions;
MakePacket(
@@ -111,7 +111,7 @@ TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) {
MakePacket(
new QuicStreamFrame(kCryptoStreamId + 1, false, 0, client_hello_str));
EXPECT_FALSE(
- ChloExtractor::Extract(*packet_, QuicSupportedVersions(), &delegate_));
+ ChloExtractor::Extract(*packet_, AllSupportedVersions(), &delegate_));
}
TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) {
@@ -122,13 +122,13 @@ TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) {
client_hello.GetSerialized().AsStringPiece().as_string());
MakePacket(new QuicStreamFrame(kCryptoStreamId, false, 1, client_hello_str));
EXPECT_FALSE(
- ChloExtractor::Extract(*packet_, QuicSupportedVersions(), &delegate_));
+ ChloExtractor::Extract(*packet_, AllSupportedVersions(), &delegate_));
}
TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) {
MakePacket(new QuicStreamFrame(kCryptoStreamId, false, 0, "foo"));
EXPECT_FALSE(
- ChloExtractor::Extract(*packet_, QuicSupportedVersions(), &delegate_));
+ ChloExtractor::Extract(*packet_, AllSupportedVersions(), &delegate_));
}
} // namespace
diff --git a/chromium/net/tools/quic/crypto_message_printer_bin.cc b/chromium/net/tools/quic/crypto_message_printer_bin.cc
index e6813c4a3c6..11eb8f83410 100644
--- a/chromium/net/tools/quic/crypto_message_printer_bin.cc
+++ b/chromium/net/tools/quic/crypto_message_printer_bin.cc
@@ -10,8 +10,8 @@
#include <iostream>
#include "base/command_line.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/quic_utils.h"
using std::cerr;
using std::cout;
diff --git a/chromium/net/tools/quic/end_to_end_test.cc b/chromium/net/tools/quic/end_to_end_test.cc
index 7f4451c94cc..aca08397a96 100644
--- a/chromium/net/tools/quic/end_to_end_test.cc
+++ b/chromium/net/tools/quic/end_to_end_test.cc
@@ -18,22 +18,24 @@
#include "base/time/time.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.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_framer.h"
-#include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_packet_creator.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_config_peer.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_session_peer.h"
#include "net/quic/test_tools/quic_spdy_session_peer.h"
+#include "net/quic/test_tools/quic_stream_sequencer_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
#include "net/test/gtest_util.h"
@@ -47,6 +49,7 @@
#include "net/tools/quic/quic_spdy_client_stream.h"
#include "net/tools/quic/test_tools/http_message.h"
#include "net/tools/quic/test_tools/packet_dropping_test_writer.h"
+#include "net/tools/quic/test_tools/packet_reordering_writer.h"
#include "net/tools/quic/test_tools/quic_client_peer.h"
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
@@ -71,7 +74,6 @@ using net::test::QuicSentPacketManagerPeer;
using net::test::QuicSessionPeer;
using net::test::QuicSpdySessionPeer;
using net::test::ReliableQuicStreamPeer;
-using net::test::ValueRestore;
using net::test::kClientDataStreamId1;
using net::test::kInitialSessionFlowControlWindowForTest;
using net::test::kInitialStreamFlowControlWindowForTest;
@@ -98,8 +100,11 @@ struct TestParams {
bool client_supports_stateless_rejects,
bool server_uses_stateless_rejects_if_peer_supported,
QuicTag congestion_control_tag,
- bool auto_tune_flow_control_window,
- bool disable_hpack_dynamic_table)
+ bool disable_hpack_dynamic_table,
+ bool force_hol_blocking,
+ bool use_cheap_stateless_reject,
+ bool buffer_packet_till_chlo,
+ bool small_client_mtu)
: client_supported_versions(client_supported_versions),
server_supported_versions(server_supported_versions),
negotiated_version(negotiated_version),
@@ -107,8 +112,11 @@ struct TestParams {
server_uses_stateless_rejects_if_peer_supported(
server_uses_stateless_rejects_if_peer_supported),
congestion_control_tag(congestion_control_tag),
- auto_tune_flow_control_window(auto_tune_flow_control_window),
- disable_hpack_dynamic_table(disable_hpack_dynamic_table) {}
+ disable_hpack_dynamic_table(disable_hpack_dynamic_table),
+ force_hol_blocking(force_hol_blocking),
+ use_cheap_stateless_reject(use_cheap_stateless_reject),
+ buffer_packet_till_chlo(buffer_packet_till_chlo),
+ small_client_mtu(small_client_mtu) {}
friend ostream& operator<<(ostream& os, const TestParams& p) {
os << "{ server_supported_versions: "
@@ -122,9 +130,11 @@ struct TestParams {
<< p.server_uses_stateless_rejects_if_peer_supported;
os << " congestion_control_tag: "
<< QuicUtils::TagToString(p.congestion_control_tag);
- os << " auto_tune_flow_control_window: " << p.auto_tune_flow_control_window;
- os << " disable_hpack_dynamic_table: " << p.disable_hpack_dynamic_table
- << " }";
+ os << " disable_hpack_dynamic_table: " << p.disable_hpack_dynamic_table;
+ os << " force_hol_blocking: " << p.force_hol_blocking;
+ os << " use_cheap_stateless_reject: " << p.use_cheap_stateless_reject;
+ os << " buffer_packet_till_chlo: " << p.buffer_packet_till_chlo;
+ os << " small_client_mtu: " << p.small_client_mtu << " }";
return os;
}
@@ -134,8 +144,11 @@ struct TestParams {
bool client_supports_stateless_rejects;
bool server_uses_stateless_rejects_if_peer_supported;
QuicTag congestion_control_tag;
- bool auto_tune_flow_control_window;
bool disable_hpack_dynamic_table;
+ bool force_hol_blocking;
+ bool use_cheap_stateless_reject;
+ bool buffer_packet_till_chlo;
+ bool small_client_mtu;
};
// Constructs various test permutations.
@@ -148,116 +161,157 @@ vector<TestParams> GetTestParams() {
// these tests need to ensure that clients are never attempting
// to do 0-RTT across incompatible versions. Chromium only supports
// a single version at a time anyway. :)
- QuicVersionVector all_supported_versions = QuicSupportedVersions();
+ QuicVersionVector all_supported_versions = AllSupportedVersions();
QuicVersionVector version_buckets[4];
for (const QuicVersion version : all_supported_versions) {
- if (version <= QUIC_VERSION_25) {
- // SPDY/4
+ if (version <= QUIC_VERSION_30) {
+ // Versions: 30
+ // v26 adds a hash of the expected leaf cert in the XLCT tag.
version_buckets[0].push_back(version);
} else if (version <= QUIC_VERSION_32) {
- // QUIC_VERSION_26 changes the kdf in a way that is incompatible with
- // version negotiation across the version 26 boundary.
+ // Versions: 31-32
+ // v31 adds a hash of the CHLO into the proof signature.
version_buckets[1].push_back(version);
} else if (version <= QUIC_VERSION_33) {
- // QUIC_VERSION_33 changes the kdf in a way that is incompatible with
- // version negotiation across the version 33 boundary, by using the
- // diversification nonce.
+ // Versions: 33
+ // v33 adds a diversification nonce into the hkdf.
version_buckets[2].push_back(version);
} else {
+ // Versions: 34+
// QUIC_VERSION_34 deprecates entropy and uses new ack and stop waiting
- // wire formats, so it is incompatible with version negotiation across the
- // version 34 boundary.
+ // wire formats.
version_buckets[3].push_back(version);
}
}
// This must be kept in sync with the number of nested for-loops below as it
// is used to prune the number of tests that are run.
- const int kMaxEnabledOptions = 5;
+ const int kMaxEnabledOptions = 7;
int max_enabled_options = 0;
vector<TestParams> params;
for (bool server_uses_stateless_rejects_if_peer_supported : {true, false}) {
for (bool client_supports_stateless_rejects : {true, false}) {
for (const QuicTag congestion_control_tag : {kRENO, kQBIC}) {
- for (bool auto_tune_flow_control_window : {true, false}) {
- for (bool disable_hpack_dynamic_table : {true, false}) {
- int enabled_options = 0;
- if (congestion_control_tag != kQBIC) {
- ++enabled_options;
- }
- if (auto_tune_flow_control_window) {
- ++enabled_options;
- }
- if (disable_hpack_dynamic_table) {
- ++enabled_options;
- }
- if (client_supports_stateless_rejects) {
- ++enabled_options;
- }
- if (server_uses_stateless_rejects_if_peer_supported) {
- ++enabled_options;
- }
- CHECK_GE(kMaxEnabledOptions, enabled_options);
- if (enabled_options > max_enabled_options) {
- max_enabled_options = enabled_options;
- }
-
- // Run tests with no options, a single option, or all the options
- // enabled to avoid a combinatorial explosion.
- if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) {
- continue;
- }
-
- for (const QuicVersionVector& client_versions : version_buckets) {
- if (client_versions.front() < QUIC_VERSION_30 &&
- FLAGS_quic_disable_pre_30) {
- continue;
- }
- CHECK(!client_versions.empty());
- // Add an entry for server and client supporting all versions.
- params.push_back(TestParams(
- client_versions, all_supported_versions,
- client_versions.front(), client_supports_stateless_rejects,
- server_uses_stateless_rejects_if_peer_supported,
- congestion_control_tag, auto_tune_flow_control_window,
- disable_hpack_dynamic_table));
-
- // Run version negotiation tests tests with no options, or all
- // the options enabled to avoid a combinatorial explosion.
- if (enabled_options > 0 && enabled_options < kMaxEnabledOptions) {
- continue;
- }
-
- // Test client supporting all versions and server supporting 1
- // version. Simulate an old server and exercise version downgrade
- // in the client. Protocol negotiation should occur. Skip the i =
- // 0 case because it is essentially the same as the default case.
- for (size_t i = 1; i < client_versions.size(); ++i) {
- if (client_versions[i] < QUIC_VERSION_30 &&
- FLAGS_quic_disable_pre_30) {
- continue;
- }
- QuicVersionVector server_supported_versions;
- server_supported_versions.push_back(client_versions[i]);
- params.push_back(TestParams(
- client_versions, server_supported_versions,
- server_supported_versions.front(),
- client_supports_stateless_rejects,
- server_uses_stateless_rejects_if_peer_supported,
- congestion_control_tag, auto_tune_flow_control_window,
- disable_hpack_dynamic_table));
- }
- }
- }
- }
- }
- }
+ for (bool disable_hpack_dynamic_table : {false}) {
+ for (bool force_hol_blocking : {true, false}) {
+ for (bool use_cheap_stateless_reject : {true, false}) {
+ for (bool buffer_packet_till_chlo : {true, false}) {
+ for (bool small_client_mtu : {true, false}) {
+ if (!buffer_packet_till_chlo && use_cheap_stateless_reject) {
+ // Doing stateless reject while not buffering packet
+ // before CHLO is not allowed.
+ break;
+ }
+ int enabled_options = 0;
+ if (force_hol_blocking) {
+ ++enabled_options;
+ }
+ if (congestion_control_tag != kQBIC) {
+ ++enabled_options;
+ }
+ if (disable_hpack_dynamic_table) {
+ ++enabled_options;
+ }
+ if (client_supports_stateless_rejects) {
+ ++enabled_options;
+ }
+ if (server_uses_stateless_rejects_if_peer_supported) {
+ ++enabled_options;
+ }
+ if (buffer_packet_till_chlo) {
+ ++enabled_options;
+ }
+ if (use_cheap_stateless_reject) {
+ ++enabled_options;
+ }
+ if (small_client_mtu) {
+ ++enabled_options;
+ }
+ CHECK_GE(kMaxEnabledOptions, enabled_options);
+ if (enabled_options > max_enabled_options) {
+ max_enabled_options = enabled_options;
+ }
+
+ // Run tests with no options, a single option, or all the
+ // options enabled to avoid a combinatorial explosion.
+ if (enabled_options > 1 &&
+ enabled_options < kMaxEnabledOptions) {
+ continue;
+ }
+
+ for (const QuicVersionVector& client_versions :
+ version_buckets) {
+ CHECK(!client_versions.empty());
+ if (FilterSupportedVersions(client_versions).empty()) {
+ continue;
+ }
+ // Add an entry for server and client supporting all
+ // versions.
+ params.push_back(TestParams(
+ client_versions, all_supported_versions,
+ client_versions.front(),
+ client_supports_stateless_rejects,
+ server_uses_stateless_rejects_if_peer_supported,
+ congestion_control_tag, disable_hpack_dynamic_table,
+ force_hol_blocking, use_cheap_stateless_reject,
+ buffer_packet_till_chlo, small_client_mtu));
+
+ // Run version negotiation tests tests with no options, or
+ // all the options enabled to avoid a combinatorial
+ // explosion.
+ if (enabled_options > 1 &&
+ enabled_options < kMaxEnabledOptions) {
+ continue;
+ }
+
+ // Test client supporting all versions and server supporting
+ // 1 version. Simulate an old server and exercise version
+ // downgrade in the client. Protocol negotiation should
+ // occur. Skip the i = 0 case because it is essentially the
+ // same as the default case.
+ for (size_t i = 1; i < client_versions.size(); ++i) {
+ QuicVersionVector server_supported_versions;
+ server_supported_versions.push_back(client_versions[i]);
+ if (FilterSupportedVersions(server_supported_versions)
+ .empty()) {
+ continue;
+ }
+ params.push_back(TestParams(
+ client_versions, server_supported_versions,
+ server_supported_versions.front(),
+ client_supports_stateless_rejects,
+ server_uses_stateless_rejects_if_peer_supported,
+ congestion_control_tag, disable_hpack_dynamic_table,
+ force_hol_blocking, use_cheap_stateless_reject,
+ buffer_packet_till_chlo, small_client_mtu));
+ } // End of version for loop.
+ } // End of 2nd version for loop.
+ } // End of small_client_mtu loop.
+ } // End of buffer_packet_till_chlo loop.
+ } // End of use_cheap_stateless_reject for loop.
+ } // End of force_hol_blocking loop.
+ } // End of disable_hpack_dynamic_table for loop.
+ } // End of congestion_control_tag for loop.
+ } // End of client_supports_stateless_rejects for loop.
CHECK_EQ(kMaxEnabledOptions, max_enabled_options);
- }
+ } // End of server_uses_stateless_rejects_if_peer_supported for loop.
return params;
}
+class SmallMtuPacketReader : public QuicPacketReader {
+ public:
+ bool ReadAndDispatchPackets(int fd,
+ int port,
+ bool potentially_small_mtu,
+ const QuicClock& clock,
+ ProcessPacketInterface* processor,
+ QuicPacketCount* packets_dropped) override {
+ return QuicPacketReader::ReadAndDispatchPackets(fd, port, true, clock,
+ processor, packets_dropped);
+ }
+};
+
class ServerDelegate : public PacketDroppingTestWriter::Delegate {
public:
explicit ServerDelegate(QuicDispatcher* dispatcher)
@@ -287,7 +341,9 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
EndToEndTest()
: initialized_(false),
server_address_(IPEndPoint(Loopback4(), 0)),
- server_hostname_("example.com"),
+ server_hostname_("test.example.com"),
+ client_writer_(nullptr),
+ server_writer_(nullptr),
server_started_(false),
strike_register_no_startup_period_(false),
chlo_multiplier_(0),
@@ -328,10 +384,14 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
QuicInMemoryCachePeer::ResetForTests();
}
+ virtual void CreateClientWithWriter() {
+ client_.reset(CreateQuicClient(client_writer_));
+ }
+
QuicTestClient* CreateQuicClient(QuicPacketWriterWrapper* writer) {
- QuicTestClient* client =
- new QuicTestClient(server_address_, server_hostname_, client_config_,
- client_supported_versions_);
+ QuicTestClient* client = new QuicTestClient(
+ server_address_, server_hostname_, client_config_,
+ client_supported_versions_, CryptoTestUtils::ProofVerifierForTesting());
client->UseWriter(writer);
client->Connect();
return client;
@@ -395,29 +455,29 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
if (GetParam().client_supports_stateless_rejects) {
copt.push_back(kSREJ);
}
- if (GetParam().auto_tune_flow_control_window) {
- copt.push_back(kAFCW);
- copt.push_back(kIFW5);
- }
if (GetParam().disable_hpack_dynamic_table) {
copt.push_back(kDHDT);
}
+ if (GetParam().force_hol_blocking) {
+ client_config_.SetForceHolBlocking();
+ }
client_config_.SetConnectionOptionsToSend(copt);
// Start the server first, because CreateQuicClient() attempts
// to connect to the server.
StartServer();
- client_.reset(CreateQuicClient(client_writer_));
+ CreateClientWithWriter();
static EpollEvent event(EPOLLOUT, false);
- client_writer_->Initialize(
- reinterpret_cast<QuicEpollConnectionHelper*>(
- QuicConnectionPeer::GetHelper(
- client_->client()->session()->connection())),
- QuicConnectionPeer::GetAlarmFactory(
- client_->client()->session()->connection()),
- new ClientDelegate(client_->client()));
-
+ if (client_writer_ != nullptr) {
+ client_writer_->Initialize(
+ reinterpret_cast<QuicEpollConnectionHelper*>(
+ QuicConnectionPeer::GetHelper(
+ client_->client()->session()->connection())),
+ QuicConnectionPeer::GetAlarmFactory(
+ client_->client()->session()->connection()),
+ new ClientDelegate(client_->client()));
+ }
initialized_ = true;
return client_->client()->connected();
}
@@ -436,10 +496,22 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
}
void StartServer() {
- server_thread_.reset(new ServerThread(
+ FLAGS_quic_buffer_packet_till_chlo = GetParam().buffer_packet_till_chlo;
+ FLAGS_quic_use_cheap_stateless_rejects =
+ GetParam().use_cheap_stateless_reject;
+ if (!FLAGS_quic_buffer_packet_till_chlo) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = false;
+ }
+ auto test_server =
new QuicTestServer(CryptoTestUtils::ProofSourceForTesting(),
- server_config_, server_supported_versions_),
- server_address_, strike_register_no_startup_period_));
+ server_config_, server_supported_versions_);
+ if (GetParam().small_client_mtu) {
+ FLAGS_quic_enforce_mtu_limit = true;
+ QuicServerPeer::SetReader(test_server, new SmallMtuPacketReader);
+ server_writer_->set_max_allowed_packet_size(kMinimumSupportedPacketSize);
+ }
+ server_thread_.reset(new ServerThread(test_server, server_address_,
+ strike_register_no_startup_period_));
if (chlo_multiplier_ != 0) {
server_thread_->server()->SetChloMultiplier(chlo_multiplier_);
}
@@ -475,7 +547,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
}
void AddToCache(StringPiece path, int response_code, StringPiece body) {
- QuicInMemoryCache::GetInstance()->AddSimpleResponse("www.google.com", path,
+ QuicInMemoryCache::GetInstance()->AddSimpleResponse(server_hostname_, path,
response_code, body);
}
@@ -509,7 +581,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
void VerifyCleanConnection(bool had_packet_loss) {
QuicConnectionStats client_stats =
client_->client()->session()->connection()->GetStats();
- if (FLAGS_quic_reply_to_rej && !had_packet_loss) {
+ if (!had_packet_loss) {
EXPECT_EQ(0u, client_stats.packets_lost);
}
EXPECT_EQ(0u, client_stats.packets_discarded);
@@ -534,7 +606,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
ASSERT_EQ(1u, dispatcher->session_map().size());
QuicSession* session = dispatcher->session_map().begin()->second;
QuicConnectionStats server_stats = session->connection()->GetStats();
- if (FLAGS_quic_reply_to_rej && !had_packet_loss) {
+ if (!had_packet_loss) {
EXPECT_EQ(0u, server_stats.packets_lost);
}
EXPECT_EQ(0u, server_stats.packets_discarded);
@@ -562,6 +634,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
stream_factory_ = factory;
}
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
bool initialized_;
IPEndPoint server_address_;
string server_hostname_;
@@ -579,6 +652,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
size_t chlo_multiplier_;
QuicTestServer::StreamFactory* stream_factory_;
bool support_server_push_;
+ bool force_hol_blocking_;
};
// Run all end to end tests with all supported versions.
@@ -586,6 +660,27 @@ INSTANTIATE_TEST_CASE_P(EndToEndTests,
EndToEndTest,
::testing::ValuesIn(GetTestParams()));
+TEST_P(EndToEndTest, HandshakeSuccessful) {
+ ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ QuicCryptoStream* crypto_stream =
+ QuicSessionPeer::GetCryptoStream(client_->client()->session());
+ QuicStreamSequencer* sequencer =
+ ReliableQuicStreamPeer::sequencer(crypto_stream);
+ EXPECT_NE(FLAGS_quic_release_crypto_stream_buffer &&
+ FLAGS_quic_reduce_sequencer_buffer_memory_life_time,
+ QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ QuicSession* server_session = dispatcher->session_map().begin()->second;
+ crypto_stream = QuicSessionPeer::GetCryptoStream(server_session);
+ sequencer = ReliableQuicStreamPeer::sequencer(crypto_stream);
+ EXPECT_NE(FLAGS_quic_release_crypto_stream_buffer &&
+ FLAGS_quic_reduce_sequencer_buffer_memory_life_time,
+ QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+}
+
TEST_P(EndToEndTest, SimpleRequestResponse) {
ASSERT_TRUE(Initialize());
@@ -1161,7 +1256,7 @@ TEST_P(EndToEndTest, DISABLED_MultipleTermination) {
ReliableQuicStreamPeer::SetWriteSideClosed(false,
client_->GetOrCreateStream());
- EXPECT_DFATAL(client_->SendData("eep", true), "Fin already buffered");
+ EXPECT_QUIC_BUG(client_->SendData("eep", true), "Fin already buffered");
}
TEST_P(EndToEndTest, Timeout) {
@@ -1203,15 +1298,9 @@ TEST_P(EndToEndTest, NegotiateMaxOpenStreams) {
}
client_->WaitForResponse();
- if (negotiated_version_ <= QUIC_VERSION_27) {
- EXPECT_FALSE(client_->connected());
- EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
- EXPECT_EQ(QUIC_TOO_MANY_OPEN_STREAMS, client_->connection_error());
- } else {
- EXPECT_TRUE(client_->connected());
- EXPECT_EQ(QUIC_REFUSED_STREAM, client_->stream_error());
- EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
- }
+ EXPECT_TRUE(client_->connected());
+ EXPECT_EQ(QUIC_REFUSED_STREAM, client_->stream_error());
+ EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
}
TEST_P(EndToEndTest, MaxIncomingDynamicStreamsLimitRespected) {
@@ -1279,7 +1368,7 @@ TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) {
}
TEST_P(EndToEndTest, NegotiateCongestionControl) {
- ValueRestore<bool> old_flag(&FLAGS_quic_allow_bbr, true);
+ FLAGS_quic_allow_bbr = true;
// Disable this flag because if connection uses multipath sent packet manager,
// static_cast here does not work.
FLAGS_quic_enable_multipath = false;
@@ -1292,7 +1381,9 @@ TEST_P(EndToEndTest, NegotiateCongestionControl) {
expected_congestion_control_type = kReno;
break;
case kTBBR:
- expected_congestion_control_type = kBBR;
+ // TODO(vasilvv): switch this back to kBBR when new BBR implementation is
+ // in.
+ expected_congestion_control_type = kCubic;
break;
case kQBIC:
expected_congestion_control_type = kCubic;
@@ -1301,11 +1392,13 @@ TEST_P(EndToEndTest, NegotiateCongestionControl) {
DLOG(FATAL) << "Unexpected congestion control tag";
}
+ server_thread_->Pause();
EXPECT_EQ(expected_congestion_control_type,
QuicSentPacketManagerPeer::GetSendAlgorithm(
*static_cast<const QuicSentPacketManager*>(
GetSentPacketManagerFromFirstServerSession()))
->GetCongestionControlType());
+ server_thread_->Resume();
}
TEST_P(EndToEndTest, LimitMaxOpenStreams) {
@@ -1619,10 +1712,8 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW);
set_client_initial_session_flow_control_receive_window(kClientSessionIFCW);
- uint32_t kServerStreamIFCW =
- GetParam().auto_tune_flow_control_window ? 32 * 1024 : 654321;
- uint32_t kServerSessionIFCW =
- GetParam().auto_tune_flow_control_window ? 48 * 1024 : 765432;
+ uint32_t kServerStreamIFCW = 32 * 1024;
+ uint32_t kServerSessionIFCW = 48 * 1024;
set_server_initial_stream_flow_control_receive_window(kServerStreamIFCW);
set_server_initial_session_flow_control_receive_window(kServerSessionIFCW);
@@ -1670,10 +1761,8 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) {
// The special headers and crypto streams should be subject to per-stream flow
// control limits, but should not be subject to connection level flow control
- const uint32_t kStreamIFCW =
- GetParam().auto_tune_flow_control_window ? 32 * 1024 : 123456;
- const uint32_t kSessionIFCW =
- GetParam().auto_tune_flow_control_window ? 48 * 1024 : 234567;
+ const uint32_t kStreamIFCW = 32 * 1024;
+ const uint32_t kSessionIFCW = 48 * 1024;
set_client_initial_stream_flow_control_receive_window(kStreamIFCW);
set_client_initial_session_flow_control_receive_window(kSessionIFCW);
set_server_initial_stream_flow_control_receive_window(kStreamIFCW);
@@ -1801,10 +1890,9 @@ class TestAckListener : public QuicAckListenerInterface {
class TestResponseListener : public QuicClient::ResponseListener {
public:
void OnCompleteResponse(QuicStreamId id,
- const BalsaHeaders& response_headers,
+ const SpdyHeaderBlock& response_headers,
const string& response_body) override {
- string debug_string;
- response_headers.DumpHeadersToString(&debug_string);
+ string debug_string = response_headers.DebugString();
DVLOG(1) << "response for stream " << id << " " << debug_string << "\n"
<< response_body;
}
@@ -1894,6 +1982,8 @@ TEST_P(EndToEndTest, ServerSendPublicReset) {
TEST_P(EndToEndTest, ServerSendPublicResetWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
// Send the public reset.
QuicConnectionId incorrect_connection_id =
client_->client()->session()->connection()->connection_id() + 1;
@@ -1957,6 +2047,8 @@ TEST_P(EndToEndTest, ClientSendPublicResetWithDifferentConnectionId) {
TEST_P(EndToEndTest, ServerSendVersionNegotiationWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
// Send the version negotiation packet.
QuicConnectionId incorrect_connection_id =
client_->client()->session()->connection()->connection_id() + 1;
@@ -2098,7 +2190,8 @@ class ServerStreamWithErrorResponseBody : public QuicSimpleServerStream {
ServerStreamWithErrorResponseBody(QuicStreamId id,
QuicSpdySession* session,
string response_body)
- : QuicSimpleServerStream(id, session), response_body_(response_body) {}
+ : QuicSimpleServerStream(id, session),
+ response_body_(std::move(response_body)) {}
~ServerStreamWithErrorResponseBody() override {}
@@ -2120,7 +2213,7 @@ class ServerStreamWithErrorResponseBody : public QuicSimpleServerStream {
class StreamWithErrorFactory : public QuicTestServer::StreamFactory {
public:
explicit StreamWithErrorFactory(string response_body)
- : response_body_(response_body) {}
+ : response_body_(std::move(response_body)) {}
~StreamWithErrorFactory() override {}
@@ -2390,7 +2483,6 @@ TEST_P(EndToEndTest, LargePostEarlyResponse) {
// POST to a URL that gets an early error response, after the headers are
// received and before the body is received.
HTTPMessage request(HttpConstants::HTTP_1_1, HttpConstants::POST, "/garbage");
- const uint32_t kBodySize = 2 * kWindowSize;
// Invalid content-length so the request will receive an early 500 response.
request.AddHeader("content-length", "-1");
request.set_skip_message_validation(true);
@@ -2404,28 +2496,11 @@ TEST_P(EndToEndTest, LargePostEarlyResponse) {
client_->WaitForInitialResponse();
EXPECT_EQ(500u, client_->response_headers()->parsed_response_code());
- if (negotiated_version_ > QUIC_VERSION_28) {
- // Receive the reset stream from server on early response.
- client_->WaitForResponseForMs(100);
- ReliableQuicStream* stream =
- client_->client()->session()->GetOrCreateStream(kClientDataStreamId1);
- // The stream is reset by server's reset stream.
- EXPECT_EQ(stream, nullptr);
- return;
- }
-
- // Send a body larger than the stream flow control window.
- string body;
- GenerateBody(&body, kBodySize);
- client_->SendData(body, true);
-
- // Run the client to let any buffered data be sent.
- // (This is OK despite already waiting for a response.)
- client_->WaitForResponse();
- // There should be no buffered data to write in the client's stream.
+ // Receive the reset stream from server on early response.
ReliableQuicStream* stream =
client_->client()->session()->GetOrCreateStream(kClientDataStreamId1);
- EXPECT_FALSE(stream != nullptr && stream->HasBufferedData());
+ // The stream is reset by server's reset stream.
+ EXPECT_EQ(stream, nullptr);
}
TEST_P(EndToEndTest, Trailers) {
@@ -2449,7 +2524,7 @@ TEST_P(EndToEndTest, Trailers) {
trailers["some-trailing-header"] = "trailing-header-value";
QuicInMemoryCache::GetInstance()->AddResponse(
- "www.google.com", "/trailer_url", std::move(headers), kBody,
+ server_hostname_, "/trailer_url", std::move(headers), kBody,
trailers.Clone());
EXPECT_EQ(kBody, client_->SendSynchronousRequest("/trailer_url"));
@@ -2462,7 +2537,6 @@ class EndToEndTestServerPush : public EndToEndTest {
const size_t kNumMaxStreams = 10;
EndToEndTestServerPush() : EndToEndTest() {
- FLAGS_quic_supports_push_promise = true;
client_config_.SetMaxStreamsPerConnection(kNumMaxStreams, kNumMaxStreams);
client_config_.SetMaxIncomingDynamicStreamsToSend(kNumMaxStreams);
server_config_.SetMaxStreamsPerConnection(kNumMaxStreams, kNumMaxStreams);
@@ -2531,7 +2605,9 @@ TEST_P(EndToEndTestServerPush, ServerPush) {
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, 0);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
DVLOG(1) << "send request for /push_example";
EXPECT_EQ(kBody, client_->SendSynchronousRequest(
@@ -2567,7 +2643,9 @@ TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
};
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, 0);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
// Send the first request: this will trigger the server to send all the push
// resources associated with this request, and these will be cached by the
@@ -2575,7 +2653,7 @@ TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
EXPECT_EQ(kBody, client_->SendSynchronousRequest(
"https://example.com/push_example"));
- for (string url : push_urls) {
+ for (const string& url : push_urls) {
// Sending subsequent requesets will not actually send anything on the wire,
// as the responses are already in the client's cache.
DVLOG(1) << "send request for pushed stream on url " << url;
@@ -2613,7 +2691,9 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) {
}
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, 0);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
// Send the first request: this will trigger the server to send all the push
// resources associated with this request, and these will be cached by the
@@ -2669,7 +2749,9 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, kBodySize);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
client_->SendRequest("https://example.com/push_example");
@@ -2715,7 +2797,10 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
EXPECT_EQ(12u, client_->num_responses());
}
+// TODO(ckrasic) - remove this when deprecating
+// FLAGS_quic_enable_server_push_by_default.
TEST_P(EndToEndTestServerPush, DisabledWithoutConnectionOption) {
+ FLAGS_quic_enable_server_push_by_default = false;
// Tests that server push won't be triggered when kSPSH is not set by client.
support_server_push_ = false;
ASSERT_TRUE(Initialize());
@@ -2730,7 +2815,9 @@ TEST_P(EndToEndTestServerPush, DisabledWithoutConnectionOption) {
};
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, 0);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
EXPECT_EQ(kBody, client_->SendSynchronousRequest(
"https://example.com/push_example"));
@@ -2821,6 +2908,61 @@ TEST_P(EndToEndTest, DISABLED_TestHugeResponseWithPacketLoss) {
}
}
+class EndToEndBufferedPacketsTest : public EndToEndTest {
+ public:
+ EndToEndBufferedPacketsTest() : EndToEndTest() {
+ FLAGS_quic_buffer_packet_till_chlo = true;
+ }
+
+ void CreateClientWithWriter() override {
+ LOG(ERROR) << "create client with reorder_writer_ ";
+ reorder_writer_ = new PacketReorderingWriter();
+ client_.reset(EndToEndTest::CreateQuicClient(reorder_writer_));
+ }
+
+ void SetUp() override {
+ // Don't initialize client writer in base class.
+ server_writer_ = new PacketDroppingTestWriter();
+ }
+
+ protected:
+ PacketReorderingWriter* reorder_writer_;
+};
+
+INSTANTIATE_TEST_CASE_P(EndToEndBufferedPacketsTests,
+ EndToEndBufferedPacketsTest,
+ testing::ValuesIn(GetTestParams()));
+
+TEST_P(EndToEndBufferedPacketsTest, Buffer0RttRequest) {
+ ASSERT_TRUE(Initialize());
+ if (negotiated_version_ <= QUIC_VERSION_32) {
+ // Since no 0-rtt for v32 and under, and this test relies on 0-rtt, skip
+ // this test if QUIC doesn't do 0-rtt.
+ return;
+ }
+ // Finish one request to make sure handshake established.
+ client_->SendSynchronousRequest("/foo");
+ // Disconnect for next 0-rtt request.
+ client_->Disconnect();
+
+ // Client get valid STK now. Do a 0-rtt request.
+ // Buffer a CHLO till another packets sent out.
+ reorder_writer_->SetDelay(1);
+ // Only send out a CHLO.
+ client_->client()->Initialize();
+ client_->client()->StartConnect();
+ ASSERT_TRUE(client_->client()->connected());
+ // Send a request before handshake finishes.
+ HTTPMessage request(HttpConstants::HTTP_1_1, HttpConstants::GET, "/bar");
+ client_->SendMessage(request);
+ client_->WaitForResponse();
+ EXPECT_EQ(kBarResponseBody, client_->response_body());
+ QuicConnectionStats client_stats =
+ client_->client()->session()->connection()->GetStats();
+ EXPECT_EQ(0u, client_stats.packets_lost);
+ EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/tools/quic/quic_client.cc b/chromium/net/tools/quic/quic_client.cc
index 224859e0537..ebb701d8f67 100644
--- a/chromium/net/tools/quic/quic_client.cc
+++ b/chromium/net/tools/quic/quic_client.cc
@@ -13,14 +13,16 @@
#include "base/logging.h"
#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "net/base/sockaddr_storage.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_socket_utils.h"
@@ -34,6 +36,7 @@
#define MMSG_MORE 0
using base::StringPiece;
+using base::StringToInt;
using std::string;
using std::vector;
@@ -41,46 +44,37 @@ namespace net {
const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
-void QuicClient::ClientQuicDataToResend::Resend() {
- client_->SendRequest(*headers_, body_, fin_);
- delete headers_;
- headers_ = nullptr;
-}
-
QuicClient::QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
EpollServer* epoll_server,
- ProofVerifier* proof_verifier)
+ std::unique_ptr<ProofVerifier> proof_verifier)
: QuicClient(server_address,
server_id,
supported_versions,
QuicConfig(),
epoll_server,
- proof_verifier) {}
+ std::move(proof_verifier)) {}
QuicClient::QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
EpollServer* epoll_server,
- ProofVerifier* proof_verifier)
+ std::unique_ptr<ProofVerifier> proof_verifier)
: QuicClientBase(
server_id,
supported_versions,
config,
new QuicEpollConnectionHelper(epoll_server, QuicAllocator::SIMPLE),
new QuicEpollAlarmFactory(epoll_server),
- proof_verifier),
- server_address_(server_address),
- local_port_(0),
+ std::move(proof_verifier)),
epoll_server_(epoll_server),
- initialized_(false),
packets_dropped_(0),
overflow_supported_(false),
- store_response_(false),
- latest_response_code_(-1),
- packet_reader_(new QuicPacketReader()) {}
+ packet_reader_(new QuicPacketReader()) {
+ set_server_address(server_address);
+}
QuicClient::~QuicClient() {
if (connected()) {
@@ -89,70 +83,27 @@ QuicClient::~QuicClient() {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
- STLDeleteElements(&data_to_resend_on_connect_);
- STLDeleteElements(&data_sent_before_handshake_);
-
CleanUpAllUDPSockets();
}
-bool QuicClient::Initialize() {
- QuicClientBase::Initialize();
-
- set_num_sent_client_hellos(0);
- set_num_stateless_rejects_received(0);
- set_connection_error(QUIC_NO_ERROR);
-
- // If an initial flow control window has not explicitly been set, then use the
- // same values that Chrome uses.
- const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
- const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
- if (config()->GetInitialStreamFlowControlWindowToSend() ==
- kMinimumFlowControlSendWindow) {
- config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
- }
- if (config()->GetInitialSessionFlowControlWindowToSend() ==
- kMinimumFlowControlSendWindow) {
- config()->SetInitialSessionFlowControlWindowToSend(
- kSessionMaxRecvWindowSize);
- }
-
+bool QuicClient::CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) {
epoll_server_->set_timeout_in_us(50 * 1000);
- if (!CreateUDPSocketAndBind()) {
- return false;
- }
-
- epoll_server_->RegisterFD(GetLatestFD(), this, kEpollFlags);
- initialized_ = true;
- return true;
-}
-
-QuicClient::QuicDataToResend::QuicDataToResend(BalsaHeaders* headers,
- StringPiece body,
- bool fin)
- : headers_(headers), body_(body), fin_(fin) {}
-
-QuicClient::QuicDataToResend::~QuicDataToResend() {
- if (headers_) {
- delete headers_;
- }
-}
-
-bool QuicClient::CreateUDPSocketAndBind() {
int fd =
- QuicSocketUtils::CreateUDPSocket(server_address_, &overflow_supported_);
+ QuicSocketUtils::CreateUDPSocket(server_address, &overflow_supported_);
if (fd < 0) {
return false;
}
IPEndPoint client_address;
- if (bind_to_address_.size() != 0) {
- client_address = IPEndPoint(bind_to_address_, local_port_);
- } else if (server_address_.GetSockAddrFamily() == AF_INET) {
- client_address = IPEndPoint(IPAddress::IPv4AllZeros(), local_port_);
+ if (bind_to_address.size() != 0) {
+ client_address = IPEndPoint(bind_to_address, bind_to_port);
+ } else if (server_address.GetSockAddrFamily() == AF_INET) {
+ client_address = IPEndPoint(IPAddress::IPv4AllZeros(), bind_to_port);
} else {
- IPAddress any6 = IPAddress::IPv6AllZeros();
- client_address = IPEndPoint(any6, local_port_);
+ client_address = IPEndPoint(IPAddress::IPv6AllZeros(), bind_to_port);
}
sockaddr_storage raw_addr;
@@ -174,92 +125,10 @@ bool QuicClient::CreateUDPSocketAndBind() {
fd_address_map_[fd] = client_address;
+ epoll_server_->RegisterFD(fd, this, kEpollFlags);
return true;
}
-bool QuicClient::Connect() {
- // Attempt multiple connects until the maximum number of client hellos have
- // been sent.
- while (!connected() &&
- GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
- StartConnect();
- while (EncryptionBeingEstablished()) {
- WaitForEvents();
- }
- if (FLAGS_enable_quic_stateless_reject_support && connected() &&
- !data_to_resend_on_connect_.empty()) {
- // A connection has been established and there was previously queued data
- // to resend. Resend it and empty the queue.
- for (QuicDataToResend* data : data_to_resend_on_connect_) {
- data->Resend();
- }
- STLDeleteElements(&data_to_resend_on_connect_);
- }
- if (session() != nullptr &&
- session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // We've successfully created a session but we're not connected, and there
- // is no stateless reject to recover from. Give up trying.
- break;
- }
- }
- if (!connected() &&
- GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
- session() != nullptr &&
- session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // The overall connection failed due too many stateless rejects.
- set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
- }
- return session()->connection()->connected();
-}
-
-void QuicClient::StartConnect() {
- DCHECK(initialized_);
- DCHECK(!connected());
-
- QuicPacketWriter* writer = CreateQuicPacketWriter();
-
- if (connected_or_attempting_connect()) {
- // Before we destroy the last session and create a new one, gather its stats
- // and update the stats for the overall connection.
- UpdateStats();
- if (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // If the last error was due to a stateless reject, queue up the data to
- // be resent on the next successful connection.
- // TODO(jokulik): I'm a little bit concerned about ordering here. Maybe
- // we should just maintain one queue?
- DCHECK(data_to_resend_on_connect_.empty());
- data_to_resend_on_connect_.swap(data_sent_before_handshake_);
- }
- }
-
- CreateQuicClientSession(new QuicConnection(
- GetNextConnectionId(), server_address_, helper(), alarm_factory(), writer,
- /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
-
- // Reset |writer()| after |session()| so that the old writer outlives the old
- // session.
- set_writer(writer);
- session()->Initialize();
- session()->CryptoConnect();
- set_connected_or_attempting_connect(true);
-}
-
-void QuicClient::Disconnect() {
- DCHECK(initialized_);
-
- if (connected()) {
- session()->connection()->CloseConnection(
- QUIC_PEER_GOING_AWAY, "Client disconnecting",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
- STLDeleteElements(&data_to_resend_on_connect_);
- STLDeleteElements(&data_sent_before_handshake_);
-
- CleanUpAllUDPSockets();
-
- initialized_ = false;
-}
-
void QuicClient::CleanUpUDPSocket(int fd) {
CleanUpUDPSocketImpl(fd);
fd_address_map_.erase(fd);
@@ -280,121 +149,9 @@ void QuicClient::CleanUpUDPSocketImpl(int fd) {
}
}
-void QuicClient::SendRequest(const BalsaHeaders& headers,
- StringPiece body,
- bool fin) {
- QuicClientPushPromiseIndex::TryHandle* handle;
- QuicAsyncStatus rv = push_promise_index()->Try(
- SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers), this, &handle);
- if (rv == QUIC_SUCCESS)
- return;
-
- if (rv == QUIC_PENDING) {
- // May need to retry request if asynchronous rendezvous fails.
- auto* new_headers = new BalsaHeaders;
- new_headers->CopyFrom(headers);
- push_promise_data_to_resend_.reset(
- new ClientQuicDataToResend(new_headers, body, fin, this));
- return;
- }
-
- QuicSpdyClientStream* stream = CreateReliableClientStream();
- if (stream == nullptr) {
- QUIC_BUG << "stream creation failed!";
- return;
- }
- stream->SendRequest(SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers),
- body, fin);
- if (FLAGS_enable_quic_stateless_reject_support) {
- // Record this in case we need to resend.
- auto* new_headers = new BalsaHeaders;
- new_headers->CopyFrom(headers);
- auto* data_to_resend =
- new ClientQuicDataToResend(new_headers, body, fin, this);
- MaybeAddQuicDataToResend(data_to_resend);
- }
-}
-
-void QuicClient::MaybeAddQuicDataToResend(QuicDataToResend* data_to_resend) {
- DCHECK(FLAGS_enable_quic_stateless_reject_support);
- if (session()->IsCryptoHandshakeConfirmed()) {
- // The handshake is confirmed. No need to continue saving requests to
- // resend.
- STLDeleteElements(&data_sent_before_handshake_);
- delete data_to_resend;
- return;
- }
-
- // The handshake is not confirmed. Push the data onto the queue of data to
- // resend if statelessly rejected.
- data_sent_before_handshake_.push_back(data_to_resend);
-}
-
-void QuicClient::SendRequestAndWaitForResponse(const BalsaHeaders& headers,
- StringPiece body,
- bool fin) {
- SendRequest(headers, body, fin);
- while (WaitForEvents()) {
- }
-}
-
-void QuicClient::SendRequestsAndWaitForResponse(
- const vector<string>& url_list) {
- for (size_t i = 0; i < url_list.size(); ++i) {
- BalsaHeaders headers;
- headers.SetRequestFirstlineFromStringPieces("GET", url_list[i], "HTTP/1.1");
- SendRequest(headers, "", true);
- }
- while (WaitForEvents()) {
- }
-}
-
-QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
- QuicSpdyClientStream* stream = QuicClientBase::CreateReliableClientStream();
- if (stream) {
- stream->set_visitor(this);
- }
- return stream;
-}
-
-bool QuicClient::WaitForEvents() {
- DCHECK(connected());
-
- epoll_server_->WaitForEventsAndExecuteCallbacks();
+void QuicClient::RunEventLoop() {
base::RunLoop().RunUntilIdle();
-
- DCHECK(session() != nullptr);
- if (!connected() &&
- session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- DCHECK(FLAGS_enable_quic_stateless_reject_support);
- DVLOG(1) << "Detected stateless reject while waiting for events. "
- << "Attempting to reconnect.";
- Connect();
- }
-
- return session()->num_active_requests() != 0;
-}
-
-bool QuicClient::MigrateSocket(const IPAddress& new_host) {
- if (!connected()) {
- return false;
- }
-
- CleanUpUDPSocket(GetLatestFD());
-
- bind_to_address_ = new_host;
- if (!CreateUDPSocketAndBind()) {
- return false;
- }
-
- epoll_server_->RegisterFD(GetLatestFD(), this, kEpollFlags);
- session()->connection()->SetSelfAddress(GetLatestClientAddress());
-
- QuicPacketWriter* writer = CreateQuicPacketWriter();
- set_writer(writer);
- session()->connection()->SetQuicPacketWriter(writer, false);
-
- return true;
+ epoll_server_->WaitForEventsAndExecuteCallbacks();
}
void QuicClient::OnEvent(int fd, EpollEvent* event) {
@@ -405,7 +162,7 @@ void QuicClient::OnEvent(int fd, EpollEvent* event) {
while (connected() && more_to_read) {
more_to_read = packet_reader_->ReadAndDispatchPackets(
GetLatestFD(), QuicClient::GetLatestClientAddress().port(),
- *helper()->GetClock(), this,
+ false /* potentially_small_mtu */, *helper()->GetClock(), this,
overflow_supported_ ? &packets_dropped_ : nullptr);
}
}
@@ -418,71 +175,11 @@ void QuicClient::OnEvent(int fd, EpollEvent* event) {
}
}
-void QuicClient::OnClose(QuicSpdyStream* stream) {
- DCHECK(stream != nullptr);
- QuicSpdyClientStream* client_stream =
- static_cast<QuicSpdyClientStream*>(stream);
- BalsaHeaders response_headers;
- SpdyBalsaUtils::SpdyHeadersToResponseHeaders(
- client_stream->response_headers(), &response_headers);
-
- if (response_listener_.get() != nullptr) {
- response_listener_->OnCompleteResponse(stream->id(), response_headers,
- client_stream->data());
- }
-
- // Store response headers and body.
- if (store_response_) {
- latest_response_code_ = response_headers.parsed_response_code();
- response_headers.DumpHeadersToString(&latest_response_headers_);
- latest_response_body_ = client_stream->data();
- latest_response_trailers_ =
- client_stream->received_trailers().DebugString();
- }
-}
-
-bool QuicClient::CheckVary(const SpdyHeaderBlock& client_request,
- const SpdyHeaderBlock& promise_request,
- const SpdyHeaderBlock& promise_response) {
- return true;
-}
-
-void QuicClient::OnRendezvousResult(QuicSpdyStream* stream) {
- std::unique_ptr<ClientQuicDataToResend> data_to_resend =
- std::move(push_promise_data_to_resend_);
- if (stream) {
- stream->set_visitor(this);
- stream->OnDataAvailable();
- } else if (data_to_resend.get()) {
- data_to_resend->Resend();
- }
-}
-
-size_t QuicClient::latest_response_code() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
- return latest_response_code_;
-}
-
-const string& QuicClient::latest_response_headers() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
- return latest_response_headers_;
-}
-
-const string& QuicClient::latest_response_body() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
- return latest_response_body_;
-}
-
-const string& QuicClient::latest_response_trailers() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
- return latest_response_trailers_;
-}
-
QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
return new QuicDefaultPacketWriter(GetLatestFD());
}
-const IPEndPoint QuicClient::GetLatestClientAddress() const {
+IPEndPoint QuicClient::GetLatestClientAddress() const {
if (fd_address_map_.empty()) {
return IPEndPoint();
}
@@ -501,7 +198,7 @@ int QuicClient::GetLatestFD() const {
void QuicClient::ProcessPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicReceivedPacket& packet) {
- session()->connection()->ProcessUdpPacket(self_address, peer_address, packet);
+ session()->ProcessUdpPacket(self_address, peer_address, packet);
}
} // namespace net
diff --git a/chromium/net/tools/quic/quic_client.h b/chromium/net/tools/quic/quic_client.h
index 99e529c4a2b..567dc6c837c 100644
--- a/chromium/net/tools/quic/quic_client.h
+++ b/chromium/net/tools/quic/quic_client.h
@@ -17,10 +17,9 @@
#include "base/strings/string_piece.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_client_push_promise_index.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_spdy_stream.h"
-#include "net/tools/balsa/balsa_headers.h"
+#include "net/quic/core/quic_client_push_promise_index.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_spdy_stream.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client_base.h"
#include "net/tools/quic/quic_client_session.h"
@@ -39,97 +38,24 @@ class QuicClientPeer;
class QuicClient : public QuicClientBase,
public EpollCallbackInterface,
- public QuicSpdyStream::Visitor,
- public ProcessPacketInterface,
- public QuicClientPushPromiseIndex::Delegate {
+ public ProcessPacketInterface {
public:
- class ResponseListener {
- public:
- ResponseListener() {}
- virtual ~ResponseListener() {}
- virtual void OnCompleteResponse(QuicStreamId id,
- const BalsaHeaders& response_headers,
- const std::string& response_body) = 0;
- };
-
- // The client uses these objects to keep track of any data to resend upon
- // receipt of a stateless reject. Recall that the client API allows callers
- // to optimistically send data to the server prior to handshake-confirmation.
- // If the client subsequently receives a stateless reject, it must tear down
- // its existing session, create a new session, and resend all previously sent
- // data. It uses these objects to keep track of all the sent data, and to
- // resend the data upon a subsequent connection.
- class QuicDataToResend {
- public:
- // Takes ownership of |headers|. |headers| may be null, since it's possible
- // to send data without headers.
- QuicDataToResend(BalsaHeaders* headers, base::StringPiece body, bool fin);
-
- virtual ~QuicDataToResend();
-
- // Must be overridden by specific classes with the actual method for
- // re-sending data.
- virtual void Resend() = 0;
-
- protected:
- BalsaHeaders* headers_;
- base::StringPiece body_;
- bool fin_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicDataToResend);
- };
-
// Create a quic client, which will have events managed by an externally owned
// EpollServer.
QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
EpollServer* epoll_server,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
EpollServer* epoll_server,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
~QuicClient() override;
- // From QuicClientBase
- bool Initialize() override;
- bool WaitForEvents() override;
- QuicSpdyClientStream* CreateReliableClientStream() override;
-
- // "Connect" to the QUIC server, including performing synchronous crypto
- // handshake.
- bool Connect();
-
- // Start the crypto handshake. This can be done in place of the synchronous
- // Connect(), but callers are responsible for making sure the crypto handshake
- // completes.
- void StartConnect();
-
- // Disconnects from the QUIC server.
- void Disconnect();
-
- // Sends an HTTP request and does not wait for response before returning.
- void SendRequest(const BalsaHeaders& headers,
- base::StringPiece body,
- bool fin);
-
- // Sends an HTTP request and waits for response before returning.
- void SendRequestAndWaitForResponse(const BalsaHeaders& headers,
- base::StringPiece body,
- bool fin);
-
- // Sends a request simple GET for each URL in |url_list|, and then waits for
- // each to complete.
- void SendRequestsAndWaitForResponse(const std::vector<std::string>& url_list);
-
- // Migrate to a new socket during an active connection.
- bool MigrateSocket(const IPAddress& new_host);
-
// From EpollCallbackInterface
void OnRegistration(EpollServer* eps, int fd, int event_mask) override {}
void OnModification(int fd, int event_mask) override {}
@@ -140,65 +66,32 @@ class QuicClient : public QuicClientBase,
void OnUnregistration(int fd, bool replaced) override {}
void OnShutdown(EpollServer* eps, int fd) override {}
- // QuicSpdyStream::Visitor
- void OnClose(QuicSpdyStream* stream) override;
-
- bool CheckVary(const SpdyHeaderBlock& client_request,
- const SpdyHeaderBlock& promise_request,
- const SpdyHeaderBlock& promise_response) override;
- void OnRendezvousResult(QuicSpdyStream*) override;
-
- // If the crypto handshake has not yet been confirmed, adds the data to the
- // queue of data to resend if the client receives a stateless reject.
- // Otherwise, deletes the data. Takes ownerership of |data_to_resend|.
- void MaybeAddQuicDataToResend(QuicDataToResend* data_to_resend);
-
- // If the client has at least one UDP socket, return address of the latest
- // created one. Otherwise, return an empty socket address.
- const IPEndPoint GetLatestClientAddress() const;
-
// If the client has at least one UDP socket, return the latest created one.
// Otherwise, return -1.
int GetLatestFD() const;
- void set_bind_to_address(const IPAddress& address) {
- bind_to_address_ = address;
- }
-
- const IPAddress& bind_to_address() const { return bind_to_address_; }
-
- void set_local_port(int local_port) { local_port_ = local_port; }
-
- const IPEndPoint& server_address() const { return server_address_; }
-
- // Takes ownership of the listener.
- void set_response_listener(ResponseListener* listener) {
- response_listener_.reset(listener);
- }
-
- void set_store_response(bool val) { store_response_ = val; }
-
- size_t latest_response_code() const;
- const std::string& latest_response_headers() const;
- const std::string& latest_response_body() const;
- const std::string& latest_response_trailers() const;
+ // From QuicClientBase
+ IPEndPoint GetLatestClientAddress() const override;
- protected:
// Implements ProcessPacketInterface. This will be called for each received
// packet.
void ProcessPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicReceivedPacket& packet) override;
- virtual QuicPacketWriter* CreateQuicPacketWriter();
+ protected:
+ // From QuicClientBase
+ QuicPacketWriter* CreateQuicPacketWriter() override;
+ void RunEventLoop() override;
+ bool CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) override;
+ void CleanUpAllUDPSockets() override;
// If |fd| is an open UDP socket, unregister and close it. Otherwise, do
// nothing.
virtual void CleanUpUDPSocket(int fd);
- // Unregister and close all open UDP sockets.
- virtual void CleanUpAllUDPSockets();
-
EpollServer* epoll_server() { return epoll_server_; }
const linked_hash_map<int, IPEndPoint>& fd_address_map() const {
@@ -208,52 +101,9 @@ class QuicClient : public QuicClientBase,
private:
friend class net::test::QuicClientPeer;
- // Specific QuicClient class for storing data to resend.
- class ClientQuicDataToResend : public QuicDataToResend {
- public:
- // Takes ownership of |headers|.
- ClientQuicDataToResend(BalsaHeaders* headers,
- base::StringPiece body,
- bool fin,
- QuicClient* client)
- : QuicDataToResend(headers, body, fin), client_(client) {
- DCHECK(headers);
- DCHECK(client);
- }
-
- ~ClientQuicDataToResend() override {}
-
- void Resend() override;
-
- private:
- QuicClient* client_;
-
- DISALLOW_COPY_AND_ASSIGN(ClientQuicDataToResend);
- };
-
- // Used during initialization: creates the UDP socket FD, sets socket options,
- // and binds the socket to our address.
- bool CreateUDPSocketAndBind();
-
// Actually clean up |fd|.
void CleanUpUDPSocketImpl(int fd);
- // If the request URL matches a push promise, bypass sending the
- // request.
- bool MaybeHandlePromised(const BalsaHeaders& headers,
- const SpdyHeaderBlock& spdy_headers,
- base::StringPiece body,
- bool fin);
-
- // Address of the server.
- const IPEndPoint server_address_;
-
- // If initialized, the address to bind to.
- IPAddress bind_to_address_;
-
- // Local port to bind to. Initialize to 0.
- int local_port_;
-
// Listens for events on the client socket.
EpollServer* epoll_server_;
@@ -261,12 +111,6 @@ class QuicClient : public QuicClientBase,
// map, the order of socket creation can be recorded.
linked_hash_map<int, IPEndPoint> fd_address_map_;
- // Listens for full responses.
- std::unique_ptr<ResponseListener> response_listener_;
-
- // Tracks if the client is initialized to connect.
- bool initialized_;
-
// If overflow_supported_ is true, this will be the number of packets dropped
// during the lifetime of the server.
QuicPacketCount packets_dropped_;
@@ -275,33 +119,10 @@ class QuicClient : public QuicClientBase,
// because the socket would otherwise overflow.
bool overflow_supported_;
- // If true, store the latest response code, headers, and body.
- bool store_response_;
- // HTTP response code from most recent response.
- size_t latest_response_code_;
- // HTTP/2 headers from most recent response.
- std::string latest_response_headers_;
- // Body of most recent response.
- std::string latest_response_body_;
- // HTTP/2 trailers from most recent response.
- std::string latest_response_trailers_;
-
- // Keeps track of any data sent before the handshake.
- std::vector<QuicDataToResend*> data_sent_before_handshake_;
-
- // Once the client receives a stateless reject, keeps track of any data that
- // must be resent upon a subsequent successful connection.
- std::vector<QuicDataToResend*> data_to_resend_on_connect_;
-
// Point to a QuicPacketReader object on the heap. The reader allocates more
// space than allowed on the stack.
- //
- // TODO(rtenneti): Chromium code doesn't use |packet_reader_|. Add support for
- // QuicPacketReader
std::unique_ptr<QuicPacketReader> packet_reader_;
- std::unique_ptr<ClientQuicDataToResend> push_promise_data_to_resend_;
-
DISALLOW_COPY_AND_ASSIGN(QuicClient);
};
diff --git a/chromium/net/tools/quic/quic_client_base.cc b/chromium/net/tools/quic/quic_client_base.cc
index 211c54d8e98..14af28a5757 100644
--- a/chromium/net/tools/quic/quic_client_base.cc
+++ b/chromium/net/tools/quic/quic_client_base.cc
@@ -4,20 +4,42 @@
#include "net/tools/quic/quic_client_base.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_server_id.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/spdy_utils.h"
+
+using base::StringPiece;
+using base::StringToInt;
+using std::string;
+using std::vector;
namespace net {
+void QuicClientBase::ClientQuicDataToResend::Resend() {
+ client_->SendRequest(*headers_, body_, fin_);
+ headers_ = nullptr;
+}
+
+QuicClientBase::QuicDataToResend::QuicDataToResend(
+ std::unique_ptr<SpdyHeaderBlock> headers,
+ StringPiece body,
+ bool fin)
+ : headers_(std::move(headers)), body_(body), fin_(fin) {}
+
+QuicClientBase::QuicDataToResend::~QuicDataToResend() {}
+
QuicClientBase::QuicClientBase(const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
QuicConnectionHelperInterface* helper,
QuicAlarmFactory* alarm_factory,
- ProofVerifier* proof_verifier)
+ std::unique_ptr<ProofVerifier> proof_verifier)
: server_id_(server_id),
+ initialized_(false),
+ local_port_(0),
config_(config),
- crypto_config_(proof_verifier),
+ crypto_config_(std::move(proof_verifier)),
helper_(helper),
alarm_factory_(alarm_factory),
supported_versions_(supported_versions),
@@ -25,18 +47,142 @@ QuicClientBase::QuicClientBase(const QuicServerId& server_id,
num_stateless_rejects_received_(0),
num_sent_client_hellos_(0),
connection_error_(QUIC_NO_ERROR),
- connected_or_attempting_connect_(false) {}
+ connected_or_attempting_connect_(false),
+ store_response_(false),
+ latest_response_code_(-1) {}
QuicClientBase::~QuicClientBase() {}
+void QuicClientBase::OnClose(QuicSpdyStream* stream) {
+ DCHECK(stream != nullptr);
+ QuicSpdyClientStream* client_stream =
+ static_cast<QuicSpdyClientStream*>(stream);
+
+ const SpdyHeaderBlock& response_headers = client_stream->response_headers();
+ if (response_listener_ != nullptr) {
+ response_listener_->OnCompleteResponse(stream->id(), response_headers,
+ client_stream->data());
+ }
+
+ // Store response headers and body.
+ if (store_response_) {
+ auto status = response_headers.find(":status");
+ if (status == response_headers.end() ||
+ !StringToInt(status->second, &latest_response_code_)) {
+ LOG(ERROR) << "Invalid response headers";
+ }
+ latest_response_headers_ = response_headers.DebugString();
+ latest_response_header_block_ = response_headers.Clone();
+ latest_response_body_ = client_stream->data();
+ latest_response_trailers_ =
+ client_stream->received_trailers().DebugString();
+ }
+}
+
bool QuicClientBase::Initialize() {
num_sent_client_hellos_ = 0;
num_stateless_rejects_received_ = 0;
connection_error_ = QUIC_NO_ERROR;
connected_or_attempting_connect_ = false;
+
+ // If an initial flow control window has not explicitly been set, then use the
+ // same values that Chrome uses.
+ const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
+ const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
+ if (config()->GetInitialStreamFlowControlWindowToSend() ==
+ kMinimumFlowControlSendWindow) {
+ config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
+ }
+ if (config()->GetInitialSessionFlowControlWindowToSend() ==
+ kMinimumFlowControlSendWindow) {
+ config()->SetInitialSessionFlowControlWindowToSend(
+ kSessionMaxRecvWindowSize);
+ }
+
+ if (!CreateUDPSocketAndBind(server_address_, bind_to_address_, local_port_)) {
+ return false;
+ }
+
+ initialized_ = true;
return true;
}
+bool QuicClientBase::Connect() {
+ // Attempt multiple connects until the maximum number of client hellos have
+ // been sent.
+ while (!connected() &&
+ GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
+ StartConnect();
+ while (EncryptionBeingEstablished()) {
+ WaitForEvents();
+ }
+ if (FLAGS_enable_quic_stateless_reject_support && connected()) {
+ // Resend any previously queued data.
+ ResendSavedData();
+ }
+ if (session() != nullptr &&
+ session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+ // We've successfully created a session but we're not connected, and there
+ // is no stateless reject to recover from. Give up trying.
+ break;
+ }
+ }
+ if (!connected() &&
+ GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
+ session() != nullptr &&
+ session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+ // The overall connection failed due too many stateless rejects.
+ set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
+ }
+ return session()->connection()->connected();
+}
+
+void QuicClientBase::StartConnect() {
+ DCHECK(initialized_);
+ DCHECK(!connected());
+
+ QuicPacketWriter* writer = CreateQuicPacketWriter();
+
+ if (connected_or_attempting_connect()) {
+ // If the last error was not a stateless reject, then the queued up data
+ // does not need to be resent.
+ if (session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+ ClearDataToResend();
+ }
+ // Before we destroy the last session and create a new one, gather its stats
+ // and update the stats for the overall connection.
+ UpdateStats();
+ }
+
+ CreateQuicClientSession(new QuicConnection(
+ GetNextConnectionId(), server_address(), helper(), alarm_factory(),
+ writer,
+ /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
+
+ // Reset |writer()| after |session()| so that the old writer outlives the old
+ // session.
+ set_writer(writer);
+ session()->Initialize();
+ session()->CryptoConnect();
+ set_connected_or_attempting_connect(true);
+}
+
+void QuicClientBase::Disconnect() {
+ DCHECK(initialized_);
+
+ if (connected()) {
+ session()->connection()->CloseConnection(
+ QUIC_PEER_GOING_AWAY, "Client disconnecting",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }
+
+ ClearDataToResend();
+
+ CleanUpAllUDPSockets();
+
+ initialized_ = false;
+}
+
ProofVerifier* QuicClientBase::proof_verifier() const {
return crypto_config_.proof_verifier();
}
@@ -56,12 +202,102 @@ bool QuicClientBase::EncryptionBeingEstablished() {
session_->connection()->connected();
}
+void QuicClientBase::SendRequest(const SpdyHeaderBlock& headers,
+ StringPiece body,
+ bool fin) {
+ QuicClientPushPromiseIndex::TryHandle* handle;
+ QuicAsyncStatus rv = push_promise_index()->Try(headers, this, &handle);
+ if (rv == QUIC_SUCCESS)
+ return;
+
+ if (rv == QUIC_PENDING) {
+ // May need to retry request if asynchronous rendezvous fails.
+ AddPromiseDataToResend(headers, body, fin);
+ return;
+ }
+
+ QuicSpdyClientStream* stream = CreateReliableClientStream();
+ if (stream == nullptr) {
+ QUIC_BUG << "stream creation failed!";
+ return;
+ }
+ stream->SendRequest(headers.Clone(), body, fin);
+ // Record this in case we need to resend.
+ MaybeAddDataToResend(headers, body, fin);
+}
+
+void QuicClientBase::SendRequestAndWaitForResponse(
+ const SpdyHeaderBlock& headers,
+ StringPiece body,
+ bool fin) {
+ SendRequest(headers, body, fin);
+ while (WaitForEvents()) {
+ }
+}
+
+void QuicClientBase::SendRequestsAndWaitForResponse(
+ const vector<string>& url_list) {
+ for (size_t i = 0; i < url_list.size(); ++i) {
+ SpdyHeaderBlock headers;
+ if (!SpdyUtils::PopulateHeaderBlockFromUrl(url_list[i], &headers)) {
+ QUIC_BUG << "Unable to create request";
+ continue;
+ }
+ SendRequest(headers, "", true);
+ }
+ while (WaitForEvents()) {
+ }
+}
+
QuicSpdyClientStream* QuicClientBase::CreateReliableClientStream() {
if (!connected()) {
return nullptr;
}
- return session_->CreateOutgoingDynamicStream(kDefaultPriority);
+ QuicSpdyClientStream* stream =
+ session_->CreateOutgoingDynamicStream(kDefaultPriority);
+ if (stream) {
+ stream->set_visitor(this);
+ }
+ return stream;
+}
+
+bool QuicClientBase::WaitForEvents() {
+ DCHECK(connected());
+
+ RunEventLoop();
+
+ DCHECK(session() != nullptr);
+ if (!connected() &&
+ session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+ DCHECK(FLAGS_enable_quic_stateless_reject_support);
+ DVLOG(1) << "Detected stateless reject while waiting for events. "
+ << "Attempting to reconnect.";
+ Connect();
+ }
+
+ return session()->num_active_requests() != 0;
+}
+
+bool QuicClientBase::MigrateSocket(const IPAddress& new_host) {
+ if (!connected()) {
+ return false;
+ }
+
+ CleanUpAllUDPSockets();
+
+ set_bind_to_address(new_host);
+ if (!CreateUDPSocketAndBind(server_address_, bind_to_address_, local_port_)) {
+ return false;
+ }
+
+ session()->connection()->SetSelfAddress(GetLatestClientAddress());
+
+ QuicPacketWriter* writer = CreateQuicPacketWriter();
+ set_writer(writer);
+ session()->connection()->SetQuicPacketWriter(writer, false);
+
+ return true;
}
void QuicClientBase::WaitForStreamToClose(QuicStreamId id) {
@@ -122,7 +358,7 @@ QuicErrorCode QuicClientBase::connection_error() const {
if (connection_error_ != QUIC_NO_ERROR) {
return connection_error_;
}
- if (session_.get() == nullptr) {
+ if (session_ == nullptr) {
return QUIC_NO_ERROR;
}
return session_->error();
@@ -150,4 +386,97 @@ QuicConnectionId QuicClientBase::GenerateNewConnectionId() {
return QuicRandom::GetInstance()->RandUint64();
}
+void QuicClientBase::MaybeAddDataToResend(const SpdyHeaderBlock& headers,
+ StringPiece body,
+ bool fin) {
+ if (!FLAGS_enable_quic_stateless_reject_support) {
+ return;
+ }
+
+ if (session()->IsCryptoHandshakeConfirmed()) {
+ // The handshake is confirmed. No need to continue saving requests to
+ // resend.
+ data_to_resend_on_connect_.clear();
+ return;
+ }
+
+ // The handshake is not confirmed. Push the data onto the queue of data to
+ // resend if statelessly rejected.
+ std::unique_ptr<SpdyHeaderBlock> new_headers(
+ new SpdyHeaderBlock(headers.Clone()));
+ std::unique_ptr<QuicDataToResend> data_to_resend(
+ new ClientQuicDataToResend(std::move(new_headers), body, fin, this));
+ MaybeAddQuicDataToResend(std::move(data_to_resend));
+}
+
+void QuicClientBase::MaybeAddQuicDataToResend(
+ std::unique_ptr<QuicDataToResend> data_to_resend) {
+ data_to_resend_on_connect_.push_back(std::move(data_to_resend));
+}
+
+void QuicClientBase::ClearDataToResend() {
+ data_to_resend_on_connect_.clear();
+}
+
+void QuicClientBase::ResendSavedData() {
+ // Calling Resend will re-enqueue the data, so swap out
+ // data_to_resend_on_connect_ before iterating.
+ vector<std::unique_ptr<QuicDataToResend>> old_data;
+ old_data.swap(data_to_resend_on_connect_);
+ for (const auto& data : old_data) {
+ data->Resend();
+ }
+}
+
+void QuicClientBase::AddPromiseDataToResend(const SpdyHeaderBlock& headers,
+ StringPiece body,
+ bool fin) {
+ std::unique_ptr<SpdyHeaderBlock> new_headers(
+ new SpdyHeaderBlock(headers.Clone()));
+ push_promise_data_to_resend_.reset(
+ new ClientQuicDataToResend(std::move(new_headers), body, fin, this));
+}
+
+bool QuicClientBase::CheckVary(const SpdyHeaderBlock& client_request,
+ const SpdyHeaderBlock& promise_request,
+ const SpdyHeaderBlock& promise_response) {
+ return true;
+}
+
+void QuicClientBase::OnRendezvousResult(QuicSpdyStream* stream) {
+ std::unique_ptr<ClientQuicDataToResend> data_to_resend =
+ std::move(push_promise_data_to_resend_);
+ if (stream) {
+ stream->set_visitor(this);
+ stream->OnDataAvailable();
+ } else if (data_to_resend.get()) {
+ data_to_resend->Resend();
+ }
+}
+
+size_t QuicClientBase::latest_response_code() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_code_;
+}
+
+const string& QuicClientBase::latest_response_headers() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_headers_;
+}
+
+const SpdyHeaderBlock& QuicClientBase::latest_response_header_block() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_header_block_;
+}
+
+const string& QuicClientBase::latest_response_body() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_body_;
+}
+
+const string& QuicClientBase::latest_response_trailers() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_trailers_;
+}
+
} // namespace net
diff --git a/chromium/net/tools/quic/quic_client_base.h b/chromium/net/tools/quic/quic_client_base.h
index 3f9e514fb89..b32cd0a4c3c 100644
--- a/chromium/net/tools/quic/quic_client_base.h
+++ b/chromium/net/tools/quic/quic_client_base.h
@@ -13,16 +13,15 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/log/net_log.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_crypto_client_config.h"
-#include "net/quic/quic_alarm_factory.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_client_push_promise_index.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/quic/core/quic_alarm_factory.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_client_push_promise_index.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_client_session.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
@@ -31,27 +30,96 @@ namespace net {
class ProofVerifier;
class QuicServerId;
-class QuicClientBase {
+class QuicClientBase : public QuicClientPushPromiseIndex::Delegate,
+ public QuicSpdyStream::Visitor {
public:
+ // A ResponseListener is notified when a complete response is received.
+ class ResponseListener {
+ public:
+ ResponseListener() {}
+ virtual ~ResponseListener() {}
+ virtual void OnCompleteResponse(QuicStreamId id,
+ const SpdyHeaderBlock& response_headers,
+ const std::string& response_body) = 0;
+ };
+
+ // The client uses these objects to keep track of any data to resend upon
+ // receipt of a stateless reject. Recall that the client API allows callers
+ // to optimistically send data to the server prior to handshake-confirmation.
+ // If the client subsequently receives a stateless reject, it must tear down
+ // its existing session, create a new session, and resend all previously sent
+ // data. It uses these objects to keep track of all the sent data, and to
+ // resend the data upon a subsequent connection.
+ class QuicDataToResend {
+ public:
+ // |headers| may be null, since it's possible to send data without headers.
+ QuicDataToResend(std::unique_ptr<SpdyHeaderBlock> headers,
+ base::StringPiece body,
+ bool fin);
+
+ virtual ~QuicDataToResend();
+
+ // Must be overridden by specific classes with the actual method for
+ // re-sending data.
+ virtual void Resend() = 0;
+
+ protected:
+ std::unique_ptr<SpdyHeaderBlock> headers_;
+ base::StringPiece body_;
+ bool fin_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicDataToResend);
+ };
+
QuicClientBase(const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
QuicConnectionHelperInterface* helper,
QuicAlarmFactory* alarm_factory,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
+
+ ~QuicClientBase() override;
- ~QuicClientBase();
+ // QuicSpdyStream::Visitor
+ void OnClose(QuicSpdyStream* stream) override;
// Initializes the client to create a connection. Should be called exactly
// once before calling StartConnect or Connect. Returns true if the
// initialization succeeds, false otherwise.
virtual bool Initialize();
+ // "Connect" to the QUIC server, including performing synchronous crypto
+ // handshake.
+ bool Connect();
+
+ // Start the crypto handshake. This can be done in place of the synchronous
+ // Connect(), but callers are responsible for making sure the crypto handshake
+ // completes.
+ void StartConnect();
+
+ // Disconnects from the QUIC server.
+ void Disconnect();
+
// Returns true if the crypto handshake has yet to establish encryption.
// Returns false if encryption is active (even if the server hasn't confirmed
// the handshake) or if the connection has been closed.
bool EncryptionBeingEstablished();
+ // Sends an HTTP request and does not wait for response before returning.
+ void SendRequest(const SpdyHeaderBlock& headers,
+ base::StringPiece body,
+ bool fin);
+
+ // Sends an HTTP request and waits for response before returning.
+ void SendRequestAndWaitForResponse(const SpdyHeaderBlock& headers,
+ base::StringPiece body,
+ bool fin);
+
+ // Sends a request simple GET for each URL in |url_list|, and then waits for
+ // each to complete.
+ void SendRequestsAndWaitForResponse(const std::vector<std::string>& url_list);
+
// Returns a newly created QuicSpdyClientStream, owned by the
// QuicSimpleClient.
virtual QuicSpdyClientStream* CreateReliableClientStream();
@@ -64,7 +132,10 @@ class QuicClientBase {
// Wait up to 50ms, and handle any events which occur.
// Returns true if there are any outstanding requests.
- virtual bool WaitForEvents() = 0;
+ bool WaitForEvents();
+
+ // Migrate to a new socket during an active connection.
+ bool MigrateSocket(const IPAddress& new_host);
QuicClientSession* session() { return session_.get(); }
@@ -88,6 +159,17 @@ class QuicClientBase {
crypto_config_.SetChannelIDSource(source);
}
+ // UseTokenBinding enables token binding negotiation in the client. This
+ // should only be called before the initial Connect(). The client will still
+ // need to check that token binding is negotiated with the server, and add
+ // token binding headers to requests if so. server, and add token binding
+ // headers to requests if so. The negotiated token binding parameters can be
+ // found on the QuicCryptoNegotiatedParameters object in
+ // token_binding_key_param.
+ void UseTokenBinding() {
+ crypto_config_.tb_key_params = QuicTagVector{kTB10};
+ }
+
const QuicVersionVector& supported_versions() const {
return supported_versions_;
}
@@ -164,10 +246,67 @@ class QuicClientBase {
return &push_promise_index_;
}
+ bool CheckVary(const SpdyHeaderBlock& client_request,
+ const SpdyHeaderBlock& promise_request,
+ const SpdyHeaderBlock& promise_response) override;
+ void OnRendezvousResult(QuicSpdyStream*) override;
+
+ // If the crypto handshake has not yet been confirmed, adds the data to the
+ // queue of data to resend if the client receives a stateless reject.
+ // Otherwise, deletes the data.
+ void MaybeAddQuicDataToResend(
+ std::unique_ptr<QuicDataToResend> data_to_resend);
+
+ void set_store_response(bool val) { store_response_ = val; }
+
+ size_t latest_response_code() const;
+ const std::string& latest_response_headers() const;
+ const SpdyHeaderBlock& latest_response_header_block() const;
+ const std::string& latest_response_body() const;
+ const std::string& latest_response_trailers() const;
+
+ void set_response_listener(std::unique_ptr<ResponseListener> listener) {
+ response_listener_ = std::move(listener);
+ }
+
+ void set_bind_to_address(IPAddress address) { bind_to_address_ = address; }
+
+ IPAddress bind_to_address() const { return bind_to_address_; }
+
+ void set_local_port(int local_port) { local_port_ = local_port; }
+
+ int local_port() const { return local_port_; }
+
+ const IPEndPoint& server_address() const { return server_address_; }
+
+ void set_server_address(const IPEndPoint& server_address) {
+ server_address_ = server_address;
+ }
+
protected:
+ // Creates a packet writer to be used for the next connection.
+ virtual QuicPacketWriter* CreateQuicPacketWriter() = 0;
+
+ // Takes ownership of |connection|.
virtual QuicClientSession* CreateQuicClientSession(
QuicConnection* connection);
+ // Runs one iteration of the event loop.
+ virtual void RunEventLoop() = 0;
+
+ // Used during initialization: creates the UDP socket FD, sets socket options,
+ // and binds the socket to our address.
+ virtual bool CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) = 0;
+
+ // Unregister and close all open UDP sockets.
+ virtual void CleanUpAllUDPSockets() = 0;
+
+ // If the client has at least one UDP socket, return address of the latest
+ // created one. Otherwise, return an empty socket address.
+ virtual IPEndPoint GetLatestClientAddress() const = 0;
+
// Generates the next ConnectionId for |server_id_|. By default, if the
// cached server config contains a server-designated ID, that ID will be
// returned. Otherwise, the next random ID will be returned.
@@ -181,6 +320,21 @@ class QuicClientBase {
// connection ID).
virtual QuicConnectionId GenerateNewConnectionId();
+ // If the crypto handshake has not yet been confirmed, adds the data to the
+ // queue of data to resend if the client receives a stateless reject.
+ // Otherwise, deletes the data.
+ void MaybeAddDataToResend(const SpdyHeaderBlock& headers,
+ base::StringPiece body,
+ bool fin);
+
+ void ClearDataToResend();
+
+ void ResendSavedData();
+
+ void AddPromiseDataToResend(const SpdyHeaderBlock& headers,
+ base::StringPiece body,
+ bool fin);
+
QuicConnectionHelperInterface* helper() { return helper_.get(); }
QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); }
@@ -194,24 +348,60 @@ class QuicClientBase {
}
private:
+ // Specific QuicClient class for storing data to resend.
+ class ClientQuicDataToResend : public QuicDataToResend {
+ public:
+ ClientQuicDataToResend(std::unique_ptr<SpdyHeaderBlock> headers,
+ base::StringPiece body,
+ bool fin,
+ QuicClientBase* client)
+ : QuicDataToResend(std::move(headers), body, fin), client_(client) {
+ DCHECK(headers_);
+ DCHECK(client);
+ }
+
+ ~ClientQuicDataToResend() override {}
+
+ void Resend() override;
+
+ private:
+ QuicClientBase* client_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientQuicDataToResend);
+ };
+
// |server_id_| is a tuple (hostname, port, is_https) of the server.
QuicServerId server_id_;
+ // Tracks if the client is initialized to connect.
+ bool initialized_;
+
+ // Address of the server.
+ IPEndPoint server_address_;
+
+ // If initialized, the address to bind to.
+ IPAddress bind_to_address_;
+
+ // Local port to bind to. Initialize to 0.
+ int local_port_;
+
// config_ and crypto_config_ contain configuration and cached state about
// servers.
QuicConfig config_;
QuicCryptoClientConfig crypto_config_;
- // Helper to be used by created connections. Needs to outlive |session_|.
+ // Helper to be used by created connections. Must outlive |session_|.
std::unique_ptr<QuicConnectionHelperInterface> helper_;
- // Helper to be used by created connections. Needs to outlive |session_|.
+ // Alarm factory to be used by created connections. Must outlive |session_|.
std::unique_ptr<QuicAlarmFactory> alarm_factory_;
- // Writer used to actually send packets to the wire. Needs to outlive
- // |session_|.
+ // Writer used to actually send packets to the wire. Must outlive |session_|.
std::unique_ptr<QuicPacketWriter> writer_;
+ // Index of pending promised streams. Must outlive |session_|.
+ QuicClientPushPromiseIndex push_promise_index_;
+
// Session which manages streams.
std::unique_ptr<QuicClientSession> session_;
@@ -247,7 +437,27 @@ class QuicClientBase {
// to the previous client-level connection.
bool connected_or_attempting_connect_;
- QuicClientPushPromiseIndex push_promise_index_;
+ // If true, store the latest response code, headers, and body.
+ bool store_response_;
+ // HTTP response code from most recent response.
+ int latest_response_code_;
+ // HTTP/2 headers from most recent response.
+ std::string latest_response_headers_;
+ // HTTP/2 headers from most recent response.
+ SpdyHeaderBlock latest_response_header_block_;
+ // Body of most recent response.
+ std::string latest_response_body_;
+ // HTTP/2 trailers from most recent response.
+ std::string latest_response_trailers_;
+
+ // Listens for full responses.
+ std::unique_ptr<ResponseListener> response_listener_;
+
+ // Keeps track of any data that must be resent upon a subsequent successful
+ // connection, in case the client receives a stateless reject.
+ std::vector<std::unique_ptr<QuicDataToResend>> data_to_resend_on_connect_;
+
+ std::unique_ptr<ClientQuicDataToResend> push_promise_data_to_resend_;
DISALLOW_COPY_AND_ASSIGN(QuicClientBase);
};
diff --git a/chromium/net/tools/quic/quic_client_bin.cc b/chromium/net/tools/quic/quic_client_bin.cc
index 26820af6e5d..07ff2fc5c98 100644
--- a/chromium/net/tools/quic/quic_client_bin.cc
+++ b/chromium/net/tools/quic/quic_client_bin.cc
@@ -55,12 +55,11 @@
#include "net/cert/cert_verifier.h"
#include "net/cert/multi_log_ct_verifier.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_utils.h"
#include "net/spdy/spdy_header_block.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client.h"
@@ -113,7 +112,7 @@ class FakeCertVerifier : public net::CertVerifier {
net::CertVerifyResult* verify_result,
const net::CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const net::BoundNetLog& net_log) override {
+ const net::NetLogWithSource& net_log) override {
return net::OK;
}
@@ -239,7 +238,7 @@ int main(int argc, char* argv[]) {
net::EpollServer epoll_server;
net::QuicServerId server_id(url.host(), url.EffectiveIntPort(),
net::PRIVACY_MODE_DISABLED);
- net::QuicVersionVector versions = net::QuicSupportedVersions();
+ net::QuicVersionVector versions = net::AllSupportedVersions();
if (FLAGS_quic_version != -1) {
versions.clear();
versions.push_back(static_cast<net::QuicVersion>(FLAGS_quic_version));
@@ -254,11 +253,12 @@ int main(int argc, char* argv[]) {
transport_security_state.reset(new TransportSecurityState);
std::unique_ptr<CTVerifier> ct_verifier(new MultiLogCTVerifier());
std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer(new CTPolicyEnforcer());
- ProofVerifierChromium* proof_verifier = new ProofVerifierChromium(
- cert_verifier.get(), ct_policy_enforcer.get(),
- transport_security_state.get(), ct_verifier.get());
- net::QuicClient client(net::IPEndPoint(ip_addr, FLAGS_port), server_id,
- versions, &epoll_server, proof_verifier);
+ std::unique_ptr<net::ProofVerifierChromium> proof_verifier(
+ new ProofVerifierChromium(cert_verifier.get(), ct_policy_enforcer.get(),
+ transport_security_state.get(),
+ ct_verifier.get()));
+ net::QuicClient client(net::IPEndPoint(ip_addr, port), server_id, versions,
+ &epoll_server, std::move(proof_verifier));
client.set_initial_max_packet_length(
FLAGS_initial_mtu != 0 ? FLAGS_initial_mtu : net::kDefaultMaxPacketSize);
if (!client.Initialize()) {
@@ -312,11 +312,10 @@ int main(int argc, char* argv[]) {
// Make sure to store the response, for later output.
client.set_store_response(true);
-
// Send the request.
net::SpdyHeaderBlock header_block =
net::SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers);
- client.SendRequestAndWaitForResponse(headers, body, /*fin=*/true);
+ client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true);
// Print request and response details.
if (!FLAGS_quiet) {
@@ -324,9 +323,8 @@ int main(int argc, char* argv[]) {
cout << "headers:" << header_block.DebugString();
if (!FLAGS_body_hex.empty()) {
// Print the user provided hex, rather than binary body.
- cout << "body hex: " << FLAGS_body_hex << endl;
- cout << "body ascii: " << net::QuicUtils::BinaryToAscii(
- net::QuicUtils::HexDecode(FLAGS_body_hex))
+ cout << "body:\n"
+ << net::QuicUtils::HexDump(net::QuicUtils::HexDecode(FLAGS_body_hex))
<< endl;
} else {
cout << "body: " << body << endl;
@@ -337,10 +335,7 @@ int main(int argc, char* argv[]) {
string response_body = client.latest_response_body();
if (!FLAGS_body_hex.empty()) {
// Assume response is binary data.
- cout << "body hex: " << net::QuicUtils::HexEncode(response_body)
- << endl;
- cout << "body ascii: " << net::QuicUtils::BinaryToAscii(response_body)
- << endl;
+ cout << "body:\n" << net::QuicUtils::HexDump(response_body) << endl;
} else {
cout << "body: " << response_body << endl;
}
diff --git a/chromium/net/tools/quic/quic_client_session.cc b/chromium/net/tools/quic/quic_client_session.cc
index a0e11b1cfb4..48ed1d0950c 100644
--- a/chromium/net/tools/quic/quic_client_session.cc
+++ b/chromium/net/tools/quic/quic_client_session.cc
@@ -5,9 +5,11 @@
#include "net/tools/quic/quic_client_session.h"
#include "base/logging.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/quic_server_id.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_server_id.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
using std::string;
@@ -90,7 +92,7 @@ int QuicClientSession::GetNumReceivedServerConfigUpdates() const {
bool QuicClientSession::ShouldCreateIncomingDynamicStream(QuicStreamId id) {
if (!connection()->connected()) {
- LOG(DFATAL) << "ShouldCreateIncomingDynamicStream called when disconnected";
+ QUIC_BUG << "ShouldCreateIncomingDynamicStream called when disconnected";
return false;
}
if (goaway_received() && respect_goaway_) {
@@ -121,7 +123,7 @@ QuicSpdyStream* QuicClientSession::CreateIncomingDynamicStream(
QuicCryptoClientStreamBase* QuicClientSession::CreateQuicCryptoStream() {
return new QuicCryptoClientStream(
- server_id_, this, new ProofVerifyContextChromium(0, BoundNetLog()),
+ server_id_, this, new ProofVerifyContextChromium(0, NetLogWithSource()),
crypto_config_, this);
}
diff --git a/chromium/net/tools/quic/quic_client_session.h b/chromium/net/tools/quic/quic_client_session.h
index fc5abbf12f6..af9ee0952f6 100644
--- a/chromium/net/tools/quic/quic_client_session.h
+++ b/chromium/net/tools/quic/quic_client_session.h
@@ -11,9 +11,9 @@
#include <string>
#include "base/macros.h"
-#include "net/quic/quic_client_session_base.h"
-#include "net/quic/quic_crypto_client_stream.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
namespace net {
@@ -24,7 +24,8 @@ class ReliableQuicStream;
class QuicClientSession : public QuicClientSessionBase {
public:
- // Caller retains ownership of |promised_by_url|.
+ // Takes ownership of |connection|. Caller retains ownership of
+ // |promised_by_url|.
QuicClientSession(const QuicConfig& config,
QuicConnection* connection,
const QuicServerId& server_id,
diff --git a/chromium/net/tools/quic/quic_client_session_test.cc b/chromium/net/tools/quic/quic_client_session_test.cc
index a38214c8b28..75d02cb8eea 100644
--- a/chromium/net/tools/quic/quic_client_session_test.cc
+++ b/chromium/net/tools/quic/quic_client_session_test.cc
@@ -8,9 +8,9 @@
#include "base/strings/stringprintf.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/mock_quic_spdy_client_stream.h"
#include "net/quic/test_tools/quic_config_peer.h"
@@ -36,7 +36,6 @@ using net::test::QuicPacketCreatorPeer;
using net::test::QuicSpdySessionPeer;
using net::test::SupportedVersions;
using net::test::TestPeerIPAddress;
-using net::test::ValueRestore;
using net::test::kClientDataStreamId1;
using net::test::kServerDataStreamId1;
using net::test::kTestPort;
@@ -141,7 +140,7 @@ class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> {
INSTANTIATE_TEST_CASE_P(Tests,
QuicClientSessionTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicClientSessionTest, CryptoConnect) {
CompleteCryptoHandshake();
diff --git a/chromium/net/tools/quic/quic_client_test.cc b/chromium/net/tools/quic/quic_client_test.cc
index dca06bddae2..dd360de33a7 100644
--- a/chromium/net/tools/quic/quic_client_test.cc
+++ b/chromium/net/tools/quic/quic_client_test.cc
@@ -43,7 +43,7 @@ QuicClient* CreateAndInitializeQuicClient(EpollServer* eps, uint16_t port) {
IPEndPoint server_address(IPEndPoint(net::test::Loopback4(), port));
QuicServerId server_id("hostname", server_address.port(),
PRIVACY_MODE_DISABLED);
- QuicVersionVector versions = QuicSupportedVersions();
+ QuicVersionVector versions = AllSupportedVersions();
QuicClient* client =
new QuicClient(server_address, server_id, versions, eps,
CryptoTestUtils::ProofVerifierForTesting());
@@ -54,7 +54,7 @@ QuicClient* CreateAndInitializeQuicClient(EpollServer* eps, uint16_t port) {
TEST(QuicClientTest, DoNotLeakFDs) {
// Create a ProofVerifier before counting the number of open FDs to work
// around some ASAN weirdness.
- delete CryptoTestUtils::ProofVerifierForTesting();
+ CryptoTestUtils::ProofVerifierForTesting().reset();
// Make sure that the QuicClient doesn't leak FDs. Doing so could cause port
// exhaustion in long running processes which repeatedly create clients.
@@ -81,7 +81,7 @@ TEST(QuicClientTest, DoNotLeakFDs) {
TEST(QuicClientTest, CreateAndCleanUpUDPSockets) {
// Create a ProofVerifier before counting the number of open FDs to work
// around some ASAN weirdness.
- delete CryptoTestUtils::ProofVerifierForTesting();
+ CryptoTestUtils::ProofVerifierForTesting().reset();
EpollServer eps;
int number_of_open_fds = NumOpenFDs();
diff --git a/chromium/net/tools/quic/quic_default_packet_writer.h b/chromium/net/tools/quic/quic_default_packet_writer.h
index 0a8f1093273..e695637b470 100644
--- a/chromium/net/tools/quic/quic_default_packet_writer.h
+++ b/chromium/net/tools/quic/quic_default_packet_writer.h
@@ -9,7 +9,8 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_packet_writer.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_packet_writer.h"
namespace net {
@@ -17,7 +18,7 @@ struct WriteResult;
// Default packet writer which wraps QuicSocketUtils WritePacket.
-class QuicDefaultPacketWriter : public QuicPacketWriter {
+class NET_EXPORT_PRIVATE QuicDefaultPacketWriter : public QuicPacketWriter {
public:
explicit QuicDefaultPacketWriter(int fd);
~QuicDefaultPacketWriter() override;
diff --git a/chromium/net/tools/quic/quic_dispatcher.cc b/chromium/net/tools/quic/quic_dispatcher.cc
index 70f2af14411..b43b8e1664f 100644
--- a/chromium/net/tools/quic/quic_dispatcher.cc
+++ b/chromium/net/tools/quic/quic_dispatcher.cc
@@ -10,21 +10,28 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/stl_util.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
#include "net/tools/quic/chlo_extractor.h"
#include "net/tools/quic/quic_per_connection_packet_writer.h"
#include "net/tools/quic/quic_simple_server_session.h"
+#include "net/tools/quic/quic_simple_server_session.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
#include "net/tools/quic/stateless_rejector.h"
using base::StringPiece;
+using std::list;
using std::string;
namespace net {
+typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
+typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
+typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;
+
namespace {
// An alarm that informs the QuicDispatcher to delete old sessions.
@@ -150,7 +157,7 @@ class StatelessConnectionTerminator {
// to give the QuicDispatcher a chance to apply policy checks to the CHLO.
class ChloValidator : public ChloExtractor::Delegate {
public:
- ChloValidator(QuicServerSessionBase::Helper* helper,
+ ChloValidator(QuicCryptoServerStream::Helper* helper,
IPEndPoint self_address,
StatelessRejector* rejector)
: helper_(helper),
@@ -175,7 +182,7 @@ class ChloValidator : public ChloExtractor::Delegate {
const string& error_details() const { return error_details_; }
private:
- QuicServerSessionBase::Helper* helper_; // Unowned.
+ QuicCryptoServerStream::Helper* helper_; // Unowned.
IPEndPoint self_address_;
StatelessRejector* rejector_; // Unowned.
bool can_accept_;
@@ -187,9 +194,9 @@ class ChloValidator : public ChloExtractor::Delegate {
QuicDispatcher::QuicDispatcher(
const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
- const QuicVersionVector& supported_versions,
+ QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
std::unique_ptr<QuicAlarmFactory> alarm_factory)
: config_(config),
crypto_config_(crypto_config),
@@ -200,20 +207,20 @@ QuicDispatcher::QuicDispatcher(
alarm_factory_(std::move(alarm_factory)),
delete_sessions_alarm_(
alarm_factory_->CreateAlarm(new DeleteSessionsAlarm(this))),
- supported_versions_(supported_versions),
- disable_quic_pre_30_(FLAGS_quic_disable_pre_30),
- allowed_supported_versions_(supported_versions),
+ buffered_packets_(this, helper_->GetClock(), alarm_factory_.get()),
current_packet_(nullptr),
- framer_(supported_versions,
+ version_manager_(version_manager),
+ framer_(GetSupportedVersions(),
/*unused*/ QuicTime::Zero(),
Perspective::IS_SERVER),
- last_error_(QUIC_NO_ERROR) {
+ last_error_(QUIC_NO_ERROR),
+ new_sessions_allowed_per_event_loop_(0u) {
framer_.set_visitor(this);
}
QuicDispatcher::~QuicDispatcher() {
- STLDeleteValues(&session_map_);
- STLDeleteElements(&closed_session_list_);
+ base::STLDeleteValues(&session_map_);
+ base::STLDeleteElements(&closed_session_list_);
}
void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) {
@@ -260,11 +267,18 @@ bool QuicDispatcher::OnUnauthenticatedPublicHeader(
QuicConnectionId connection_id = header.connection_id;
SessionMap::iterator it = session_map_.find(connection_id);
if (it != session_map_.end()) {
+ DCHECK(!buffered_packets_.HasBufferedPackets(connection_id));
it->second->ProcessUdpPacket(current_server_address_,
current_client_address_, *current_packet_);
return false;
}
+ if (FLAGS_quic_buffer_packets_after_chlo &&
+ buffered_packets_.HasChloForConnection(connection_id)) {
+ BufferEarlyPacket(connection_id);
+ return false;
+ }
+
if (!OnUnauthenticatedUnknownPublicHeader(header)) {
return false;
}
@@ -319,29 +333,35 @@ bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
return false;
}
- // Packet's connection ID is unknown.
- // Apply the validity checks.
+ // Packet's connection ID is unknown. Apply the validity checks.
QuicPacketFate fate = ValidityChecks(header);
if (fate == kFateProcess) {
- fate = MaybeRejectStatelessly(connection_id, header);
+ // Execute stateless rejection logic to determine the packet fate, then
+ // invoke ProcessUnauthenticatedHeaderFate.
+ MaybeRejectStatelessly(connection_id, header);
+ } else {
+ // If the fate is already known, process it without executing stateless
+ // rejection logic.
+ ProcessUnauthenticatedHeaderFate(fate, connection_id, header.packet_number);
}
+
+ return false;
+}
+
+void QuicDispatcher::ProcessUnauthenticatedHeaderFate(
+ QuicPacketFate fate,
+ QuicConnectionId connection_id,
+ QuicPacketNumber packet_number) {
switch (fate) {
case kFateProcess: {
- // Create a session and process the packet.
- QuicServerSessionBase* session =
- CreateQuicSession(connection_id, current_client_address_);
- DVLOG(1) << "Created new session for " << connection_id;
- session_map_.insert(std::make_pair(connection_id, session));
- session->ProcessUdpPacket(current_server_address_,
- current_client_address_, *current_packet_);
+ ProcessChlo();
break;
}
case kFateTimeWait:
// MaybeRejectStatelessly might have already added the connection to
// time wait, in which case it should not be added again.
if (!FLAGS_quic_use_cheap_stateless_rejects ||
- !time_wait_list_manager_->IsConnectionIdInTimeWait(
- header.public_header.connection_id)) {
+ !time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) {
// Add this connection_id to the time-wait state, to safely reject
// future packets.
DVLOG(1) << "Adding connection ID " << connection_id
@@ -350,19 +370,20 @@ bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
connection_id, framer_.version(),
/*connection_rejected_statelessly=*/false, nullptr);
}
- DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
- header.public_header.connection_id));
+ DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
time_wait_list_manager_->ProcessPacket(
- current_server_address_, current_client_address_,
- header.public_header.connection_id, header.packet_number,
- *current_packet_);
+ current_server_address_, current_client_address_, connection_id,
+ packet_number, *current_packet_);
+ break;
+ case kFateBuffer:
+ // This packet is a non-CHLO packet which has arrived out of order.
+ // Buffer it.
+ BufferEarlyPacket(connection_id);
break;
case kFateDrop:
// Do nothing with the packet.
break;
}
-
- return false;
}
QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
@@ -412,7 +433,7 @@ void QuicDispatcher::CleanUpSession(SessionMap::iterator it,
}
void QuicDispatcher::DeleteSessions() {
- STLDeleteElements(&closed_session_list_);
+ base::STLDeleteElements(&closed_session_list_);
}
void QuicDispatcher::OnCanWrite() {
@@ -463,8 +484,8 @@ void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id,
<< ", with details: " << error_details;
if (closed_session_list_.empty()) {
- delete_sessions_alarm_->Cancel();
- delete_sessions_alarm_->Set(helper()->GetClock()->ApproximateNow());
+ delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(),
+ QuicTime::Delta::Zero());
}
closed_session_list_.push_back(it->second);
const bool should_close_statelessly =
@@ -594,20 +615,49 @@ void QuicDispatcher::OnPacketComplete() {
DCHECK(false);
}
-QuicServerSessionBase* QuicDispatcher::CreateQuicSession(
+void QuicDispatcher::OnExpiredPackets(
QuicConnectionId connection_id,
- const IPEndPoint& client_address) {
- // The QuicServerSessionBase takes ownership of |connection| below.
- QuicConnection* connection = new QuicConnection(
- connection_id, client_address, helper_.get(), alarm_factory_.get(),
- CreatePerConnectionWriter(),
- /* owns_writer= */ true, Perspective::IS_SERVER, GetSupportedVersions());
+ BufferedPacketList early_arrived_packets) {
+ time_wait_list_manager_->AddConnectionIdToTimeWait(
+ connection_id, framer_.version(), false, nullptr);
+}
+
+void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) {
+ // Reset the counter before starting creating connections.
+ new_sessions_allowed_per_event_loop_ = max_connections_to_create;
+ for (; new_sessions_allowed_per_event_loop_ > 0;
+ --new_sessions_allowed_per_event_loop_) {
+ QuicConnectionId connection_id;
+ list<BufferedPacket> packets =
+ buffered_packets_.DeliverPacketsForNextConnection(&connection_id);
+ if (packets.empty()) {
+ return;
+ }
+ QuicServerSessionBase* session =
+ CreateQuicSession(connection_id, packets.front().client_address);
+ DVLOG(1) << "Created new session for " << connection_id;
+ session_map_.insert(std::make_pair(connection_id, session));
+ DeliverPacketsToSession(packets, session);
+ }
+}
- QuicServerSessionBase* session = new QuicSimpleServerSession(
- config_, connection, this, session_helper_.get(), crypto_config_,
- &compressed_certs_cache_);
- session->Initialize();
- return session;
+bool QuicDispatcher::HasChlosBuffered() const {
+ return buffered_packets_.HasChlosBuffered();
+}
+
+void QuicDispatcher::OnNewConnectionAdded(QuicConnectionId connection_id) {
+ VLOG(1) << "Received packet from new connection " << connection_id;
+}
+
+// Return true if there is any packet buffered in the store.
+bool QuicDispatcher::HasBufferedPackets(QuicConnectionId connection_id) {
+ return buffered_packets_.HasBufferedPackets(connection_id);
+}
+
+void QuicDispatcher::OnBufferPacketFailure(EnqueuePacketResult result,
+ QuicConnectionId connection_id) {
+ DVLOG(1) << "Fail to buffer packet on connection " << connection_id
+ << " because of " << result;
}
void QuicDispatcher::OnConnectionRejectedStatelessly() {}
@@ -623,6 +673,79 @@ QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
alarm_factory_.get());
}
+void QuicDispatcher::BufferEarlyPacket(QuicConnectionId connection_id) {
+ bool is_new_connection = !buffered_packets_.HasBufferedPackets(connection_id);
+ EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
+ connection_id, *current_packet_, current_server_address_,
+ current_client_address_, /*is_chlo=*/false);
+ if (rs != EnqueuePacketResult::SUCCESS) {
+ OnBufferPacketFailure(rs, connection_id);
+ } else if (is_new_connection) {
+ OnNewConnectionAdded(connection_id);
+ }
+}
+
+void QuicDispatcher::ProcessChlo() {
+ QUIC_BUG_IF(!FLAGS_quic_buffer_packet_till_chlo &&
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop)
+ << "Try to limit connection creation per epoll event while not "
+ "supporting packet buffer. "
+ "--quic_limit_num_new_sessions_per_epoll_loop = true "
+ "--quic_buffer_packet_till_chlo = false";
+
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop &&
+ FLAGS_quic_buffer_packet_till_chlo &&
+ new_sessions_allowed_per_event_loop_ <= 0) {
+ // Can't create new session any more. Wait till next event loop.
+ if (!buffered_packets_.HasChloForConnection(current_connection_id_)) {
+ // Only buffer one CHLO per connection. Remove this condition check when
+ // --gfe2_reloadable_flag_quic_buffer_packets_after_chlo
+ // is deprecated because after that retransmitted CHLO should be buffered
+ // earlier in OnUnauthenticatedPublicHeader().
+ bool is_new_connection =
+ !buffered_packets_.HasBufferedPackets(current_connection_id_);
+ EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
+ current_connection_id_, *current_packet_, current_server_address_,
+ current_client_address_, /*is_chlo=*/true);
+ if (rs != EnqueuePacketResult::SUCCESS) {
+ OnBufferPacketFailure(rs, current_connection_id_);
+ } else if (is_new_connection) {
+ OnNewConnectionAdded(current_connection_id_);
+ }
+ }
+ return;
+ }
+
+ // Creates a new session and process all buffered packets for this connection.
+ QuicServerSessionBase* session =
+ CreateQuicSession(current_connection_id_, current_client_address_);
+ if (FLAGS_quic_enforce_mtu_limit &&
+ current_packet().potentially_small_mtu()) {
+ session->connection()->set_largest_packet_size_supported(
+ kMinimumSupportedPacketSize);
+ }
+ DVLOG(1) << "Created new session for " << current_connection_id_;
+ session_map_.insert(std::make_pair(current_connection_id_, session));
+ std::list<BufferedPacket> packets =
+ buffered_packets_.DeliverPackets(current_connection_id_);
+ // Check if CHLO is the first packet arrived on this connection.
+ if (FLAGS_quic_buffer_packet_till_chlo && packets.empty()) {
+ OnNewConnectionAdded(current_connection_id_);
+ }
+ // Process CHLO at first.
+ session->ProcessUdpPacket(current_server_address_, current_client_address_,
+ *current_packet_);
+
+ // Deliver queued-up packets in the same order as they arrived.
+ // Do this even when flag is off because there might be still some packets
+ // buffered in the store before flag is turned off.
+ DeliverPacketsToSession(packets, session);
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop &&
+ FLAGS_quic_buffer_packet_till_chlo) {
+ --new_sessions_allowed_per_event_loop_;
+ }
+}
+
bool QuicDispatcher::HandlePacketForTimeWait(
const QuicPacketPublicHeader& header) {
if (header.reset_flag) {
@@ -653,30 +776,70 @@ bool QuicDispatcher::OnUnauthenticatedUnknownPublicHeader(
return true;
}
-QuicDispatcher::QuicPacketFate QuicDispatcher::MaybeRejectStatelessly(
- QuicConnectionId connection_id,
- const QuicPacketHeader& header) {
+class StatelessRejectorProcessDoneCallback
+ : public StatelessRejector::ProcessDoneCallback {
+ public:
+ StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher,
+ QuicPacketNumber packet_number,
+ QuicVersion first_version)
+ : dispatcher_(dispatcher),
+ packet_number_(packet_number),
+ first_version_(first_version) {}
+
+ void Run(std::unique_ptr<StatelessRejector> rejector) override {
+ dispatcher_->OnStatelessRejectorProcessDone(std::move(rejector),
+ packet_number_, first_version_);
+ }
+
+ private:
+ QuicDispatcher* dispatcher_;
+ QuicPacketNumber packet_number_;
+ QuicVersion first_version_;
+};
+
+void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id,
+ const QuicPacketHeader& header) {
// TODO(rch): This logic should probably live completely inside the rejector.
if (!FLAGS_quic_use_cheap_stateless_rejects ||
!FLAGS_enable_quic_stateless_reject_support ||
header.public_header.versions.front() <= QUIC_VERSION_32 ||
!ShouldAttemptCheapStatelessRejection()) {
- return kFateProcess;
+ // Not use cheap stateless reject.
+ if (FLAGS_quic_buffer_packet_till_chlo &&
+ !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
+ nullptr)) {
+ // Buffer non-CHLO packets.
+ ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id,
+ header.packet_number);
+ return;
+ }
+ ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id,
+ header.packet_number);
+ return;
}
- StatelessRejector rejector(header.public_header.versions.front(),
- supported_versions_, crypto_config_,
- &compressed_certs_cache_, helper()->GetClock(),
- helper()->GetRandomGenerator(),
- current_client_address_, current_server_address_);
+ std::unique_ptr<StatelessRejector> rejector(new StatelessRejector(
+ header.public_header.versions.front(), GetSupportedVersions(),
+ crypto_config_, &compressed_certs_cache_, helper()->GetClock(),
+ helper()->GetRandomGenerator(), current_packet_->length(),
+ current_client_address_, current_server_address_));
ChloValidator validator(session_helper_.get(), current_server_address_,
- &rejector);
- if (!ChloExtractor::Extract(*current_packet_, supported_versions_,
+ rejector.get());
+ if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
&validator)) {
- // TODO(rch): Since there was no CHLO in this packet, buffer it until one
- // arrives.
- DLOG(ERROR) << "Dropping undecryptable packet.";
- return kFateDrop;
+ if (!FLAGS_quic_buffer_packet_till_chlo) {
+ QUIC_BUG
+ << "Have to drop packet because buffering non-chlo packet is "
+ "not supported while trying to do stateless reject. "
+ "--gfe2_reloadable_flag_quic_buffer_packet_till_chlo false"
+ " --gfe2_reloadable_flag_quic_use_cheap_stateless_rejects true";
+ ProcessUnauthenticatedHeaderFate(kFateDrop, connection_id,
+ header.packet_number);
+ return;
+ }
+ ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id,
+ header.packet_number);
+ return;
}
if (!validator.can_accept()) {
@@ -686,51 +849,76 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::MaybeRejectStatelessly(
terminator.CloseConnection(QUIC_HANDSHAKE_FAILED,
validator.error_details());
OnConnectionClosedStatelessly(QUIC_HANDSHAKE_FAILED);
- return kFateTimeWait;
+ ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id,
+ header.packet_number);
+ return;
}
- // This packet included a CHLO. See if it can be rejected statelessly.
- switch (rejector.state()) {
+ // Continue stateless rejector processing
+ std::unique_ptr<StatelessRejectorProcessDoneCallback> cb(
+ new StatelessRejectorProcessDoneCallback(
+ this, header.packet_number, header.public_header.versions.front()));
+ StatelessRejector::Process(std::move(rejector), std::move(cb));
+}
+
+void QuicDispatcher::OnStatelessRejectorProcessDone(
+ std::unique_ptr<StatelessRejector> rejector,
+ QuicPacketNumber packet_number,
+ QuicVersion first_version) {
+ QuicPacketFate fate;
+ switch (rejector->state()) {
case StatelessRejector::FAILED: {
// There was an error processing the client hello.
- StatelessConnectionTerminator terminator(
- connection_id, &framer_, helper(), time_wait_list_manager_.get());
- terminator.CloseConnection(rejector.error(), rejector.error_details());
- return kFateTimeWait;
+ StatelessConnectionTerminator terminator(rejector->connection_id(),
+ &framer_, helper(),
+ time_wait_list_manager_.get());
+ terminator.CloseConnection(rejector->error(), rejector->error_details());
+ fate = kFateTimeWait;
+ break;
}
case StatelessRejector::UNSUPPORTED:
// Cheap stateless rejects are not supported so process the packet.
- return kFateProcess;
+ fate = kFateProcess;
+ break;
case StatelessRejector::ACCEPTED:
// Contains a valid CHLO, so process the packet and create a connection.
- return kFateProcess;
+ fate = kFateProcess;
+ break;
case StatelessRejector::REJECTED: {
- DCHECK_EQ(framer_.version(), header.public_header.versions.front());
- StatelessConnectionTerminator terminator(
- connection_id, &framer_, helper(), time_wait_list_manager_.get());
+ DCHECK_EQ(framer_.version(), first_version);
+ StatelessConnectionTerminator terminator(rejector->connection_id(),
+ &framer_, helper(),
+ time_wait_list_manager_.get());
terminator.RejectConnection(
- rejector.reply().GetSerialized().AsStringPiece());
+ rejector->reply().GetSerialized().AsStringPiece());
OnConnectionRejectedStatelessly();
- return kFateTimeWait;
+ fate = kFateTimeWait;
+ break;
}
- }
- QUIC_BUG << "Rejector has unknown invalid state.";
- return kFateDrop;
+ default:
+ QUIC_BUG << "Rejector has invalid state " << rejector->state();
+ fate = kFateDrop;
+ break;
+ }
+ ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(),
+ packet_number);
}
const QuicVersionVector& QuicDispatcher::GetSupportedVersions() {
- // Filter (or un-filter) the list of supported versions based on the flag.
- if (disable_quic_pre_30_ != FLAGS_quic_disable_pre_30) {
- DCHECK_EQ(supported_versions_.capacity(),
- allowed_supported_versions_.capacity());
- disable_quic_pre_30_ = FLAGS_quic_disable_pre_30;
- supported_versions_ = FilterSupportedVersions(allowed_supported_versions_);
- }
- return supported_versions_;
+ return version_manager_->GetSupportedVersions();
+}
+
+void QuicDispatcher::DeliverPacketsToSession(
+ const std::list<BufferedPacket>& packets,
+ QuicServerSessionBase* session) {
+ for (const BufferedPacket& packet : packets) {
+ session->ProcessUdpPacket(packet.server_address, packet.client_address,
+ *(packet.packet));
+ }
}
} // namespace net
diff --git a/chromium/net/tools/quic/quic_dispatcher.h b/chromium/net/tools/quic/quic_dispatcher.h
index db972530435..8d9197a4806 100644
--- a/chromium/net/tools/quic/quic_dispatcher.h
+++ b/chromium/net/tools/quic/quic_dispatcher.h
@@ -15,20 +15,23 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
#include "net/base/linked_hash_map.h"
-#include "net/quic/crypto/quic_compressed_certs_cache.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_blocked_writer_interface.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_session_base.h"
+#include "net/quic/core/crypto/quic_compressed_certs_cache.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_blocked_writer_interface.h"
+#include "net/quic/core/quic_buffered_packet_store.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_session_base.h"
+
#include "net/tools/quic/quic_process_packet_interface.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
+#include "net/tools/quic/stateless_rejector.h"
namespace net {
class QuicConfig;
class QuicCryptoServerConfig;
-class QuicServerSessionBase;
namespace test {
class QuicDispatcherPeer;
@@ -37,7 +40,8 @@ class QuicDispatcherPeer;
class QuicDispatcher : public QuicServerSessionBase::Visitor,
public ProcessPacketInterface,
public QuicBlockedWriterInterface,
- public QuicFramerVisitorInterface {
+ public QuicFramerVisitorInterface,
+ public QuicBufferedPacketStore::VisitorInterface {
public:
// Ideally we'd have a linked_hash_set: the boolean is unused.
typedef linked_hash_map<QuicBlockedWriterInterface*,
@@ -47,9 +51,9 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
- const QuicVersionVector& supported_versions,
+ QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
std::unique_ptr<QuicAlarmFactory> alarm_factory);
~QuicDispatcher() override;
@@ -85,6 +89,9 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
// time-wait list.
void OnConnectionAddedToTimeWaitList(QuicConnectionId connection_id) override;
+ void OnPacketBeingDispatchedToSession(
+ QuicServerSessionBase* session) override {}
+
typedef std::unordered_map<QuicConnectionId, QuicServerSessionBase*>
SessionMap;
@@ -139,10 +146,21 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override;
void OnPacketComplete() override;
+ // QuicBufferedPacketStore::VisitorInterface implementation.
+ void OnExpiredPackets(QuicConnectionId connection_id,
+ QuicBufferedPacketStore::BufferedPacketList
+ early_arrived_packets) override;
+
+ // Create connections for previously buffered CHLOs as many as allowed.
+ virtual void ProcessBufferedChlos(size_t max_connections_to_create);
+
+ // Return true if there is CHLO buffered.
+ virtual bool HasChlosBuffered() const;
+
protected:
virtual QuicServerSessionBase* CreateQuicSession(
QuicConnectionId connection_id,
- const IPEndPoint& client_address);
+ const IPEndPoint& client_address) = 0;
// Called when a connection is rejected statelessly.
virtual void OnConnectionRejectedStatelessly();
@@ -163,6 +181,8 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
kFateProcess,
// Put the connection ID into time-wait state and send a public reset.
kFateTimeWait,
+ // Buffer the packet.
+ kFateBuffer,
// Drop the packet (ignore and give no response).
kFateDrop,
};
@@ -176,12 +196,22 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
// will be owned by the dispatcher as time_wait_list_manager_
virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager();
+ // Called when |current_packet_| is a data packet that has arrived before
+ // the CHLO or it is any kind of packet while a CHLO on same connection has
+ // already been in the buffer.
+ void BufferEarlyPacket(QuicConnectionId connection_id);
+
+ // Called when |current_packet_| is a CHLO packet. Creates a new connection
+ // and delivers any buffered packets for that connection id.
+ void ProcessChlo();
+
QuicTimeWaitListManager* time_wait_list_manager() {
return time_wait_list_manager_.get();
}
const QuicVersionVector& GetSupportedVersions();
+ QuicConnectionId current_connection_id() { return current_connection_id_; }
const IPEndPoint& current_server_address() { return current_server_address_; }
const IPEndPoint& current_client_address() { return current_client_address_; }
const QuicReceivedPacket& current_packet() { return *current_packet_; }
@@ -198,7 +228,7 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
QuicConnectionHelperInterface* helper() { return helper_.get(); }
- QuicServerSessionBase::Helper* session_helper() {
+ QuicCryptoServerStream::Helper* session_helper() {
return session_helper_.get();
}
@@ -225,8 +255,21 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
virtual bool OnUnauthenticatedUnknownPublicHeader(
const QuicPacketPublicHeader& header);
+ // Called when a new connection starts to be handled by this dispatcher.
+ // Either this connection is created or its packets is buffered while waiting
+ // for CHLO.
+ virtual void OnNewConnectionAdded(QuicConnectionId connection_id);
+
+ bool HasBufferedPackets(QuicConnectionId connection_id);
+
+ // Called when BufferEarlyPacket() fail to buffer the packet.
+ virtual void OnBufferPacketFailure(
+ QuicBufferedPacketStore::EnqueuePacketResult result,
+ QuicConnectionId connection_id);
+
private:
friend class net::test::QuicDispatcherPeer;
+ friend class StatelessRejectorProcessDoneCallback;
// Removes the session from the session map and write blocked list, and adds
// the ConnectionId to the time-wait list. If |session_closed_statelessly| is
@@ -236,11 +279,33 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
bool HandlePacketForTimeWait(const QuicPacketPublicHeader& header);
// Attempts to reject the connection statelessly, if stateless rejects are
- // possible and if the current packet contains a CHLO message.
- // Returns a fate which describes what subsequent processing should be
- // performed on the packets, like ValidityChecks.
- QuicPacketFate MaybeRejectStatelessly(QuicConnectionId connection_id,
- const QuicPacketHeader& header);
+ // possible and if the current packet contains a CHLO message. Determines a
+ // fate which describes what subsequent processing should be performed on the
+ // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate.
+ void MaybeRejectStatelessly(QuicConnectionId connection_id,
+ const QuicPacketHeader& header);
+
+ // Deliver |packets| to |session| for further processing.
+ void DeliverPacketsToSession(
+ const std::list<QuicBufferedPacketStore::BufferedPacket>& packets,
+ QuicServerSessionBase* session);
+
+ // Perform the appropriate actions on the current packet based on |fate| -
+ // either process, buffer, or drop it.
+ void ProcessUnauthenticatedHeaderFate(QuicPacketFate fate,
+ QuicConnectionId connection_id,
+ QuicPacketNumber packet_number);
+
+ // Invoked when StatelessRejector::Process completes.
+ void OnStatelessRejectorProcessDone(
+ std::unique_ptr<StatelessRejector> rejector,
+ QuicPacketNumber packet_number,
+ QuicVersion first_version);
+
+ void set_new_sessions_allowed_per_event_loop(
+ int16_t new_sessions_allowed_per_event_loop) {
+ new_sessions_allowed_per_event_loop_ = new_sessions_allowed_per_event_loop;
+ }
const QuicConfig& config_;
@@ -264,7 +329,7 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
std::unique_ptr<QuicConnectionHelperInterface> helper_;
// The helper used for all sessions.
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper_;
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper_;
// Creates alarms.
std::unique_ptr<QuicAlarmFactory> alarm_factory_;
@@ -275,17 +340,9 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
// The writer to write to the socket with.
std::unique_ptr<QuicPacketWriter> writer_;
- // This vector contains QUIC versions which we currently support.
- // This should be ordered such that the highest supported version is the first
- // element, with subsequent elements in descending order (versions can be
- // skipped as necessary).
- QuicVersionVector supported_versions_;
-
- // FLAGS_quic_disable_pre_30
- bool disable_quic_pre_30_;
- // The list of versions that may be supported by this dispatcher.
- // |supported_versions| is derived from this list and |disable_quic_pre_30_|.
- const QuicVersionVector allowed_supported_versions_;
+ // Packets which are buffered until a connection can be created to handle
+ // them.
+ QuicBufferedPacketStore buffered_packets_;
// Information about the packet currently being handled.
IPEndPoint current_client_address_;
@@ -293,12 +350,19 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
const QuicReceivedPacket* current_packet_;
QuicConnectionId current_connection_id_;
+ // Used to get the supported versions based on flag. Does not own.
+ QuicVersionManager* version_manager_;
+
QuicFramer framer_;
// The last error set by SetLastError(), which is called by
// framer_visitor_->OnError().
QuicErrorCode last_error_;
+ // A backward counter of how many new sessions can be create within current
+ // event loop. When reaches 0, it means can't create sessions for now.
+ int16_t new_sessions_allowed_per_event_loop_;
+
DISALLOW_COPY_AND_ASSIGN(QuicDispatcher);
};
diff --git a/chromium/net/tools/quic/quic_dispatcher_test.cc b/chromium/net/tools/quic/quic_dispatcher_test.cc
index a063a2daf66..23ca8797bae 100644
--- a/chromium/net/tools/quic/quic_dispatcher_test.cc
+++ b/chromium/net/tools/quic/quic_dispatcher_test.cc
@@ -9,42 +9,53 @@
#include <string>
#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_buffered_packet_store_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
#include "net/tools/epoll_server/epoll_server.h"
+#include "net/tools/quic/chlo_extractor.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_packet_writer_wrapper.h"
-#include "net/tools/quic/quic_simple_server_session_helper.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
+#include "net/tools/quic/stateless_rejector.h"
#include "net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h"
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::IntToString;
using base::StringPiece;
using net::EpollServer;
using net::test::ConstructEncryptedPacket;
using net::test::CryptoTestUtils;
using net::test::MockQuicConnection;
using net::test::MockQuicConnectionHelper;
-using net::test::ValueRestore;
+using std::ostream;
using std::string;
using std::vector;
+using testing::CreateFunctor;
using testing::DoAll;
using testing::InSequence;
using testing::Invoke;
using testing::WithoutArgs;
using testing::_;
+static const size_t kDefaultMaxConnectionsInStore = 100;
+static const size_t kMaxConnectionsWithoutCHLO =
+ kDefaultMaxConnectionsInStore / 2;
+static const int16_t kMaxNumSessionsToCreate = 16;
+
namespace net {
namespace test {
namespace {
@@ -62,7 +73,8 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
crypto_config,
compressed_certs_cache),
crypto_stream_(QuicServerSessionBase::GetCryptoStream()) {}
- ~TestQuicSpdyServerSession() override{};
+
+ ~TestQuicSpdyServerSession() override { delete connection(); };
MOCK_METHOD3(OnConnectionClosed,
void(QuicErrorCode error,
@@ -77,7 +89,7 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
QuicCompressedCertsCache* compressed_certs_cache) override {
return new QuicCryptoServerStream(
crypto_config, compressed_certs_cache,
- FLAGS_enable_quic_stateless_reject_support, this);
+ FLAGS_enable_quic_stateless_reject_support, this, stream_helper());
}
void SetCryptoStream(QuicCryptoServerStream* crypto_stream) {
@@ -88,6 +100,10 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
return crypto_stream_;
}
+ QuicCryptoServerStream::Helper* stream_helper() {
+ return QuicServerSessionBase::stream_helper();
+ }
+
private:
QuicCryptoServerStreamBase* crypto_stream_;
@@ -98,15 +114,17 @@ class TestDispatcher : public QuicDispatcher {
public:
TestDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
EpollServer* eps)
: QuicDispatcher(
config,
crypto_config,
- QuicSupportedVersions(),
+ version_manager,
std::unique_ptr<QuicEpollConnectionHelper>(
new QuicEpollConnectionHelper(eps, QuicAllocator::BUFFER_POOL)),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(
+ QuicRandom::GetInstance())),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(eps))) {}
@@ -114,6 +132,8 @@ class TestDispatcher : public QuicDispatcher {
QuicServerSessionBase*(QuicConnectionId connection_id,
const IPEndPoint& client_address));
+ MOCK_METHOD1(OnNewConnectionAdded, void(QuicConnectionId connection_id));
+
using QuicDispatcher::current_server_address;
using QuicDispatcher::current_client_address;
};
@@ -144,43 +164,29 @@ class MockServerConnection : public MockQuicConnection {
QuicDispatcher* dispatcher_;
};
-QuicServerSessionBase* CreateSession(
- QuicDispatcher* dispatcher,
- const QuicConfig& config,
- QuicConnectionId connection_id,
- const IPEndPoint& client_address,
- MockQuicConnectionHelper* helper,
- MockAlarmFactory* alarm_factory,
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache,
- TestQuicSpdyServerSession** session) {
- MockServerConnection* connection = new MockServerConnection(
- connection_id, helper, alarm_factory, dispatcher);
- *session = new TestQuicSpdyServerSession(config, connection, crypto_config,
- compressed_certs_cache);
- connection->set_visitor(*session);
- ON_CALL(*connection, CloseConnection(_, _, _))
- .WillByDefault(WithoutArgs(Invoke(
- connection, &MockServerConnection::UnregisterOnConnectionClosed)));
- EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>((*session)->connection()),
- ProcessUdpPacket(_, client_address, _));
-
- return *session;
-}
-
class QuicDispatcherTest : public ::testing::Test {
public:
QuicDispatcherTest()
: helper_(&eps_, QuicAllocator::BUFFER_POOL),
alarm_factory_(&eps_),
+ version_manager_(AllSupportedVersions()),
crypto_config_(QuicCryptoServerConfig::TESTING,
QuicRandom::GetInstance(),
CryptoTestUtils::ProofSourceForTesting()),
- dispatcher_(config_, &crypto_config_, &eps_),
+ dispatcher_(new TestDispatcher(config_,
+ &crypto_config_,
+ &version_manager_,
+ &eps_)),
time_wait_list_manager_(nullptr),
session1_(nullptr),
- session2_(nullptr) {
- dispatcher_.InitializeWithWriter(new QuicDefaultPacketWriter(1));
+ session2_(nullptr),
+ store_(nullptr) {}
+
+ void SetUp() override {
+ dispatcher_->InitializeWithWriter(new QuicDefaultPacketWriter(1));
+ // Set the counter to some value to start with.
+ QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(
+ dispatcher_.get(), kMaxNumSessionsToCreate);
}
~QuicDispatcherTest() override {}
@@ -231,8 +237,8 @@ class QuicDispatcherTest : public ::testing::Test {
QuicPathId path_id,
QuicPacketNumber packet_number) {
ProcessPacket(client_address, connection_id, has_version_flag,
- QuicSupportedVersions().front(), data, connection_id_length,
- packet_number_length, packet_number);
+ CurrentSupportedVersions().front(), data,
+ connection_id_length, packet_number_length, packet_number);
}
// Processes a packet.
@@ -251,22 +257,55 @@ class QuicDispatcherTest : public ::testing::Test {
std::unique_ptr<QuicReceivedPacket> received_packet(
ConstructReceivedPacket(*packet, helper_.GetClock()->Now()));
- data_ = string(packet->data(), packet->length());
- dispatcher_.ProcessPacket(server_address_, client_address,
- *received_packet);
+ if (ChloExtractor::Extract(*packet, versions, nullptr)) {
+ // Add CHLO packet to the beginning to be verified first, because it is
+ // also processed first by new session.
+ data_connection_map_[connection_id].push_front(
+ string(packet->data(), packet->length()));
+ } else {
+ // For non-CHLO, always append to last.
+ data_connection_map_[connection_id].push_back(
+ string(packet->data(), packet->length()));
+ }
+ dispatcher_->ProcessPacket(server_address_, client_address,
+ *received_packet);
}
- void ValidatePacket(const QuicEncryptedPacket& packet) {
- EXPECT_EQ(data_.length(), packet.AsStringPiece().length());
- EXPECT_EQ(data_, packet.AsStringPiece());
+ void ValidatePacket(QuicConnectionId conn_id,
+ const QuicEncryptedPacket& packet) {
+ EXPECT_EQ(data_connection_map_[conn_id].front().length(),
+ packet.AsStringPiece().length());
+ EXPECT_EQ(data_connection_map_[conn_id].front(), packet.AsStringPiece());
+ data_connection_map_[conn_id].pop_front();
+ }
+
+ QuicServerSessionBase* CreateSession(
+ QuicDispatcher* dispatcher,
+ const QuicConfig& config,
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address,
+ MockQuicConnectionHelper* helper,
+ MockAlarmFactory* alarm_factory,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ TestQuicSpdyServerSession** session) {
+ MockServerConnection* connection = new MockServerConnection(
+ connection_id, helper, alarm_factory, dispatcher);
+ *session = new TestQuicSpdyServerSession(config, connection, crypto_config,
+ compressed_certs_cache);
+ connection->set_visitor(*session);
+ ON_CALL(*connection, CloseConnection(_, _, _))
+ .WillByDefault(WithoutArgs(Invoke(
+ connection, &MockServerConnection::UnregisterOnConnectionClosed)));
+ return *session;
}
void CreateTimeWaitListManager() {
- time_wait_list_manager_ =
- new MockTimeWaitListManager(QuicDispatcherPeer::GetWriter(&dispatcher_),
- &dispatcher_, &helper_, &alarm_factory_);
+ time_wait_list_manager_ = new MockTimeWaitListManager(
+ QuicDispatcherPeer::GetWriter(dispatcher_.get()), dispatcher_.get(),
+ &helper_, &alarm_factory_);
// dispatcher_ takes the ownership of time_wait_list_manager_.
- QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
time_wait_list_manager_);
}
@@ -276,46 +315,57 @@ class QuicDispatcherTest : public ::testing::Test {
return client_hello.GetSerialized().AsStringPiece().as_string();
}
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
EpollServer eps_;
QuicEpollConnectionHelper helper_;
MockQuicConnectionHelper mock_helper_;
QuicEpollAlarmFactory alarm_factory_;
MockAlarmFactory mock_alarm_factory_;
QuicConfig config_;
+ QuicVersionManager version_manager_;
QuicCryptoServerConfig crypto_config_;
IPEndPoint server_address_;
- TestDispatcher dispatcher_;
+ std::unique_ptr<TestDispatcher> dispatcher_;
MockTimeWaitListManager* time_wait_list_manager_;
TestQuicSpdyServerSession* session1_;
TestQuicSpdyServerSession* session2_;
- string data_;
+ std::map<QuicConnectionId, std::list<string>> data_connection_map_;
+ QuicBufferedPacketStore* store_;
};
TEST_F(QuicDispatcherTest, ProcessPackets) {
IPEndPoint client_address(net::test::Loopback4(), 1);
server_address_ = IPEndPoint(net::test::Any4(), 5);
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 1, client_address, &mock_helper_,
+ dispatcher_.get(), config_, 1, client_address, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
ProcessPacket(client_address, 1, true, false, SerializeCHLO());
- EXPECT_EQ(client_address, dispatcher_.current_client_address());
- EXPECT_EQ(server_address_, dispatcher_.current_server_address());
+ EXPECT_EQ(client_address, dispatcher_->current_client_address());
+ EXPECT_EQ(server_address_, dispatcher_->current_server_address());
- EXPECT_CALL(dispatcher_, CreateQuicSession(2, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(2, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 2, client_address, &mock_helper_,
+ dispatcher_.get(), config_, 2, client_address, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session2_)));
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session2_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session2_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 2))));
ProcessPacket(client_address, 2, true, false, SerializeCHLO());
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
ProcessUdpPacket(_, _, _))
.Times(1)
- .WillOnce(testing::WithArgs<2>(
- Invoke(this, &QuicDispatcherTest::ValidatePacket)));
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
ProcessPacket(client_address, 1, false, false, "data");
}
@@ -323,7 +373,7 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) {
IPEndPoint client_address(net::test::Loopback4(), 1);
server_address_ = IPEndPoint(net::test::Any4(), 5);
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address)).Times(0);
QuicVersion version = static_cast<QuicVersion>(QuicVersionMin() - 1);
ProcessPacket(client_address, 1, true, version, SerializeCHLO(),
PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1);
@@ -332,18 +382,22 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) {
TEST_F(QuicDispatcherTest, Shutdown) {
IPEndPoint client_address(net::test::Loopback4(), 1);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 1, client_address, &mock_helper_,
+ dispatcher_.get(), config_, 1, client_address, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
ProcessPacket(client_address, 1, true, false, SerializeCHLO());
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
- dispatcher_.Shutdown();
+ dispatcher_->Shutdown();
}
TEST_F(QuicDispatcherTest, TimeWaitListManager) {
@@ -352,11 +406,16 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
// Create a new session.
IPEndPoint client_address(net::test::Loopback4(), 1);
QuicConnectionId connection_id = 1;
- EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, connection_id, client_address, &mock_helper_,
- &mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+ dispatcher_.get(), config_, connection_id, client_address,
+ &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
+
ProcessPacket(client_address, connection_id, true, false, SerializeCHLO());
// Close the connection by sending public reset packet.
@@ -368,8 +427,8 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
packet.nonce_proof = 132232;
std::unique_ptr<QuicEncryptedPacket> encrypted(
QuicFramer::BuildPublicResetPacket(packet));
- std::unique_ptr<QuicReceivedPacket> received(
- ConstructReceivedPacket(*encrypted, helper_.GetClock()->Now()));
+ std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
+ *encrypted, session1_->connection()->clock()->Now()));
EXPECT_CALL(*session1_, OnConnectionClosed(QUIC_PUBLIC_RESET, _,
ConnectionCloseSource::FROM_PEER))
.Times(1)
@@ -381,7 +440,7 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
.WillOnce(
Invoke(reinterpret_cast<MockQuicConnection*>(session1_->connection()),
&MockQuicConnection::ReallyProcessUdpPacket));
- dispatcher_.ProcessPacket(IPEndPoint(), client_address, *received);
+ dispatcher_->ProcessPacket(IPEndPoint(), client_address, *received);
EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
// Dispatcher forwards subsequent packets for this connection_id to the time
@@ -401,7 +460,7 @@ TEST_F(QuicDispatcherTest, NoVersionPacketToTimeWaitListManager) {
QuicConnectionId connection_id = 1;
// Dispatcher forwards all packets for this connection_id to the time wait
// list manager.
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
ProcessPacket(_, _, connection_id, _, _))
.Times(1);
@@ -417,7 +476,7 @@ TEST_F(QuicDispatcherTest, ProcessPacketWithZeroPort) {
server_address_ = IPEndPoint(net::test::Any4(), 5);
// dispatcher_ should drop this packet.
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address)).Times(0);
EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
.Times(0);
@@ -429,19 +488,23 @@ TEST_F(QuicDispatcherTest, OKSeqNoPacketProcessed) {
QuicConnectionId connection_id = 1;
server_address_ = IPEndPoint(net::test::Any4(), 5);
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 1, client_address, &mock_helper_,
+ dispatcher_.get(), config_, 1, client_address, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
// A packet whose packet number is the largest that is allowed to start a
// connection.
ProcessPacket(client_address, connection_id, true, false, SerializeCHLO(),
PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
kDefaultPathId,
QuicDispatcher::kMaxReasonableInitialPacketNumber);
- EXPECT_EQ(client_address, dispatcher_.current_client_address());
- EXPECT_EQ(server_address_, dispatcher_.current_server_address());
+ EXPECT_EQ(client_address, dispatcher_->current_client_address());
+ EXPECT_EQ(server_address_, dispatcher_->current_server_address());
}
TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) {
@@ -451,7 +514,7 @@ TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) {
QuicConnectionId connection_id = 1;
// Dispatcher forwards this packet for this connection_id to the time wait
// list manager.
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
ProcessPacket(_, _, connection_id, _, _))
.Times(1);
@@ -470,11 +533,13 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream {
public:
MockQuicCryptoServerStream(const QuicCryptoServerConfig& crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
- QuicServerSessionBase* session)
+ QuicServerSessionBase* session,
+ QuicCryptoServerStream::Helper* helper)
: QuicCryptoServerStream(&crypto_config,
compressed_certs_cache,
FLAGS_enable_quic_stateless_reject_support,
- session) {}
+ session,
+ helper) {}
void set_handshake_confirmed_for_testing(bool handshake_confirmed) {
handshake_confirmed_ = handshake_confirmed;
}
@@ -530,7 +595,8 @@ class QuicDispatcherStatelessRejectTest
: public QuicDispatcherTest,
public ::testing::WithParamInterface<StatelessRejectTestParams> {
public:
- QuicDispatcherStatelessRejectTest() : crypto_stream1_(nullptr) {}
+ QuicDispatcherStatelessRejectTest()
+ : QuicDispatcherTest(), crypto_stream1_(nullptr) {}
~QuicDispatcherStatelessRejectTest() override {
if (crypto_stream1_) {
@@ -541,6 +607,7 @@ class QuicDispatcherStatelessRejectTest
// This test setup assumes that all testing will be done using
// crypto_stream1_.
void SetUp() override {
+ QuicDispatcherTest::SetUp();
FLAGS_enable_quic_stateless_reject_support =
GetParam().enable_stateless_rejects_via_flag;
}
@@ -553,17 +620,18 @@ class QuicDispatcherStatelessRejectTest
GetParam().client_supports_statelesss_rejects;
}
- // Sets up dispatcher_, sesession1_, and crypto_stream1_ based on
+ // Sets up dispatcher_, session1_, and crypto_stream1_ based on
// the test parameters.
QuicServerSessionBase* CreateSessionBasedOnTestParams(
QuicConnectionId connection_id,
const IPEndPoint& client_address) {
- CreateSession(&dispatcher_, config_, connection_id, client_address,
+ CreateSession(dispatcher_.get(), config_, connection_id, client_address,
&mock_helper_, &mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_);
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_);
crypto_stream1_ = new MockQuicCryptoServerStream(
- crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), session1_);
+ crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()),
+ session1_, session1_->stream_helper());
session1_->SetCryptoStream(crypto_stream1_);
crypto_stream1_->set_handshake_confirmed_for_testing(
GetParam().crypto_handshake_successful);
@@ -587,10 +655,14 @@ TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) {
IPEndPoint client_address(net::test::Loopback4(), 1);
QuicConnectionId connection_id = 1;
- EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
.WillOnce(testing::Return(
CreateSessionBasedOnTestParams(connection_id, client_address)));
-
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))));
// Process the first packet for the connection.
ProcessPacket(client_address, connection_id, true, false, SerializeCHLO());
if (ExpectStatelessReject()) {
@@ -616,24 +688,30 @@ TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) {
ProcessUdpPacket(_, _, _))
.Times(1)
.WillOnce(testing::WithArgs<2>(
- Invoke(this, &QuicDispatcherTest::ValidatePacket)));
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))));
}
ProcessPacket(client_address, connection_id, true, false, "data");
}
TEST_P(QuicDispatcherStatelessRejectTest, CheapRejects) {
FLAGS_quic_use_cheap_stateless_rejects = true;
+ FLAGS_quic_buffer_packet_till_chlo = true;
CreateTimeWaitListManager();
IPEndPoint client_address(net::test::Loopback4(), 1);
QuicConnectionId connection_id = 1;
if (GetParam().enable_stateless_rejects_via_flag) {
- EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
.Times(0);
} else {
- EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
.WillOnce(testing::Return(
CreateSessionBasedOnTestParams(connection_id, client_address)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
}
VLOG(1) << "ExpectStatelessReject: " << ExpectStatelessReject();
@@ -660,6 +738,88 @@ TEST_P(QuicDispatcherStatelessRejectTest, CheapRejects) {
}
}
+TEST_P(QuicDispatcherStatelessRejectTest, BufferNonChlo) {
+ FLAGS_quic_use_cheap_stateless_rejects = true;
+ CreateTimeWaitListManager();
+
+ const IPEndPoint client_address(net::test::Loopback4(), 1);
+ const QuicConnectionId connection_id = 1;
+
+ if (!GetParam().enable_stateless_rejects_via_flag &&
+ !FLAGS_quic_buffer_packet_till_chlo) {
+ // If stateless rejects are not being used and early arrived packets are not
+ // buffered, then a connection will be created immediately.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
+ .WillOnce(testing::Return(
+ CreateSessionBasedOnTestParams(connection_id, client_address)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, client_address, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))));
+ }
+ bool first_packet_dropped = GetParam().enable_stateless_rejects_via_flag &&
+ !FLAGS_quic_buffer_packet_till_chlo;
+ if (first_packet_dropped) {
+ // Never do stateless reject while
+ // FLAGS_quic_buffer_packet_till_chlo is off.
+ EXPECT_QUIC_BUG(
+ ProcessPacket(client_address, connection_id, true, false,
+ "NOT DATA FOR A CHLO"),
+ "Have to drop packet because buffering non-chlo packet is "
+ "not supported while trying to do stateless reject. "
+ "--gfe2_reloadable_flag_quic_buffer_packet_till_chlo false "
+ "--gfe2_reloadable_flag_quic_use_cheap_stateless_rejects true");
+ } else {
+ ProcessPacket(client_address, connection_id, true, false,
+ "NOT DATA FOR A CHLO");
+ }
+
+ // Process the first packet for the connection.
+ // clang-format off
+ CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
+ "CHLO",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "NONC", "1234567890123456789012",
+ "VER\0", "Q025",
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ if (GetParam().enable_stateless_rejects_via_flag ||
+ FLAGS_quic_buffer_packet_till_chlo) {
+ // If stateless rejects are enabled then a connection will be created now
+ // and the buffered packet will be processed
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
+ .WillOnce(testing::Return(
+ CreateSessionBasedOnTestParams(connection_id, client_address)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, client_address, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))));
+ }
+ if (!first_packet_dropped) {
+ // Expect both packets to be passed to ProcessUdpPacket(). And one of them
+ // is already expected in CreateSessionBasedOnTestParams().
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, client_address, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))))
+ .RetiresOnSaturation();
+ } else {
+ // Since first packet is dropped, remove it from map to skip
+ // ValidatePacket() on it.
+ data_connection_map_[connection_id].pop_front();
+ }
+ ProcessPacket(client_address, connection_id, true, false,
+ client_hello.GetSerialized().AsStringPiece().as_string());
+ EXPECT_FALSE(
+ time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
+}
+
// Verify the stopgap test: Packets with truncated connection IDs should be
// dropped.
class QuicDispatcherTestStrayPacketConnectionId : public QuicDispatcherTest {};
@@ -672,7 +832,7 @@ TEST_F(QuicDispatcherTestStrayPacketConnectionId,
IPEndPoint client_address(net::test::Loopback4(), 1);
QuicConnectionId connection_id = 1;
// Dispatcher drops this packet.
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
ProcessPacket(_, _, connection_id, _, _))
.Times(0);
@@ -707,39 +867,48 @@ class BlockingWriter : public QuicPacketWriterWrapper {
class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest {
public:
void SetUp() override {
+ QuicDispatcherTest::SetUp();
writer_ = new BlockingWriter;
- QuicDispatcherPeer::UseWriter(&dispatcher_, writer_);
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), writer_);
IPEndPoint client_address(net::test::Loopback4(), 1);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 1, client_address, &helper_, &alarm_factory_,
- &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_),
- &session1_)));
+ dispatcher_.get(), config_, 1, client_address, &helper_,
+ &alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
ProcessPacket(client_address, 1, true, false, SerializeCHLO());
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 2, client_address, &helper_, &alarm_factory_,
- &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_),
- &session2_)));
+ dispatcher_.get(), config_, 2, client_address, &helper_,
+ &alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session2_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session2_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 2))));
ProcessPacket(client_address, 2, true, false, SerializeCHLO());
- blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(&dispatcher_);
+ blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(dispatcher_.get());
}
void TearDown() override {
EXPECT_CALL(*connection1(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
EXPECT_CALL(*connection2(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
- dispatcher_.Shutdown();
+ dispatcher_->Shutdown();
}
void SetBlocked() { writer_->write_blocked_ = true; }
void BlockConnection2() {
writer_->write_blocked_ = true;
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection2());
}
protected:
@@ -751,95 +920,95 @@ class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest {
TEST_F(QuicDispatcherWriteBlockedListTest, BasicOnCanWrite) {
// No OnCanWrite calls because no connections are blocked.
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Register connection 1 for events, and make sure it's notified.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// It should get only one notification.
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
- EXPECT_FALSE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_FALSE(dispatcher_->HasPendingWrites());
}
TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteOrder) {
// Make sure we handle events in order.
InSequence s;
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite());
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Check the other ordering.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection2());
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
EXPECT_CALL(*connection2(), OnCanWrite());
EXPECT_CALL(*connection1(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
}
TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteRemove) {
// Add and remove one connction.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Add and remove one connction and make sure it doesn't affect others.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Add it, remove it, and add it back and make sure things are OK.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
}
TEST_F(QuicDispatcherWriteBlockedListTest, DoubleAdd) {
// Make sure a double add does not necessitate a double remove.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Make sure a double add does not result in two OnCanWrite calls.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
}
TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlock) {
// Finally make sure if we write block on a write call, we stop calling.
InSequence s;
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite())
.WillOnce(Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// And we'll resume where we left off when we get another call.
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
}
TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) {
@@ -847,37 +1016,495 @@ TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) {
// but should not be immediately called due to limits.
InSequence s;
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite());
EXPECT_CALL(*connection2(), OnCanWrite())
.WillOnce(
Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2));
- dispatcher_.OnCanWrite();
- EXPECT_TRUE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_TRUE(dispatcher_->HasPendingWrites());
// Now call OnCanWrite again, and connection1 should get its second chance
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
- EXPECT_FALSE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_FALSE(dispatcher_->HasPendingWrites());
}
TEST_F(QuicDispatcherWriteBlockedListTest, TestWriteLimits) {
// Finally make sure if we write block on a write call, we stop calling.
InSequence s;
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite())
.WillOnce(Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
- EXPECT_TRUE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_TRUE(dispatcher_->HasPendingWrites());
// And we'll resume where we left off when we get another call.
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
- EXPECT_FALSE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_FALSE(dispatcher_->HasPendingWrites());
+}
+
+// Tests that bufferring packets works in stateful reject, expensive stateless
+// reject and cheap stateless reject.
+struct BufferedPacketStoreTestParams {
+ BufferedPacketStoreTestParams(bool enable_stateless_rejects_via_flag,
+ bool support_cheap_stateless_reject)
+ : enable_stateless_rejects_via_flag(enable_stateless_rejects_via_flag),
+ support_cheap_stateless_reject(support_cheap_stateless_reject) {}
+
+ friend ostream& operator<<(ostream& os,
+ const BufferedPacketStoreTestParams& p) {
+ os << "{ enable_stateless_rejects_via_flag: "
+ << p.enable_stateless_rejects_via_flag << std::endl;
+ os << " support_cheap_stateless_reject: "
+ << p.support_cheap_stateless_reject << " }";
+ return os;
+ }
+
+ // This only enables the stateless reject feature via the feature-flag.
+ // This should be a no-op if the peer does not support them.
+ bool enable_stateless_rejects_via_flag;
+ // Whether to do cheap stateless or not.
+ bool support_cheap_stateless_reject;
+};
+
+vector<BufferedPacketStoreTestParams> GetBufferedPacketStoreTestParams() {
+ vector<BufferedPacketStoreTestParams> params;
+ for (bool enable_stateless_rejects_via_flag : {true, false}) {
+ for (bool support_cheap_stateless_reject : {true, false}) {
+ params.push_back(BufferedPacketStoreTestParams(
+ enable_stateless_rejects_via_flag, support_cheap_stateless_reject));
+ }
+ }
+ return params;
+}
+
+// A dispatcher whose stateless rejector will always ACCEPTs CHLO.
+class BufferedPacketStoreTest
+ : public QuicDispatcherTest,
+ public ::testing::WithParamInterface<BufferedPacketStoreTestParams> {
+ public:
+ BufferedPacketStoreTest()
+ : QuicDispatcherTest(), client_addr_(Loopback4(), 1234) {
+ FLAGS_quic_buffer_packet_till_chlo = true;
+ FLAGS_quic_use_cheap_stateless_rejects =
+ GetParam().support_cheap_stateless_reject;
+ FLAGS_enable_quic_stateless_reject_support =
+ GetParam().enable_stateless_rejects_via_flag;
+ }
+
+ void SetUp() override {
+ QuicDispatcherTest::SetUp();
+ clock_ = QuicDispatcherPeer::GetHelper(dispatcher_.get())->GetClock();
+
+ QuicVersion version = AllSupportedVersions().front();
+ CryptoHandshakeMessage chlo = CryptoTestUtils::GenerateDefaultInchoateCHLO(
+ clock_, version, &crypto_config_);
+ chlo.SetVector(net::kCOPT, net::QuicTagVector{net::kSREJ});
+ // Pass an inchoate CHLO.
+ CryptoTestUtils::GenerateFullCHLO(
+ chlo, &crypto_config_, server_ip_, client_addr_, version, clock_,
+ &proof_, QuicDispatcherPeer::GetCache(dispatcher_.get()), &full_chlo_);
+ }
+
+ string SerializeFullCHLO() {
+ return full_chlo_.GetSerialized().AsStringPiece().as_string();
+ }
+
+ protected:
+ IPAddress server_ip_;
+ IPEndPoint client_addr_;
+ QuicCryptoProof proof_;
+ const QuicClock* clock_;
+ CryptoHandshakeMessage full_chlo_;
+};
+
+INSTANTIATE_TEST_CASE_P(
+ BufferedPacketStoreTests,
+ BufferedPacketStoreTest,
+ ::testing::ValuesIn(GetBufferedPacketStoreTestParams()));
+
+TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
+ InSequence s;
+ IPEndPoint client_address(Loopback4(), 1);
+ server_address_ = IPEndPoint(Any4(), 5);
+ QuicConnectionId conn_id = 1;
+ // A bunch of non-CHLO should be buffered upon arrival, and the first one
+ // should trigger OnNewConnectionAdded().
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id)).Times(1);
+ for (size_t i = 1; i <= kDefaultMaxUndecryptablePackets + 1; ++i) {
+ ProcessPacket(client_address, conn_id, true, false,
+ "data packet " + IntToString(i + 1),
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
+ kDefaultPathId,
+ /*packet_number=*/i + 1);
+ }
+ EXPECT_EQ(0u, dispatcher_->session_map().size())
+ << "No session should be created before CHLO arrives.";
+
+ // Pop out the last packet as it is also be dropped by the store.
+ data_connection_map_[conn_id].pop_back();
+ // When CHLO arrives, a new session should be created, and all packets
+ // buffered should be delivered to the session.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+
+ // Only |kDefaultMaxUndecryptablePackets| packets were buffered, and they
+ // should be delivered in arrival order.
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(kDefaultMaxUndecryptablePackets + 1) // + 1 for CHLO.
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+}
+
+TEST_P(BufferedPacketStoreTest,
+ ProcessNonChloPacketsForDifferentConnectionsUptoLimit) {
+ InSequence s;
+ server_address_ = IPEndPoint(Any4(), 5);
+ // A bunch of non-CHLO should be buffered upon arrival.
+ size_t kNumConnections = (FLAGS_quic_limit_num_new_sessions_per_epoll_loop
+ ? kMaxConnectionsWithoutCHLO
+ : kDefaultMaxConnectionsInStore) +
+ 1;
+ for (size_t i = 1; i <= kNumConnections; ++i) {
+ IPEndPoint client_address(Loopback4(), i);
+ QuicConnectionId conn_id = i;
+ if (i <= kNumConnections - 1) {
+ // As they are on different connection, they should trigger
+ // OnNewConnectionAdded(). The last packet should be dropped.
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
+ }
+ ProcessPacket(client_address, conn_id, true, false,
+ "data packet on connection " + IntToString(i),
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
+ kDefaultPathId,
+ /*packet_number=*/2);
+ }
+
+ // Pop out the packet on last connection as it shouldn't be enqueued in store
+ // as well.
+ data_connection_map_[kNumConnections].pop_front();
+
+ // Reset session creation counter to ensure processing CHLO can always
+ // create session.
+ QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(dispatcher_.get(),
+ kNumConnections);
+ // Process CHLOs to create session for these connections.
+ for (size_t i = 1; i <= kNumConnections; ++i) {
+ IPEndPoint client_address(Loopback4(), i);
+ QuicConnectionId conn_id = i;
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ if (conn_id == kNumConnections) {
+ // The last CHLO should trigger OnNewConnectionAdded() since it's the
+ // first packet arrives on that connection.
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
+ }
+ // First |kNumConnections| - 1 connections should have buffered
+ // a packet in store. The rest should have been dropped.
+ size_t upper_limit = FLAGS_quic_limit_num_new_sessions_per_epoll_loop
+ ? kMaxConnectionsWithoutCHLO
+ : kDefaultMaxConnectionsInStore;
+ size_t num_packet_to_process = i <= upper_limit ? 2u : 1u;
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, client_address, _))
+ .Times(num_packet_to_process)
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+ }
+}
+
+// Tests that store delivers empty packet list if CHLO arrives firstly.
+TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) {
+ QuicConnectionId conn_id = 1;
+ IPEndPoint client_address(Loopback4(), 1);
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+}
+
+// Tests that a retransmitted CHLO arrives after a connection for the
+// CHLO has been created.
+TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
+ InSequence s;
+ IPEndPoint client_address(Loopback4(), 1);
+ server_address_ = IPEndPoint(Any4(), 5);
+ QuicConnectionId conn_id = 1;
+ ProcessPacket(client_address, conn_id, true, false,
+ "data packet " + IntToString(2), PACKET_8BYTE_CONNECTION_ID,
+ PACKET_6BYTE_PACKET_NUMBER, kDefaultPathId,
+ /*packet_number=*/2);
+
+ // When CHLO arrives, a new session should be created, and all packets
+ // buffered should be delivered to the session.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address))
+ .Times(1) // Only triggered by 1st CHLO.
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(3) // Triggered by 1 data packet and 2 CHLOs.
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+}
+
+// Tests that expiration of a connection add connection id to time wait list.
+TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) {
+ InSequence s;
+ CreateTimeWaitListManager();
+ QuicBufferedPacketStore* store =
+ QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
+ QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock());
+
+ IPEndPoint client_address(Loopback4(), 1);
+ server_address_ = IPEndPoint(Any4(), 5);
+ QuicConnectionId conn_id = 1;
+ ProcessPacket(client_address, conn_id, true, false,
+ "data packet " + IntToString(2), PACKET_8BYTE_CONNECTION_ID,
+ PACKET_6BYTE_PACKET_NUMBER, kDefaultPathId,
+ /*packet_number=*/2);
+
+ mock_helper_.AdvanceTime(
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs));
+ QuicAlarm* alarm = QuicBufferedPacketStorePeer::expiration_alarm(store);
+ // Cancel alarm as if it had been fired.
+ alarm->Cancel();
+ store->OnExpirationTimeout();
+ // New arrived CHLO will be dropped because this connection is in time wait
+ // list.
+ ASSERT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id));
+ EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, conn_id, _, _));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+}
+
+TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ // Process more than (|kMaxNumSessionsToCreate| +
+ // |kDefaultMaxConnectionsInStore|) CHLOs,
+ // the first |kMaxNumSessionsToCreate| should create connections immediately,
+ // the next |kDefaultMaxConnectionsInStore| should be buffered,
+ // the rest should be dropped.
+ QuicBufferedPacketStore* store =
+ QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
+ const size_t kNumCHLOs =
+ kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore + 1;
+ for (size_t conn_id = 1; conn_id <= kNumCHLOs; ++conn_id) {
+ if (conn_id < kNumCHLOs) {
+ // Except the last connection, all connections for previous CHLOs should
+ // be regarded as newly added.
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
+ }
+ if (conn_id <= kMaxNumSessionsToCreate) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(
+ *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+ if (conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore &&
+ conn_id > kMaxNumSessionsToCreate) {
+ EXPECT_TRUE(store->HasChloForConnection(conn_id));
+ } else {
+ // First |kMaxNumSessionsToCreate| CHLOs should be passed to new
+ // connections immediately, and the last CHLO should be dropped as the
+ // store is full.
+ EXPECT_FALSE(store->HasChloForConnection(conn_id));
+ }
+ }
+
+ // Graduately consume buffered CHLOs. The buffered connections should be
+ // created but the dropped one shouldn't.
+ for (size_t conn_id = kMaxNumSessionsToCreate + 1;
+ conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore;
+ ++conn_id) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(kNumCHLOs, client_addr_))
+ .Times(0);
+
+ while (store->HasChlosBuffered()) {
+ dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
+ }
+
+ EXPECT_EQ(static_cast<size_t>(kMaxNumSessionsToCreate) +
+ kDefaultMaxConnectionsInStore,
+ session1_->connection_id());
+}
+
+// Duplicated CHLO shouldn't be buffered.
+TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ for (QuicConnectionId conn_id = 1; conn_id <= kMaxNumSessionsToCreate + 1;
+ ++conn_id) {
+ // Last CHLO will be buffered. Others will create connection right away.
+ if (conn_id <= kMaxNumSessionsToCreate) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(
+ *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+ }
+ // Retransmit CHLO on last connection should be dropped.
+ QuicConnectionId last_connection = kMaxNumSessionsToCreate + 1;
+ ProcessPacket(client_addr_, last_connection, true, false,
+ SerializeFullCHLO());
+
+ size_t packets_buffered = 2;
+ if (!FLAGS_quic_buffer_packets_after_chlo) {
+ // The packet sent above is dropped when flag is off.
+ packets_buffered = 1;
+ }
+
+ // Reset counter and process buffered CHLO.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, last_connection, client_addr_,
+ &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ // Only one packet(CHLO) should be process.
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(packets_buffered)
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), last_connection))));
+ dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
+}
+
+TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ QuicConnectionId last_connection_id = kMaxNumSessionsToCreate + 1;
+ for (QuicConnectionId conn_id = 1; conn_id <= last_connection_id; ++conn_id) {
+ // Last CHLO will be buffered. Others will create connection right away.
+ if (conn_id <= kMaxNumSessionsToCreate) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(
+ *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+ }
+
+ // Process another |kDefaultMaxUndecryptablePackets| + 1 data packets. The
+ // last one should be dropped.
+ for (QuicPacketNumber packet_number = 2;
+ packet_number <= kDefaultMaxUndecryptablePackets + 2; ++packet_number) {
+ ProcessPacket(client_addr_, last_connection_id, true, false, "data packet");
+ }
+
+ // Reset counter and process buffered CHLO.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, last_connection_id, client_addr_,
+ &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ // Only CHLO and following |kDefaultMaxUndecryptablePackets| data packets
+ // should be process.
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(kDefaultMaxUndecryptablePackets + 1)
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), last_connection_id))));
+ dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
+}
+
+// Tests that when dispatcher's packet buffer is full, a CHLO on connection
+// which doesn't have buffered CHLO should be buffered.
+TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ QuicBufferedPacketStore* store =
+ QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
+
+ QuicConnectionId conn_id = 1;
+ ProcessPacket(client_addr_, conn_id, true, false, "data packet",
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
+ kDefaultPathId,
+ /*packet_number=*/1);
+ // Fill packet buffer to full with CHLOs on other connections. Need to feed
+ // extra CHLOs because the first |kMaxNumSessionsToCreate| are going to create
+ // session directly.
+ for (conn_id = 2;
+ conn_id <= kDefaultMaxConnectionsInStore + kMaxNumSessionsToCreate;
+ ++conn_id) {
+ if (conn_id <= kMaxNumSessionsToCreate + 1) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(
+ *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+ }
+ EXPECT_FALSE(store->HasChloForConnection(/*connection_id=*/1));
+
+ // CHLO on connection 1 should still be buffered.
+ ProcessPacket(client_addr_, /*connection_id=*/1, true, false,
+ SerializeFullCHLO());
+ EXPECT_TRUE(store->HasChloForConnection(/*connection_id=*/1));
}
} // namespace
diff --git a/chromium/net/tools/quic/quic_epoll_alarm_factory.cc b/chromium/net/tools/quic/quic_epoll_alarm_factory.cc
index 21a166a70d5..56377b237b3 100644
--- a/chromium/net/tools/quic/quic_epoll_alarm_factory.cc
+++ b/chromium/net/tools/quic/quic_epoll_alarm_factory.cc
@@ -23,8 +23,7 @@ class QuicEpollAlarm : public QuicAlarm {
void SetImpl() override {
DCHECK(deadline().IsInitialized());
epoll_server_->RegisterAlarm(
- deadline().Subtract(QuicTime::Zero()).ToMicroseconds(),
- &epoll_alarm_impl_);
+ (deadline() - QuicTime::Zero()).ToMicroseconds(), &epoll_alarm_impl_);
}
void CancelImpl() override {
diff --git a/chromium/net/tools/quic/quic_epoll_alarm_factory.h b/chromium/net/tools/quic/quic_epoll_alarm_factory.h
index 6b59ccc781e..1f94b79417e 100644
--- a/chromium/net/tools/quic/quic_epoll_alarm_factory.h
+++ b/chromium/net/tools/quic/quic_epoll_alarm_factory.h
@@ -5,8 +5,8 @@
#ifndef NET_QUIC_QUIC_EPOLL_ALARM_FACTORY_H_
#define NET_QUIC_QUIC_EPOLL_ALARM_FACTORY_H_
-#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_alarm_factory.h"
+#include "net/quic/core/quic_alarm.h"
+#include "net/quic/core/quic_alarm_factory.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc b/chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc
index 5dfe70185ec..3118be88a91 100644
--- a/chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc
+++ b/chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc
@@ -48,11 +48,11 @@ TEST_P(QuicEpollAlarmFactoryTest, CreateAlarm) {
QuicTime start = clock_.Now();
QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(start.Add(delta));
+ alarm->Set(start + delta);
epoll_server_.AdvanceByAndWaitForEventsAndExecuteCallbacks(
delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock_.Now());
+ EXPECT_EQ(start + delta, clock_.Now());
}
TEST_P(QuicEpollAlarmFactoryTest, CreateAlarmAndCancel) {
@@ -64,11 +64,11 @@ TEST_P(QuicEpollAlarmFactoryTest, CreateAlarmAndCancel) {
QuicTime start = clock_.Now();
QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(start.Add(delta));
+ alarm->Set(start + delta);
alarm->Cancel();
epoll_server_.AdvanceByExactlyAndCallCallbacks(delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock_.Now());
+ EXPECT_EQ(start + delta, clock_.Now());
EXPECT_FALSE(unowned_delegate->fired());
}
@@ -81,18 +81,18 @@ TEST_P(QuicEpollAlarmFactoryTest, CreateAlarmAndReset) {
QuicTime start = clock_.Now();
QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(clock_.Now().Add(delta));
+ alarm->Set(clock_.Now() + delta);
alarm->Cancel();
QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
- alarm->Set(clock_.Now().Add(new_delta));
+ alarm->Set(clock_.Now() + new_delta);
epoll_server_.AdvanceByExactlyAndCallCallbacks(delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock_.Now());
+ EXPECT_EQ(start + delta, clock_.Now());
EXPECT_FALSE(unowned_delegate->fired());
epoll_server_.AdvanceByExactlyAndCallCallbacks(
- new_delta.Subtract(delta).ToMicroseconds());
- EXPECT_EQ(start.Add(new_delta), clock_.Now());
+ (new_delta - delta).ToMicroseconds());
+ EXPECT_EQ(start + new_delta, clock_.Now());
EXPECT_TRUE(unowned_delegate->fired());
}
@@ -105,28 +105,25 @@ TEST_P(QuicEpollAlarmFactoryTest, CreateAlarmAndUpdate) {
QuicTime start = clock_.Now();
QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(clock_.Now().Add(delta));
+ alarm->Set(clock_.Now() + delta);
QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
- alarm->Update(clock_.Now().Add(new_delta),
- QuicTime::Delta::FromMicroseconds(1));
+ alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
epoll_server_.AdvanceByExactlyAndCallCallbacks(delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock_.Now());
+ EXPECT_EQ(start + delta, clock_.Now());
EXPECT_FALSE(unowned_delegate->fired());
// Move the alarm forward 1us and ensure it doesn't move forward.
- alarm->Update(clock_.Now().Add(new_delta),
- QuicTime::Delta::FromMicroseconds(2));
+ alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(2));
epoll_server_.AdvanceByExactlyAndCallCallbacks(
- new_delta.Subtract(delta).ToMicroseconds());
- EXPECT_EQ(start.Add(new_delta), clock_.Now());
+ (new_delta - delta).ToMicroseconds());
+ EXPECT_EQ(start + new_delta, clock_.Now());
EXPECT_TRUE(unowned_delegate->fired());
// Set the alarm via an update call.
new_delta = QuicTime::Delta::FromMicroseconds(5);
- alarm->Update(clock_.Now().Add(new_delta),
- QuicTime::Delta::FromMicroseconds(1));
+ alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
EXPECT_TRUE(alarm->IsSet());
// Update it with an uninitialized time and ensure it's cancelled.
diff --git a/chromium/net/tools/quic/quic_epoll_clock.cc b/chromium/net/tools/quic/quic_epoll_clock.cc
index cb7717647b7..357bc500c63 100644
--- a/chromium/net/tools/quic/quic_epoll_clock.cc
+++ b/chromium/net/tools/quic/quic_epoll_clock.cc
@@ -14,13 +14,13 @@ QuicEpollClock::QuicEpollClock(EpollServer* epoll_server)
QuicEpollClock::~QuicEpollClock() {}
QuicTime QuicEpollClock::ApproximateNow() const {
- return QuicTime::Zero().Add(
- QuicTime::Delta::FromMicroseconds(epoll_server_->ApproximateNowInUsec()));
+ return QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(
+ epoll_server_->ApproximateNowInUsec());
}
QuicTime QuicEpollClock::Now() const {
- return QuicTime::Zero().Add(
- QuicTime::Delta::FromMicroseconds(epoll_server_->NowInUsec()));
+ return QuicTime::Zero() +
+ QuicTime::Delta::FromMicroseconds(epoll_server_->NowInUsec());
}
QuicWallTime QuicEpollClock::WallNow() const {
@@ -30,8 +30,8 @@ QuicWallTime QuicEpollClock::WallNow() const {
QuicTime QuicEpollClock::ConvertWallTimeToQuicTime(
const QuicWallTime& walltime) const {
- return QuicTime::Zero().Add(
- QuicTime::Delta::FromMicroseconds(walltime.ToUNIXMicroseconds()));
-};
+ return QuicTime::Zero() +
+ QuicTime::Delta::FromMicroseconds(walltime.ToUNIXMicroseconds());
+}
} // namespace net
diff --git a/chromium/net/tools/quic/quic_epoll_clock.h b/chromium/net/tools/quic/quic_epoll_clock.h
index 520c529c9b7..509d3bf7e4d 100644
--- a/chromium/net/tools/quic/quic_epoll_clock.h
+++ b/chromium/net/tools/quic/quic_epoll_clock.h
@@ -7,8 +7,8 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_time.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_time.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_epoll_clock_test.cc b/chromium/net/tools/quic/quic_epoll_clock_test.cc
index 039e8bfa318..03d26b82106 100644
--- a/chromium/net/tools/quic/quic_epoll_clock_test.cc
+++ b/chromium/net/tools/quic/quic_epoll_clock_test.cc
@@ -16,13 +16,13 @@ TEST(QuicEpollClockTest, ApproximateNowInUsec) {
epoll_server.set_now_in_usec(1000000);
EXPECT_EQ(1000000,
- clock.ApproximateNow().Subtract(QuicTime::Zero()).ToMicroseconds());
+ (clock.ApproximateNow() - QuicTime::Zero()).ToMicroseconds());
EXPECT_EQ(1u, clock.WallNow().ToUNIXSeconds());
EXPECT_EQ(1000000u, clock.WallNow().ToUNIXMicroseconds());
epoll_server.AdvanceBy(5);
EXPECT_EQ(1000005,
- clock.ApproximateNow().Subtract(QuicTime::Zero()).ToMicroseconds());
+ (clock.ApproximateNow() - QuicTime::Zero()).ToMicroseconds());
EXPECT_EQ(1u, clock.WallNow().ToUNIXSeconds());
EXPECT_EQ(1000005u, clock.WallNow().ToUNIXMicroseconds());
@@ -36,10 +36,10 @@ TEST(QuicEpollClockTest, NowInUsec) {
QuicEpollClock clock(&epoll_server);
epoll_server.set_now_in_usec(1000000);
- EXPECT_EQ(1000000, clock.Now().Subtract(QuicTime::Zero()).ToMicroseconds());
+ EXPECT_EQ(1000000, (clock.Now() - QuicTime::Zero()).ToMicroseconds());
epoll_server.AdvanceBy(5);
- EXPECT_EQ(1000005, clock.Now().Subtract(QuicTime::Zero()).ToMicroseconds());
+ EXPECT_EQ(1000005, (clock.Now() - QuicTime::Zero()).ToMicroseconds());
}
} // namespace test
diff --git a/chromium/net/tools/quic/quic_epoll_connection_helper.cc b/chromium/net/tools/quic/quic_epoll_connection_helper.cc
index eec8fc5fd73..3f9671080e0 100644
--- a/chromium/net/tools/quic/quic_epoll_connection_helper.cc
+++ b/chromium/net/tools/quic/quic_epoll_connection_helper.cc
@@ -10,7 +10,7 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/quic_random.h"
+#include "net/quic/core/crypto/quic_random.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_socket_utils.h"
diff --git a/chromium/net/tools/quic/quic_epoll_connection_helper.h b/chromium/net/tools/quic/quic_epoll_connection_helper.h
index ccd7536b2bc..01964b35b9b 100644
--- a/chromium/net/tools/quic/quic_epoll_connection_helper.h
+++ b/chromium/net/tools/quic/quic_epoll_connection_helper.h
@@ -12,11 +12,11 @@
#include <set>
#include "base/macros.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_simple_buffer_allocator.h"
-#include "net/quic/quic_time.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/core/quic_time.h"
#include "net/tools/quic/quic_default_packet_writer.h"
#include "net/tools/quic/quic_epoll_clock.h"
diff --git a/chromium/net/tools/quic/quic_epoll_connection_helper_test.cc b/chromium/net/tools/quic/quic_epoll_connection_helper_test.cc
index 078eef7b397..0f9106fe088 100644
--- a/chromium/net/tools/quic/quic_epoll_connection_helper_test.cc
+++ b/chromium/net/tools/quic/quic_epoll_connection_helper_test.cc
@@ -4,7 +4,7 @@
#include "net/tools/quic/quic_epoll_connection_helper.h"
-#include "net/quic/crypto/quic_random.h"
+#include "net/quic/core/crypto/quic_random.h"
#include "net/tools/quic/test_tools/mock_epoll_server.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,7 +30,7 @@ TEST_F(QuicEpollConnectionHelperTest, GetClock) {
QuicTime::Delta delta = QuicTime::Delta::FromMilliseconds(5);
epoll_server_.AdvanceBy(delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock->Now());
+ EXPECT_EQ(start + delta, clock->Now());
}
TEST_F(QuicEpollConnectionHelperTest, GetRandomGenerator) {
diff --git a/chromium/net/tools/quic/quic_in_memory_cache.cc b/chromium/net/tools/quic/quic_in_memory_cache.cc
index 3b2f9e00b57..a63f4996e76 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache.cc
+++ b/chromium/net/tools/quic/quic_in_memory_cache.cc
@@ -14,7 +14,7 @@
#include "base/strings/stringprintf.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
-#include "net/quic/quic_bug_tracker.h"
+#include "net/quic/core/quic_bug_tracker.h"
#include "net/spdy/spdy_http_utils.h"
using base::FilePath;
@@ -69,7 +69,7 @@ class ResourceFileImpl : public net::QuicInMemoryCache::ResourceFile {
body_ = StringPiece(file_contents_.data() + headers_end,
file_contents_.size() - headers_end);
- CreateSpdyHeadersFromHttpResponse(*http_headers_, HTTP2, &spdy_headers_);
+ CreateSpdyHeadersFromHttpResponse(*http_headers_, &spdy_headers_);
}
private:
@@ -119,9 +119,10 @@ void QuicInMemoryCache::ResourceFile::SetHostPathFromBase(StringPiece base) {
}
StringPiece QuicInMemoryCache::ResourceFile::RemoveScheme(StringPiece url) {
- if (url.starts_with("https://")) {
+ if (base::StartsWith(url, "https://", base::CompareCase::INSENSITIVE_ASCII)) {
url.remove_prefix(8);
- } else if (url.starts_with("http://")) {
+ } else if (base::StartsWith(url, "http://",
+ base::CompareCase::INSENSITIVE_ASCII)) {
url.remove_prefix(7);
}
return url;
@@ -142,6 +143,8 @@ QuicInMemoryCache* QuicInMemoryCache::GetInstance() {
const QuicInMemoryCache::Response* QuicInMemoryCache::GetResponse(
StringPiece host,
StringPiece path) const {
+ base::AutoLock lock(response_mutex_);
+
ResponseMap::const_iterator it = responses_.find(GetKey(host, path));
if (it == responses_.end()) {
DVLOG(1) << "Get response for resource failed: host " << host << " path "
@@ -178,6 +181,7 @@ void QuicInMemoryCache::AddSimpleResponseWithServerPushResources(
}
void QuicInMemoryCache::AddDefaultResponse(Response* response) {
+ base::AutoLock lock(response_mutex_);
default_response_.reset(response);
}
@@ -208,7 +212,8 @@ void QuicInMemoryCache::AddSpecialResponse(StringPiece host,
QuicInMemoryCache::QuicInMemoryCache() {}
void QuicInMemoryCache::ResetForTests() {
- STLDeleteValues(&responses_);
+ base::AutoLock lock(response_mutex_);
+ base::STLDeleteValues(&responses_);
server_push_resources_.clear();
}
@@ -268,6 +273,8 @@ void QuicInMemoryCache::InitializeFromDirectory(const string& cache_directory) {
list<ServerPushInfo> QuicInMemoryCache::GetServerPushResources(
string request_url) {
+ base::AutoLock lock(response_mutex_);
+
list<ServerPushInfo> resources;
auto resource_range = server_push_resources_.equal_range(request_url);
for (auto it = resource_range.first; it != resource_range.second; ++it) {
@@ -279,7 +286,10 @@ list<ServerPushInfo> QuicInMemoryCache::GetServerPushResources(
}
QuicInMemoryCache::~QuicInMemoryCache() {
- STLDeleteValues(&responses_);
+ {
+ base::AutoLock lock(response_mutex_);
+ base::STLDeleteValues(&responses_);
+ }
}
void QuicInMemoryCache::AddResponseImpl(StringPiece host,
@@ -288,9 +298,11 @@ void QuicInMemoryCache::AddResponseImpl(StringPiece host,
SpdyHeaderBlock response_headers,
StringPiece response_body,
SpdyHeaderBlock response_trailers) {
+ base::AutoLock lock(response_mutex_);
+
DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\"";
string key = GetKey(host, path);
- if (ContainsKey(responses_, key)) {
+ if (base::ContainsKey(responses_, key)) {
QUIC_BUG << "Response for '" << key << "' already exists!";
return;
}
@@ -321,13 +333,22 @@ void QuicInMemoryCache::MaybeAddServerPushResources(
DVLOG(1) << "Add request-resource association: request url " << request_url
<< " push url " << push_resource.request_url
<< " response headers " << push_resource.headers.DebugString();
- server_push_resources_.insert(std::make_pair(request_url, push_resource));
+ {
+ base::AutoLock lock(response_mutex_);
+ server_push_resources_.insert(std::make_pair(request_url, push_resource));
+ }
string host = push_resource.request_url.host();
if (host.empty()) {
host = request_host.as_string();
}
string path = push_resource.request_url.path();
- if (responses_.find(GetKey(host, path)) == responses_.end()) {
+ bool found_existing_response = false;
+ {
+ base::AutoLock lock(response_mutex_);
+ found_existing_response =
+ base::ContainsKey(responses_, GetKey(host, path));
+ }
+ if (!found_existing_response) {
// Add a server push response to responses map, if it is not in the map.
StringPiece body = push_resource.body;
DVLOG(1) << "Add response for push resource: host " << host << " path "
@@ -339,6 +360,7 @@ void QuicInMemoryCache::MaybeAddServerPushResources(
bool QuicInMemoryCache::PushResourceExistsInCache(string original_request_url,
ServerPushInfo resource) {
+ base::AutoLock lock(response_mutex_);
auto resource_range =
server_push_resources_.equal_range(original_request_url);
for (auto it = resource_range.first; it != resource_range.second; ++it) {
diff --git a/chromium/net/tools/quic/quic_in_memory_cache.h b/chromium/net/tools/quic/quic_in_memory_cache.h
index 2747c9303be..174a7d51635 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache.h
+++ b/chromium/net/tools/quic/quic_in_memory_cache.h
@@ -17,7 +17,7 @@
#include "base/memory/singleton.h"
#include "base/strings/string_piece.h"
#include "net/http/http_response_headers.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_framer.h"
#include "url/gurl.h"
@@ -234,6 +234,10 @@ class QuicInMemoryCache {
// A map from request URL to associated server push responses (if any).
std::multimap<std::string, ServerPushInfo> server_push_resources_;
+ // Protects against concurrent access from test threads setting responses, and
+ // server threads accessing those responses.
+ mutable base::Lock response_mutex_;
+
DISALLOW_COPY_AND_ASSIGN(QuicInMemoryCache);
};
diff --git a/chromium/net/tools/quic/quic_in_memory_cache_test.cc b/chromium/net/tools/quic/quic_in_memory_cache_test.cc
index d31e8fd813e..d220e482af0 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache_test.cc
+++ b/chromium/net/tools/quic/quic_in_memory_cache_test.cc
@@ -69,7 +69,7 @@ TEST_F(QuicInMemoryCacheTest, AddSimpleResponseGetResponse) {
const QuicInMemoryCache::Response* response =
cache->GetResponse("www.google.com", "/");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
EXPECT_EQ(response_body.size(), response->body().length());
}
@@ -106,9 +106,9 @@ TEST_F(QuicInMemoryCacheTest, ReadsCacheDir) {
QuicInMemoryCache::GetInstance()->GetResponse("quic.test.url",
"/index.html");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
- ASSERT_TRUE(ContainsKey(response->headers(), "connection"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), "connection"));
EXPECT_EQ("close", response->headers().find("connection")->second);
EXPECT_LT(0U, response->body().length());
}
@@ -137,9 +137,9 @@ TEST_F(QuicInMemoryCacheTest, UsesOriginalUrl) {
QuicInMemoryCache::GetInstance()->GetResponse("quic.test.url",
"/index.html");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
- ASSERT_TRUE(ContainsKey(response->headers(), "connection"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), "connection"));
EXPECT_EQ("close", response->headers().find("connection")->second);
EXPECT_LT(0U, response->body().length());
}
@@ -164,20 +164,20 @@ TEST_F(QuicInMemoryCacheTest, DefaultResponse) {
// Now we should get the default response for the original request.
response = cache->GetResponse("www.google.com", "/");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
// Now add a set response for / and make sure it is returned
cache->AddSimpleResponse("www.google.com", "/", 302, "");
response = cache->GetResponse("www.google.com", "/");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("302", response->headers().find(":status")->second);
// We should get the default response for other requests.
response = cache->GetResponse("www.google.com", "/asd");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
}
@@ -249,7 +249,7 @@ TEST_F(QuicInMemoryCacheTest, GetServerPushResourcesAndPushResponses) {
const QuicInMemoryCache::Response* response =
cache->GetResponse(host, path);
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ(push_response_status[i++],
response->headers().find(":status")->second);
EXPECT_EQ(push_resource.body, response->body());
diff --git a/chromium/net/tools/quic/quic_packet_printer_bin.cc b/chromium/net/tools/quic/quic_packet_printer_bin.cc
index a19b679b735..8be7be5fda3 100644
--- a/chromium/net/tools/quic/quic_packet_printer_bin.cc
+++ b/chromium/net/tools/quic/quic_packet_printer_bin.cc
@@ -40,8 +40,8 @@
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_utils.h"
using std::cerr;
using std::string;
@@ -184,7 +184,7 @@ int main(int argc, char* argv[]) {
return 1;
}
string hex = net::QuicUtils::HexDecode(ArgToString(args[1]));
- net::QuicVersionVector versions = net::QuicSupportedVersions();
+ net::QuicVersionVector versions = net::AllSupportedVersions();
// Fake a time since we're not actually generating acks.
net::QuicTime start(net::QuicTime::Zero());
net::QuicFramer framer(versions, start, perspective);
diff --git a/chromium/net/tools/quic/quic_packet_reader.cc b/chromium/net/tools/quic/quic_packet_reader.cc
index f3e1fea8480..6a443e57f12 100644
--- a/chromium/net/tools/quic/quic_packet_reader.cc
+++ b/chromium/net/tools/quic/quic_packet_reader.cc
@@ -15,8 +15,8 @@
#include "base/logging.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
#include "net/tools/quic/quic_dispatcher.h"
#include "net/tools/quic/quic_process_packet_interface.h"
#include "net/tools/quic/quic_socket_utils.h"
@@ -63,21 +63,23 @@ QuicPacketReader::~QuicPacketReader() {}
bool QuicPacketReader::ReadAndDispatchPackets(
int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped) {
#if MMSG_MORE
- return ReadAndDispatchManyPackets(fd, port, clock, processor,
- packets_dropped);
+ return ReadAndDispatchManyPackets(fd, port, potentially_small_mtu, clock,
+ processor, packets_dropped);
#else
- return ReadAndDispatchSinglePacket(fd, port, clock, processor,
- packets_dropped);
+ return ReadAndDispatchSinglePacket(fd, port, potentially_small_mtu, clock,
+ processor, packets_dropped);
#endif
}
bool QuicPacketReader::ReadAndDispatchManyPackets(
int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped) {
@@ -98,7 +100,6 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
return false; // recvmmsg failed.
}
- QuicTime fallback_timestamp = QuicTime::Zero();
QuicWallTime fallback_walltimestamp = QuicWallTime::Zero();
for (int i = 0; i < packets_read; ++i) {
if (mmsg_hdr_[i].msg_len == 0) {
@@ -114,12 +115,9 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
IPEndPoint client_address = IPEndPoint(packets_[i].raw_address);
IPAddress server_ip;
- QuicTime packet_timestamp = QuicTime::Zero();
QuicWallTime packet_walltimestamp = QuicWallTime::Zero();
- bool latched_walltimestamps = FLAGS_quic_socket_walltimestamps;
QuicSocketUtils::GetAddressAndTimestampFromMsghdr(
- &mmsg_hdr_[i].msg_hdr, &server_ip, &packet_timestamp,
- &packet_walltimestamp, latched_walltimestamps);
+ &mmsg_hdr_[i].msg_hdr, &server_ip, &packet_walltimestamp);
if (!IsInitializedAddress(server_ip)) {
QUIC_BUG << "Unable to get server address.";
continue;
@@ -127,24 +125,19 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
// This isn't particularly desirable, but not all platforms support socket
// timestamping.
- if (latched_walltimestamps) {
- if (packet_walltimestamp.IsZero()) {
- if (fallback_walltimestamp.IsZero()) {
- fallback_walltimestamp = clock.WallNow();
- }
- packet_walltimestamp = fallback_walltimestamp;
- }
- packet_timestamp = clock.ConvertWallTimeToQuicTime(packet_walltimestamp);
- } else {
- if (packet_timestamp == QuicTime::Zero()) {
- if (fallback_timestamp == QuicTime::Zero()) {
- fallback_timestamp = clock.Now();
- }
- packet_timestamp = fallback_timestamp;
+ if (packet_walltimestamp.IsZero()) {
+ if (fallback_walltimestamp.IsZero()) {
+ fallback_walltimestamp = clock.WallNow();
}
+ packet_walltimestamp = fallback_walltimestamp;
}
+ QuicTime timestamp = clock.ConvertWallTimeToQuicTime(packet_walltimestamp);
+ int ttl = 0;
+ bool has_ttl =
+ QuicSocketUtils::GetTtlFromMsghdr(&mmsg_hdr_[i].msg_hdr, &ttl);
QuicReceivedPacket packet(reinterpret_cast<char*>(packets_[i].iov.iov_base),
- mmsg_hdr_[i].msg_len, packet_timestamp, false);
+ mmsg_hdr_[i].msg_len, timestamp, false,
+ potentially_small_mtu, ttl, has_ttl);
IPEndPoint server_address(server_ip, port);
processor->ProcessPacket(server_address, client_address, packet);
}
@@ -166,20 +159,18 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
bool QuicPacketReader::ReadAndDispatchSinglePacket(
int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped) {
- bool latched_walltimestamps = FLAGS_quic_socket_walltimestamps;
char buf[kMaxPacketSize];
IPEndPoint client_address;
IPAddress server_ip;
- QuicTime timestamp = QuicTime::Zero();
QuicWallTime walltimestamp = QuicWallTime::Zero();
- int bytes_read = QuicSocketUtils::ReadPacket(
- fd, buf, arraysize(buf), packets_dropped, &server_ip, &timestamp,
- &walltimestamp, latched_walltimestamps, &client_address);
-
+ int bytes_read =
+ QuicSocketUtils::ReadPacket(fd, buf, arraysize(buf), packets_dropped,
+ &server_ip, &walltimestamp, &client_address);
if (bytes_read < 0) {
return false; // ReadPacket failed.
}
@@ -190,18 +181,14 @@ bool QuicPacketReader::ReadAndDispatchSinglePacket(
}
// This isn't particularly desirable, but not all platforms support socket
// timestamping.
- if (latched_walltimestamps) {
- if (walltimestamp.IsZero()) {
- walltimestamp = clock.WallNow();
- }
- timestamp = clock.ConvertWallTimeToQuicTime(walltimestamp);
- } else {
- if (timestamp == QuicTime::Zero()) {
- timestamp = clock.Now();
- }
+ if (walltimestamp.IsZero()) {
+ walltimestamp = clock.WallNow();
}
+ QuicTime timestamp = clock.ConvertWallTimeToQuicTime(walltimestamp);
- QuicReceivedPacket packet(buf, bytes_read, timestamp, false);
+ QuicReceivedPacket packet(buf, bytes_read, timestamp, false /* owns_buffer */,
+ potentially_small_mtu, -1 /* ttl */,
+ false /* ttl_valid */);
IPEndPoint server_address(server_ip, port);
processor->ProcessPacket(server_address, client_address, packet);
diff --git a/chromium/net/tools/quic/quic_packet_reader.h b/chromium/net/tools/quic/quic_packet_reader.h
index b388406b478..a4d207581b7 100644
--- a/chromium/net/tools/quic/quic_packet_reader.h
+++ b/chromium/net/tools/quic/quic_packet_reader.h
@@ -11,8 +11,8 @@
#include <sys/socket.h>
#include "base/macros.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_process_packet_interface.h"
#include "net/tools/quic/quic_socket_utils.h"
@@ -44,8 +44,11 @@ class QuicPacketReader {
// to track dropped packets and some packets are read.
// If the socket has timestamping enabled, the per packet timestamps will be
// passed to the processor. Otherwise, |clock| will be used.
+ // If |potentially_small_mtu| is set, the incoming packets have been
+ // identified as potentially having an unusually small MTU.
virtual bool ReadAndDispatchPackets(int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped);
@@ -57,6 +60,7 @@ class QuicPacketReader {
// Reads and dispatches many packets using recvmmsg.
bool ReadAndDispatchManyPackets(int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped);
@@ -64,6 +68,7 @@ class QuicPacketReader {
// Reads and dispatches a single packet using recvmsg.
static bool ReadAndDispatchSinglePacket(int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped);
diff --git a/chromium/net/tools/quic/quic_packet_writer_wrapper.cc b/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
index 3d008f09c73..de3d92b2e46 100644
--- a/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
+++ b/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
@@ -4,7 +4,7 @@
#include "net/tools/quic/quic_packet_writer_wrapper.h"
-#include "net/quic/quic_types.h"
+#include "net/quic/core/quic_types.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_packet_writer_wrapper.h b/chromium/net/tools/quic/quic_packet_writer_wrapper.h
index 34642a6282d..ea1f9fcb10f 100644
--- a/chromium/net/tools/quic/quic_packet_writer_wrapper.h
+++ b/chromium/net/tools/quic/quic_packet_writer_wrapper.h
@@ -10,7 +10,7 @@
#include <memory>
#include "base/macros.h"
-#include "net/quic/quic_packet_writer.h"
+#include "net/quic/core/quic_packet_writer.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_per_connection_packet_writer.h b/chromium/net/tools/quic/quic_per_connection_packet_writer.h
index 6902f3af839..cc48b635e14 100644
--- a/chromium/net/tools/quic/quic_per_connection_packet_writer.h
+++ b/chromium/net/tools/quic/quic_per_connection_packet_writer.h
@@ -8,8 +8,8 @@
#include <stddef.h>
#include "base/macros.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
namespace net {
@@ -17,7 +17,7 @@ namespace net {
class QuicPerConnectionPacketWriter : public QuicPacketWriter {
public:
// Does not take ownership of |shared_writer|.
- QuicPerConnectionPacketWriter(QuicPacketWriter* shared_writer);
+ explicit QuicPerConnectionPacketWriter(QuicPacketWriter* shared_writer);
~QuicPerConnectionPacketWriter() override;
QuicPacketWriter* shared_writer() const { return shared_writer_; }
diff --git a/chromium/net/tools/quic/quic_process_packet_interface.h b/chromium/net/tools/quic/quic_process_packet_interface.h
index aa1035d946b..600bc70844b 100644
--- a/chromium/net/tools/quic/quic_process_packet_interface.h
+++ b/chromium/net/tools/quic/quic_process_packet_interface.h
@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_reject_reason_decoder_bin.cc b/chromium/net/tools/quic/quic_reject_reason_decoder_bin.cc
new file mode 100644
index 00000000000..aba019947b7
--- /dev/null
+++ b/chromium/net/tools/quic/quic_reject_reason_decoder_bin.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2016 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.
+
+// Decodes the packet HandshakeFailureReason from the chromium histogram
+// Net.QuicClientHelloRejectReasons
+
+#include <iostream>
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+
+using base::CommandLine;
+using base::StringToUint;
+using net::HandshakeFailureReason;
+using net::CryptoUtils;
+using net::MAX_FAILURE_REASON;
+using std::cerr;
+using std::cout;
+
+int main(int argc, char* argv[]) {
+ CommandLine::Init(argc, argv);
+ CommandLine* line = CommandLine::ForCurrentProcess();
+ const CommandLine::StringVector& args = line->GetArgs();
+
+ if (args.size() != 1) {
+ cerr << "Missing argument (Usage: " << argv[0] << " <packed_reason>\n";
+ return 1;
+ }
+
+ uint32_t packed_error = 0;
+ if (!StringToUint(args[0], &packed_error)) {
+ cerr << "Unable to parse: " << args[0] << "\n";
+ return 2;
+ }
+
+ for (int i = 1; i < MAX_FAILURE_REASON; ++i) {
+ if ((packed_error & (1 << (i - 1))) == 0) {
+ continue;
+ }
+ HandshakeFailureReason reason = static_cast<HandshakeFailureReason>(i);
+ cout << CryptoUtils::HandshakeFailureReasonToString(reason) << "\n";
+ }
+ return 0;
+}
diff --git a/chromium/net/tools/quic/quic_server.cc b/chromium/net/tools/quic/quic_server.cc
index 94fdfdaca09..fb5d5912b0f 100644
--- a/chromium/net/tools/quic/quic_server.cc
+++ b/chromium/net/tools/quic/quic_server.cc
@@ -15,19 +15,20 @@
#include "net/base/ip_endpoint.h"
#include "net/base/sockaddr_storage.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_dispatcher.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_clock.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_packet_reader.h"
-#include "net/tools/quic/quic_simple_server_session_helper.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
#include "net/tools/quic/quic_socket_utils.h"
#ifndef SO_RXQ_OVFL
@@ -47,14 +48,16 @@ const char kSourceAddressTokenSecret[] = "secret";
} // namespace
-QuicServer::QuicServer(ProofSource* proof_source)
- : QuicServer(proof_source,
+const size_t kNumSessionsToCreatePerSocketEvent = 16;
+
+QuicServer::QuicServer(std::unique_ptr<ProofSource> proof_source)
+ : QuicServer(std::move(proof_source),
QuicConfig(),
QuicCryptoServerConfig::ConfigOptions(),
- QuicSupportedVersions()) {}
+ AllSupportedVersions()) {}
QuicServer::QuicServer(
- ProofSource* proof_source,
+ std::unique_ptr<ProofSource> proof_source,
const QuicConfig& config,
const QuicCryptoServerConfig::ConfigOptions& crypto_config_options,
const QuicVersionVector& supported_versions)
@@ -65,9 +68,9 @@ QuicServer::QuicServer(
config_(config),
crypto_config_(kSourceAddressTokenSecret,
QuicRandom::GetInstance(),
- proof_source),
+ std::move(proof_source)),
crypto_config_options_(crypto_config_options),
- supported_versions_(supported_versions),
+ version_manager_(supported_versions),
packet_reader_(new QuicPacketReader()) {
Initialize();
}
@@ -147,12 +150,12 @@ QuicDefaultPacketWriter* QuicServer::CreateWriter(int fd) {
QuicDispatcher* QuicServer::CreateQuicDispatcher() {
QuicEpollAlarmFactory alarm_factory(&epoll_server_);
- return new QuicDispatcher(
- config_, &crypto_config_, supported_versions_,
+ return new QuicSimpleDispatcher(
+ config_, &crypto_config_, &version_manager_,
std::unique_ptr<QuicEpollConnectionHelper>(new QuicEpollConnectionHelper(
&epoll_server_, QuicAllocator::BUFFER_POOL)),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(&epoll_server_)));
}
@@ -176,12 +179,25 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) {
if (event->in_events & EPOLLIN) {
DVLOG(1) << "EPOLLIN";
+
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop &&
+ FLAGS_quic_buffer_packet_till_chlo) {
+ dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent);
+ }
+
bool more_to_read = true;
while (more_to_read) {
more_to_read = packet_reader_->ReadAndDispatchPackets(
- fd_, port_, QuicEpollClock(&epoll_server_), dispatcher_.get(),
+ fd_, port_, false /* potentially_small_mtu */,
+ QuicEpollClock(&epoll_server_), dispatcher_.get(),
overflow_supported_ ? &packets_dropped_ : nullptr);
}
+
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop &&
+ FLAGS_quic_buffer_packet_till_chlo && dispatcher_->HasChlosBuffered()) {
+ // Register EPOLLIN event to consume buffered CHLO(s).
+ event->out_ready_mask |= EPOLLIN;
+ }
}
if (event->in_events & EPOLLOUT) {
dispatcher_->OnCanWrite();
diff --git a/chromium/net/tools/quic/quic_server.h b/chromium/net/tools/quic/quic_server.h
index 76ff17a45b0..0a5b9035e6e 100644
--- a/chromium/net/tools/quic/quic_server.h
+++ b/chromium/net/tools/quic/quic_server.h
@@ -17,10 +17,10 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_framer.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_framer.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_default_packet_writer.h"
@@ -35,8 +35,8 @@ class QuicPacketReader;
class QuicServer : public EpollCallbackInterface {
public:
- explicit QuicServer(ProofSource* proof_source);
- QuicServer(ProofSource* proof_source,
+ explicit QuicServer(std::unique_ptr<ProofSource> proof_source);
+ QuicServer(std::unique_ptr<ProofSource> proof_source,
const QuicConfig& config,
const QuicCryptoServerConfig::ConfigOptions& server_config_options,
const QuicVersionVector& supported_versions);
@@ -81,13 +81,12 @@ class QuicServer : public EpollCallbackInterface {
const QuicConfig& config() const { return config_; }
const QuicCryptoServerConfig& crypto_config() const { return crypto_config_; }
- const QuicVersionVector& supported_versions() const {
- return supported_versions_;
- }
EpollServer* epoll_server() { return &epoll_server_; }
QuicDispatcher* dispatcher() { return dispatcher_.get(); }
+ QuicVersionManager* version_manager() { return &version_manager_; }
+
private:
friend class net::test::QuicServerPeer;
@@ -122,11 +121,8 @@ class QuicServer : public EpollCallbackInterface {
// crypto_config_options_ contains crypto parameters for the handshake.
QuicCryptoServerConfig::ConfigOptions crypto_config_options_;
- // This vector contains QUIC versions which we currently support.
- // This should be ordered such that the highest supported version is the first
- // element, with subsequent elements in descending order (versions can be
- // skipped as necessary).
- QuicVersionVector supported_versions_;
+ // Used to generate current supported versions.
+ QuicVersionManager version_manager_;
// Point to a QuicPacketReader object on the heap. The reader allocates more
// space than allowed on the stack.
diff --git a/chromium/net/tools/quic/quic_server_bin.cc b/chromium/net/tools/quic/quic_server_bin.cc
index 983c58443bc..b1eafd73f01 100644
--- a/chromium/net/tools/quic/quic_server_bin.cc
+++ b/chromium/net/tools/quic/quic_server_bin.cc
@@ -14,19 +14,21 @@
#include "base/strings/string_number_conversions.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/proof_source_chromium.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/chromium/crypto/proof_source_chromium.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_server.h"
// The port the quic server will listen on.
int32_t FLAGS_port = 6121;
-net::ProofSource* CreateProofSource(const base::FilePath& cert_path,
- const base::FilePath& key_path) {
- net::ProofSourceChromium* proof_source = new net::ProofSourceChromium();
+std::unique_ptr<net::ProofSource> CreateProofSource(
+ const base::FilePath& cert_path,
+ const base::FilePath& key_path) {
+ std::unique_ptr<net::ProofSourceChromium> proof_source(
+ new net::ProofSourceChromium());
CHECK(proof_source->Initialize(cert_path, key_path, base::FilePath()));
- return proof_source;
+ return std::move(proof_source);
}
int main(int argc, char* argv[]) {
@@ -84,7 +86,7 @@ int main(int argc, char* argv[]) {
CreateProofSource(line->GetSwitchValuePath("certificate_file"),
line->GetSwitchValuePath("key_file")),
config, net::QuicCryptoServerConfig::ConfigOptions(),
- net::QuicSupportedVersions());
+ net::AllSupportedVersions());
server.SetStrikeRegisterNoStartupPeriod();
int rc = server.CreateUDPSocketAndListen(net::IPEndPoint(ip, FLAGS_port));
diff --git a/chromium/net/tools/quic/quic_server_test.cc b/chromium/net/tools/quic/quic_server_test.cc
index fbada53be56..0cefdb52fff 100644
--- a/chromium/net/tools/quic/quic_server_test.cc
+++ b/chromium/net/tools/quic/quic_server_test.cc
@@ -4,13 +4,14 @@
#include "net/tools/quic/quic_server.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/mock_quic_dispatcher.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
-#include "net/tools/quic/quic_simple_server_session_helper.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
+#include "net/tools/quic/test_tools/quic_server_peer.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
@@ -22,20 +23,138 @@ namespace test {
namespace {
+class MockQuicSimpleDispatcher : public QuicSimpleDispatcher {
+ public:
+ MockQuicSimpleDispatcher(
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory)
+ : QuicSimpleDispatcher(config,
+ crypto_config,
+ version_manager,
+ std::move(helper),
+ std::move(session_helper),
+ std::move(alarm_factory)) {}
+ ~MockQuicSimpleDispatcher() override {}
+
+ MOCK_METHOD0(OnCanWrite, void());
+ MOCK_CONST_METHOD0(HasPendingWrites, bool());
+ MOCK_CONST_METHOD0(HasChlosBuffered, bool());
+ MOCK_METHOD1(ProcessBufferedChlos, void(size_t));
+};
+
+class TestQuicServer : public QuicServer {
+ public:
+ TestQuicServer() : QuicServer(CryptoTestUtils::ProofSourceForTesting()) {}
+
+ ~TestQuicServer() override {}
+
+ MockQuicSimpleDispatcher* mock_dispatcher() { return mock_dispatcher_; }
+
+ protected:
+ QuicDispatcher* CreateQuicDispatcher() override {
+ mock_dispatcher_ = new MockQuicSimpleDispatcher(
+ config(), &crypto_config(), version_manager(),
+ std::unique_ptr<QuicEpollConnectionHelper>(
+ new QuicEpollConnectionHelper(epoll_server(),
+ QuicAllocator::BUFFER_POOL)),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicEpollAlarmFactory>(
+ new QuicEpollAlarmFactory(epoll_server())));
+ return mock_dispatcher_;
+ }
+
+ MockQuicSimpleDispatcher* mock_dispatcher_;
+};
+
+class QuicServerEpollInTest : public ::testing::Test {
+ public:
+ QuicServerEpollInTest()
+ : port_(net::test::kTestPort), server_address_(Loopback4(), port_) {}
+
+ void StartListening() {
+ server_.CreateUDPSocketAndListen(server_address_);
+ ASSERT_TRUE(QuicServerPeer::SetSmallSocket(&server_));
+
+ if (!server_.overflow_supported()) {
+ LOG(WARNING) << "Overflow not supported. Not testing.";
+ return;
+ }
+ }
+
+ protected:
+ QuicFlagSaver saver_;
+ int port_;
+ IPEndPoint server_address_;
+ TestQuicServer server_;
+};
+
+// Tests that if dispatcher has CHLOs waiting for connection creation, EPOLLIN
+// event should try to create connections for them. And set epoll mask with
+// EPOLLIN if there are still CHLOs remaining at the end of epoll event.
+TEST_F(QuicServerEpollInTest, ProcessBufferedCHLOsOnEpollin) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ FLAGS_quic_buffer_packet_till_chlo = true;
+ // Given an EPOLLIN event, try to create session for buffered CHLOs. In first
+ // event, dispatcher can't create session for all of CHLOs. So listener should
+ // register another EPOLLIN event by itself. Even without new packet arrival,
+ // the rest CHLOs should be process in next epoll event.
+ StartListening();
+ bool more_chlos = true;
+ MockQuicSimpleDispatcher* dispatcher_ = server_.mock_dispatcher();
+ DCHECK(dispatcher_ != nullptr);
+ EXPECT_CALL(*dispatcher_, OnCanWrite()).Times(testing::AnyNumber());
+ EXPECT_CALL(*dispatcher_, ProcessBufferedChlos(_)).Times(2);
+ EXPECT_CALL(*dispatcher_, HasPendingWrites()).Times(testing::AnyNumber());
+ // Expect there are still CHLOs buffered after 1st event. But not any more
+ // after 2nd event.
+ EXPECT_CALL(*dispatcher_, HasChlosBuffered())
+ .WillOnce(testing::Return(true))
+ .WillOnce(
+ DoAll(testing::Assign(&more_chlos, false), testing::Return(false)));
+
+ // Send a packet to trigger epoll event.
+ int fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
+ ASSERT_LT(0, fd);
+
+ char buf[1024];
+ memset(buf, 0, arraysize(buf));
+ sockaddr_storage storage;
+ socklen_t storage_size = sizeof(storage);
+ ASSERT_TRUE(server_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&storage),
+ &storage_size));
+ int rc = sendto(fd, buf, arraysize(buf), 0,
+ reinterpret_cast<sockaddr*>(&storage), storage_size);
+ if (rc < 0) {
+ DVLOG(1) << errno << " " << strerror(errno);
+ }
+
+ while (more_chlos) {
+ server_.WaitForEvents();
+ }
+}
+
class QuicServerDispatchPacketTest : public ::testing::Test {
public:
QuicServerDispatchPacketTest()
: crypto_config_("blah",
QuicRandom::GetInstance(),
CryptoTestUtils::ProofSourceForTesting()),
+ version_manager_(AllSupportedVersions()),
dispatcher_(
config_,
&crypto_config_,
+ &version_manager_,
std::unique_ptr<QuicEpollConnectionHelper>(
new QuicEpollConnectionHelper(&eps_,
QuicAllocator::BUFFER_POOL)),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(
+ QuicRandom::GetInstance())),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(&eps_))) {
dispatcher_.InitializeWithWriter(new QuicDefaultPacketWriter(1234));
@@ -49,6 +168,7 @@ class QuicServerDispatchPacketTest : public ::testing::Test {
protected:
QuicConfig config_;
QuicCryptoServerConfig crypto_config_;
+ QuicVersionManager version_manager_;
EpollServer eps_;
MockQuicDispatcher dispatcher_;
};
diff --git a/chromium/net/tools/quic/quic_simple_client.cc b/chromium/net/tools/quic/quic_simple_client.cc
index d179b371a91..48126191ad2 100644
--- a/chromium/net/tools/quic/quic_simple_client.cc
+++ b/chromium/net/tools/quic/quic_simple_client.cc
@@ -12,63 +12,56 @@
#include "net/base/net_errors.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_chromium_packet_reader.h"
-#include "net/quic/quic_chromium_packet_writer.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/spdy_utils.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/chromium/quic_chromium_alarm_factory.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/udp/udp_client_socket.h"
using std::string;
using std::vector;
+using base::StringPiece;
namespace net {
-void QuicSimpleClient::ClientQuicDataToResend::Resend() {
- client_->SendRequest(*headers_, body_, fin_);
- delete headers_;
- headers_ = nullptr;
-}
-
-QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
- const QuicServerId& server_id,
- const QuicVersionVector& supported_versions,
- ProofVerifier* proof_verifier)
- : QuicClientBase(server_id,
- supported_versions,
- QuicConfig(),
- CreateQuicConnectionHelper(),
- CreateQuicAlarmFactory(),
- proof_verifier),
- server_address_(server_address),
- local_port_(0),
- initialized_(false),
- packet_reader_started_(false),
- weak_factory_(this) {}
-
-QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
- const QuicServerId& server_id,
- const QuicVersionVector& supported_versions,
- const QuicConfig& config,
- ProofVerifier* proof_verifier)
+QuicSimpleClient::QuicSimpleClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ std::unique_ptr<ProofVerifier> proof_verifier)
+ : QuicSimpleClient(server_address,
+ server_id,
+ supported_versions,
+ QuicConfig(),
+ std::move(proof_verifier)) {}
+
+QuicSimpleClient::QuicSimpleClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ const QuicConfig& config,
+ std::unique_ptr<ProofVerifier> proof_verifier)
: QuicClientBase(server_id,
supported_versions,
config,
CreateQuicConnectionHelper(),
CreateQuicAlarmFactory(),
- proof_verifier),
- server_address_(server_address),
- local_port_(0),
+ std::move(proof_verifier)),
initialized_(false),
packet_reader_started_(false),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ set_server_address(server_address);
+}
QuicSimpleClient::~QuicSimpleClient() {
if (connected()) {
@@ -76,49 +69,25 @@ QuicSimpleClient::~QuicSimpleClient() {
QUIC_PEER_GOING_AWAY, "Shutting down",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
- STLDeleteElements(&data_to_resend_on_connect_);
- STLDeleteElements(&data_sent_before_handshake_);
-}
-
-bool QuicSimpleClient::Initialize() {
- DCHECK(!initialized_);
-
- QuicClientBase::Initialize();
-
- if (!CreateUDPSocket()) {
- return false;
- }
-
- initialized_ = true;
- return true;
-}
-
-QuicSimpleClient::QuicDataToResend::QuicDataToResend(HttpRequestInfo* headers,
- base::StringPiece body,
- bool fin)
- : headers_(headers), body_(body), fin_(fin) {}
-
-QuicSimpleClient::QuicDataToResend::~QuicDataToResend() {
- if (headers_) {
- delete headers_;
- }
}
-bool QuicSimpleClient::CreateUDPSocket() {
+bool QuicSimpleClient::CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) {
std::unique_ptr<UDPClientSocket> socket(
new UDPClientSocket(DatagramSocket::DEFAULT_BIND, RandIntCallback(),
- &net_log_, NetLog::Source()));
+ &net_log_, NetLogSource()));
- int address_family = server_address_.GetSockAddrFamily();
- if (bind_to_address_.size() != 0) {
- client_address_ = IPEndPoint(bind_to_address_, local_port_);
+ int address_family = server_address.GetSockAddrFamily();
+ if (bind_to_address.size() != 0) {
+ client_address_ = IPEndPoint(bind_to_address, bind_to_port);
} else if (address_family == AF_INET) {
- client_address_ = IPEndPoint(IPAddress::IPv4AllZeros(), local_port_);
+ client_address_ = IPEndPoint(IPAddress::IPv4AllZeros(), bind_to_port);
} else {
- client_address_ = IPEndPoint(IPAddress::IPv6AllZeros(), local_port_);
+ client_address_ = IPEndPoint(IPAddress::IPv6AllZeros(), bind_to_port);
}
- int rc = socket->Connect(server_address_);
+ int rc = socket->Connect(server_address);
if (rc != OK) {
LOG(ERROR) << "Connect failed: " << ErrorToShortString(rc);
return false;
@@ -146,7 +115,7 @@ bool QuicSimpleClient::CreateUDPSocket() {
packet_reader_.reset(new QuicChromiumPacketReader(
socket_.get(), &clock_, this, kQuicYieldAfterPacketsRead,
QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
- BoundNetLog()));
+ NetLogWithSource()));
if (socket != nullptr) {
socket->Close();
@@ -155,231 +124,23 @@ bool QuicSimpleClient::CreateUDPSocket() {
return true;
}
-void QuicSimpleClient::StartPacketReaderIfNotStarted() {
- if (!packet_reader_started_) {
- packet_reader_->StartReading();
- packet_reader_started_ = true;
- }
-}
-
-bool QuicSimpleClient::Connect() {
- // Attempt multiple connects until the maximum number of client hellos have
- // been sent.
- while (!connected() &&
- GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
- StartConnect();
- StartPacketReaderIfNotStarted();
- while (EncryptionBeingEstablished()) {
- WaitForEvents();
- }
- if (FLAGS_enable_quic_stateless_reject_support && connected() &&
- !data_to_resend_on_connect_.empty()) {
- // A connection has been established and there was previously queued data
- // to resend. Resend it and empty the queue.
- for (QuicDataToResend* data : data_to_resend_on_connect_) {
- data->Resend();
- }
- STLDeleteElements(&data_to_resend_on_connect_);
- }
- if (session() != nullptr &&
- session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // We've successfully created a session but we're not connected, and there
- // is no stateless reject to recover from. Give up trying.
- break;
- }
- }
- if (!connected() &&
- GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
- session() != nullptr &&
- session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // The overall connection failed due too many stateless rejects.
- set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
- }
- return session()->connection()->connected();
-}
-
-void QuicSimpleClient::StartConnect() {
- DCHECK(initialized_);
- DCHECK(!connected());
-
- set_writer(CreateQuicPacketWriter());
-
- if (connected_or_attempting_connect()) {
- // Before we destroy the last session and create a new one, gather its stats
- // and update the stats for the overall connection.
- UpdateStats();
- if (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // If the last error was due to a stateless reject, queue up the data to
- // be resent on the next successful connection.
- // TODO(jokulik): I'm a little bit concerned about ordering here. Maybe
- // we should just maintain one queue?
- DCHECK(data_to_resend_on_connect_.empty());
- data_to_resend_on_connect_.swap(data_sent_before_handshake_);
- }
- }
-
- CreateQuicClientSession(new QuicConnection(
- GetNextConnectionId(), server_address_, helper(), alarm_factory(),
- writer(),
- /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
-
- session()->Initialize();
- session()->CryptoConnect();
- set_connected_or_attempting_connect(true);
-}
-
-void QuicSimpleClient::Disconnect() {
- DCHECK(initialized_);
-
- if (connected()) {
- session()->connection()->CloseConnection(
- QUIC_PEER_GOING_AWAY, "Client disconnecting",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
- STLDeleteElements(&data_to_resend_on_connect_);
- STLDeleteElements(&data_sent_before_handshake_);
-
+void QuicSimpleClient::CleanUpAllUDPSockets() {
reset_writer();
packet_reader_.reset();
packet_reader_started_ = false;
- initialized_ = false;
}
-void QuicSimpleClient::SendRequest(const HttpRequestInfo& headers,
- base::StringPiece body,
- bool fin) {
- QuicSpdyClientStream* stream = CreateReliableClientStream();
- if (stream == nullptr) {
- LOG(DFATAL) << "stream creation failed!";
- return;
- }
- SpdyHeaderBlock header_block;
- CreateSpdyHeadersFromHttpRequest(headers, headers.extra_headers, net::HTTP2,
- true, &header_block);
- stream->set_visitor(this);
- stream->SendRequest(std::move(header_block), body, fin);
- if (FLAGS_enable_quic_stateless_reject_support) {
- // Record this in case we need to resend.
- auto* new_headers = new HttpRequestInfo;
- *new_headers = headers;
- auto* data_to_resend =
- new ClientQuicDataToResend(new_headers, body, fin, this);
- MaybeAddQuicDataToResend(data_to_resend);
- }
-}
-
-void QuicSimpleClient::MaybeAddQuicDataToResend(
- QuicDataToResend* data_to_resend) {
- DCHECK(FLAGS_enable_quic_stateless_reject_support);
- if (session()->IsCryptoHandshakeConfirmed()) {
- // The handshake is confirmed. No need to continue saving requests to
- // resend.
- STLDeleteElements(&data_sent_before_handshake_);
- delete data_to_resend;
- return;
- }
-
- // The handshake is not confirmed. Push the data onto the queue of data to
- // resend if statelessly rejected.
- data_sent_before_handshake_.push_back(data_to_resend);
-}
-
-void QuicSimpleClient::SendRequestAndWaitForResponse(
- const HttpRequestInfo& request,
- base::StringPiece body,
- bool fin) {
- SendRequest(request, body, fin);
- while (WaitForEvents()) {
- }
-}
-
-void QuicSimpleClient::SendRequestsAndWaitForResponse(
- const base::CommandLine::StringVector& url_list) {
- for (size_t i = 0; i < url_list.size(); ++i) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL(url_list[i]);
- SendRequest(request, "", true);
- }
-
- while (WaitForEvents()) {
+void QuicSimpleClient::StartPacketReaderIfNotStarted() {
+ if (!packet_reader_started_) {
+ packet_reader_->StartReading();
+ packet_reader_started_ = true;
}
}
-bool QuicSimpleClient::WaitForEvents() {
- DCHECK(connected());
-
+void QuicSimpleClient::RunEventLoop() {
+ StartPacketReaderIfNotStarted();
base::RunLoop().RunUntilIdle();
-
- DCHECK(session() != nullptr);
- if (!connected() &&
- session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- DCHECK(FLAGS_enable_quic_stateless_reject_support);
- DVLOG(1) << "Detected stateless reject while waiting for events. "
- << "Attempting to reconnect.";
- Connect();
- }
-
- return session()->num_active_requests() != 0;
-}
-
-bool QuicSimpleClient::MigrateSocket(const IPAddress& new_host) {
- if (!connected()) {
- return false;
- }
-
- bind_to_address_ = new_host;
- if (!CreateUDPSocket()) {
- return false;
- }
-
- session()->connection()->SetSelfAddress(client_address_);
-
- QuicPacketWriter* writer = CreateQuicPacketWriter();
- set_writer(writer);
- session()->connection()->SetQuicPacketWriter(writer, false);
-
- return true;
-}
-
-void QuicSimpleClient::OnClose(QuicSpdyStream* stream) {
- DCHECK(stream != nullptr);
- QuicSpdyClientStream* client_stream =
- static_cast<QuicSpdyClientStream*>(stream);
- HttpResponseInfo response;
- SpdyHeadersToHttpResponse(client_stream->response_headers(), net::HTTP2,
- &response);
- if (response_listener_.get() != nullptr) {
- response_listener_->OnCompleteResponse(stream->id(), *response.headers,
- client_stream->data());
- }
-
- // Store response headers and body.
- if (store_response_) {
- latest_response_code_ = client_stream->response_code();
- response.headers->GetNormalizedHeaders(&latest_response_headers_);
- latest_response_body_ = client_stream->data();
- }
-}
-
-size_t QuicSimpleClient::latest_response_code() const {
- LOG_IF(DFATAL, !store_response_) << "Response not stored!";
- return latest_response_code_;
-}
-
-const string& QuicSimpleClient::latest_response_headers() const {
- LOG_IF(DFATAL, !store_response_) << "Response not stored!";
- return latest_response_headers_;
-}
-
-const string& QuicSimpleClient::latest_response_body() const {
- LOG_IF(DFATAL, !store_response_) << "Response not stored!";
- return latest_response_body_;
-}
-
-QuicConnectionId QuicSimpleClient::GenerateNewConnectionId() {
- return helper()->GetRandomGenerator()->RandUint64();
}
QuicChromiumConnectionHelper* QuicSimpleClient::CreateQuicConnectionHelper() {
@@ -401,6 +162,10 @@ void QuicSimpleClient::OnReadError(int result,
Disconnect();
}
+IPEndPoint QuicSimpleClient::GetLatestClientAddress() const {
+ return client_address_;
+}
+
bool QuicSimpleClient::OnPacket(const QuicReceivedPacket& packet,
IPEndPoint local_address,
IPEndPoint peer_address) {
diff --git a/chromium/net/tools/quic/quic_simple_client.h b/chromium/net/tools/quic/quic_simple_client.h
index b94399c87a9..a7109b190a0 100644
--- a/chromium/net/tools/quic/quic_simple_client.h
+++ b/chromium/net/tools/quic/quic_simple_client.h
@@ -20,9 +20,9 @@
#include "net/base/ip_endpoint.h"
#include "net/http/http_response_headers.h"
#include "net/log/net_log.h"
-#include "net/quic/quic_chromium_packet_reader.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_spdy_stream.h"
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_spdy_stream.h"
#include "net/tools/quic/quic_client_base.h"
namespace net {
@@ -38,168 +38,45 @@ class QuicClientPeer;
} // namespace test
class QuicSimpleClient : public QuicClientBase,
- public QuicSpdyStream::Visitor,
public QuicChromiumPacketReader::Visitor {
public:
- class ResponseListener {
- public:
- ResponseListener() {}
- virtual ~ResponseListener() {}
- virtual void OnCompleteResponse(QuicStreamId id,
- const HttpResponseHeaders& response_headers,
- const std::string& response_body) = 0;
- };
-
- // The client uses these objects to keep track of any data to resend upon
- // receipt of a stateless reject. Recall that the client API allows callers
- // to optimistically send data to the server prior to handshake-confirmation.
- // If the client subsequently receives a stateless reject, it must tear down
- // its existing session, create a new session, and resend all previously sent
- // data. It uses these objects to keep track of all the sent data, and to
- // resend the data upon a subsequent connection.
- class QuicDataToResend {
- public:
- // Takes ownership of |headers|. |headers| may be null, since it's possible
- // to send data without headers.
- QuicDataToResend(HttpRequestInfo* headers,
- base::StringPiece body,
- bool fin);
-
- virtual ~QuicDataToResend();
-
- // Must be overridden by specific classes with the actual method for
- // re-sending data.
- virtual void Resend() = 0;
-
- protected:
- HttpRequestInfo* headers_;
- base::StringPiece body_;
- bool fin_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicDataToResend);
- };
-
// Create a quic client, which will have events managed by an externally owned
// EpollServer.
QuicSimpleClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
QuicSimpleClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
~QuicSimpleClient() override;
- // From QuicClientBase
- bool Initialize() override;
- bool WaitForEvents() override;
- QuicConnectionId GenerateNewConnectionId() override;
-
- // "Connect" to the QUIC server, including performing synchronous crypto
- // handshake.
- bool Connect();
-
- // Start the crypto handshake. This can be done in place of the synchronous
- // Connect(), but callers are responsible for making sure the crypto handshake
- // completes.
- void StartConnect();
-
- // Disconnects from the QUIC server.
- void Disconnect();
-
- // Sends an HTTP request and does not wait for response before returning.
- void SendRequest(const HttpRequestInfo& headers,
- base::StringPiece body,
- bool fin);
-
- // Sends an HTTP request and waits for response before returning.
- void SendRequestAndWaitForResponse(const HttpRequestInfo& headers,
- base::StringPiece body,
- bool fin);
-
- // Sends a request simple GET for each URL in |args|, and then waits for
- // each to complete.
- void SendRequestsAndWaitForResponse(
- const base::CommandLine::StringVector& url_list);
-
- // Migrate to a new socket during an active connection.
- bool MigrateSocket(const IPAddress& new_host);
-
// QuicChromiumPacketReader::Visitor
void OnReadError(int result, const DatagramClientSocket* socket) override;
bool OnPacket(const QuicReceivedPacket& packet,
IPEndPoint local_address,
IPEndPoint peer_address) override;
- // QuicSpdyStream::Visitor
- void OnClose(QuicSpdyStream* stream) override;
-
- // If the crypto handshake has not yet been confirmed, adds the data to the
- // queue of data to resend if the client receives a stateless reject.
- // Otherwise, deletes the data. Takes ownerership of |data_to_resend|.
- void MaybeAddQuicDataToResend(QuicDataToResend* data_to_resend);
-
- void set_bind_to_address(const IPAddress& address) {
- bind_to_address_ = address;
- }
-
- const IPAddress& bind_to_address() const { return bind_to_address_; }
-
- void set_local_port(int local_port) { local_port_ = local_port; }
-
- const IPEndPoint& server_address() const { return server_address_; }
-
- const IPEndPoint& client_address() const { return client_address_; }
-
- // Takes ownership of the listener.
- void set_response_listener(ResponseListener* listener) {
- response_listener_.reset(listener);
- }
-
- void set_store_response(bool val) { store_response_ = val; }
-
- size_t latest_response_code() const;
- const std::string& latest_response_headers() const;
- const std::string& latest_response_body() const;
+ // From QuicClientBase
+ IPEndPoint GetLatestClientAddress() const override;
protected:
- virtual QuicChromiumAlarmFactory* CreateQuicAlarmFactory();
- virtual QuicChromiumConnectionHelper* CreateQuicConnectionHelper();
- virtual QuicPacketWriter* CreateQuicPacketWriter();
+ // From QuicClientBase
+ QuicPacketWriter* CreateQuicPacketWriter() override;
+ void RunEventLoop() override;
+ bool CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) override;
+ void CleanUpAllUDPSockets() override;
private:
friend class net::test::QuicClientPeer;
- // Specific QuicClient class for storing data to resend.
- class ClientQuicDataToResend : public QuicDataToResend {
- public:
- // Takes ownership of |headers|.
- ClientQuicDataToResend(HttpRequestInfo* headers,
- base::StringPiece body,
- bool fin,
- QuicSimpleClient* client)
- : QuicDataToResend(headers, body, fin), client_(client) {
- DCHECK(headers);
- DCHECK(client);
- }
-
- ~ClientQuicDataToResend() override {}
-
- void Resend() override;
-
- private:
- QuicSimpleClient* client_;
-
- DISALLOW_COPY_AND_ASSIGN(ClientQuicDataToResend);
- };
-
- // Used during initialization: creates the UDP socket FD, sets socket options,
- // and binds the socket to our address.
- bool CreateUDPSocket();
+ QuicChromiumAlarmFactory* CreateQuicAlarmFactory();
+ QuicChromiumConnectionHelper* CreateQuicConnectionHelper();
// Read a UDP packet and hand it to the framer.
bool ReadAndProcessPacket();
@@ -209,51 +86,15 @@ class QuicSimpleClient : public QuicClientBase,
// Used by |helper_| to time alarms.
QuicClock clock_;
- // Address of the server.
- const IPEndPoint server_address_;
-
// Address of the client if the client is connected to the server.
IPEndPoint client_address_;
- // If initialized, the address to bind to.
- IPAddress bind_to_address_;
-
- // Local port to bind to. Initialize to 0.
- int local_port_;
-
// UDP socket connected to the server.
std::unique_ptr<UDPClientSocket> socket_;
- // Listens for full responses.
- std::unique_ptr<ResponseListener> response_listener_;
-
// Tracks if the client is initialized to connect.
bool initialized_;
- // If overflow_supported_ is true, this will be the number of packets dropped
- // during the lifetime of the server.
- QuicPacketCount packets_dropped_;
-
- // True if the kernel supports SO_RXQ_OVFL, the number of packets dropped
- // because the socket would otherwise overflow.
- bool overflow_supported_;
-
- // If true, store the latest response code, headers, and body.
- bool store_response_;
- // HTTP response code from most recent response.
- size_t latest_response_code_;
- // HTTP headers from most recent response.
- std::string latest_response_headers_;
- // Body of most recent response.
- std::string latest_response_body_;
-
- // Keeps track of any data sent before the handshake.
- std::vector<QuicDataToResend*> data_sent_before_handshake_;
-
- // Once the client receives a stateless reject, keeps track of any data that
- // must be resent upon a subsequent successful connection.
- std::vector<QuicDataToResend*> data_to_resend_on_connect_;
-
// The log used for the sockets.
NetLog net_log_;
diff --git a/chromium/net/tools/quic/quic_simple_client_bin.cc b/chromium/net/tools/quic/quic_simple_client_bin.cc
index 7cbb6dbdb8b..5fcf760986a 100644
--- a/chromium/net/tools/quic/quic_simple_client_bin.cc
+++ b/chromium/net/tools/quic/quic_simple_client_bin.cc
@@ -56,11 +56,10 @@
#include "net/cert/multi_log_ct_verifier.h"
#include "net/http/http_request_info.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_utils.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/tools/quic/quic_simple_client.h"
@@ -113,7 +112,7 @@ class FakeCertVerifier : public net::CertVerifier {
net::CertVerifyResult* verify_result,
const net::CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const net::BoundNetLog& net_log) override {
+ const net::NetLogWithSource& net_log) override {
return net::OK;
}
@@ -240,7 +239,7 @@ int main(int argc, char* argv[]) {
// Build the client, and try to connect.
net::QuicServerId server_id(url.host(), url.EffectiveIntPort(),
net::PRIVACY_MODE_DISABLED);
- net::QuicVersionVector versions = net::QuicSupportedVersions();
+ net::QuicVersionVector versions = net::AllSupportedVersions();
if (FLAGS_quic_version != -1) {
versions.clear();
versions.push_back(static_cast<net::QuicVersion>(FLAGS_quic_version));
@@ -254,11 +253,12 @@ int main(int argc, char* argv[]) {
new TransportSecurityState);
std::unique_ptr<CTVerifier> ct_verifier(new MultiLogCTVerifier());
std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer(new CTPolicyEnforcer());
- ProofVerifierChromium* proof_verifier = new ProofVerifierChromium(
- cert_verifier.get(), ct_policy_enforcer.get(),
- transport_security_state.get(), ct_verifier.get());
+ std::unique_ptr<ProofVerifierChromium> proof_verifier(
+ new ProofVerifierChromium(cert_verifier.get(), ct_policy_enforcer.get(),
+ transport_security_state.get(),
+ ct_verifier.get()));
net::QuicSimpleClient client(net::IPEndPoint(ip_addr, port), server_id,
- versions, proof_verifier);
+ versions, std::move(proof_verifier));
client.set_initial_max_packet_length(
FLAGS_initial_mtu != 0 ? FLAGS_initial_mtu : net::kDefaultMaxPacketSize);
if (!client.Initialize()) {
@@ -316,9 +316,8 @@ int main(int argc, char* argv[]) {
// Send the request.
net::SpdyHeaderBlock header_block;
net::CreateSpdyHeadersFromHttpRequest(request, request.extra_headers,
- net::HTTP2, /*direct=*/true,
- &header_block);
- client.SendRequestAndWaitForResponse(request, body, /*fin=*/true);
+ /*direct=*/true, &header_block);
+ client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true);
// Print request and response details.
if (!FLAGS_quiet) {
@@ -326,9 +325,8 @@ int main(int argc, char* argv[]) {
cout << "headers:" << header_block.DebugString();
if (!FLAGS_body_hex.empty()) {
// Print the user provided hex, rather than binary body.
- cout << "body hex: " << FLAGS_body_hex << endl;
- cout << "body ascii: " << net::QuicUtils::BinaryToAscii(
- net::QuicUtils::HexDecode(FLAGS_body_hex))
+ cout << "body:\n"
+ << net::QuicUtils::HexDump(net::QuicUtils::HexDecode(FLAGS_body_hex))
<< endl;
} else {
cout << "body: " << body << endl;
@@ -339,10 +337,7 @@ int main(int argc, char* argv[]) {
string response_body = client.latest_response_body();
if (!FLAGS_body_hex.empty()) {
// Assume response is binary data.
- cout << "body hex: " << net::QuicUtils::HexEncode(response_body)
- << endl;
- cout << "body ascii: " << net::QuicUtils::BinaryToAscii(response_body)
- << endl;
+ cout << "body:\n" << net::QuicUtils::HexDump(response_body) << endl;
} else {
cout << "body: " << response_body << endl;
}
diff --git a/chromium/net/tools/quic/quic_simple_client_test.cc b/chromium/net/tools/quic/quic_simple_client_test.cc
index 02a5807b683..0a571a797b7 100644
--- a/chromium/net/tools/quic/quic_simple_client_test.cc
+++ b/chromium/net/tools/quic/quic_simple_client_test.cc
@@ -18,7 +18,7 @@ TEST(QuicSimpleClientTest, Initialize) {
IPEndPoint server_address(IPEndPoint(net::test::Loopback4(), 80));
QuicServerId server_id("hostname", server_address.port(),
PRIVACY_MODE_DISABLED);
- QuicVersionVector versions = QuicSupportedVersions();
+ QuicVersionVector versions = AllSupportedVersions();
QuicSimpleClient client(server_address, server_id, versions,
CryptoTestUtils::ProofVerifierForTesting());
EXPECT_TRUE(client.Initialize());
diff --git a/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.cc b/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.cc
new file mode 100644
index 00000000000..9f2870ac9a7
--- /dev/null
+++ b/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
+
+namespace net {
+
+QuicSimpleCryptoServerStreamHelper::QuicSimpleCryptoServerStreamHelper(
+ QuicRandom* random)
+ : random_(random) {}
+
+QuicSimpleCryptoServerStreamHelper::~QuicSimpleCryptoServerStreamHelper() {}
+
+QuicConnectionId
+ QuicSimpleCryptoServerStreamHelper::GenerateConnectionIdForReject(
+ QuicConnectionId /*connection_id*/) const {
+ return random_->RandUint64();
+}
+
+bool QuicSimpleCryptoServerStreamHelper::CanAcceptClientHello(
+ const CryptoHandshakeMessage& message,
+ const IPEndPoint& self_address,
+ std::string* error_details) const {
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.h b/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.h
new file mode 100644
index 00000000000..5402a21fc7a
--- /dev/null
+++ b/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_TOOLS_QUIC_SIMPLE_CRYPTO_SERVER_STREAM_HELPER_H_
+#define NET_QUIC_TOOLS_QUIC_SIMPLE_CRYPTO_SERVER_STREAM_HELPER_H_
+
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+
+namespace net {
+
+// Simple helper for server crypto streams which generates a new random
+// connection ID for stateless rejects.
+class QuicSimpleCryptoServerStreamHelper
+ : public QuicCryptoServerStream::Helper {
+ public:
+ explicit QuicSimpleCryptoServerStreamHelper(QuicRandom* random);
+
+ ~QuicSimpleCryptoServerStreamHelper() override;
+
+ QuicConnectionId GenerateConnectionIdForReject(
+ QuicConnectionId /*connection_id*/) const override;
+
+ bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
+ const IPEndPoint& self_address,
+ std::string* error_details) const override;
+
+ private:
+ QuicRandom* random_; // Unowned.
+};
+
+} // namespace net
+
+#endif // NET_QUIC_TOOLS_QUIC_SIMPLE_CRYPTO_SERVER_STREAM_HELPER_H_
diff --git a/chromium/net/tools/quic/quic_simple_dispatcher.cc b/chromium/net/tools/quic/quic_simple_dispatcher.cc
new file mode 100644
index 00000000000..bcad0565cea
--- /dev/null
+++ b/chromium/net/tools/quic/quic_simple_dispatcher.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/tools/quic/quic_simple_dispatcher.h"
+
+#include "net/tools/quic/quic_simple_server_session.h"
+
+namespace net {
+
+QuicSimpleDispatcher::QuicSimpleDispatcher(
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory)
+ : QuicDispatcher(config,
+ crypto_config,
+ version_manager,
+ std::move(helper),
+ std::move(session_helper),
+ std::move(alarm_factory)) {}
+
+QuicSimpleDispatcher::~QuicSimpleDispatcher() {}
+
+QuicServerSessionBase* QuicSimpleDispatcher::CreateQuicSession(
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address) {
+ // The QuicServerSessionBase takes ownership of |connection| below.
+ QuicConnection* connection = new QuicConnection(
+ connection_id, client_address, helper(), alarm_factory(),
+ CreatePerConnectionWriter(),
+ /* owns_writer= */ true, Perspective::IS_SERVER, GetSupportedVersions());
+
+ QuicServerSessionBase* session =
+ new QuicSimpleServerSession(config(), connection, this, session_helper(),
+ crypto_config(), compressed_certs_cache());
+ session->Initialize();
+ return session;
+}
+
+} // namespace net
diff --git a/chromium/net/tools/quic/quic_simple_dispatcher.h b/chromium/net/tools/quic/quic_simple_dispatcher.h
new file mode 100644
index 00000000000..15b6b3c09de
--- /dev/null
+++ b/chromium/net/tools/quic/quic_simple_dispatcher.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TOOLS_QUIC_QUIC_SIMPLE_DISPATCHER_H_
+#define NET_TOOLS_QUIC_QUIC_SIMPLE_DISPATCHER_H_
+
+#include "net/tools/quic/quic_dispatcher.h"
+
+namespace net {
+
+class QuicSimpleDispatcher : public QuicDispatcher {
+ public:
+ QuicSimpleDispatcher(
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory);
+
+ ~QuicSimpleDispatcher() override;
+
+ protected:
+ QuicServerSessionBase* CreateQuicSession(
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address) override;
+};
+
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_QUIC_SIMPLE_DISPATCHER_H_
diff --git a/chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h b/chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h
index d1d4881efb3..c5a62bdc452 100644
--- a/chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h
+++ b/chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h
@@ -9,8 +9,8 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_simple_server.cc b/chromium/net/tools/quic/quic_simple_server.cc
index 814feabd87e..4848cdd901c 100644
--- a/chromium/net/tools/quic/quic_simple_server.cc
+++ b/chromium/net/tools/quic/quic_simple_server.cc
@@ -11,12 +11,13 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_protocol.h"
-#include "net/tools/quic/quic_dispatcher.h"
+#include "net/log/net_log_source.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
#include "net/tools/quic/quic_simple_per_connection_packet_writer.h"
#include "net/tools/quic/quic_simple_server_packet_writer.h"
#include "net/tools/quic/quic_simple_server_session_helper.h"
@@ -27,60 +28,30 @@ namespace net {
namespace {
const char kSourceAddressTokenSecret[] = "secret";
+const size_t kNumSessionsToCreatePerSocketEvent = 16;
// Allocate some extra space so we can send an error if the client goes over
// the limit.
const int kReadBufferSize = 2 * kMaxPacketSize;
-class SimpleQuicDispatcher : public QuicDispatcher {
- public:
- SimpleQuicDispatcher(const QuicConfig& config,
- const QuicCryptoServerConfig* crypto_config,
- const QuicVersionVector& supported_versions,
- QuicConnectionHelperInterface* helper,
- QuicAlarmFactory* alarm_factory)
- : QuicDispatcher(
- config,
- crypto_config,
- supported_versions,
- std::unique_ptr<QuicConnectionHelperInterface>(helper),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
- std::unique_ptr<QuicAlarmFactory>(alarm_factory)) {}
-
- protected:
- QuicServerSessionBase* CreateQuicSession(
- QuicConnectionId connection_id,
- const IPEndPoint& client_address) override {
- QuicServerSessionBase* session =
- QuicDispatcher::CreateQuicSession(connection_id, client_address);
- static_cast<QuicSimplePerConnectionPacketWriter*>(
- session->connection()->writer())
- ->set_connection(session->connection());
- return session;
- }
-
- QuicPacketWriter* CreatePerConnectionWriter() override {
- return new QuicSimplePerConnectionPacketWriter(
- static_cast<QuicSimpleServerPacketWriter*>(writer()));
- }
-};
-
} // namespace
-QuicSimpleServer::QuicSimpleServer(ProofSource* proof_source,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions)
- : helper_(
+QuicSimpleServer::QuicSimpleServer(
+ std::unique_ptr<ProofSource> proof_source,
+ const QuicConfig& config,
+ const QuicCryptoServerConfig::ConfigOptions& crypto_config_options,
+ const QuicVersionVector& supported_versions)
+ : version_manager_(supported_versions),
+ helper_(
new QuicChromiumConnectionHelper(&clock_, QuicRandom::GetInstance())),
alarm_factory_(new QuicChromiumAlarmFactory(
base::ThreadTaskRunnerHandle::Get().get(),
&clock_)),
config_(config),
+ crypto_config_options_(crypto_config_options),
crypto_config_(kSourceAddressTokenSecret,
QuicRandom::GetInstance(),
- proof_source),
- supported_versions_(supported_versions),
+ std::move(proof_source)),
read_pending_(false),
synchronous_read_count_(0),
read_buffer_(new IOBufferWithSize(kReadBufferSize)),
@@ -110,14 +81,14 @@ void QuicSimpleServer::Initialize() {
std::unique_ptr<CryptoHandshakeMessage> scfg(crypto_config_.AddDefaultConfig(
helper_->GetRandomGenerator(), helper_->GetClock(),
- QuicCryptoServerConfig::ConfigOptions()));
+ crypto_config_options_));
}
QuicSimpleServer::~QuicSimpleServer() {}
int QuicSimpleServer::Listen(const IPEndPoint& address) {
std::unique_ptr<UDPServerSocket> socket(
- new UDPServerSocket(&net_log_, NetLog::Source()));
+ new UDPServerSocket(&net_log_, NetLogSource()));
socket->AllowAddressReuse();
@@ -153,8 +124,12 @@ int QuicSimpleServer::Listen(const IPEndPoint& address) {
socket_.swap(socket);
- dispatcher_.reset(new SimpleQuicDispatcher(
- config_, &crypto_config_, supported_versions_, helper_, alarm_factory_));
+ dispatcher_.reset(new QuicSimpleDispatcher(
+ config_, &crypto_config_, &version_manager_,
+ std::unique_ptr<QuicConnectionHelperInterface>(helper_),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicAlarmFactory>(alarm_factory_)));
QuicSimpleServerPacketWriter* writer =
new QuicSimpleServerPacketWriter(socket_.get(), dispatcher_.get());
dispatcher_->InitializeWithWriter(writer);
@@ -174,6 +149,11 @@ void QuicSimpleServer::Shutdown() {
}
void QuicSimpleServer::StartReading() {
+ if (synchronous_read_count_ == 0) {
+ // Only process buffered packets once per message loop.
+ dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent);
+ }
+
if (read_pending_) {
return;
}
@@ -185,6 +165,12 @@ void QuicSimpleServer::StartReading() {
if (result == ERR_IO_PENDING) {
synchronous_read_count_ = 0;
+ if (dispatcher_->HasChlosBuffered()) {
+ // No more packets to read, so yield before processing buffered packets.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&QuicSimpleServer::StartReading,
+ weak_factory_.GetWeakPtr()));
+ }
return;
}
diff --git a/chromium/net/tools/quic/quic_simple_server.h b/chromium/net/tools/quic/quic_simple_server.h
index 7fe28a424a9..4b24d9cef73 100644
--- a/chromium/net/tools/quic/quic_simple_server.h
+++ b/chromium/net/tools/quic/quic_simple_server.h
@@ -14,11 +14,11 @@
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
#include "net/log/net_log.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_config.h"
+#include "net/quic/chromium/quic_chromium_alarm_factory.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_config.h"
namespace net {
@@ -33,9 +33,11 @@ class QuicSimpleServerPeer;
class QuicSimpleServer {
public:
- QuicSimpleServer(ProofSource* proof_source,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions);
+ QuicSimpleServer(
+ std::unique_ptr<ProofSource> proof_source,
+ const QuicConfig& config,
+ const QuicCryptoServerConfig::ConfigOptions& crypto_config_options,
+ const QuicVersionVector& supported_versions);
virtual ~QuicSimpleServer();
@@ -59,12 +61,16 @@ class QuicSimpleServer {
QuicDispatcher* dispatcher() { return dispatcher_.get(); }
+ IPEndPoint server_address() const { return server_address_; }
+
private:
friend class test::QuicSimpleServerPeer;
// Initialize the internal state of the server.
void Initialize();
+ QuicVersionManager version_manager_;
+
// Accepts data from the framer and demuxes clients to sessions.
std::unique_ptr<QuicDispatcher> dispatcher_;
@@ -83,15 +89,12 @@ class QuicSimpleServer {
// config_ contains non-crypto parameters that are negotiated in the crypto
// handshake.
QuicConfig config_;
+ // crypto_config_ contains crypto parameters that are negotiated in the crypto
+ // handshake.
+ QuicCryptoServerConfig::ConfigOptions crypto_config_options_;
// crypto_config_ contains crypto parameters for the handshake.
QuicCryptoServerConfig crypto_config_;
- // This vector contains QUIC versions which we currently support.
- // This should be ordered such that the highest supported version is the first
- // element, with subsequent elements in descending order (versions can be
- // skipped as necessary).
- QuicVersionVector supported_versions_;
-
// The address that the server listens on.
IPEndPoint server_address_;
diff --git a/chromium/net/tools/quic/quic_simple_server_bin.cc b/chromium/net/tools/quic/quic_simple_server_bin.cc
index b04bf15bce3..9187c9957dc 100644
--- a/chromium/net/tools/quic/quic_simple_server_bin.cc
+++ b/chromium/net/tools/quic/quic_simple_server_bin.cc
@@ -14,19 +14,21 @@
#include "base/strings/string_number_conversions.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/proof_source_chromium.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/chromium/crypto/proof_source_chromium.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_simple_server.h"
// The port the quic server will listen on.
int32_t FLAGS_port = 6121;
-net::ProofSource* CreateProofSource(const base::FilePath& cert_path,
- const base::FilePath& key_path) {
- net::ProofSourceChromium* proof_source = new net::ProofSourceChromium();
+std::unique_ptr<net::ProofSource> CreateProofSource(
+ const base::FilePath& cert_path,
+ const base::FilePath& key_path) {
+ std::unique_ptr<net::ProofSourceChromium> proof_source(
+ new net::ProofSourceChromium());
CHECK(proof_source->Initialize(cert_path, key_path, base::FilePath()));
- return proof_source;
+ return std::move(proof_source);
}
int main(int argc, char* argv[]) {
@@ -83,7 +85,8 @@ int main(int argc, char* argv[]) {
net::QuicSimpleServer server(
CreateProofSource(line->GetSwitchValuePath("certificate_file"),
line->GetSwitchValuePath("key_file")),
- config, net::QuicSupportedVersions());
+ config, net::QuicCryptoServerConfig::ConfigOptions(),
+ net::AllSupportedVersions());
server.SetStrikeRegisterNoStartupPeriod();
int rc = server.Listen(net::IPEndPoint(ip, FLAGS_port));
diff --git a/chromium/net/tools/quic/quic_simple_server_packet_writer.cc b/chromium/net/tools/quic/quic_simple_server_packet_writer.cc
index 7d64b316e23..a145086d782 100644
--- a/chromium/net/tools/quic/quic_simple_server_packet_writer.cc
+++ b/chromium/net/tools/quic/quic_simple_server_packet_writer.cc
@@ -45,7 +45,9 @@ void QuicSimpleServerPacketWriter::OnWriteComplete(int rv) {
DCHECK_NE(rv, ERR_IO_PENDING);
write_blocked_ = false;
WriteResult result(rv < 0 ? WRITE_STATUS_ERROR : WRITE_STATUS_OK, rv);
- base::ResetAndReturn(&callback_).Run(result);
+ if (!callback_.is_null()) {
+ base::ResetAndReturn(&callback_).Run(result);
+ }
blocked_writer_->OnCanWrite();
}
@@ -71,7 +73,6 @@ WriteResult QuicSimpleServerPacketWriter::WritePacket(
scoped_refptr<StringIOBuffer> buf(
new StringIOBuffer(std::string(buffer, buf_len)));
DCHECK(!IsWriteBlocked());
- DCHECK(!callback_.is_null());
int rv;
if (buf_len <= static_cast<size_t>(std::numeric_limits<int>::max())) {
rv = socket_->SendTo(
diff --git a/chromium/net/tools/quic/quic_simple_server_packet_writer.h b/chromium/net/tools/quic/quic_simple_server_packet_writer.h
index 3a6b562d639..d4cc814eadf 100644
--- a/chromium/net/tools/quic/quic_simple_server_packet_writer.h
+++ b/chromium/net/tools/quic/quic_simple_server_packet_writer.h
@@ -11,9 +11,9 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -33,15 +33,19 @@ class QuicSimpleServerPacketWriter : public QuicPacketWriter {
QuicBlockedWriterInterface* blocked_writer);
~QuicSimpleServerPacketWriter() override;
- // Use this method to write packets rather than WritePacket:
- // QuicSimpleServerPacketWriter requires a callback to exist for every
- // write, which will be called once the write completes.
- virtual WriteResult WritePacketWithCallback(const char* buffer,
- size_t buf_len,
- const IPAddress& self_address,
- const IPEndPoint& peer_address,
- PerPacketOptions* options,
- WriteCallback callback);
+ // Wraps WritePacket, and ensures that |callback| is run on successful write.
+ WriteResult WritePacketWithCallback(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options,
+ WriteCallback callback);
+
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) override;
void OnWriteComplete(int rv);
@@ -51,14 +55,6 @@ class QuicSimpleServerPacketWriter : public QuicPacketWriter {
void SetWritable() override;
QuicByteCount GetMaxPacketSize(const IPEndPoint& peer_address) const override;
- protected:
- // Do not call WritePacket on its own -- use WritePacketWithCallback
- WriteResult WritePacket(const char* buffer,
- size_t buf_len,
- const IPAddress& self_address,
- const IPEndPoint& peer_address,
- PerPacketOptions* options) override;
-
private:
UDPServerSocket* socket_;
diff --git a/chromium/net/tools/quic/quic_simple_server_session.cc b/chromium/net/tools/quic/quic_simple_server_session.cc
index 3db89a4cafe..64d987bacdf 100644
--- a/chromium/net/tools/quic/quic_simple_server_session.cc
+++ b/chromium/net/tools/quic/quic_simple_server_session.cc
@@ -8,11 +8,11 @@
#include "base/logging.h"
#include "base/stl_util.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_spdy_session.h"
-#include "net/quic/reliable_quic_stream.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_spdy_session.h"
+#include "net/quic/core/reliable_quic_stream.h"
#include "net/tools/quic/quic_simple_server_stream.h"
#include "url/gurl.h"
@@ -24,7 +24,7 @@ QuicSimpleServerSession::QuicSimpleServerSession(
const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache)
: QuicServerSessionBase(config,
@@ -35,7 +35,9 @@ QuicSimpleServerSession::QuicSimpleServerSession(
compressed_certs_cache),
highest_promised_stream_id_(0) {}
-QuicSimpleServerSession::~QuicSimpleServerSession() {}
+QuicSimpleServerSession::~QuicSimpleServerSession() {
+ delete connection();
+}
QuicCryptoServerStreamBase*
QuicSimpleServerSession::CreateQuicCryptoServerStream(
@@ -43,7 +45,7 @@ QuicSimpleServerSession::CreateQuicCryptoServerStream(
QuicCompressedCertsCache* compressed_certs_cache) {
return new QuicCryptoServerStream(crypto_config, compressed_certs_cache,
FLAGS_enable_quic_stateless_reject_support,
- this);
+ this, stream_helper());
}
void QuicSimpleServerSession::StreamDraining(QuicStreamId id) {
@@ -175,7 +177,7 @@ void QuicSimpleServerSession::SendPushPromise(QuicStreamId original_stream_id,
DVLOG(1) << "stream " << original_stream_id
<< " send PUSH_PROMISE for promised stream " << promised_stream_id;
headers_stream()->WritePushPromise(original_stream_id, promised_stream_id,
- std::move(headers), nullptr);
+ std::move(headers));
}
void QuicSimpleServerSession::HandlePromisedPushRequests() {
diff --git a/chromium/net/tools/quic/quic_simple_server_session.h b/chromium/net/tools/quic/quic_simple_server_session.h
index fe806a43463..16ebdfb22fd 100644
--- a/chromium/net/tools/quic/quic_simple_server_session.h
+++ b/chromium/net/tools/quic/quic_simple_server_session.h
@@ -18,10 +18,10 @@
#include <vector>
#include "base/macros.h"
-#include "net/quic/quic_crypto_server_stream.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_session_base.h"
-#include "net/quic/quic_spdy_session.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_session_base.h"
+#include "net/quic/core/quic_spdy_session.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_simple_server_stream.h"
@@ -58,10 +58,11 @@ class QuicSimpleServerSession : public QuicServerSessionBase {
bool is_cancelled;
};
+ // Takes ownership of |connection|.
QuicSimpleServerSession(const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache);
diff --git a/chromium/net/tools/quic/quic_simple_server_session_helper.h b/chromium/net/tools/quic/quic_simple_server_session_helper.h
index 6ef33fa8d11..a876983b758 100644
--- a/chromium/net/tools/quic/quic_simple_server_session_helper.h
+++ b/chromium/net/tools/quic/quic_simple_server_session_helper.h
@@ -5,14 +5,14 @@
#ifndef NET_TOOLS_QUIC_QUIC_SIMPLE_SERVER_SESSION_HELPER_H_
#define NET_TOOLS_QUIC_QUIC_SIMPLE_SERVER_SESSION_HELPER_H_
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_server_session_base.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_server_session_base.h"
namespace net {
// Simple helper for server sessions which generates a new random
// connection ID for stateless rejects.
-class QuicSimpleServerSessionHelper : public QuicServerSessionBase::Helper {
+class QuicSimpleServerSessionHelper : public QuicCryptoServerStream::Helper {
public:
explicit QuicSimpleServerSessionHelper(QuicRandom* random);
diff --git a/chromium/net/tools/quic/quic_simple_server_session_helper_test.cc b/chromium/net/tools/quic/quic_simple_server_session_helper_test.cc
index e739ada62da..c25c60e54a8 100644
--- a/chromium/net/tools/quic/quic_simple_server_session_helper_test.cc
+++ b/chromium/net/tools/quic/quic_simple_server_session_helper_test.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/tools/quic/quic_simple_server_session_helper.h"
-
#include "net/quic/test_tools/mock_random.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
+
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
-TEST(QuicSimpleServerSessionHelperTest, GenerateConnectionIdForReject) {
+TEST(QuicSimpleCryptoServerStreamHelperTest, GenerateConnectionIdForReject) {
test::MockRandom random;
- QuicSimpleServerSessionHelper helper(&random);
+ QuicSimpleCryptoServerStreamHelper helper(&random);
EXPECT_EQ(random.RandUint64(), helper.GenerateConnectionIdForReject(42));
}
diff --git a/chromium/net/tools/quic/quic_simple_server_session_test.cc b/chromium/net/tools/quic/quic_simple_server_session_test.cc
index 8e93f9bb37f..518ce1da058 100644
--- a/chromium/net/tools/quic/quic_simple_server_session_test.cc
+++ b/chromium/net/tools/quic/quic_simple_server_session_test.cc
@@ -9,12 +9,12 @@
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_crypto_server_stream.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_config_peer.h"
#include "net/quic/test_tools/quic_connection_peer.h"
@@ -43,7 +43,6 @@ using net::test::QuicSessionPeer;
using net::test::QuicSpdySessionPeer;
using net::test::QuicSustainedBandwidthRecorderPeer;
using net::test::SupportedVersions;
-using net::test::ValueRestore;
using net::test::kClientDataStreamId1;
using net::test::kClientDataStreamId2;
using net::test::kClientDataStreamId3;
@@ -54,6 +53,7 @@ using testing::StrictMock;
using testing::_;
using testing::InSequence;
using testing::Return;
+using testing::AtLeast;
namespace net {
namespace test {
@@ -70,16 +70,14 @@ class MockQuicHeadersStream : public QuicHeadersStream {
// mocked directly.
size_t WritePushPromise(QuicStreamId original_stream_id,
QuicStreamId promised_stream_id,
- SpdyHeaderBlock headers,
- QuicAckListenerInterface* ack_listener) override {
- return WritePushPromiseMock(original_stream_id, promised_stream_id, headers,
- ack_listener);
+ SpdyHeaderBlock headers) override {
+ return WritePushPromiseMock(original_stream_id, promised_stream_id,
+ headers);
}
- MOCK_METHOD4(WritePushPromiseMock,
+ MOCK_METHOD3(WritePushPromiseMock,
size_t(QuicStreamId original_stream_id,
QuicStreamId promised_stream_id,
- const SpdyHeaderBlock& headers,
- QuicAckListenerInterface* ack_listener));
+ const SpdyHeaderBlock& headers));
size_t WriteHeaders(QuicStreamId stream_id,
SpdyHeaderBlock headers,
@@ -101,11 +99,13 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream {
explicit MockQuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
- QuicServerSessionBase* session)
+ QuicServerSessionBase* session,
+ QuicCryptoServerStream::Helper* helper)
: QuicCryptoServerStream(crypto_config,
compressed_certs_cache,
FLAGS_enable_quic_stateless_reject_support,
- session) {}
+ session,
+ helper) {}
~MockQuicCryptoServerStream() override {}
MOCK_METHOD1(SendServerConfigUpdate,
@@ -181,7 +181,6 @@ class QuicSimpleServerSessionTest
CryptoTestUtils::ProofSourceForTesting()),
compressed_certs_cache_(
QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
- FLAGS_quic_always_log_bugs_for_tests = true;
config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest);
config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest);
QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_,
@@ -194,9 +193,9 @@ class QuicSimpleServerSessionTest
connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
&helper_, &alarm_factory_, Perspective::IS_SERVER,
SupportedVersions(GetParam()));
- session_.reset(new QuicSimpleServerSession(
- config_, connection_, &owner_, &session_helper_, &crypto_config_,
- &compressed_certs_cache_));
+ session_.reset(new QuicSimpleServerSession(config_, connection_, &owner_,
+ &stream_helper_, &crypto_config_,
+ &compressed_certs_cache_));
MockClock clock;
handshake_message_.reset(crypto_config_.AddDefaultConfig(
QuicRandom::GetInstance(), &clock,
@@ -205,14 +204,13 @@ class QuicSimpleServerSessionTest
visitor_ = QuicConnectionPeer::GetVisitor(connection_);
headers_stream_ = new MockQuicHeadersStream(session_.get());
QuicSpdySessionPeer::SetHeadersStream(session_.get(), headers_stream_);
- // TODO(jri): Remove this line once tests pass.
- FLAGS_quic_cede_correctly = false;
session_->OnConfigNegotiated();
}
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
StrictMock<MockQuicServerSessionVisitor> owner_;
- StrictMock<MockQuicServerSessionHelper> session_helper_;
+ StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
StrictMock<MockQuicConnectionWithSendStreamData>* connection_;
@@ -227,7 +225,7 @@ class QuicSimpleServerSessionTest
INSTANTIATE_TEST_CASE_P(Tests,
QuicSimpleServerSessionTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) {
// Open a stream, then reset it.
@@ -302,9 +300,9 @@ TEST_P(QuicSimpleServerSessionTest, CreateIncomingDynamicStreamDisconnected) {
// Tests that incoming stream creation fails when connection is not connected.
size_t initial_num_open_stream = session_->GetNumOpenIncomingStreams();
QuicConnectionPeer::TearDownLocalConnectionState(connection_);
- EXPECT_DFATAL(QuicSimpleServerSessionPeer::CreateIncomingDynamicStream(
- session_.get(), kClientDataStreamId1),
- "ShouldCreateIncomingDynamicStream called when disconnected");
+ EXPECT_QUIC_BUG(QuicSimpleServerSessionPeer::CreateIncomingDynamicStream(
+ session_.get(), kClientDataStreamId1),
+ "ShouldCreateIncomingDynamicStream called when disconnected");
EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenIncomingStreams());
}
@@ -330,9 +328,9 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamDisconnected) {
// Tests that outgoing stream creation fails when connection is not connected.
size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams();
QuicConnectionPeer::TearDownLocalConnectionState(connection_);
- EXPECT_DFATAL(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream(
- session_.get(), kDefaultPriority),
- "ShouldCreateOutgoingDynamicStream called when disconnected");
+ EXPECT_QUIC_BUG(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream(
+ session_.get(), kDefaultPriority),
+ "ShouldCreateOutgoingDynamicStream called when disconnected");
EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams());
}
@@ -341,9 +339,9 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUnencrypted) {
// Tests that outgoing stream creation fails when encryption has not yet been
// established.
size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams();
- EXPECT_DFATAL(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream(
- session_.get(), kDefaultPriority),
- "Encryption not established so no outgoing stream created.");
+ EXPECT_QUIC_BUG(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream(
+ session_.get(), kDefaultPriority),
+ "Encryption not established so no outgoing stream created.");
EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams());
}
@@ -360,8 +358,9 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) {
EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
// Assume encryption already established.
- MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream(
- &crypto_config_, &compressed_certs_cache_, session_.get());
+ MockQuicCryptoServerStream* crypto_stream =
+ new MockQuicCryptoServerStream(&crypto_config_, &compressed_certs_cache_,
+ session_.get(), &stream_helper_);
crypto_stream->set_encryption_established(true);
QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
@@ -434,9 +433,9 @@ class QuicSimpleServerSessionServerPushTest
connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
&helper_, &alarm_factory_, Perspective::IS_SERVER,
SupportedVersions(GetParam()));
- session_.reset(new QuicSimpleServerSession(
- config_, connection_, &owner_, &session_helper_, &crypto_config_,
- &compressed_certs_cache_));
+ session_.reset(new QuicSimpleServerSession(config_, connection_, &owner_,
+ &stream_helper_, &crypto_config_,
+ &compressed_certs_cache_));
session_->Initialize();
// Needed to make new session flow control window and server push work.
session_->OnConfigNegotiated();
@@ -447,7 +446,9 @@ class QuicSimpleServerSessionServerPushTest
// Assume encryption already established.
MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream(
- &crypto_config_, &compressed_certs_cache_, session_.get());
+ &crypto_config_, &compressed_certs_cache_, session_.get(),
+ &stream_helper_);
+
crypto_stream->set_encryption_established(true);
QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
}
@@ -483,9 +484,8 @@ class QuicSimpleServerSessionServerPushTest
push_resources.push_back(QuicInMemoryCache::ServerPushInfo(
resource_url, SpdyHeaderBlock(), kDefaultPriority, body));
// PUSH_PROMISED are sent for all the resources.
- EXPECT_CALL(
- *headers_stream_,
- WritePushPromiseMock(kClientDataStreamId1, stream_id, _, nullptr));
+ EXPECT_CALL(*headers_stream_,
+ WritePushPromiseMock(kClientDataStreamId1, stream_id, _));
if (i <= kMaxStreamsForTest) {
// |kMaxStreamsForTest| promised responses should be sent.
EXPECT_CALL(
@@ -493,11 +493,25 @@ class QuicSimpleServerSessionServerPushTest
WriteHeadersMock(stream_id, _, false, kDefaultPriority, nullptr));
// Since flow control window is smaller than response body, not the
// whole body will be sent.
- EXPECT_CALL(*connection_,
- SendStreamData(stream_id, _, 0, false, nullptr))
- .WillOnce(
- Return(QuicConsumedData(kStreamFlowControlWindowSize, false)));
- EXPECT_CALL(*connection_, SendBlocked(stream_id));
+ if (!session_->force_hol_blocking()) {
+ EXPECT_CALL(*connection_,
+ SendStreamData(stream_id, _, 0, false, nullptr))
+ .WillOnce(Return(
+ QuicConsumedData(kStreamFlowControlWindowSize, false)));
+ EXPECT_CALL(*connection_, SendBlocked(stream_id));
+ } else {
+ // The forced HOL blocking encapsulates the stream data into
+ // HTTP/2 DATA frames within the headers stream. HTTP/2
+ // DATA frames are limited to a max size of 16KB, so the
+ // 64KB body will be fragemented into four DATA frames.
+ EXPECT_CALL(*connection_, SendStreamData(_, _, _, false, nullptr))
+ .Times(body_size / 16384)
+ .WillOnce(Return(QuicConsumedData(9 + 16394, false)))
+ .WillOnce(Return(QuicConsumedData(9 + 16394, false)))
+ .WillOnce(Return(QuicConsumedData(9 + 16394, false)))
+ .WillOnce(Return(QuicConsumedData(9 + 16394, false)));
+ EXPECT_CALL(*connection_, SendBlocked(_));
+ }
}
}
session_->PromisePushResources(request_url, push_resources,
@@ -507,12 +521,16 @@ class QuicSimpleServerSessionServerPushTest
INSTANTIATE_TEST_CASE_P(Tests,
QuicSimpleServerSessionServerPushTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
// Tests that given more than kMaxOpenStreamForTest resources, all their
// PUSH_PROMISE's will be sent out and only |kMaxOpenStreamForTest| streams
// will be opened and send push response.
+
+ if (session_->force_hol_blocking()) {
+ return;
+ }
size_t num_resources = kMaxStreamsForTest + 5;
PromisePushResources(num_resources);
EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
@@ -520,6 +538,10 @@ TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
TEST_P(QuicSimpleServerSessionServerPushTest,
HandlePromisedPushRequestsAfterStreamDraining) {
+ if (session_->force_hol_blocking()) {
+ return;
+ }
+
// Tests that after promised stream queued up, when an opened stream is marked
// draining, a queued promised stream will become open and send push response.
size_t num_resources = kMaxStreamsForTest + 1;
@@ -543,6 +565,9 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
TEST_P(QuicSimpleServerSessionServerPushTest,
ResetPromisedStreamToCancelServerPush) {
+ if (session_->force_hol_blocking()) {
+ return;
+ }
// Tests that after all resources are promised, a RST frame from client can
// prevent a promised resource to be send out.
@@ -579,6 +604,9 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
TEST_P(QuicSimpleServerSessionServerPushTest,
CloseStreamToHandleMorePromisedStream) {
+ if (session_->force_hol_blocking()) {
+ return;
+ }
// Tests that closing a open outgoing stream can trigger a promised resource
// in the queue to be send out.
size_t num_resources = kMaxStreamsForTest + 1;
diff --git a/chromium/net/tools/quic/quic_simple_server_stream.cc b/chromium/net/tools/quic/quic_simple_server_stream.cc
index dda6a420d18..685955f3c61 100644
--- a/chromium/net/tools/quic/quic_simple_server_stream.cc
+++ b/chromium/net/tools/quic/quic_simple_server_stream.cc
@@ -12,10 +12,10 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_spdy_stream.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_spdy_stream.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_protocol.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_simple_server_session.h"
@@ -136,8 +136,8 @@ void QuicSimpleServerStream::PushResponse(
}
void QuicSimpleServerStream::SendResponse() {
- if (!ContainsKey(request_headers_, ":authority") ||
- !ContainsKey(request_headers_, ":path")) {
+ if (!base::ContainsKey(request_headers_, ":authority") ||
+ !base::ContainsKey(request_headers_, ":path")) {
DVLOG(1) << "Request headers do not contain :authority or :path.";
SendErrorResponse();
return;
@@ -250,11 +250,13 @@ void QuicSimpleServerStream::SendHeadersAndBodyAndTrailers(
return;
}
- // Send the body, with a FIN if there's nothing else to send.
+ // Send the body, with a FIN if there's no trailers to send.
send_fin = response_trailers.empty();
DVLOG(1) << "Writing body (fin = " << send_fin
<< ") with size: " << body.size();
- WriteOrBufferData(body, send_fin, nullptr);
+ if (!body.empty() || send_fin) {
+ WriteOrBufferData(body, send_fin, nullptr);
+ }
if (send_fin) {
// Nothing else to send.
return;
diff --git a/chromium/net/tools/quic/quic_simple_server_stream.h b/chromium/net/tools/quic/quic_simple_server_stream.h
index e270ed65f17..7217ad3aef6 100644
--- a/chromium/net/tools/quic/quic_simple_server_stream.h
+++ b/chromium/net/tools/quic/quic_simple_server_stream.h
@@ -10,8 +10,8 @@
#include <string>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_spdy_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_spdy_stream.h"
#include "net/spdy/spdy_framer.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_simple_server_stream_test.cc b/chromium/net/tools/quic/quic_simple_server_stream_test.cc
index 5161c9f223c..eddc1a08b1c 100644
--- a/chromium/net/tools/quic/quic_simple_server_stream_test.cc
+++ b/chromium/net/tools/quic/quic_simple_server_stream_test.cc
@@ -8,11 +8,11 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
@@ -87,7 +87,7 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession {
explicit MockQuicSimpleServerSession(
QuicConnection* connection,
MockQuicServerSessionVisitor* owner,
- MockQuicServerSessionHelper* helper,
+ MockQuicCryptoServerStreamHelper* helper,
QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache)
: QuicSimpleServerSession(DefaultQuicConfig(),
@@ -190,7 +190,6 @@ class QuicSimpleServerStreamTest
crypto_config_.get(),
&compressed_certs_cache_),
body_("hello world") {
- FLAGS_quic_always_log_bugs_for_tests = true;
SpdyHeaderBlock request_headers;
request_headers[":host"] = "";
request_headers[":authority"] = "www.google.com";
@@ -233,7 +232,7 @@ class QuicSimpleServerStreamTest
MockAlarmFactory alarm_factory_;
StrictMock<MockQuicConnection>* connection_;
StrictMock<MockQuicServerSessionVisitor> session_owner_;
- StrictMock<MockQuicServerSessionHelper> session_helper_;
+ StrictMock<MockQuicCryptoServerStreamHelper> session_helper_;
std::unique_ptr<QuicCryptoServerConfig> crypto_config_;
QuicCompressedCertsCache compressed_certs_cache_;
StrictMock<MockQuicSimpleServerSession> session_;
@@ -244,7 +243,7 @@ class QuicSimpleServerStreamTest
INSTANTIATE_TEST_CASE_P(Tests,
QuicSimpleServerStreamTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSimpleServerStreamTest, TestFraming) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
@@ -286,11 +285,7 @@ TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) {
stream_->set_fin_sent(true);
stream_->CloseWriteSide();
- if (GetParam() > QUIC_VERSION_28) {
- EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
- } else {
- EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
- }
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
stream_->StopReading();
}
@@ -472,9 +467,9 @@ TEST_P(QuicSimpleServerStreamTest, SendReponseWithPushResources) {
TEST_P(QuicSimpleServerStreamTest, PushResponseOnClientInitiatedStream) {
// Calling PushResponse() on a client initialted stream is never supposed to
// happen.
- EXPECT_DFATAL(stream_->PushResponse(SpdyHeaderBlock()),
- "Client initiated stream"
- " shouldn't be used as promised stream.");
+ EXPECT_QUIC_BUG(stream_->PushResponse(SpdyHeaderBlock()),
+ "Client initiated stream"
+ " shouldn't be used as promised stream.");
}
TEST_P(QuicSimpleServerStreamTest, PushResponseOnServerInitiatedStream) {
@@ -601,11 +596,7 @@ TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorWithEarlyResponse) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
.Times(1)
.WillOnce(Return(QuicConsumedData(3, true)));
- if (GetParam() > QUIC_VERSION_28) {
- EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
- } else {
- EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
- }
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
EXPECT_FALSE(stream_->fin_received());
QuicSimpleServerStreamPeer::SendErrorResponse(stream_);
EXPECT_TRUE(stream_->reading_stopped());
diff --git a/chromium/net/tools/quic/quic_simple_server_test.cc b/chromium/net/tools/quic/quic_simple_server_test.cc
index 2bf39601b99..091c08761f5 100644
--- a/chromium/net/tools/quic/quic_simple_server_test.cc
+++ b/chromium/net/tools/quic/quic_simple_server_test.cc
@@ -4,8 +4,9 @@
#include "net/tools/quic/quic_simple_server.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/mock_quic_dispatcher.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -25,12 +26,14 @@ class QuicChromeServerDispatchPacketTest : public ::testing::Test {
: crypto_config_("blah",
QuicRandom::GetInstance(),
CryptoTestUtils::ProofSourceForTesting()),
+ version_manager_(AllSupportedVersions()),
dispatcher_(
config_,
&crypto_config_,
+ &version_manager_,
std::unique_ptr<MockQuicConnectionHelper>(
new net::test::MockQuicConnectionHelper),
- std::unique_ptr<QuicServerSessionBase::Helper>(
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
std::unique_ptr<MockAlarmFactory>(
new net::test::MockAlarmFactory)) {
@@ -45,6 +48,7 @@ class QuicChromeServerDispatchPacketTest : public ::testing::Test {
protected:
QuicConfig config_;
QuicCryptoServerConfig crypto_config_;
+ QuicVersionManager version_manager_;
net::test::MockQuicDispatcher dispatcher_;
};
diff --git a/chromium/net/tools/quic/quic_socket_utils.cc b/chromium/net/tools/quic/quic_socket_utils.cc
index 61ec3783511..a6bc4c0c496 100644
--- a/chromium/net/tools/quic/quic_socket_utils.cc
+++ b/chromium/net/tools/quic/quic_socket_utils.cc
@@ -13,9 +13,9 @@
#include <string>
#include "base/logging.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
#ifndef SO_RXQ_OVFL
#define SO_RXQ_OVFL 40
@@ -27,9 +27,7 @@ namespace net {
void QuicSocketUtils::GetAddressAndTimestampFromMsghdr(
struct msghdr* hdr,
IPAddress* address,
- QuicTime* timestamp,
- QuicWallTime* walltimestamp,
- bool latched_walltimestamps) {
+ QuicWallTime* walltimestamp) {
if (hdr->msg_controllen > 0) {
for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
cmsg = CMSG_NXTHDR(hdr, cmsg)) {
@@ -52,12 +50,7 @@ void QuicSocketUtils::GetAddressAndTimestampFromMsghdr(
timespec* ts = &lts->systime;
int64_t usec = (static_cast<int64_t>(ts->tv_sec) * 1000 * 1000) +
(static_cast<int64_t>(ts->tv_nsec) / 1000);
- if (latched_walltimestamps) {
- *walltimestamp = QuicWallTime::FromUNIXMicroseconds(usec);
- } else {
- *timestamp =
- QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(usec));
- }
+ *walltimestamp = QuicWallTime::FromUNIXMicroseconds(usec);
}
}
}
@@ -71,7 +64,24 @@ bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr* hdr,
for (cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
cmsg = CMSG_NXTHDR(hdr, cmsg)) {
if (cmsg->cmsg_type == SO_RXQ_OVFL) {
- *dropped_packets = *(reinterpret_cast<int*> CMSG_DATA(cmsg));
+ *dropped_packets = *(reinterpret_cast<uint32_t*> CMSG_DATA(cmsg));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// static
+bool QuicSocketUtils::GetTtlFromMsghdr(struct msghdr* hdr, int* ttl) {
+ if (hdr->msg_controllen > 0) {
+ struct cmsghdr* cmsg;
+ for (cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
+ cmsg = CMSG_NXTHDR(hdr, cmsg)) {
+ if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) ||
+ (cmsg->cmsg_level == IPPROTO_IPV6 &&
+ cmsg->cmsg_type == IPV6_HOPLIMIT)) {
+ *ttl = *(reinterpret_cast<int*>(CMSG_DATA(cmsg)));
return true;
}
}
@@ -122,9 +132,7 @@ int QuicSocketUtils::ReadPacket(int fd,
size_t buf_len,
QuicPacketCount* dropped_packets,
IPAddress* self_address,
- QuicTime* timestamp,
QuicWallTime* walltimestamp,
- bool latched_walltimestamps,
IPEndPoint* peer_address) {
DCHECK(peer_address != nullptr);
char cbuf[kSpaceForCmsg];
@@ -176,13 +184,7 @@ int QuicSocketUtils::ReadPacket(int fd,
walltimestamp = &stack_walltimestamp;
}
- QuicTime stack_timestamp = QuicTime::Zero();
- if (timestamp == nullptr) {
- timestamp = &stack_timestamp;
- }
-
- GetAddressAndTimestampFromMsghdr(&hdr, self_address, timestamp, walltimestamp,
- latched_walltimestamps);
+ GetAddressAndTimestampFromMsghdr(&hdr, self_address, walltimestamp);
if (raw_address.ss_family == AF_INET) {
CHECK(peer_address->FromSockAddr(
diff --git a/chromium/net/tools/quic/quic_socket_utils.h b/chromium/net/tools/quic/quic_socket_utils.h
index 0bad8381969..f8cc5392c5f 100644
--- a/chromium/net/tools/quic/quic_socket_utils.h
+++ b/chromium/net/tools/quic/quic_socket_utils.h
@@ -16,8 +16,8 @@
#include "base/macros.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_types.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_types.h"
namespace net {
@@ -38,30 +38,31 @@ class QuicSocketUtils {
public:
// The first integer is for overflow. The in6_pktinfo is the larger of the
// address structures present. LinuxTimestamping is present for socket
- // timestamping.
+ // timestamping. The subsequent int is for ttl.
// The final int is a sentinel so the msg_controllen feedback
// can be used to detect larger control messages than there is space for.
static const int kSpaceForCmsg =
CMSG_SPACE(CMSG_LEN(sizeof(int)) + CMSG_LEN(sizeof(in6_pktinfo)) +
CMSG_LEN(sizeof(LinuxTimestamping)) +
+ CMSG_LEN(sizeof(int)) +
CMSG_LEN(sizeof(int)));
// Fills in |address| if |hdr| contains IP_PKTINFO or IPV6_PKTINFO. Fills in
// |timestamp| if |hdr| contains |SO_TIMESTAMPING|. |address| and |timestamp|
// must not be null.
- // TODO(rjshade): Delete the |timestamp| argument when removing
- // FLAGS_quic_socket_timestamps_walltime
static void GetAddressAndTimestampFromMsghdr(struct msghdr* hdr,
IPAddress* address,
- QuicTime* timestamp,
- QuicWallTime* walltimestamp,
- bool latched_walltimestamps);
+ QuicWallTime* walltimestamp);
// If the msghdr contains an SO_RXQ_OVFL entry, this will set dropped_packets
// to the correct value and return true. Otherwise it will return false.
static bool GetOverflowFromMsghdr(struct msghdr* hdr,
QuicPacketCount* dropped_packets);
+ // If the msghdr contains an IP_TTL entry, this will set ttl to the correct
+ // value and return true. Otherwise it will return false.
+ static bool GetTtlFromMsghdr(struct msghdr* hdr, int* ttl);
+
// Sets either IP_PKTINFO or IPV6_PKTINFO on the socket, based on
// address_family. Returns the return code from setsockopt.
static int SetGetAddressInfo(int fd, int address_family);
@@ -90,16 +91,12 @@ class QuicSocketUtils {
// received packet, assuming a packet was read and the platform supports
// packet receipt timestamping. If the platform does not support packet
// receipt timestamping, timestamp will not be changed.
- // TODO(rjshade): Delete the |timestamp| argument when removing
- // FLAGS_quic_socket_timestamps_walltime
static int ReadPacket(int fd,
char* buffer,
size_t buf_len,
QuicPacketCount* dropped_packets,
IPAddress* self_address,
- QuicTime* timestamp,
QuicWallTime* walltimestamp,
- bool latched_walltimestamps,
IPEndPoint* peer_address);
// Writes buf_len to the socket. If writing is successful, sets the result's
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream.cc b/chromium/net/tools/quic/quic_spdy_client_stream.cc
index 521c7b66e1f..253571ea39f 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream.cc
+++ b/chromium/net/tools/quic/quic_spdy_client_stream.cc
@@ -9,9 +9,9 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_client_promised_info.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_alarm.h"
+#include "net/quic/core/quic_client_promised_info.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_protocol.h"
#include "net/tools/quic/quic_client_session.h"
#include "net/tools/quic/spdy_balsa_utils.h"
@@ -103,7 +103,7 @@ void QuicSpdyClientStream::OnTrailingHeadersComplete(
size_t frame_len,
const QuicHeaderList& header_list) {
QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
- MarkTrailersConsumed(decompressed_trailers().length());
+ MarkTrailersConsumed();
}
void QuicSpdyClientStream::OnPromiseHeadersComplete(QuicStreamId promised_id,
@@ -149,12 +149,10 @@ void QuicSpdyClientStream::OnPromiseHeaderList(
}
void QuicSpdyClientStream::OnDataAvailable() {
- if (FLAGS_quic_supports_push_promise) {
- // For push streams, visitor will not be set until the rendezvous
- // between server promise and client request is complete.
- if (visitor() == nullptr)
- return;
- }
+ // For push streams, visitor will not be set until the rendezvous
+ // between server promise and client request is complete.
+ if (visitor() == nullptr)
+ return;
while (HasBytesToRead()) {
struct iovec iov;
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream.h b/chromium/net/tools/quic/quic_spdy_client_stream.h
index 04eb4932620..96ce11d086a 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream.h
+++ b/chromium/net/tools/quic/quic_spdy_client_stream.h
@@ -11,8 +11,8 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_spdy_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_spdy_stream.h"
#include "net/spdy/spdy_framer.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream_test.cc b/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
index af3cb3c8cde..20f524a2ba1 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -8,8 +8,8 @@
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_client_session.h"
@@ -26,7 +26,6 @@ using net::test::kClientDataStreamId1;
using net::test::kServerDataStreamId1;
using net::test::kInitialSessionFlowControlWindowForTest;
using net::test::kInitialStreamFlowControlWindowForTest;
-using net::test::ValueRestore;
using std::string;
using testing::StrictMock;
diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager.cc b/chromium/net/tools/quic/quic_time_wait_list_manager.cc
index 6686238a03c..4f99cb02fb9 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager.cc
@@ -12,15 +12,15 @@
#include "base/macros.h"
#include "base/stl_util.h"
#include "net/base/ip_endpoint.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/quic_clock.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_session_base.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_session_base.h"
+#include "net/quic/core/quic_utils.h"
using base::StringPiece;
@@ -91,7 +91,7 @@ QuicTimeWaitListManager::QuicTimeWaitListManager(
QuicTimeWaitListManager::~QuicTimeWaitListManager() {
connection_id_clean_up_alarm_->Cancel();
- STLDeleteElements(&pending_packets_queue_);
+ base::STLDeleteElements(&pending_packets_queue_);
}
void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
@@ -127,7 +127,7 @@ void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
bool QuicTimeWaitListManager::IsConnectionIdInTimeWait(
QuicConnectionId connection_id) const {
- return ContainsKey(connection_id_map_, connection_id);
+ return base::ContainsKey(connection_id_map_, connection_id);
}
QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId(
@@ -261,15 +261,13 @@ bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
}
void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
- connection_id_clean_up_alarm_->Cancel();
QuicTime::Delta next_alarm_interval = QuicTime::Delta::Zero();
if (!connection_id_map_.empty()) {
QuicTime oldest_connection_id =
connection_id_map_.begin()->second.time_added;
QuicTime now = clock_->ApproximateNow();
- if (now.Subtract(oldest_connection_id) < time_wait_period_) {
- next_alarm_interval =
- oldest_connection_id.Add(time_wait_period_).Subtract(now);
+ if (now - oldest_connection_id < time_wait_period_) {
+ next_alarm_interval = oldest_connection_id + time_wait_period_ - now;
} else {
LOG(ERROR) << "ConnectionId lingered for longer than time_wait_period_";
}
@@ -278,8 +276,8 @@ void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
next_alarm_interval = time_wait_period_;
}
- connection_id_clean_up_alarm_->Set(
- clock_->ApproximateNow().Add(next_alarm_interval));
+ connection_id_clean_up_alarm_->Update(
+ clock_->ApproximateNow() + next_alarm_interval, QuicTime::Delta::Zero());
}
bool QuicTimeWaitListManager::MaybeExpireOldestConnection(
@@ -300,7 +298,7 @@ bool QuicTimeWaitListManager::MaybeExpireOldestConnection(
void QuicTimeWaitListManager::CleanUpOldConnectionIds() {
QuicTime now = clock_->ApproximateNow();
- QuicTime expiration = now.Subtract(time_wait_period_);
+ QuicTime expiration = now - time_wait_period_;
while (MaybeExpireOldestConnection(expiration)) {
}
diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager.h b/chromium/net/tools/quic/quic_time_wait_list_manager.h
index 136ee4bc650..52daa92a31b 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager.h
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager.h
@@ -16,16 +16,17 @@
#include "base/macros.h"
#include "net/base/linked_hash_map.h"
-#include "net/quic/quic_blocked_writer_interface.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_session_base.h"
+#include "net/quic/core/quic_blocked_writer_interface.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_session_base.h"
namespace net {
namespace test {
+class QuicDispatcherPeer;
class QuicTimeWaitListManagerPeer;
} // namespace test
@@ -113,6 +114,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface {
const QuicPublicResetPacket& packet);
private:
+ friend class test::QuicDispatcherPeer;
friend class test::QuicTimeWaitListManagerPeer;
// Internal structure to store pending public reset packets.
diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc b/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc
index a1d06b4c4fd..54b5ea809d4 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -7,17 +7,16 @@
#include <errno.h>
#include <memory>
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/null_encrypter.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
@@ -31,7 +30,6 @@ using net::test::BuildUnsizedDataPacket;
using net::test::NoOpFramerVisitor;
using net::test::QuicVersionMax;
using net::test::QuicVersionMin;
-using net::test::ValueRestore;
using net::test::MockPacketWriter;
using testing::Args;
@@ -154,6 +152,7 @@ class QuicTimeWaitListManagerTest : public ::testing::Test {
packet_number, "data");
}
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
NiceMock<MockFakeTimeEpollServer> epoll_server_;
QuicEpollConnectionHelper helper_;
QuicEpollAlarmFactory alarm_factory_;
@@ -177,7 +176,7 @@ class ValidatePublicResetPacketPredicate
const std::tr1::tuple<const char*, int> packet_buffer,
testing::MatchResultListener* /* listener */) const override {
FramerVisitorCapturingPublicReset visitor;
- QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(),
+ QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(),
Perspective::IS_CLIENT);
framer.set_visitor(&visitor);
QuicEncryptedPacket encrypted(std::tr1::get<0>(packet_buffer),
@@ -227,15 +226,14 @@ TEST_F(QuicTimeWaitListManagerTest, CheckStatelessConnectionIdInTimeWait) {
TEST_F(QuicTimeWaitListManagerTest, SendVersionNegotiationPacket) {
std::unique_ptr<QuicEncryptedPacket> packet(
QuicFramer::BuildVersionNegotiationPacket(connection_id_,
- QuicSupportedVersions()));
+ AllSupportedVersions()));
EXPECT_CALL(writer_,
WritePacket(_, packet->length(), server_address_.address(),
client_address_, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
time_wait_list_manager_.SendVersionNegotiationPacket(
- connection_id_, QuicSupportedVersions(), server_address_,
- client_address_);
+ connection_id_, AllSupportedVersions(), server_address_, client_address_);
EXPECT_EQ(0u, time_wait_list_manager_.num_connections());
}
@@ -353,11 +351,11 @@ TEST_F(QuicTimeWaitListManagerTest, CleanUpOldConnectionIds) {
QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
// Now set the current time as time_wait_period + offset usecs.
- epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
+ epoll_server_.set_now_in_usec((time_wait_period + offset).ToMicroseconds());
// After all the old connection_ids are cleaned up, check the next alarm
// interval.
int64_t next_alarm_time = epoll_server_.ApproximateNowInUsec() +
- time_wait_period.Subtract(offset).ToMicroseconds();
+ (time_wait_period - offset).ToMicroseconds();
EXPECT_CALL(epoll_server_, RegisterAlarm(next_alarm_time, _));
time_wait_list_manager_.CleanUpOldConnectionIds();
@@ -479,7 +477,7 @@ TEST_F(QuicTimeWaitListManagerTest, AddConnectionIdTwice) {
QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
// Now set the current time as time_wait_period + offset usecs.
- epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
+ epoll_server_.set_now_in_usec((time_wait_period + offset).ToMicroseconds());
// After the connection_ids are cleaned up, check the next alarm interval.
int64_t next_alarm_time =
epoll_server_.ApproximateNowInUsec() + time_wait_period.ToMicroseconds();
diff --git a/chromium/net/tools/quic/spdy_balsa_utils.cc b/chromium/net/tools/quic/spdy_balsa_utils.cc
index 8f1ebd2eac4..b5764208990 100644
--- a/chromium/net/tools/quic/spdy_balsa_utils.cc
+++ b/chromium/net/tools/quic/spdy_balsa_utils.cc
@@ -12,8 +12,8 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "net/base/linked_hash_map.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_frame_builder.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_protocol.h"
@@ -189,25 +189,29 @@ void SpdyHeadersToRequestHeaders(const SpdyHeaderBlock& header_block,
method = method_it->second.as_string();
}
string uri;
- if (path_it == end_it) {
- uri = "/";
- } else {
- uri = path_it->second.as_string();
- }
- request_headers->SetRequestFirstlineFromStringPieces(
- method, uri, net::kHttp2VersionString);
-
if (scheme_it == end_it) {
- request_headers->AppendHeader("Scheme", "https");
+ uri += "https";
} else {
- request_headers->AppendHeader("Scheme", scheme_it->second);
+ uri += scheme_it->second.as_string();
}
+ uri += "://";
+
if (authority_it != end_it) {
+ uri += authority_it->second.as_string();
request_headers->AppendHeader("host", authority_it->second);
} else if (host_it != end_it) {
+ uri += host_it->second.as_string();
request_headers->AppendHeader("host", host_it->second);
}
+ if (path_it == end_it) {
+ uri += "/";
+ } else {
+ uri += path_it->second.as_string();
+ }
+ request_headers->SetRequestFirstlineFromStringPieces(
+ method, uri, net::kHttp2VersionString);
+
for (BlockIt it = header_block.begin(); it != header_block.end(); ++it) {
if (!IsSpecialSpdyHeader(it, request_headers)) {
if (it->second.empty()) {
diff --git a/chromium/net/tools/quic/spdy_balsa_utils.h b/chromium/net/tools/quic/spdy_balsa_utils.h
index a1d555a642b..dadb0eca479 100644
--- a/chromium/net/tools/quic/spdy_balsa_utils.h
+++ b/chromium/net/tools/quic/spdy_balsa_utils.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_protocol.h"
diff --git a/chromium/net/tools/quic/spdy_balsa_utils_test.cc b/chromium/net/tools/quic/spdy_balsa_utils_test.cc
index c8591ea0df9..bf26667be27 100644
--- a/chromium/net/tools/quic/spdy_balsa_utils_test.cc
+++ b/chromium/net/tools/quic/spdy_balsa_utils_test.cc
@@ -58,7 +58,7 @@ TEST(SpdyBalsaUtilsTest, SpdyHeadersToRequestHeaders) {
SpdyBalsaUtils::SpdyHeadersToRequestHeaders(spdy_headers, &request_headers);
EXPECT_EQ("GET", request_headers.request_method());
EXPECT_EQ("HTTP/1.1", request_headers.request_version());
- EXPECT_EQ("/foo", request_headers.request_uri());
+ EXPECT_EQ("https://www.google.com/foo", request_headers.request_uri());
EXPECT_EQ("www.google.com", request_headers.GetHeader("host"));
EXPECT_TRUE(request_headers.HasHeader("bar"));
EXPECT_EQ("", request_headers.GetHeader("bar"));
@@ -76,7 +76,7 @@ TEST(SpdyBalsaUtilsTest, SpdyHeadersToRequestHeaders) {
SpdyBalsaUtils::SpdyHeadersToRequestHeaders(spdy_headers1, &request_headers1);
EXPECT_EQ("GET", request_headers1.request_method());
EXPECT_EQ("HTTP/1.1", request_headers1.request_version());
- EXPECT_EQ("/foo", request_headers1.request_uri());
+ EXPECT_EQ("http://www.google.com/foo", request_headers1.request_uri());
EXPECT_EQ("www.google.com", request_headers1.GetHeader("host"));
}
diff --git a/chromium/net/tools/quic/stateless_rejector.cc b/chromium/net/tools/quic/stateless_rejector.cc
index 0fbbedd88c4..6cf95304d90 100644
--- a/chromium/net/tools/quic/stateless_rejector.cc
+++ b/chromium/net/tools/quic/stateless_rejector.cc
@@ -4,26 +4,33 @@
#include "net/tools/quic/stateless_rejector.h"
-#include "net/quic/quic_crypto_server_stream.h"
-#include "net/quic/quic_flags.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_flags.h"
namespace net {
class StatelessRejector::ValidateCallback
: public ValidateClientHelloResultCallback {
public:
- explicit ValidateCallback(StatelessRejector* rejector)
- : rejector_(rejector) {}
+ explicit ValidateCallback(
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb)
+ : rejector_(std::move(rejector)), cb_(std::move(cb)) {}
~ValidateCallback() override {}
- void RunImpl(const CryptoHandshakeMessage& client_hello,
- const Result& result) override {
- rejector_->ProcessClientHello(client_hello, result);
+ void Run(scoped_refptr<Result> result,
+ std::unique_ptr<ProofSource::Details> /* proof_source_details */)
+ override {
+ StatelessRejector* rejector_ptr = rejector_.get();
+ rejector_ptr->ProcessClientHello(std::move(result), std::move(rejector_),
+ std::move(cb_));
}
private:
- StatelessRejector* rejector_;
+ std::unique_ptr<StatelessRejector> rejector_;
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb_;
};
StatelessRejector::StatelessRejector(
@@ -33,20 +40,21 @@ StatelessRejector::StatelessRejector(
QuicCompressedCertsCache* compressed_certs_cache,
const QuicClock* clock,
QuicRandom* random,
+ QuicByteCount chlo_packet_size,
const IPEndPoint& client_address,
const IPEndPoint& server_address)
- : state_(FAILED),
+ : state_(UNKNOWN),
error_(QUIC_INTERNAL_ERROR),
version_(version),
versions_(versions),
connection_id_(0),
+ chlo_packet_size_(chlo_packet_size),
client_address_(client_address),
server_address_(server_address),
clock_(clock),
random_(random),
crypto_config_(crypto_config),
- compressed_certs_cache_(compressed_certs_cache),
- chlo_(nullptr) {}
+ compressed_certs_cache_(compressed_certs_cache) {}
StatelessRejector::~StatelessRejector() {}
@@ -56,6 +64,7 @@ void StatelessRejector::OnChlo(QuicVersion version,
const CryptoHandshakeMessage& message) {
DCHECK_EQ(kCHLO, message.tag());
DCHECK_NE(connection_id, server_designated_connection_id);
+ DCHECK_EQ(state_, UNKNOWN);
if (!FLAGS_enable_quic_stateless_reject_support ||
!FLAGS_quic_use_cheap_stateless_rejects ||
@@ -67,36 +76,85 @@ void StatelessRejector::OnChlo(QuicVersion version,
connection_id_ = connection_id;
server_designated_connection_id_ = server_designated_connection_id;
- chlo_ = &message;
+ chlo_ = message; // Note: copies the message
+}
- crypto_config_->ValidateClientHello(
- message, client_address_.address(), server_address_.address(), version_,
- clock_, &proof_, new ValidateCallback(this));
+void StatelessRejector::Process(std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<ProcessDoneCallback> done_cb) {
+ // If we were able to make a decision about this CHLO based purely on the
+ // information available in OnChlo, just invoke the done callback immediately.
+ if (rejector->state() != UNKNOWN) {
+ done_cb->Run(std::move(rejector));
+ return;
+ }
+
+ StatelessRejector* rejector_ptr = rejector.get();
+ rejector_ptr->crypto_config_->ValidateClientHello(
+ rejector_ptr->chlo_, rejector_ptr->client_address_.address(),
+ rejector_ptr->server_address_.address(), rejector_ptr->version_,
+ rejector_ptr->clock_, &rejector_ptr->proof_,
+ std::unique_ptr<ValidateCallback>(
+ new ValidateCallback(std::move(rejector), std::move(done_cb))));
}
+class StatelessRejector::ProcessClientHelloCallback
+ : public ProcessClientHelloResultCallback {
+ public:
+ ProcessClientHelloCallback(
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb)
+ : rejector_(std::move(rejector)), done_cb_(std::move(done_cb)) {}
+
+ void Run(
+ QuicErrorCode error,
+ const std::string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce) override {
+ StatelessRejector* rejector_ptr = rejector_.get();
+ rejector_ptr->ProcessClientHelloDone(
+ error, error_details, std::move(message), std::move(rejector_),
+ std::move(done_cb_));
+ }
+
+ private:
+ std::unique_ptr<StatelessRejector> rejector_;
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb_;
+};
+
void StatelessRejector::ProcessClientHello(
- const CryptoHandshakeMessage& client_hello,
- const ValidateClientHelloResultCallback::Result& result) {
- QuicCryptoNegotiatedParameters params;
- DiversificationNonce diversification_nonce;
- QuicErrorCode error = crypto_config_->ProcessClientHello(
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) {
+ std::unique_ptr<ProcessClientHelloCallback> cb(
+ new ProcessClientHelloCallback(std::move(rejector), std::move(done_cb)));
+ crypto_config_->ProcessClientHello(
result,
/*reject_only=*/true, connection_id_, server_address_.address(),
client_address_, version_, versions_,
/*use_stateless_rejects=*/true, server_designated_connection_id_, clock_,
- random_, compressed_certs_cache_, &params, &proof_, &reply_,
- &diversification_nonce, &error_details_);
+ random_, compressed_certs_cache_, &params_, &proof_,
+ QuicCryptoStream::CryptoMessageFramingOverhead(version_),
+ chlo_packet_size_, std::move(cb));
+}
+
+void StatelessRejector::ProcessClientHelloDone(
+ QuicErrorCode error,
+ const std::string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) {
+ reply_ = std::move(message);
+
if (error != QUIC_NO_ERROR) {
error_ = error;
- return;
- }
-
- if (reply_.tag() == kSREJ) {
+ error_details_ = error_details;
+ state_ = FAILED;
+ } else if (reply_->tag() == kSREJ) {
state_ = REJECTED;
- return;
+ } else {
+ state_ = ACCEPTED;
}
-
- state_ = ACCEPTED;
+ done_cb->Run(std::move(rejector));
}
} // namespace net
diff --git a/chromium/net/tools/quic/stateless_rejector.h b/chromium/net/tools/quic/stateless_rejector.h
index 07a666d0cc7..c8dcd4b97c8 100644
--- a/chromium/net/tools/quic/stateless_rejector.h
+++ b/chromium/net/tools/quic/stateless_rejector.h
@@ -6,9 +6,9 @@
#define NET_QUIC_STATELESS_REJECTOR_H_
#include "base/strings/string_piece.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -17,6 +17,7 @@ namespace net {
class StatelessRejector {
public:
enum State {
+ UNKNOWN, // State has not yet been determined
UNSUPPORTED, // Stateless rejects are not supported
FAILED, // There was an error processing the CHLO.
ACCEPTED, // The CHLO was accepted
@@ -29,18 +30,30 @@ class StatelessRejector {
QuicCompressedCertsCache* compressed_certs_cache,
const QuicClock* clock,
QuicRandom* random,
+ QuicByteCount chlo_packet_size,
const IPEndPoint& client_address,
const IPEndPoint& server_address);
~StatelessRejector();
- // Called when |chlo| is received for |connection_id| to determine
- // if it should be statelessly rejected.
+ // Called when |chlo| is received for |connection_id|.
void OnChlo(QuicVersion version,
QuicConnectionId connection_id,
QuicConnectionId server_designated_connection_id,
const CryptoHandshakeMessage& chlo);
+ class ProcessDoneCallback {
+ public:
+ virtual ~ProcessDoneCallback() = default;
+ virtual void Run(std::unique_ptr<StatelessRejector> rejector) = 0;
+ };
+
+ // Perform processing to determine whether the CHLO received in OnChlo should
+ // be statelessly rejected, and invoke the callback once a decision has been
+ // made.
+ static void Process(std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<ProcessDoneCallback> done_cb);
+
// Returns the state of the rejector after OnChlo() has been called.
State state() const { return state_; }
@@ -50,8 +63,11 @@ class StatelessRejector {
// Returns the error details when state() returns FAILED.
std::string error_details() const { return error_details_; }
+ // Returns the connection ID.
+ QuicConnectionId connection_id() const { return connection_id_; }
+
// Returns the SREJ message when state() returns REJECTED.
- const CryptoHandshakeMessage& reply() const { return reply_; }
+ const CryptoHandshakeMessage& reply() const { return *reply_; }
private:
// Helper class which is passed in to
@@ -59,9 +75,20 @@ class StatelessRejector {
class ValidateCallback;
friend class ValidateCallback;
+ class ProcessClientHelloCallback;
+ friend class ProcessClientHelloCallback;
+
void ProcessClientHello(
- const CryptoHandshakeMessage& client_hello,
- const ValidateClientHelloResultCallback::Result& result);
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb);
+
+ void ProcessClientHelloDone(
+ QuicErrorCode error,
+ const std::string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb);
State state_;
QuicErrorCode error_;
@@ -70,16 +97,18 @@ class StatelessRejector {
QuicVersionVector versions_;
QuicConnectionId connection_id_;
QuicConnectionId server_designated_connection_id_;
+ QuicByteCount chlo_packet_size_;
IPEndPoint client_address_;
IPEndPoint server_address_;
const QuicClock* clock_;
QuicRandom* random_;
const QuicCryptoServerConfig* crypto_config_;
QuicCompressedCertsCache* compressed_certs_cache_;
- const CryptoHandshakeMessage* chlo_;
- CryptoHandshakeMessage reply_;
+ CryptoHandshakeMessage chlo_;
+ std::unique_ptr<CryptoHandshakeMessage> reply_;
CryptoFramer crypto_framer_;
QuicCryptoProof proof_;
+ QuicCryptoNegotiatedParameters params_;
DISALLOW_COPY_AND_ASSIGN(StatelessRejector);
};
diff --git a/chromium/net/tools/quic/stateless_rejector_test.cc b/chromium/net/tools/quic/stateless_rejector_test.cc
index 97f7839998a..d773ff53de7 100644
--- a/chromium/net/tools/quic/stateless_rejector_test.cc
+++ b/chromium/net/tools/quic/stateless_rejector_test.cc
@@ -7,9 +7,11 @@
#include <memory>
#include <vector>
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/proof_source.h"
-#include "net/quic/quic_utils.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/proof_source.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_crypto_server_config_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -28,21 +30,38 @@ const QuicConnectionId kServerDesignateConnectionId = 24;
// All four combinations of the two flags involved.
enum FlagsMode { ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED };
+const char* FlagsModeToString(FlagsMode mode) {
+ switch (mode) {
+ case ENABLED:
+ return "ENABLED";
+ case STATELESS_DISABLED:
+ return "STATELESS_DISABLED";
+ case CHEAP_DISABLED:
+ return "CHEAP_DISABLED";
+ case BOTH_DISABLED:
+ return "BOTH_DISABLED";
+ default:
+ DLOG(FATAL) << "Unexpected FlagsMode";
+ return nullptr;
+ }
+}
+
// Test various combinations of QUIC version and flag state.
struct TestParams {
QuicVersion version;
FlagsMode flags;
- friend ostream& operator<<(ostream& os, const TestParams& p) {
- os << "{ version: " << p.version << " flags: " << p.flags << " }";
- return os;
- }
};
+string TestParamToString(const testing::TestParamInfo<TestParams>& params) {
+ return base::StringPrintf("v%i_%s", params.param.version,
+ FlagsModeToString(params.param.flags));
+}
+
vector<TestParams> GetTestParams() {
vector<TestParams> params;
for (FlagsMode flags :
{ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED}) {
- for (QuicVersion version : QuicSupportedVersions()) {
+ for (QuicVersion version : AllSupportedVersions()) {
TestParams param;
param.version = version;
param.flags = flags;
@@ -62,14 +81,16 @@ class StatelessRejectorTest : public ::testing::TestWithParam<TestParams> {
config_peer_(&config_),
compressed_certs_cache_(
QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
- rejector_(GetParam().version,
- QuicSupportedVersions(),
- &config_,
- &compressed_certs_cache_,
- &clock_,
- QuicRandom::GetInstance(),
- IPEndPoint(net::test::Loopback4(), 12345),
- IPEndPoint(net::test::Loopback4(), 443)) {
+ rejector_(base::MakeUnique<StatelessRejector>(
+ GetParam().version,
+ AllSupportedVersions(),
+ &config_,
+ &compressed_certs_cache_,
+ &clock_,
+ QuicRandom::GetInstance(),
+ kDefaultMaxPacketSize,
+ IPEndPoint(net::test::Loopback4(), 12345),
+ IPEndPoint(net::test::Loopback4(), 443))) {
FLAGS_enable_quic_stateless_reject_support =
GetParam().flags == ENABLED || GetParam().flags == CHEAP_DISABLED;
FLAGS_quic_use_cheap_stateless_rejects =
@@ -111,13 +132,26 @@ class StatelessRejectorTest : public ::testing::TestWithParam<TestParams> {
}
protected:
+ class ProcessDoneCallback : public StatelessRejector::ProcessDoneCallback {
+ public:
+ explicit ProcessDoneCallback(StatelessRejectorTest* test) : test_(test) {}
+ void Run(std::unique_ptr<StatelessRejector> rejector) override {
+ test_->rejector_ = std::move(rejector);
+ }
+
+ private:
+ StatelessRejectorTest* test_;
+ };
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+
std::unique_ptr<ProofSource> proof_source_;
MockClock clock_;
QuicCryptoServerConfig config_;
QuicCryptoServerConfigPeer config_peer_;
QuicCompressedCertsCache compressed_certs_cache_;
QuicCryptoServerConfig::ConfigOptions config_options_;
- StatelessRejector rejector_;
+ std::unique_ptr<StatelessRejector> rejector_;
// Values used in CHLO messages
string scid_hex_;
@@ -129,31 +163,39 @@ class StatelessRejectorTest : public ::testing::TestWithParam<TestParams> {
INSTANTIATE_TEST_CASE_P(Flags,
StatelessRejectorTest,
- ::testing::ValuesIn(GetTestParams()));
+ ::testing::ValuesIn(GetTestParams()),
+ TestParamToString);
TEST_P(StatelessRejectorTest, InvalidChlo) {
// clang-format off
const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
"CHLO",
+ "PDMD", "X509",
"COPT", "SREJ",
nullptr);
// clang-format on
- rejector_.OnChlo(GetParam().version, kConnectionId,
- kServerDesignateConnectionId, client_hello);
+ rejector_->OnChlo(GetParam().version, kConnectionId,
+ kServerDesignateConnectionId, client_hello);
if (GetParam().flags != ENABLED || GetParam().version <= QUIC_VERSION_32) {
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_.state());
+ EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
return;
}
- EXPECT_EQ(StatelessRejector::FAILED, rejector_.state());
- EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, rejector_.error());
+ // The StatelessRejector is undecided - proceed with async processing
+ ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
+ StatelessRejector::Process(std::move(rejector_),
+ base::MakeUnique<ProcessDoneCallback>(this));
+
+ EXPECT_EQ(StatelessRejector::FAILED, rejector_->state());
+ EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, rejector_->error());
}
TEST_P(StatelessRejectorTest, ValidChloWithoutSrejSupport) {
// clang-format off
const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
"CHLO",
+ "PDMD", "X509",
"AEAD", "AESG",
"KEXS", "C255",
"PUBS", pubs_hex_.c_str(),
@@ -163,15 +205,16 @@ TEST_P(StatelessRejectorTest, ValidChloWithoutSrejSupport) {
nullptr);
// clang-format on
- rejector_.OnChlo(GetParam().version, kConnectionId,
- kServerDesignateConnectionId, client_hello);
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_.state());
+ rejector_->OnChlo(GetParam().version, kConnectionId,
+ kServerDesignateConnectionId, client_hello);
+ EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
}
TEST_P(StatelessRejectorTest, RejectChlo) {
// clang-format off
const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
"CHLO",
+ "PDMD", "X509",
"AEAD", "AESG",
"KEXS", "C255",
"COPT", "SREJ",
@@ -184,14 +227,20 @@ TEST_P(StatelessRejectorTest, RejectChlo) {
nullptr);
// clang-format on
- rejector_.OnChlo(GetParam().version, kConnectionId,
- kServerDesignateConnectionId, client_hello);
+ rejector_->OnChlo(GetParam().version, kConnectionId,
+ kServerDesignateConnectionId, client_hello);
if (GetParam().flags != ENABLED || GetParam().version <= QUIC_VERSION_32) {
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_.state());
+ EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
return;
}
- ASSERT_EQ(StatelessRejector::REJECTED, rejector_.state());
- const CryptoHandshakeMessage& reply = rejector_.reply();
+
+ // The StatelessRejector is undecided - proceed with async processing
+ ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
+ StatelessRejector::Process(std::move(rejector_),
+ base::MakeUnique<ProcessDoneCallback>(this));
+
+ ASSERT_EQ(StatelessRejector::REJECTED, rejector_->state());
+ const CryptoHandshakeMessage& reply = rejector_->reply();
EXPECT_EQ(kSREJ, reply.tag());
const uint32_t* reject_reasons;
size_t num_reject_reasons;
@@ -210,6 +259,7 @@ TEST_P(StatelessRejectorTest, AcceptChlo) {
// clang-format off
const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
"CHLO",
+ "PDMD", "X509",
"AEAD", "AESG",
"KEXS", "C255",
"COPT", "SREJ",
@@ -223,13 +273,19 @@ TEST_P(StatelessRejectorTest, AcceptChlo) {
nullptr);
// clang-format on
- rejector_.OnChlo(GetParam().version, kConnectionId,
- kServerDesignateConnectionId, client_hello);
+ rejector_->OnChlo(GetParam().version, kConnectionId,
+ kServerDesignateConnectionId, client_hello);
if (GetParam().flags != ENABLED || GetParam().version <= QUIC_VERSION_32) {
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_.state());
+ EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
return;
}
- EXPECT_EQ(StatelessRejector::ACCEPTED, rejector_.state());
+
+ // The StatelessRejector is undecided - proceed with async processing
+ ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
+ StatelessRejector::Process(std::move(rejector_),
+ base::MakeUnique<ProcessDoneCallback>(this));
+
+ EXPECT_EQ(StatelessRejector::ACCEPTED, rejector_->state());
}
} // namespace
diff --git a/chromium/net/tools/quic/synchronous_host_resolver.cc b/chromium/net/tools/quic/synchronous_host_resolver.cc
index 7bdf5fd6e25..ba1e51b3f5b 100644
--- a/chromium/net/tools/quic/synchronous_host_resolver.cc
+++ b/chromium/net/tools/quic/synchronous_host_resolver.cc
@@ -15,7 +15,8 @@
#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
#include "net/dns/host_resolver_impl.h"
-#include "net/dns/single_request_host_resolver.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -60,16 +61,16 @@ void ResolverThread::Run() {
net::HostResolver::Options options;
options.max_concurrent_resolves = 6;
options.max_retry_attempts = 3u;
- std::unique_ptr<net::HostResolverImpl> resolver_impl(
+ std::unique_ptr<net::HostResolverImpl> resolver(
new net::HostResolverImpl(options, &net_log));
- SingleRequestHostResolver resolver(resolver_impl.get());
+ std::unique_ptr<net::HostResolver::Request> request;
HostPortPair host_port_pair(host_, 80);
- rv_ = resolver.Resolve(HostResolver::RequestInfo(host_port_pair),
- DEFAULT_PRIORITY, addresses_,
- base::Bind(&ResolverThread::OnResolutionComplete,
- weak_factory_.GetWeakPtr()),
- BoundNetLog());
+ rv_ = resolver->Resolve(HostResolver::RequestInfo(host_port_pair),
+ DEFAULT_PRIORITY, addresses_,
+ base::Bind(&ResolverThread::OnResolutionComplete,
+ weak_factory_.GetWeakPtr()),
+ &request, NetLogWithSource());
if (rv_ != ERR_IO_PENDING)
return;
diff --git a/chromium/net/tools/quic/synchronous_host_resolver.h b/chromium/net/tools/quic/synchronous_host_resolver.h
index 7089c874251..d41f0afb79b 100644
--- a/chromium/net/tools/quic/synchronous_host_resolver.h
+++ b/chromium/net/tools/quic/synchronous_host_resolver.h
@@ -8,7 +8,6 @@
#define NET_TOOLS_QUIC_SYNCHRONOUS_HOST_RESOLVER_H_
#include "net/base/address_list.h"
-#include "net/base/net_export.h"
#include "net/dns/host_resolver.h"
namespace net {
diff --git a/chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h b/chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h
index a9efa7f1d91..c58b7662f26 100644
--- a/chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h
+++ b/chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h
@@ -8,7 +8,7 @@
#include <stddef.h>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_packet_writer_wrapper.h"
namespace net {
diff --git a/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc b/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc
index 9b5d4c0a186..f3ae2b05686 100644
--- a/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc
+++ b/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc
@@ -11,9 +11,9 @@ MockQuicServerSessionVisitor::MockQuicServerSessionVisitor() {}
MockQuicServerSessionVisitor::~MockQuicServerSessionVisitor() {}
-MockQuicServerSessionHelper::MockQuicServerSessionHelper() {}
+MockQuicCryptoServerStreamHelper::MockQuicCryptoServerStreamHelper() {}
-MockQuicServerSessionHelper::~MockQuicServerSessionHelper() {}
+MockQuicCryptoServerStreamHelper::~MockQuicCryptoServerStreamHelper() {}
} // namespace test
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h b/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h
index 52d59d2e795..d89f49cb8a0 100644
--- a/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h
+++ b/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h
@@ -6,7 +6,8 @@
#define NET_TOOLS_QUIC_TEST_TOOLS_MOCK_QUIC_SERVER_SESSION_VISITOR_H_
#include "base/macros.h"
-#include "net/quic/quic_server_session_base.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_server_session_base.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace net {
@@ -24,15 +25,17 @@ class MockQuicServerSessionVisitor : public QuicServerSessionBase::Visitor {
void(QuicBlockedWriterInterface* blocked_writer));
MOCK_METHOD1(OnConnectionAddedToTimeWaitList,
void(QuicConnectionId connection_id));
+ MOCK_METHOD1(OnPacketBeingDispatchedToSession,
+ void(QuicServerSessionBase* session));
private:
DISALLOW_COPY_AND_ASSIGN(MockQuicServerSessionVisitor);
};
-class MockQuicServerSessionHelper : public QuicServerSessionBase::Helper {
+class MockQuicCryptoServerStreamHelper : public QuicCryptoServerStream::Helper {
public:
- MockQuicServerSessionHelper();
- ~MockQuicServerSessionHelper() override;
+ MockQuicCryptoServerStreamHelper();
+ ~MockQuicCryptoServerStreamHelper() override;
MOCK_CONST_METHOD1(GenerateConnectionIdForReject,
QuicConnectionId(QuicConnectionId connection_id));
MOCK_CONST_METHOD3(CanAcceptClientHello,
@@ -41,7 +44,7 @@ class MockQuicServerSessionHelper : public QuicServerSessionBase::Helper {
std::string* error_details));
private:
- DISALLOW_COPY_AND_ASSIGN(MockQuicServerSessionHelper);
+ DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStreamHelper);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
index 4d85d5a85f9..54424887951 100644
--- a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
+++ b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -50,6 +50,7 @@ PacketDroppingTestWriter::PacketDroppingTestWriter()
: clock_(nullptr),
cur_buffer_size_(0),
num_calls_to_write_(0),
+ max_allowed_packet_size_(std::numeric_limits<QuicByteCount>::max()),
config_mutex_(),
fake_packet_loss_percentage_(0),
fake_drop_first_n_packets_(0),
@@ -81,6 +82,7 @@ WriteResult PacketDroppingTestWriter::WritePacket(
const IPAddress& self_address,
const IPEndPoint& peer_address,
PerPacketOptions* options) {
+ CHECK_LE(buf_len, max_allowed_packet_size_);
++num_calls_to_write_;
ReleaseOldPackets();
@@ -118,14 +120,14 @@ WriteResult PacketDroppingTestWriter::WritePacket(
}
// Queue it to be sent.
- QuicTime send_time = clock_->ApproximateNow().Add(fake_packet_delay_);
+ QuicTime send_time = clock_->ApproximateNow() + fake_packet_delay_;
if (!fake_bandwidth_.IsZero()) {
// Calculate a time the bandwidth limit would impose.
QuicTime::Delta bandwidth_delay = QuicTime::Delta::FromMicroseconds(
(buf_len * kNumMicrosPerSecond) / fake_bandwidth_.ToBytesPerSecond());
send_time = delayed_packets_.empty()
- ? send_time.Add(bandwidth_delay)
- : delayed_packets_.back().send_time.Add(bandwidth_delay);
+ ? send_time + bandwidth_delay
+ : delayed_packets_.back().send_time + bandwidth_delay;
}
std::unique_ptr<PerPacketOptions> delayed_options;
if (options != nullptr) {
diff --git a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
index 2e3fcbca0ea..ff058b5660a 100644
--- a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
+++ b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -16,7 +16,7 @@
#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "net/base/ip_address.h"
-#include "net/quic/quic_alarm.h"
+#include "net/quic/core/quic_alarm.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_epoll_clock.h"
#include "net/tools/quic/quic_packet_writer_wrapper.h"
@@ -121,6 +121,12 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
// Useful for reproducing very flaky issues.
void set_seed(uint64_t seed) { simple_random_.set_seed(seed); }
+ // Sets the maximum allowed packet size to be sent. Packets larger than
+ // |packet_size| will cause the write to check-fail.
+ void set_max_allowed_packet_size(QuicByteCount packet_size) {
+ max_allowed_packet_size_ = packet_size;
+ }
+
private:
// Writes out the next packet to the contained writer and returns the time
// for the next delayed packet to be written.
@@ -162,6 +168,7 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
DelayedPacketList delayed_packets_;
QuicByteCount cur_buffer_size_;
uint64_t num_calls_to_write_;
+ QuicByteCount max_allowed_packet_size_;
base::Lock config_mutex_;
int32_t fake_packet_loss_percentage_;
diff --git a/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc b/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc
new file mode 100644
index 00000000000..a11f7d8e393
--- /dev/null
+++ b/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc
@@ -0,0 +1,50 @@
+// Copyright 2013 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/tools/quic/test_tools/packet_reordering_writer.h"
+
+namespace net {
+namespace test {
+
+PacketReorderingWriter::PacketReorderingWriter() {}
+
+PacketReorderingWriter::~PacketReorderingWriter() {}
+
+WriteResult PacketReorderingWriter::WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) {
+ if (!delay_next_) {
+ WriteResult wr = QuicPacketWriterWrapper::WritePacket(
+ buffer, buf_len, self_address, peer_address, options);
+ --num_packets_to_wait_;
+ if (num_packets_to_wait_ == 0) {
+ // It's time to write the delayed packet.
+ QuicPacketWriterWrapper::WritePacket(
+ delayed_data_.data(), delayed_data_.length(), delayed_self_address_,
+ delayed_peer_address_, delayed_options_.get());
+ }
+ return wr;
+ }
+ // Still have packet to wait.
+ DCHECK_LT(0u, num_packets_to_wait_) << "Only allow one packet to be delayed";
+ delayed_data_ = std::string(buffer, buf_len);
+ delayed_self_address_ = self_address;
+ delayed_peer_address_ = peer_address;
+ if (options != nullptr) {
+ delayed_options_.reset(options->Clone());
+ }
+ delay_next_ = false;
+ return WriteResult(WRITE_STATUS_OK, buf_len);
+}
+
+void PacketReorderingWriter::SetDelay(size_t num_packets_to_wait) {
+ DCHECK_GT(num_packets_to_wait, 0u);
+ num_packets_to_wait_ = num_packets_to_wait;
+ delay_next_ = true;
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/packet_reordering_writer.h b/chromium/net/tools/quic/test_tools/packet_reordering_writer.h
new file mode 100644
index 00000000000..d09aeb84a3a
--- /dev/null
+++ b/chromium/net/tools/quic/test_tools/packet_reordering_writer.h
@@ -0,0 +1,45 @@
+// Copyright 2013 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_TOOLS_QUIC_TEST_TOOLS_PACKET_REORDERING_WRITER_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_PACKET_REORDERING_WRITER_H_
+
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
+
+namespace net {
+
+namespace test {
+
+// This packet writer allows delaying writing the next packet after
+// SetDelay(num_packets_to_wait)
+// is called and buffer this packet and write it after it writes next
+// |num_packets_to_wait| packets. It doesn't support delaying a packet while
+// there is already a packet delayed.
+class PacketReorderingWriter : public QuicPacketWriterWrapper {
+ public:
+ PacketReorderingWriter();
+
+ ~PacketReorderingWriter() override;
+
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) override;
+
+ void SetDelay(size_t num_packets_to_wait);
+
+ private:
+ bool delay_next_ = false;
+ size_t num_packets_to_wait_ = 0;
+ std::string delayed_data_;
+ IPAddress delayed_self_address_;
+ IPEndPoint delayed_peer_address_;
+ std::unique_ptr<PerPacketOptions> delayed_options_;
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_PACKET_REORDERING_WRITER_H_
diff --git a/chromium/net/tools/quic/test_tools/quic_client_peer.cc b/chromium/net/tools/quic/test_tools/quic_client_peer.cc
index 961cc823e2d..aca80df0c20 100644
--- a/chromium/net/tools/quic/test_tools/quic_client_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_client_peer.cc
@@ -16,7 +16,9 @@ QuicCryptoClientConfig* QuicClientPeer::GetCryptoConfig(QuicClient* client) {
// static
bool QuicClientPeer::CreateUDPSocketAndBind(QuicClient* client) {
- return client->CreateUDPSocketAndBind();
+ return client->CreateUDPSocketAndBind(client->server_address(),
+ client->bind_to_address(),
+ client->local_port());
}
// static
diff --git a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
index 48a61f71d68..bb528841e83 100644
--- a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
@@ -62,10 +62,35 @@ QuicErrorCode QuicDispatcherPeer::GetAndClearLastError(
}
// static
+QuicBufferedPacketStore* QuicDispatcherPeer::GetBufferedPackets(
+ QuicDispatcher* dispatcher) {
+ return &(dispatcher->buffered_packets_);
+}
+
+// static
const QuicDispatcher::SessionMap& QuicDispatcherPeer::session_map(
QuicDispatcher* dispatcher) {
return dispatcher->session_map();
}
+// static
+void QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(
+ QuicDispatcher* dispatcher,
+ size_t num_session_allowed) {
+ return dispatcher->set_new_sessions_allowed_per_event_loop(
+ num_session_allowed);
+}
+
+// static
+void QuicDispatcherPeer::SendPublicReset(
+ QuicDispatcher* dispatcher,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address,
+ QuicConnectionId connection_id,
+ QuicPacketNumber rejected_packet_number) {
+ dispatcher->time_wait_list_manager()->SendPublicReset(
+ server_address, client_address, connection_id, rejected_packet_number);
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
index 4ff4d2d38b6..c415fc39ad1 100644
--- a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
+++ b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
@@ -41,9 +41,22 @@ class QuicDispatcherPeer {
// visitor's OnError() method. Then set that record to QUIC_NO_ERROR.
static QuicErrorCode GetAndClearLastError(QuicDispatcher* dispatcher);
+ static QuicBufferedPacketStore* GetBufferedPackets(
+ QuicDispatcher* dispatcher);
+
static const QuicDispatcher::SessionMap& session_map(
QuicDispatcher* dispatcher);
+ static void set_new_sessions_allowed_per_event_loop(
+ QuicDispatcher* dispatcher,
+ size_t num_session_allowed);
+
+ static void SendPublicReset(QuicDispatcher* dispatcher,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address,
+ QuicConnectionId connection_id,
+ QuicPacketNumber rejected_packet_number);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicDispatcherPeer);
};
diff --git a/chromium/net/tools/quic/test_tools/quic_test_client.cc b/chromium/net/tools/quic/test_tools/quic_test_client.cc
index 914c4f8ab03..e58916b0ee5 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_client.cc
+++ b/chromium/net/tools/quic/test_tools/quic_test_client.cc
@@ -7,14 +7,17 @@
#include <memory>
#include <utility>
+#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "net/base/completion_callback.h"
#include "net/base/net_errors.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/x509_certificate.h"
-#include "net/quic/crypto/proof_verifier.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -35,28 +38,36 @@ using net::test::QuicSpdySessionPeer;
using net::test::ReliableQuicStreamPeer;
using std::string;
using std::vector;
+using testing::_;
+using testing::Invoke;
namespace net {
namespace test {
namespace {
// RecordingProofVerifier accepts any certificate chain and records the common
-// name of the leaf.
+// name of the leaf and then delegates the actual verfication to an actual
+// verifier. If no optional verifier is provided, then VerifyProof will return
+// success.
class RecordingProofVerifier : public ProofVerifier {
public:
+ explicit RecordingProofVerifier(std::unique_ptr<ProofVerifier> verifier)
+ : verifier_(std::move(verifier)) {}
+
// ProofVerifier interface.
- QuicAsyncStatus VerifyProof(const string& hostname,
- const uint16_t port,
- const string& server_config,
- QuicVersion quic_version,
- StringPiece chlo_hash,
- const vector<string>& certs,
- const string& cert_sct,
- const string& signature,
- const ProofVerifyContext* context,
- string* error_details,
- std::unique_ptr<ProofVerifyDetails>* details,
- ProofVerifierCallback* callback) override {
+ QuicAsyncStatus VerifyProof(
+ const string& hostname,
+ const uint16_t port,
+ const string& server_config,
+ QuicVersion quic_version,
+ StringPiece chlo_hash,
+ const vector<string>& certs,
+ const string& cert_sct,
+ const string& signature,
+ const ProofVerifyContext* context,
+ string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) override {
common_name_.clear();
if (certs.empty()) {
return QUIC_FAILURE;
@@ -79,6 +90,22 @@ class RecordingProofVerifier : public ProofVerifier {
// common_name_ = cert->subject().GetDisplayName();
cert_sct_ = cert_sct;
+ if (!verifier_) {
+ return QUIC_SUCCESS;
+ }
+
+ return verifier_->VerifyProof(
+ hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
+ signature, context, error_details, details, std::move(callback));
+ }
+
+ QuicAsyncStatus VerifyCertChain(
+ const std::string& hostname,
+ const std::vector<std::string>& certs,
+ const ProofVerifyContext* verify_context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) override {
return QUIC_SUCCESS;
}
@@ -87,6 +114,7 @@ class RecordingProofVerifier : public ProofVerifier {
const string& cert_sct() const { return cert_sct_; }
private:
+ std::unique_ptr<ProofVerifier> verifier_;
string common_name_;
string cert_sct_;
};
@@ -103,9 +131,11 @@ BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers) {
}
BalsaHeaders* headers = new BalsaHeaders;
headers->CopyFrom(*const_headers);
- if (!uri.starts_with("https://") && !uri.starts_with("http://")) {
+ if (!base::StartsWith(uri, "https://",
+ base::CompareCase::INSENSITIVE_ASCII) &&
+ !base::StartsWith(uri, "http://", base::CompareCase::INSENSITIVE_ASCII)) {
// If we have a relative URL, set some defaults.
- string full_uri = "https://www.google.com";
+ string full_uri = "https://test.example.com";
full_uri.append(uri.as_string());
headers->SetRequestUri(full_uri);
}
@@ -129,14 +159,39 @@ MockableQuicClient::MockableQuicClient(
const QuicConfig& config,
const QuicVersionVector& supported_versions,
EpollServer* epoll_server)
+ : MockableQuicClient(server_address,
+ server_id,
+ config,
+ supported_versions,
+ epoll_server,
+ nullptr) {}
+
+MockableQuicClient::MockableQuicClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server,
+ std::unique_ptr<ProofVerifier> proof_verifier)
: QuicClient(server_address,
server_id,
supported_versions,
config,
epoll_server,
- new RecordingProofVerifier()),
+ base::WrapUnique(
+ new RecordingProofVerifier(std::move(proof_verifier)))),
override_connection_id_(0),
- test_writer_(nullptr) {}
+ test_writer_(nullptr),
+ track_last_incoming_packet_(false) {}
+
+void MockableQuicClient::ProcessPacket(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicReceivedPacket& packet) {
+ QuicClient::ProcessPacket(self_address, peer_address, packet);
+ if (track_last_incoming_packet_) {
+ last_incoming_packet_.reset(packet.Clone());
+ }
+}
MockableQuicClient::~MockableQuicClient() {
if (connected()) {
@@ -187,11 +242,31 @@ QuicTestClient::QuicTestClient(IPEndPoint server_address,
config,
supported_versions,
&epoll_server_)),
+ response_complete_(false),
allow_bidirectional_data_(false) {
Initialize();
}
-QuicTestClient::QuicTestClient() : allow_bidirectional_data_(false) {}
+QuicTestClient::QuicTestClient(IPEndPoint server_address,
+ const string& server_hostname,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ std::unique_ptr<ProofVerifier> proof_verifier)
+ : client_(new MockableQuicClient(server_address,
+ QuicServerId(server_hostname,
+ server_address.port(),
+ PRIVACY_MODE_DISABLED),
+ config,
+ supported_versions,
+ &epoll_server_,
+ std::move(proof_verifier))),
+ response_complete_(false),
+ allow_bidirectional_data_(false) {
+ Initialize();
+}
+
+QuicTestClient::QuicTestClient()
+ : response_complete_(false), allow_bidirectional_data_(false) {}
QuicTestClient::~QuicTestClient() {
if (stream_) {
@@ -248,10 +323,10 @@ ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest(
return 1;
if (rv == QUIC_PENDING) {
// May need to retry request if asynchronous rendezvous fails.
- auto* new_headers = new BalsaHeaders;
- new_headers->CopyFrom(*headers);
- push_promise_data_to_resend_.reset(
- new TestClientDataToResend(new_headers, body, fin, this, delegate));
+ std::unique_ptr<SpdyHeaderBlock> new_headers(new SpdyHeaderBlock(
+ SpdyBalsaUtils::RequestHeadersToSpdyHeaders(*headers)));
+ push_promise_data_to_resend_.reset(new TestClientDataToResend(
+ std::move(new_headers), body, fin, this, delegate));
return 1;
}
}
@@ -286,24 +361,29 @@ ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest(
ret = body.length();
}
if (FLAGS_enable_quic_stateless_reject_support) {
- BalsaHeaders* new_headers = nullptr;
+ std::unique_ptr<SpdyHeaderBlock> new_headers;
if (headers) {
- new_headers = new BalsaHeaders;
- new_headers->CopyFrom(*headers);
+ new_headers.reset(new SpdyHeaderBlock(
+ SpdyBalsaUtils::RequestHeadersToSpdyHeaders(*headers)));
}
- auto* data_to_resend =
- new TestClientDataToResend(new_headers, body, fin, this, delegate);
- client()->MaybeAddQuicDataToResend(data_to_resend);
+ std::unique_ptr<QuicClientBase::QuicDataToResend> data_to_resend(
+ new TestClientDataToResend(std::move(new_headers), body, fin, this,
+ delegate));
+ client()->MaybeAddQuicDataToResend(std::move(data_to_resend));
}
return ret;
}
ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
stream_ = nullptr; // Always force creation of a stream for SendMessage.
+ // Any response we might have received for a previous request would no longer
+ // be valid. TODO(jeffpiazza): There's probably additional client state that
+ // should be reset here, too, if we were being more careful.
+ response_complete_ = false;
// If we're not connected, try to find an sni hostname.
if (!connected()) {
- GURL url(message.headers()->request_uri().as_string());
+ GURL url(message.headers()->request_uri());
if (override_sni_set_) {
client_->set_server_id(QuicServerId(override_sni_, url.EffectiveIntPort(),
PRIVACY_MODE_DISABLED));
@@ -386,6 +466,14 @@ string QuicTestClient::SendSynchronousRequest(const string& uri) {
return SendCustomSynchronousRequest(message);
}
+void QuicTestClient::SetStream(QuicSpdyClientStream* stream) {
+ stream_ = stream;
+ if (stream_ != nullptr) {
+ response_complete_ = false;
+ stream_->set_visitor(this);
+ }
+}
+
QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
if (!connect_attempted_ || auto_reconnect_) {
if (!connected()) {
@@ -396,14 +484,11 @@ QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
}
}
if (!stream_) {
- stream_ = client_->CreateReliableClientStream();
- if (stream_ == nullptr) {
- return nullptr;
+ SetStream(client_->CreateReliableClientStream());
+ if (stream_) {
+ stream_->SetPriority(priority_);
+ stream_->set_allow_bidirectional_data(allow_bidirectional_data_);
}
- stream_->set_visitor(this);
- QuicSpdyClientStream* cs = reinterpret_cast<QuicSpdyClientStream*>(stream_);
- cs->SetPriority(priority_);
- cs->set_allow_bidirectional_data(allow_bidirectional_data_);
}
return stream_;
@@ -485,7 +570,7 @@ bool QuicTestClient::HaveActiveStream() {
!client_->session()->IsClosedStream(stream_->id()));
}
-void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
+void QuicTestClient::WaitUntil(int timeout_ms, std::function<bool()> trigger) {
int64_t timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
int64_t old_timeout_us = epoll_server()->timeout_in_us();
if (timeout_us > 0) {
@@ -495,35 +580,16 @@ void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
QuicConnectionPeer::GetHelper(client()->session()->connection())
->GetClock();
QuicTime end_waiting_time =
- clock->Now().Add(QuicTime::Delta::FromMicroseconds(timeout_us));
- while (HaveActiveStream() &&
+ clock->Now() + QuicTime::Delta::FromMicroseconds(timeout_us);
+ while (HaveActiveStream() && !(trigger && trigger()) &&
(timeout_us < 0 || clock->Now() < end_waiting_time)) {
client_->WaitForEvents();
}
if (timeout_us > 0) {
epoll_server()->set_timeout_in_us(old_timeout_us);
}
-}
-
-void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
- int64_t timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
- int64_t old_timeout_us = epoll_server()->timeout_in_us();
- if (timeout_us > 0) {
- epoll_server()->set_timeout_in_us(timeout_us);
- }
- const QuicClock* clock =
- QuicConnectionPeer::GetHelper(client()->session()->connection())
- ->GetClock();
- QuicTime end_waiting_time =
- clock->Now().Add(QuicTime::Delta::FromMicroseconds(timeout_us));
- while (stream_ != nullptr &&
- !client_->session()->IsClosedStream(stream_->id()) &&
- stream_->stream_bytes_read() == 0 &&
- (timeout_us < 0 || clock->Now() < end_waiting_time)) {
- client_->WaitForEvents();
- }
- if (timeout_us > 0) {
- epoll_server()->set_timeout_in_us(old_timeout_us);
+ if (trigger && !trigger()) {
+ VLOG(1) << "Client WaitUntil returning with trigger returning false.";
}
}
@@ -553,15 +619,27 @@ const SpdyHeaderBlock& QuicTestClient::response_trailers() const {
}
int64_t QuicTestClient::response_size() const {
- return bytes_read_;
+ return bytes_read();
}
size_t QuicTestClient::bytes_read() const {
- return bytes_read_;
+ // While stream_ is available, its member functions provide more accurate
+ // information. bytes_read_ is updated only when stream_ becomes null.
+ if (stream_) {
+ return stream_->stream_bytes_read() + stream_->header_bytes_read();
+ } else {
+ return bytes_read_;
+ }
}
size_t QuicTestClient::bytes_written() const {
- return bytes_written_;
+ // While stream_ is available, its member functions provide more accurate
+ // information. bytes_written_ is updated only when stream_ becomes null.
+ if (stream_) {
+ return stream_->stream_bytes_written() + stream_->header_bytes_written();
+ } else {
+ return bytes_written_;
+ }
}
void QuicTestClient::OnClose(QuicSpdyStream* stream) {
@@ -601,9 +679,8 @@ bool QuicTestClient::CheckVary(const SpdyHeaderBlock& client_request,
void QuicTestClient::OnRendezvousResult(QuicSpdyStream* stream) {
std::unique_ptr<TestClientDataToResend> data_to_resend =
std::move(push_promise_data_to_resend_);
- stream_ = static_cast<QuicSpdyClientStream*>(stream);
+ SetStream(static_cast<QuicSpdyClientStream*>(stream));
if (stream) {
- stream->set_visitor(this);
stream->OnDataAvailable();
} else if (data_to_resend.get()) {
data_to_resend->Resend();
@@ -662,12 +739,11 @@ void QuicTestClient::WaitForWriteToFlush() {
}
void QuicTestClient::TestClientDataToResend::Resend() {
- test_client_->GetOrCreateStreamAndSendRequest(headers_, body_, fin_,
+ BalsaHeaders balsa_headers;
+ SpdyBalsaUtils::SpdyHeadersToRequestHeaders(*headers_, &balsa_headers);
+ test_client_->GetOrCreateStreamAndSendRequest(&balsa_headers, body_, fin_,
delegate_);
- if (headers_ != nullptr) {
- delete headers_;
- headers_ = nullptr;
- }
+ headers_.reset();
}
// static
diff --git a/chromium/net/tools/quic/test_tools/quic_test_client.h b/chromium/net/tools/quic/test_tools/quic_test_client.h
index b76d1cfce20..3e52fc956db 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_client.h
+++ b/chromium/net/tools/quic/test_tools/quic_test_client.h
@@ -15,14 +15,15 @@
#include "base/macros.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_packet_creator.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/balsa/balsa_frame.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client.h"
#include "net/tools/quic/test_tools/simple_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
using base::StringPiece;
@@ -30,6 +31,7 @@ namespace net {
class ProofVerifier;
+class ProofVerifier;
class QuicPacketWriterWrapper;
namespace test {
@@ -37,7 +39,7 @@ namespace test {
class HTTPMessage;
class MockableQuicClient;
-// A quic client which allows mocking out writes.
+// A quic client which allows mocking out reads and writes.
class MockableQuicClient : public QuicClient {
public:
MockableQuicClient(IPEndPoint server_address,
@@ -51,7 +53,19 @@ class MockableQuicClient : public QuicClient {
const QuicVersionVector& supported_versions,
EpollServer* epoll_server);
+ MockableQuicClient(IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server,
+ std::unique_ptr<ProofVerifier> proof_verifier);
+
~MockableQuicClient() override;
+
+ void ProcessPacket(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicReceivedPacket& packet) override;
+
QuicPacketWriter* CreateQuicPacketWriter() override;
QuicConnectionId GenerateNewConnectionId() override;
void UseWriter(QuicPacketWriterWrapper* writer);
@@ -60,11 +74,21 @@ class MockableQuicClient : public QuicClient {
const CachedNetworkParameters& cached_network_params) {
cached_network_paramaters_ = cached_network_params;
}
+ const QuicReceivedPacket* last_incoming_packet() {
+ return last_incoming_packet_.get();
+ }
+ void set_track_last_incoming_packet(bool track) {
+ track_last_incoming_packet_ = track;
+ }
private:
QuicConnectionId override_connection_id_; // ConnectionId to use, if nonzero
QuicPacketWriterWrapper* test_writer_;
CachedNetworkParameters cached_network_paramaters_;
+ // The last incoming packet, iff |track_last_incoming_packet_| is true.
+ std::unique_ptr<QuicReceivedPacket> last_incoming_packet_;
+ // If true, copy each packet from ProcessPacket into |last_incoming_packet_|
+ bool track_last_incoming_packet_;
DISALLOW_COPY_AND_ASSIGN(MockableQuicClient);
};
@@ -81,6 +105,11 @@ class QuicTestClient : public test::SimpleClient,
const std::string& server_hostname,
const QuicConfig& config,
const QuicVersionVector& supported_versions);
+ QuicTestClient(IPEndPoint server_address,
+ const std::string& server_hostname,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ std::unique_ptr<ProofVerifier> proof_verifier);
~QuicTestClient() override;
@@ -111,8 +140,7 @@ class QuicTestClient : public test::SimpleClient,
void Disconnect() override;
IPEndPoint local_address() const override;
void ClearPerRequestState() override;
- void WaitForResponseForMs(int timeout_ms) override;
- void WaitForInitialResponseForMs(int timeout_ms) override;
+ void WaitUntil(int timeout_ms, std::function<bool()> trigger) override;
ssize_t Send(const void* buffer, size_t size) override;
bool response_complete() const override;
bool response_headers_complete() const override;
@@ -157,6 +185,8 @@ class QuicTestClient : public test::SimpleClient,
// ConnectionId instead of a random one.
void UseConnectionId(QuicConnectionId connection_id);
+ // Update internal stream_ pointer and perform accompanying housekeeping.
+ void SetStream(QuicSpdyClientStream* stream);
// Returns nullptr if the maximum number of streams have already been created.
QuicSpdyClientStream* GetOrCreateStream();
@@ -202,6 +232,10 @@ class QuicTestClient : public test::SimpleClient,
size_t num_responses() const { return num_responses_; }
+ void set_server_address(const IPEndPoint& server_address) {
+ client_->set_server_address(server_address);
+ }
+
// Explicitly set the SNI value for this client, overriding the default
// behavior which extracts the SNI value from the request URL.
void OverrideSni(const std::string& sni) {
@@ -219,12 +253,12 @@ class QuicTestClient : public test::SimpleClient,
private:
class TestClientDataToResend : public QuicClient::QuicDataToResend {
public:
- TestClientDataToResend(BalsaHeaders* headers,
- StringPiece body,
+ TestClientDataToResend(std::unique_ptr<SpdyHeaderBlock> headers,
+ base::StringPiece body,
bool fin,
QuicTestClient* test_client,
QuicAckListenerInterface* delegate)
- : QuicClient::QuicDataToResend(headers, body, fin),
+ : QuicClient::QuicDataToResend(std::move(headers), body, fin),
test_client_(test_client),
delegate_(delegate) {}
@@ -257,6 +291,8 @@ class QuicTestClient : public test::SimpleClient,
SpdyPriority priority_;
std::string response_;
+ // bytes_read_ and bytes_written_ are updated only when stream_ is released;
+ // prefer bytes_read() and bytes_written() member functions.
uint64_t bytes_read_;
uint64_t bytes_written_;
// The number of uncompressed HTTP header bytes received.
diff --git a/chromium/net/tools/quic/test_tools/quic_test_server.cc b/chromium/net/tools/quic/test_tools/quic_test_server.cc
index 1edf41a448f..6c400a52fe3 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_server.cc
+++ b/chromium/net/tools/quic/test_tools/quic_test_server.cc
@@ -10,19 +10,19 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/tools/quic/quic_dispatcher.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
#include "net/tools/quic/quic_simple_server_session.h"
-#include "net/tools/quic/quic_simple_server_session_helper.h"
#include "net/tools/quic/quic_simple_server_stream.h"
namespace net {
@@ -34,7 +34,7 @@ class CustomStreamSession : public QuicSimpleServerSession {
const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
QuicTestServer::StreamFactory* factory,
@@ -75,21 +75,21 @@ class CustomStreamSession : public QuicSimpleServerSession {
QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned.
};
-class QuicTestDispatcher : public QuicDispatcher {
+class QuicTestDispatcher : public QuicSimpleDispatcher {
public:
QuicTestDispatcher(
const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
- const QuicVersionVector& versions,
+ QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
std::unique_ptr<QuicAlarmFactory> alarm_factory)
- : QuicDispatcher(config,
- crypto_config,
- versions,
- std::move(helper),
- std::move(session_helper),
- std::move(alarm_factory)),
+ : QuicSimpleDispatcher(config,
+ crypto_config,
+ version_manager,
+ std::move(helper),
+ std::move(session_helper),
+ std::move(alarm_factory)),
session_factory_(nullptr),
stream_factory_(nullptr),
crypto_stream_factory_(nullptr) {}
@@ -99,7 +99,7 @@ class QuicTestDispatcher : public QuicDispatcher {
base::AutoLock lock(factory_lock_);
if (session_factory_ == nullptr && stream_factory_ == nullptr &&
crypto_stream_factory_ == nullptr) {
- return QuicDispatcher::CreateQuicSession(id, client);
+ return QuicSimpleDispatcher::CreateQuicSession(id, client);
}
QuicConnection* connection = new QuicConnection(
id, client, helper(), alarm_factory(), CreatePerConnectionWriter(),
@@ -149,24 +149,24 @@ class QuicTestDispatcher : public QuicDispatcher {
QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned.
};
-QuicTestServer::QuicTestServer(ProofSource* proof_source)
- : QuicServer(proof_source) {}
+QuicTestServer::QuicTestServer(std::unique_ptr<ProofSource> proof_source)
+ : QuicServer(std::move(proof_source)) {}
-QuicTestServer::QuicTestServer(ProofSource* proof_source,
+QuicTestServer::QuicTestServer(std::unique_ptr<ProofSource> proof_source,
const QuicConfig& config,
const QuicVersionVector& supported_versions)
- : QuicServer(proof_source,
+ : QuicServer(std::move(proof_source),
config,
QuicCryptoServerConfig::ConfigOptions(),
supported_versions) {}
QuicDispatcher* QuicTestServer::CreateQuicDispatcher() {
return new QuicTestDispatcher(
- config(), &crypto_config(), supported_versions(),
+ config(), &crypto_config(), version_manager(),
std::unique_ptr<QuicEpollConnectionHelper>(new QuicEpollConnectionHelper(
epoll_server(), QuicAllocator::BUFFER_POOL)),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(epoll_server())));
}
@@ -191,7 +191,7 @@ ImmediateGoAwaySession::ImmediateGoAwaySession(
const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache)
: QuicSimpleServerSession(config,
diff --git a/chromium/net/tools/quic/test_tools/quic_test_server.h b/chromium/net/tools/quic/test_tools/quic_test_server.h
index 071466853e5..75084bc0455 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_server.h
+++ b/chromium/net/tools/quic/test_tools/quic_test_server.h
@@ -9,7 +9,7 @@
#include <string>
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_session.h"
+#include "net/quic/core/quic_session.h"
#include "net/tools/quic/quic_dispatcher.h"
#include "net/tools/quic/quic_server.h"
#include "net/tools/quic/quic_simple_server_session.h"
@@ -35,7 +35,7 @@ class QuicTestServer : public QuicServer {
const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache) = 0;
};
@@ -60,8 +60,8 @@ class QuicTestServer : public QuicServer {
QuicServerSessionBase* session) = 0;
};
- explicit QuicTestServer(ProofSource* proof_source);
- QuicTestServer(ProofSource* proof_source,
+ explicit QuicTestServer(std::unique_ptr<ProofSource> proof_source);
+ QuicTestServer(std::unique_ptr<ProofSource> proof_source,
const QuicConfig& config,
const QuicVersionVector& supported_versions);
@@ -91,7 +91,7 @@ class ImmediateGoAwaySession : public QuicSimpleServerSession {
ImmediateGoAwaySession(const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache);
// Override to send GoAway.
diff --git a/chromium/net/tools/quic/test_tools/server_thread.h b/chromium/net/tools/quic/test_tools/server_thread.h
index b907fd16010..898679dae4c 100644
--- a/chromium/net/tools/quic/test_tools/server_thread.h
+++ b/chromium/net/tools/quic/test_tools/server_thread.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "base/threading/simple_thread.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_config.h"
+#include "net/quic/core/quic_config.h"
#include "net/tools/quic/quic_server.h"
namespace net {
diff --git a/chromium/net/tools/quic/test_tools/simple_client.cc b/chromium/net/tools/quic/test_tools/simple_client.cc
index 3559da1375e..f6ac39f3c56 100644
--- a/chromium/net/tools/quic/test_tools/simple_client.cc
+++ b/chromium/net/tools/quic/test_tools/simple_client.cc
@@ -4,6 +4,8 @@
#include "net/tools/quic/test_tools/simple_client.h"
+#include "net/tools/balsa/balsa_headers.h"
+
namespace net {
namespace test {
@@ -16,6 +18,18 @@ void SimpleClient::WaitForInitialResponse() {
WaitForInitialResponseForMs(-1);
}
+void SimpleClient::WaitForResponseForMs(int timeout_ms) {
+ WaitUntil(timeout_ms, [this]() { return response_complete(); });
+ if (response_complete()) {
+ VLOG(1) << "Client received response:" << response_headers()->DebugString()
+ << response_body();
+ }
+}
+
+void SimpleClient::WaitForInitialResponseForMs(int timeout_ms) {
+ WaitUntil(timeout_ms, [this]() { return response_size() != 0; });
+}
+
int SimpleClient::ResetSocket() {
LOG(FATAL) << "SimpleClient::ResetSocket is not implemented";
return 0;
diff --git a/chromium/net/tools/quic/test_tools/simple_client.h b/chromium/net/tools/quic/test_tools/simple_client.h
index 3c5d02cfd0a..68b5c897d51 100644
--- a/chromium/net/tools/quic/test_tools/simple_client.h
+++ b/chromium/net/tools/quic/test_tools/simple_client.h
@@ -55,11 +55,13 @@ class SimpleClient {
// Returns once a complete response or a connection close has been received
// from the server, or once the timeout expires. -1 for no timeout.
- virtual void WaitForResponseForMs(int timeout_ms) = 0;
+ virtual void WaitForResponseForMs(int timeout_ms);
// Waits for some data or response from the server, or once the timeout
// expires. -1 for no timeout.
- virtual void WaitForInitialResponseForMs(int timeout_ms) = 0;
+ virtual void WaitForInitialResponseForMs(int timeout_ms);
+
+ virtual void WaitUntil(int timeout_ms, std::function<bool()> trigger) = 0;
// Clears any outstanding state from the last request.
virtual void ClearPerRequestState() = 0;