Landing Recent QUIC changes until 2015-11-09 20:32 UTC
Add client-side support of cert transparency for QUIC, gated at QUIC_VERSION_30.
With this change, when the negotiated version > QUIC_VERSION_29, the client indicates that it supports cert transparency in client hello, and caches the CSCT value if it exists in server's response. However, the client NEITHER demands SCT NOR verifies the received SCT (e.g., it is up to Chrome how to verify).
Merge internal change: 107397642
https://codereview.chromium.org/1435943002/
Not sending QUIC packets if the send alarm is set. Behind FLAGS_respect_send_alarm
This fixes a subtle bug where we weren't always respecting priorities when writing.
I posit that if we are send limited by the sent packet manager, we expect to
resume with OnCanWrite, and resume the highest priority session. Unfortunately
right now that's not the case. When the highest priority session gets blocked
by the sent packet manager it schedules the alarm. However it's perfectly
possible that before the alarm fires, we get an incoming request, process it,
that stream checks to see if it can write, and when CanWrite checks now(), we
are past the time when the alarm should have fired (due to doing a lot of work,
busy machine, what have you) and write data for the random stream.
Merge internal change: 107380116
https://codereview.chromium.org/1439653002/
Add token binding negotiation to QUIC
This adds a tag (TBKP) to the SCFG and CHLO messages containing a taglist as a value of the supported token binding key parameters (P256 is currently the only supported param). This replaces the TLS token binding negotiation extension as part of the broader Token Binding spec when done over QUIC.
Token binding negotiation is off by default - it must be turned on server-side in QuicCryptoServerConfig::ConfigOptions and client side in QuicCryptoClientConfig. If it is enabled, the application layer using QUIC must handle the rest of the Token Binding protocol.
More information (including links to the Token Binding specs) is in this doc: https://docs.google.com/document/d/12eKfkdC7g5IGUCtghzg7Wi__qiEkY65fX09n8sjLtHg/edit?pli=1#heading=h.y8fw05yhvdsg
Merge internal change: 107277639
https://codereview.chromium.org/1437893002/
Make comments for EndToEndTest.LargePostEarlyResponse more clear. Rearrange code to clarifying the logic when sending request header and body separately.
Merge internal change: 107261172
https://codereview.chromium.org/1433353002/
Further reduce the number of QUIC end-to-end test variations that we run from 54 to 30, by only running the version negotiation variants when either all or none of other options are enabled.
Among other things, this will help the perfomance of these test
in the Chrome memory bots.
Merge internal change: 107172676
https://codereview.chromium.org/1414953012/
Add some helper methods to QuicTestServer
Merge internal change: 107150707
https://codereview.chromium.org/1433813002/
Move the call to revive packets from QuicConnection::ProcessUdpPacket to QuicConnection::OnPacketComplete. This avoid hitting a DCHECK in the EndToEnd tests when: FEC is enabled, stateless rejects are enabled and packets are reordered.
Merge internal change: 107136813
https://codereview.chromium.org/1419303009/
Reduce the number of QUIC end-to-end test combinations that are from from 240 to 46, by looking at five of the options, and only running when either none of them, all of them or just one of them is enabled.
Merge internal change: 107135565
https://codereview.chromium.org/1418503022/
Clean up "magic" constants in QuicFramerTest to add comments which explains their values and extract out to named constants.
Merge internal change: 107036345
https://codereview.chromium.org/1435673002/
Replace QuicEncryptedPacket argument in QuicConnectionDebugVisitor::OnPacketSent with an encrypted length. No functional change.
Merge internal change: 107034442
https://codereview.chromium.org/1433783004/
Override ReliableQuicStream::StopReading() to send RST_STREAM+NO_ERROR if CloseWriteSide() is called before StopReading().
Currently we always call StopReading() before calling CloseWriteSide(). However, there is not restriction to prevent calling StopReading() after CloseWrite(), in which case we should also send a QUIC_STREAM_NO_ERROR rst to stop the peer to sending more data. This feature improves RST_STREAM+NO_ERROR mechanism to be more future-proof.
Merge internal change: 106990301
https://codereview.chromium.org/1433063002/
Update the comment of --quic_version.
Merge internal change: 106978852
https://codereview.chromium.org/1425823005/
Pass in connection ID and supported version to QuicFramer::BuildVersionNegotiationPacket, instead of passing in a QuicPacketHeader and supported versions.
Merge internal change: 106955386
https://codereview.chromium.org/1433703005/
Change bufferring data structure for QuicStreamSequencer. Protected by FLAGS_quic_use_stream_sequencer_buffer.
Swith QuicStreamSequencer's underlying data structure from QuicFrameList to StreamSequencerBuffer.
Merge internal change: 106947577
https://codereview.chromium.org/1433793002/
Add include to reflect what is already used.
Merge internal change: 106946658
https://codereview.chromium.org/1433013003/
Add a data structure QuicMultipathTransmissionsMap which is not in use now.
QuicMultipathTransmissionsMap manages packets which are transmitted across multiple paths. Also add a new struct QuicPathIdPacketNumber which comprises both QuicPathId and QuicPacketNumber.
Merge internal change: 106938391
https://codereview.chromium.org/1431363002/
Earlier check for nullptr.
Merge internal change: 106859834
https://codereview.chromium.org/1433783003/
Quic streams honor RST_STREAM + NO_ERROR on the write side.
Override QuicDataStream CloseWriteSide method to honor QUIC_STREAM_NO_ERROR on QUIC_VERSION_29 or later versions: send rst stream when writing to a stream initiated by the peer is finished but incoming data hasn't been received completely.
Merge internal change: 106853342
https://codereview.chromium.org/1413373013/
Add OnConnectionMigration method to QuicSentPacketManager. Add OnConnectionMigration interface to SendAlgorithmInterface and RttStats. No functional change expected.
This change is preparing to reset cwnd and rtt measurement when the client migrates to a different network.
Merge internal change: 106851267
https://codereview.chromium.org/1435553004/
Factoring a QuicCryptoServerStreamBase API out of QuicCryptoServerStream
Merge internal change: 106845785
https://codereview.chromium.org/1413613016/
Deprecate --gfe2_reloadable_flag_quic_stop_checking_for_mismatch_ids
Merge internal change: 106845547
https://codereview.chromium.org/1418963008/
No functional change. Minor change to reorder when the list of QuicAckListeners is swapped into the TransmissionInfo in order to avoid an extra allocation.
Merge internal change: 106814823
https://codereview.chromium.org/1428303003/
Review URL: https://codereview.chromium.org/1437023002
Cr-Commit-Position: refs/heads/master@{#359370}
diff --git a/net/net.gypi b/net/net.gypi
index 9d97fd1..070cf4f 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -345,6 +345,8 @@
'quic/quic_frame_list.h',
'quic/quic_framer.cc',
'quic/quic_framer.h',
+ 'quic/quic_multipath_transmissions_map.cc',
+ 'quic/quic_multipath_transmissions_map.h',
'quic/quic_packet_creator.cc',
'quic/quic_packet_creator.h',
'quic/quic_packet_generator.cc',
@@ -1542,6 +1544,7 @@
'quic/quic_headers_stream_test.cc',
'quic/quic_http_stream_test.cc',
'quic/quic_http_utils_test.cc',
+ 'quic/quic_multipath_transmissions_map_test.cc',
'quic/quic_network_transaction_unittest.cc',
'quic/quic_packet_creator_test.cc',
'quic/quic_packet_generator_test.cc',
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index f9c3f7b..bc59aec4 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -52,6 +52,7 @@
QuicByteCount bytes,
HasRetransmittableData is_retransmittable) override;
void OnRetransmissionTimeout(bool packets_retransmitted) override;
+ void OnConnectionMigration() override {}
QuicTime::Delta TimeUntilSend(
QuicTime now,
QuicByteCount bytes_in_flight,
diff --git a/net/quic/congestion_control/rtt_stats.h b/net/quic/congestion_control/rtt_stats.h
index a14cfcb..df1df773 100644
--- a/net/quic/congestion_control/rtt_stats.h
+++ b/net/quic/congestion_control/rtt_stats.h
@@ -38,6 +38,9 @@
// |num_samples| UpdateRtt calls.
void SampleNewRecentMinRtt(uint32 num_samples);
+ // Called when connection migrates and rtt measurement needs to be reset.
+ void OnConnectionMigration() {}
+
// Returns the EWMA smoothed RTT for the connection.
// May return Zero if no valid updates have occurred.
QuicTime::Delta smoothed_rtt() const {
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index f59def5f..4f090f91 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -75,6 +75,9 @@
// nor OnPacketLost will be called for these packets.
virtual void OnRetransmissionTimeout(bool packets_retransmitted) = 0;
+ // Called when connection migrates and cwnd needs to be reset.
+ virtual void OnConnectionMigration() = 0;
+
// Calculate the time until we can send the next packet.
virtual QuicTime::Delta TimeUntilSend(
QuicTime now,
diff --git a/net/quic/congestion_control/tcp_cubic_bytes_sender.h b/net/quic/congestion_control/tcp_cubic_bytes_sender.h
index 9040fb6..e340fcc 100644
--- a/net/quic/congestion_control/tcp_cubic_bytes_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_bytes_sender.h
@@ -54,6 +54,7 @@
QuicByteCount bytes,
HasRetransmittableData is_retransmittable) override;
void OnRetransmissionTimeout(bool packets_retransmitted) override;
+ void OnConnectionMigration() override {}
QuicTime::Delta TimeUntilSend(
QuicTime now,
QuicByteCount bytes_in_flight,
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index e4eb9081..723ab07 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -56,6 +56,7 @@
QuicByteCount bytes,
HasRetransmittableData is_retransmittable) override;
void OnRetransmissionTimeout(bool packets_retransmitted) override;
+ void OnConnectionMigration() override {}
QuicTime::Delta TimeUntilSend(
QuicTime now,
QuicByteCount bytes_in_flight,
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index 7676c8cc..26e69bc 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -14,6 +14,7 @@
QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
: key_exchange(0),
aead(0),
+ token_binding_key_param(0),
x509_ecdsa_supported(false),
x509_supported(false),
sct_supported_by_client(false) {}
diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h
index ef4fe22..2f432a40 100644
--- a/net/quic/crypto/crypto_handshake.h
+++ b/net/quic/crypto/crypto_handshake.h
@@ -129,6 +129,7 @@
// bytes of x coordinate, followed by 32 bytes of y coordinate. Both values
// are big-endian and the pair is a P-256 public key.
std::string channel_id;
+ QuicTag token_binding_key_param;
// Used when generating proof signature when sending server config updates.
bool x509_ecdsa_supported;
@@ -179,6 +180,10 @@
// Authenticated encryption with associated data (AEAD) algorithms.
QuicTagVector aead;
+ // Supported Token Binding key parameters that can be negotiated in the client
+ // hello.
+ QuicTagVector tb_key_params;
+
const CommonCertSets* common_cert_sets;
private:
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc
index 9cf25ad..d45b6aa1 100644
--- a/net/quic/crypto/crypto_handshake_message.cc
+++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -249,6 +249,7 @@
done = true;
}
break;
+ case kTBKP:
case kKEXS:
case kAEAD:
case kCOPT:
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 18dbc0c..84120805 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -147,6 +147,7 @@
// flow control receive window.
const QuicTag kUAID = TAG('U', 'A', 'I', 'D'); // Client's User Agent ID.
const QuicTag kXLCT = TAG('X', 'L', 'C', 'T'); // Expected leaf certificate.
+const QuicTag kTBKP = TAG('T', 'B', 'K', 'P'); // Token Binding key params.
// Rejection tags
const QuicTag kRREJ = TAG('R', 'R', 'E', 'J'); // Reasons for server sending
diff --git a/net/quic/crypto/crypto_utils.cc b/net/quic/crypto/crypto_utils.cc
index 555a2b9..67c1c38 100644
--- a/net/quic/crypto/crypto_utils.cc
+++ b/net/quic/crypto/crypto_utils.cc
@@ -201,4 +201,38 @@
return QUIC_NO_ERROR;
}
+QuicErrorCode CryptoUtils::ValidateClientHello(
+ const CryptoHandshakeMessage& client_hello,
+ QuicVersion version,
+ const QuicVersionVector& supported_versions,
+ string* error_details) {
+ if (client_hello.tag() != kCHLO) {
+ *error_details = "Bad tag";
+ return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
+ }
+
+ // If the client's preferred version is not the version we are currently
+ // speaking, then the client went through a version negotiation. In this
+ // case, we need to make sure that we actually do not support this version
+ // and that it wasn't a downgrade attack.
+ QuicTag client_version_tag;
+ if (client_hello.GetUint32(kVER, &client_version_tag) != QUIC_NO_ERROR) {
+ *error_details = "client hello missing version list";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ QuicVersion client_version = QuicTagToQuicVersion(client_version_tag);
+ if (client_version != version) {
+ // Just because client_version is a valid version enum doesn't mean that
+ // this server actually supports that version, so we check to see if
+ // it's actually in the supported versions list.
+ for (size_t i = 0; i < supported_versions.size(); ++i) {
+ if (client_version == supported_versions[i]) {
+ *error_details = "Downgrade attack detected";
+ return QUIC_VERSION_NEGOTIATION_MISMATCH;
+ }
+ }
+ }
+ return QUIC_NO_ERROR;
+}
+
} // namespace net
diff --git a/net/quic/crypto/crypto_utils.h b/net/quic/crypto/crypto_utils.h
index ff9c951..6d40074 100644
--- a/net/quic/crypto/crypto_utils.h
+++ b/net/quic/crypto/crypto_utils.h
@@ -85,6 +85,18 @@
const QuicVersionVector& negotiated_versions,
std::string* error_details);
+ // Validates that |client_hello| is actually a CHLO and that this is not part
+ // of a downgrade attack.
+ // This includes verifiying versions and detecting downgrade attacks.
+ //
+ // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
+ // code and sets |error_details|.
+ static QuicErrorCode ValidateClientHello(
+ const CryptoHandshakeMessage& client_hello,
+ QuicVersion version,
+ const QuicVersionVector& supported_versions,
+ std::string* error_details);
+
private:
DISALLOW_COPY_AND_ASSIGN(CryptoUtils);
};
diff --git a/net/quic/crypto/proof_test.cc b/net/quic/crypto/proof_test.cc
index d24c9e0..3a7db6fb 100644
--- a/net/quic/crypto/proof_test.cc
+++ b/net/quic/crypto/proof_test.cc
@@ -72,7 +72,7 @@
new TestProofVerifierCallback(&comp_callback, &ok, &error_details);
QuicAsyncStatus status = verifier->VerifyProof(
- hostname, server_config, certs, proof, verify_context.get(),
+ hostname, server_config, certs, "", proof, verify_context.get(),
&error_details, &details, callback);
switch (status) {
diff --git a/net/quic/crypto/proof_verifier.h b/net/quic/crypto/proof_verifier.h
index 87339da4..0ec346a 100644
--- a/net/quic/crypto/proof_verifier.h
+++ b/net/quic/crypto/proof_verifier.h
@@ -76,6 +76,7 @@
virtual QuicAsyncStatus VerifyProof(const std::string& hostname,
const std::string& server_config,
const std::vector<std::string>& certs,
+ const std::string& cert_sct,
const std::string& signature,
const ProofVerifyContext* context,
std::string* error_details,
diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc
index 8defdad..68f2286 100644
--- a/net/quic/crypto/proof_verifier_chromium.cc
+++ b/net/quic/crypto/proof_verifier_chromium.cc
@@ -58,6 +58,7 @@
QuicAsyncStatus VerifyProof(const std::string& hostname,
const std::string& server_config,
const std::vector<std::string>& certs,
+ const std::string& cert_sct,
const std::string& signature,
std::string* error_details,
scoped_ptr<ProofVerifyDetails>* verify_details,
@@ -130,6 +131,7 @@
const string& hostname,
const string& server_config,
const vector<string>& certs,
+ const std::string& cert_sct,
const string& signature,
std::string* error_details,
scoped_ptr<ProofVerifyDetails>* verify_details,
@@ -382,6 +384,7 @@
const std::string& hostname,
const std::string& server_config,
const std::vector<std::string>& certs,
+ const std::string& cert_sct,
const std::string& signature,
const ProofVerifyContext* verify_context,
std::string* error_details,
@@ -397,8 +400,8 @@
this, cert_verifier_, cert_policy_enforcer_, transport_security_state_,
chromium_context->cert_verify_flags, chromium_context->net_log));
QuicAsyncStatus status =
- job->VerifyProof(hostname, server_config, certs, signature, error_details,
- verify_details, callback);
+ job->VerifyProof(hostname, server_config, certs, cert_sct, signature,
+ error_details, verify_details, callback);
if (status == QUIC_PENDING) {
active_jobs_.insert(job.release());
}
diff --git a/net/quic/crypto/proof_verifier_chromium.h b/net/quic/crypto/proof_verifier_chromium.h
index 46d63e1..77a6714 100644
--- a/net/quic/crypto/proof_verifier_chromium.h
+++ b/net/quic/crypto/proof_verifier_chromium.h
@@ -65,6 +65,7 @@
QuicAsyncStatus VerifyProof(const std::string& hostname,
const std::string& server_config,
const std::vector<std::string>& certs,
+ const std::string& cert_sct,
const std::string& signature,
const ProofVerifyContext* verify_context,
std::string* error_details,
diff --git a/net/quic/crypto/proof_verifier_chromium_test.cc b/net/quic/crypto/proof_verifier_chromium_test.cc
index 9e0f598..9a7f0db 100644
--- a/net/quic/crypto/proof_verifier_chromium_test.cc
+++ b/net/quic/crypto/proof_verifier_chromium_test.cc
@@ -161,7 +161,7 @@
DummyProofVerifierCallback* callback = new DummyProofVerifierCallback;
QuicAsyncStatus status = proof_verifier.VerifyProof(
- kTestHostname, kTestConfig, certs, GetTestSignature(),
+ kTestHostname, kTestConfig, certs, "", GetTestSignature(),
verify_context.get(), &error_details, &details, callback);
ASSERT_EQ(QUIC_FAILURE, status);
delete callback;
@@ -183,7 +183,7 @@
DummyProofVerifierCallback* callback = new DummyProofVerifierCallback;
QuicAsyncStatus status = proof_verifier.VerifyProof(
- kTestHostname, kTestConfig, certs, kTestConfig, verify_context.get(),
+ kTestHostname, kTestConfig, certs, "", kTestConfig, verify_context.get(),
&error_details, &details, callback);
ASSERT_EQ(QUIC_FAILURE, status);
delete callback;
@@ -214,7 +214,7 @@
DummyProofVerifierCallback* callback = new DummyProofVerifierCallback;
QuicAsyncStatus status = proof_verifier.VerifyProof(
- kTestHostname, kTestConfig, certs, GetTestSignature(),
+ kTestHostname, kTestConfig, certs, "", GetTestSignature(),
verify_context.get(), &error_details, &details, callback);
ASSERT_EQ(QUIC_SUCCESS, status);
delete callback;
@@ -254,7 +254,7 @@
DummyProofVerifierCallback* callback = new DummyProofVerifierCallback;
QuicAsyncStatus status = proof_verifier.VerifyProof(
- kTestHostname, kTestConfig, certs, GetTestSignature(),
+ kTestHostname, kTestConfig, certs, "", GetTestSignature(),
verify_context.get(), &error_details, &details, callback);
ASSERT_EQ(QUIC_SUCCESS, status);
delete callback;
@@ -294,7 +294,7 @@
DummyProofVerifierCallback* callback = new DummyProofVerifierCallback;
QuicAsyncStatus status = proof_verifier.VerifyProof(
- kTestHostname, kTestConfig, certs, GetTestSignature(),
+ kTestHostname, kTestConfig, certs, "", GetTestSignature(),
verify_context.get(), &error_details, &details, callback);
ASSERT_EQ(QUIC_SUCCESS, status);
delete callback;
@@ -335,7 +335,7 @@
DummyProofVerifierCallback* callback = new DummyProofVerifierCallback;
QuicAsyncStatus status = proof_verifier.VerifyProof(
- kTestHostname, kTestConfig, certs, GetTestSignature(),
+ kTestHostname, kTestConfig, certs, "", GetTestSignature(),
verify_context.get(), &error_details, &details, callback);
ASSERT_EQ(QUIC_SUCCESS, status);
delete callback;
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index b9b0bcd4..0eb5e371 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -188,6 +188,7 @@
}
void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
+ StringPiece cert_sct,
StringPiece signature) {
bool has_changed =
signature != server_config_sig_ || certs_.size() != certs.size();
@@ -208,6 +209,7 @@
// If the proof has changed then it needs to be revalidated.
SetProofInvalid();
certs_ = certs;
+ cert_sct_ = cert_sct.as_string();
server_config_sig_ = signature.as_string();
}
@@ -215,6 +217,7 @@
server_config_.clear();
source_address_token_.clear();
certs_.clear();
+ cert_sct_.clear();
server_config_sig_.clear();
server_config_valid_ = false;
proof_verify_details_.reset();
@@ -227,6 +230,7 @@
void QuicCryptoClientConfig::CachedState::ClearProof() {
SetProofInvalid();
certs_.clear();
+ cert_sct_.clear();
server_config_sig_.clear();
}
@@ -243,6 +247,7 @@
StringPiece server_config,
StringPiece source_address_token,
const vector<string>& certs,
+ const string& cert_sct,
StringPiece signature,
QuicWallTime now) {
DCHECK(server_config_.empty());
@@ -264,6 +269,7 @@
signature.CopyToString(&server_config_sig_);
source_address_token.CopyToString(&source_address_token_);
certs_ = certs;
+ cert_sct_ = cert_sct;
return true;
}
@@ -280,6 +286,10 @@
return certs_;
}
+const string& QuicCryptoClientConfig::CachedState::cert_sct() const {
+ return cert_sct_;
+}
+
const string& QuicCryptoClientConfig::CachedState::signature() const {
return server_config_sig_;
}
@@ -302,6 +312,10 @@
source_address_token_ = token.as_string();
}
+void QuicCryptoClientConfig::CachedState::set_cert_sct(StringPiece cert_sct) {
+ cert_sct_ = cert_sct.as_string();
+}
+
void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
ProofVerifyDetails* details) {
proof_verify_details_.reset(details);
@@ -314,6 +328,7 @@
server_config_ = other.server_config_;
source_address_token_ = other.source_address_token_;
certs_ = other.certs_;
+ cert_sct_ = other.cert_sct_;
server_config_sig_ = other.server_config_sig_;
server_config_valid_ = other.server_config_valid_;
server_designated_connection_ids_ = other.server_designated_connection_ids_;
@@ -419,6 +434,10 @@
out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
}
+ if (preferred_version > QUIC_VERSION_29) {
+ out->SetStringPiece(kCertificateSCTTag, "");
+ }
+
const vector<string>& certs = cached->certs();
// We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
// client config is being used for multiple connections, another connection
@@ -467,6 +486,10 @@
}
out->SetStringPiece(kSCID, scid);
+ if (preferred_version > QUIC_VERSION_29) {
+ out->SetStringPiece(kCertificateSCTTag, "");
+ }
+
const QuicTag* their_aeads;
const QuicTag* their_key_exchanges;
size_t num_their_aeads, num_their_key_exchanges;
@@ -497,6 +520,26 @@
out->SetTaglist(kAEAD, out_params->aead, 0);
out->SetTaglist(kKEXS, out_params->key_exchange, 0);
+ if (!tb_key_params.empty()) {
+ const QuicTag* their_tbkps;
+ size_t num_their_tbkps;
+ switch (scfg->GetTaglist(kTBKP, &their_tbkps, &num_their_tbkps)) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ break;
+ case QUIC_NO_ERROR:
+ if (QuicUtils::FindMutualTag(tb_key_params, their_tbkps,
+ num_their_tbkps, QuicUtils::LOCAL_PRIORITY,
+ &out_params->token_binding_key_param,
+ nullptr)) {
+ out->SetTaglist(kTBKP, out_params->token_binding_key_param, 0);
+ }
+ break;
+ default:
+ *error_details = "Invalid TBKP";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ }
+
StringPiece public_value;
if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) !=
QUIC_NO_ERROR) {
@@ -645,6 +688,7 @@
QuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig(
const CryptoHandshakeMessage& message,
QuicWallTime now,
+ const QuicVersion version,
const vector<string>& cached_certs,
CachedState* cached,
string* error_details) {
@@ -672,7 +716,7 @@
cached->set_source_address_token(token);
}
- StringPiece proof, cert_bytes;
+ StringPiece proof, cert_bytes, cert_sct;
bool has_proof = message.GetStringPiece(kPROF, &proof);
bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes);
if (has_proof && has_cert) {
@@ -683,7 +727,10 @@
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
- cached->SetProof(certs, proof);
+ if (version > QUIC_VERSION_29) {
+ message.GetStringPiece(kCertificateSCTTag, &cert_sct);
+ }
+ cached->SetProof(certs, cert_sct, proof);
} else {
// Secure QUIC: clear existing proof as we have been sent a new SCFG
// without matching proof/certs.
@@ -706,6 +753,7 @@
QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
const CryptoHandshakeMessage& rej,
QuicWallTime now,
+ const QuicVersion version,
CachedState* cached,
QuicCryptoNegotiatedParameters* out_params,
string* error_details) {
@@ -716,8 +764,8 @@
return QUIC_CRYPTO_INTERNAL_ERROR;
}
- QuicErrorCode error = CacheNewServerConfig(rej, now, out_params->cached_certs,
- cached, error_details);
+ QuicErrorCode error = CacheNewServerConfig(
+ rej, now, version, out_params->cached_certs, cached, error_details);
if (error != QUIC_NO_ERROR) {
return error;
}
@@ -829,6 +877,7 @@
QuicErrorCode QuicCryptoClientConfig::ProcessServerConfigUpdate(
const CryptoHandshakeMessage& server_config_update,
QuicWallTime now,
+ const QuicVersion version,
CachedState* cached,
QuicCryptoNegotiatedParameters* out_params,
string* error_details) {
@@ -838,8 +887,7 @@
*error_details = "ServerConfigUpdate must have kSCUP tag.";
return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
}
-
- return CacheNewServerConfig(server_config_update, now,
+ return CacheNewServerConfig(server_config_update, now, version,
out_params->cached_certs, cached, error_details);
}
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h
index 3ab50954..6a2085f 100644
--- a/net/quic/crypto/quic_crypto_client_config.h
+++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -82,6 +82,7 @@
// SetProof stores a certificate chain and signature.
void SetProof(const std::vector<std::string>& certs,
+ base::StringPiece cert_sct,
base::StringPiece signature);
// Clears all the data.
@@ -103,6 +104,7 @@
const std::string& server_config() const;
const std::string& source_address_token() const;
const std::vector<std::string>& certs() const;
+ const std::string& cert_sct() const;
const std::string& signature() const;
bool proof_valid() const;
uint64 generation_counter() const;
@@ -110,6 +112,8 @@
void set_source_address_token(base::StringPiece token);
+ void set_cert_sct(base::StringPiece cert_sct);
+
// Adds the connection ID to the queue of server-designated connection-ids.
void add_server_designated_connection_id(QuicConnectionId connection_id);
@@ -150,6 +154,7 @@
bool Initialize(base::StringPiece server_config,
base::StringPiece source_address_token,
const std::vector<std::string>& certs,
+ const std::string& cert_sct,
base::StringPiece signature,
QuicWallTime now);
@@ -158,6 +163,7 @@
std::string source_address_token_; // An opaque proof of IP ownership.
std::vector<std::string> certs_; // A list of certificates in leaf-first
// order.
+ std::string cert_sct_; // Signed timestamp of the leaf cert.
std::string server_config_sig_; // A signature of |server_config_|.
bool server_config_valid_; // True if |server_config_| is correctly
// signed and |certs_| has been
@@ -238,6 +244,7 @@
// reject reason for secure vs insecure QUIC.
QuicErrorCode ProcessRejection(const CryptoHandshakeMessage& rej,
QuicWallTime now,
+ QuicVersion version,
CachedState* cached,
QuicCryptoNegotiatedParameters* out_params,
std::string* error_details);
@@ -267,6 +274,7 @@
QuicErrorCode ProcessServerConfigUpdate(
const CryptoHandshakeMessage& server_update,
QuicWallTime now,
+ const QuicVersion version,
CachedState* cached,
QuicCryptoNegotiatedParameters* out_params,
std::string* error_details);
@@ -322,6 +330,7 @@
QuicErrorCode CacheNewServerConfig(
const CryptoHandshakeMessage& message,
QuicWallTime now,
+ const QuicVersion version,
const std::vector<std::string>& cached_certs,
CachedState* cached,
std::string* error_details);
diff --git a/net/quic/crypto/quic_crypto_client_config_test.cc b/net/quic/crypto/quic_crypto_client_config_test.cc
index 205ebf84..238011f 100644
--- a/net/quic/crypto/quic_crypto_client_config_test.cc
+++ b/net/quic/crypto/quic_crypto_client_config_test.cc
@@ -319,7 +319,7 @@
// TODO(rch): Populate other fields of |state|.
vector<string> certs(1);
certs[0] = "Hello Cert";
- state->SetProof(certs, "signature");
+ state->SetProof(certs, "cert_sct", "signature");
state->set_source_address_token("TOKEN");
state->SetProofValid();
EXPECT_EQ(1u, state->generation_counter());
@@ -341,6 +341,7 @@
EXPECT_FALSE(cleared_cache->proof_valid());
EXPECT_TRUE(cleared_cache->server_config().empty());
EXPECT_TRUE(cleared_cache->certs().empty());
+ EXPECT_TRUE(cleared_cache->cert_sct().empty());
EXPECT_TRUE(cleared_cache->signature().empty());
EXPECT_EQ(2u, cleared_cache->generation_counter());
}
@@ -388,9 +389,10 @@
QuicCryptoNegotiatedParameters out_params;
string error;
QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection(
- rej, QuicWallTime::FromUNIXSeconds(0), &cached,
- &out_params, &error));
+ EXPECT_EQ(QUIC_NO_ERROR,
+ config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
+ QuicSupportedVersions().front(), &cached,
+ &out_params, &error));
EXPECT_FALSE(cached.has_server_designated_connection_id());
EXPECT_FALSE(cached.has_server_nonce());
}
@@ -409,9 +411,10 @@
QuicCryptoNegotiatedParameters out_params;
string error;
QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection(
- rej, QuicWallTime::FromUNIXSeconds(0), &cached,
- &out_params, &error));
+ EXPECT_EQ(QUIC_NO_ERROR,
+ config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
+ QuicSupportedVersions().front(), &cached,
+ &out_params, &error));
EXPECT_TRUE(cached.has_server_designated_connection_id());
EXPECT_EQ(kConnectionId, cached.GetNextServerDesignatedConnectionId());
EXPECT_EQ(server_nonce, cached.GetNextServerNonce());
@@ -428,10 +431,10 @@
QuicCryptoNegotiatedParameters out_params;
string error;
QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- EXPECT_EQ(
- QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
- config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), &cached,
- &out_params, &error));
+ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
+ config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
+ QuicSupportedVersions().front(), &cached,
+ &out_params, &error));
EXPECT_FALSE(cached.has_server_designated_connection_id());
EXPECT_EQ("Missing kRCID", error);
}
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc
index c523dd4..e4c052f 100644
--- a/net/quic/crypto/quic_crypto_server_config.cc
+++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -205,6 +205,7 @@
QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
: expiry_time(QuicWallTime::Zero()),
channel_id_enabled(false),
+ token_binding_enabled(false),
p256(false) {}
QuicCryptoServerConfig::QuicCryptoServerConfig(
@@ -322,6 +323,10 @@
msg.SetTaglist(kPDMD, kCHID, 0);
}
+ if (options.token_binding_enabled) {
+ msg.SetTaglist(kTBKP, kP256, 0);
+ }
+
if (options.id.empty()) {
// We need to ensure that the SCID changes whenever the server config does
// thus we make it a hash of the rest of the server config.
@@ -547,27 +552,10 @@
validate_chlo_result.client_hello;
const ClientHelloInfo& info = validate_chlo_result.info;
- // If the client's preferred version is not the version we are currently
- // speaking, then the client went through a version negotiation. In this
- // case, we need to make sure that we actually do not support this version
- // and that it wasn't a downgrade attack.
- QuicTag client_version_tag;
- if (client_hello.GetUint32(kVER, &client_version_tag) != QUIC_NO_ERROR) {
- *error_details = "client hello missing version list";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- QuicVersion client_version = QuicTagToQuicVersion(client_version_tag);
- if (client_version != version) {
- // Just because client_version is a valid version enum doesn't mean that
- // this server actually supports that version, so we check to see if
- // it's actually in the supported versions list.
- for (size_t i = 0; i < supported_versions.size(); ++i) {
- if (client_version == supported_versions[i]) {
- *error_details = "Downgrade attack detected";
- return QUIC_VERSION_NEGOTIATION_MISMATCH;
- }
- }
- }
+ QuicErrorCode valid = CryptoUtils::ValidateClientHello(
+ client_hello, version, supported_versions, error_details);
+ if (valid != QUIC_NO_ERROR)
+ return valid;
StringPiece requested_scid;
client_hello.GetStringPiece(kSCID, &requested_scid);
@@ -658,6 +646,25 @@
return QUIC_CRYPTO_NO_SUPPORT;
}
+ if (!requested_config->tb_key_params.empty()) {
+ const QuicTag* their_tbkps;
+ size_t num_their_tbkps;
+ switch (client_hello.GetTaglist(kTBKP, &their_tbkps, &num_their_tbkps)) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ break;
+ case QUIC_NO_ERROR:
+ if (QuicUtils::FindMutualTag(
+ requested_config->tb_key_params, their_tbkps, num_their_tbkps,
+ QuicUtils::LOCAL_PRIORITY, ¶ms->token_binding_key_param,
+ nullptr)) {
+ break;
+ }
+ default:
+ *error_details = "Invalid Token Binding key parameter";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ }
+
StringPiece public_value;
if (!client_hello.GetStringPiece(kPUBS, &public_value)) {
*error_details = "Missing public value";
@@ -1318,6 +1325,17 @@
return nullptr;
}
+ const QuicTag* tbkp_tags;
+ size_t tbkp_len;
+ QuicErrorCode err;
+ if ((err = msg->GetTaglist(kTBKP, &tbkp_tags, &tbkp_len)) !=
+ QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND &&
+ err != QUIC_NO_ERROR) {
+ LOG(WARNING) << "Server config message is missing or has invalid TBKP";
+ return nullptr;
+ }
+ config->tb_key_params = vector<QuicTag>(tbkp_tags, tbkp_tags + tbkp_len);
+
StringPiece orbit;
if (!msg->GetStringPiece(kORBT, &orbit)) {
LOG(WARNING) << "Server config message is missing ORBT";
diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h
index 3bf6d7c..c35eca4 100644
--- a/net/quic/crypto/quic_crypto_server_config.h
+++ b/net/quic/crypto/quic_crypto_server_config.h
@@ -125,6 +125,9 @@
// channel_id_enabled controls whether the server config will indicate
// support for ChannelIDs.
bool channel_id_enabled;
+ // token_binding_enabled controls whether the server config will indicate
+ // support for Token Binding.
+ bool token_binding_enabled;
// id contains the server config id for the resulting config. If empty, a
// random id is generated.
std::string id;
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc
index a2f0eaf..cf7d74e 100644
--- a/net/quic/quic_chromium_client_session_test.cc
+++ b/net/quic/quic_chromium_client_session_test.cc
@@ -91,8 +91,9 @@
void CompleteCryptoHandshake() {
ASSERT_EQ(ERR_IO_PENDING,
session_.CryptoConnect(false, callback_.callback()));
- CryptoTestUtils::HandshakeWithFakeServer(&helper_, connection_,
- session_.GetCryptoStream());
+ CryptoTestUtils::FakeServerOptions server_options;
+ CryptoTestUtils::HandshakeWithFakeServer(
+ &helper_, connection_, session_.GetCryptoStream(), server_options);
ASSERT_EQ(OK, callback_.WaitForResult());
}
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index fc68aa4c..79d5131 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -1162,6 +1162,12 @@
packet_generator_.AddControlFrame(QuicFrame(new QuicRstStreamFrame(
id, AdjustErrorForVersion(error, version()), bytes_written)));
+ if (error == QUIC_STREAM_NO_ERROR && version() > QUIC_VERSION_28) {
+ // All data for streams which are reset with QUIC_STREAM_NO_ERROR must
+ // be received by the peer.
+ return;
+ }
+
sent_packet_manager_.CancelRetransmissionsForStream(id);
// Remove all queued packets which only contain data for the reset stream.
QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
@@ -1363,6 +1369,7 @@
<< peer_address_.ToString() << ", migrating connection.";
visitor_->OnConnectionMigration();
+ sent_packet_manager_.OnConnectionMigration(type);
}
time_of_last_received_packet_ = clock_->Now();
@@ -1467,6 +1474,11 @@
return false;
}
+ // If the send alarm is set, wait for it to fire.
+ if (FLAGS_respect_send_alarm && send_alarm_->IsSet()) {
+ return false;
+ }
+
QuicTime now = clock_->Now();
QuicTime::Delta delay = sent_packet_manager_.TimeUntilSend(
now, retransmittable);
@@ -1482,7 +1494,9 @@
<< "ms";
return false;
}
- send_alarm_->Cancel();
+ if (!FLAGS_respect_send_alarm) {
+ send_alarm_->Cancel();
+ }
return true;
}
@@ -1578,8 +1592,8 @@
// Pass the write result to the visitor.
debug_visitor_->OnPacketSent(
packet->serialized_packet, packet->original_packet_number,
- packet->encryption_level, packet->transmission_type, *encrypted,
- packet_send_time);
+ packet->encryption_level, packet->transmission_type,
+ encrypted->length(), packet_send_time);
}
if (packet->transmission_type == NOT_RETRANSMISSION) {
time_of_last_sent_new_packet_ = packet_send_time;
@@ -1979,11 +1993,11 @@
return;
}
connected_ = false;
+ DCHECK(visitor_ != nullptr);
+ visitor_->OnConnectionClosed(error, from_peer);
if (debug_visitor_ != nullptr) {
debug_visitor_->OnConnectionClosed(error, from_peer);
}
- DCHECK(visitor_ != nullptr);
- visitor_->OnConnectionClosed(error, from_peer);
// Cancel the alarms so they don't trigger any action now that the
// connection is closed.
ack_alarm_->Cancel();
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 6a9d162..45b079c 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -158,7 +158,7 @@
QuicPacketNumber original_packet_number,
EncryptionLevel level,
TransmissionType transmission_type,
- const QuicEncryptedPacket& packet,
+ size_t encrypted_length,
QuicTime sent_time) {}
// Called when a packet has been received, but before it is
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index d5dc67d5..b1446a4 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -438,13 +438,13 @@
QuicPacketNumber original_packet_number,
EncryptionLevel level,
TransmissionType transmission_type,
- const QuicEncryptedPacket& packet,
+ size_t encrypted_length,
QuicTime sent_time) {
if (original_packet_number == 0) {
net_log_.AddEvent(
NetLog::TYPE_QUIC_SESSION_PACKET_SENT,
- base::Bind(&NetLogQuicPacketSentCallback, serialized_packet,
- level, transmission_type, packet.length(), sent_time));
+ base::Bind(&NetLogQuicPacketSentCallback, serialized_packet, level,
+ transmission_type, encrypted_length, sent_time));
} else {
net_log_.AddEvent(
NetLog::TYPE_QUIC_SESSION_PACKET_RETRANSMITTED,
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 9e687f2..358bd80 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -44,7 +44,7 @@
QuicPacketNumber original_packet_number,
EncryptionLevel level,
TransmissionType transmission_type,
- const QuicEncryptedPacket& packet,
+ size_t encrypted_length,
QuicTime sent_time) override;
void OnPacketReceived(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index e79ed5a..15dd943 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -2426,7 +2426,7 @@
connection_.SendStreamDataWithString(stream_id, "foo", 0, !kFin, nullptr);
// Now that there is a queued packet, reset the stream.
- connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+ connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
// Unblock the connection and verify that only the RST_STREAM is sent.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
@@ -2436,6 +2436,30 @@
EXPECT_EQ(1u, writer_->rst_stream_frames().size());
}
+TEST_P(QuicConnectionTest, SendQueuedPacketForQuicRstStreamNoError) {
+ // Block the connection to queue the packet.
+ BlockOnNextWrite();
+
+ QuicStreamId stream_id = 2;
+ connection_.SendStreamDataWithString(stream_id, "foo", 0, !kFin, nullptr);
+
+ // Now that there is a queued packet, reset the stream.
+ connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+
+ // Unblock the connection and verify that the RST_STREAM is sent and the data
+ // packet is sent on QUIC_VERSION_29 or later versions.
+ if (version() > QUIC_VERSION_28) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AtLeast(2));
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ }
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->rst_stream_frames().size());
+}
+
TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnNack) {
QuicStreamId stream_id = 2;
QuicPacketNumber last_packet;
@@ -2444,7 +2468,7 @@
SendStreamDataToPeer(stream_id, "fooos", 7, !kFin, &last_packet);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+ connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
// Lose a packet and ensure it does not trigger retransmission.
QuicAckFrame nack_two = InitAckFrame(last_packet);
@@ -2459,16 +2483,68 @@
ProcessAckPacket(&nack_two);
}
+TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnNack) {
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
+ SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
+ SendStreamDataToPeer(stream_id, "fooos", 7, !kFin, &last_packet);
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+
+ // Lose a packet, ensure it triggers retransmission on QUIC_VERSION_29
+ // or later versions.
+ QuicAckFrame nack_two = InitAckFrame(last_packet);
+ NackPacket(last_packet - 1, &nack_two);
+ PacketNumberSet lost_packets;
+ lost_packets.insert(last_packet - 1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
+ .WillOnce(Return(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ if (version() > QUIC_VERSION_28) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AtLeast(1));
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
+ ProcessAckPacket(&nack_two);
+}
+
TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnRTO) {
QuicStreamId stream_id = 2;
QuicPacketNumber last_packet;
SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
+
+ // Fire the RTO and verify that the RST_STREAM is resent, not stream data.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->rst_stream_frames().size());
+ EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
+}
+
+TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnRTO) {
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
- // Fire the RTO and verify that the RST_STREAM is resent, not stream data.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ // Fire the RTO and verify that the RST_STREAM is resent, the stream data
+ // is only sent on QUIC_VERSION_29 or later versions.
+ if (version() > QUIC_VERSION_28) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AtLeast(2));
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ }
clock_.AdvanceTime(DefaultRetransmissionTime());
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_EQ(1u, writer_->frame_count());
@@ -2496,7 +2572,7 @@
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
ProcessAckPacket(&ack);
- connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+ connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
// Unblock the connection and verify that the RST_STREAM is sent but not the
// second data packet nor a retransmit.
@@ -2508,6 +2584,48 @@
EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
}
+TEST_P(QuicConnectionTest, SendPendingRetransmissionForQuicRstStreamNoError) {
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
+ SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
+ BlockOnNextWrite();
+ connection_.SendStreamDataWithString(stream_id, "fooos", 7, !kFin, nullptr);
+
+ // Lose a packet which will trigger a pending retransmission.
+ QuicAckFrame ack = InitAckFrame(last_packet);
+ NackPacket(last_packet - 1, &ack);
+ PacketNumberSet lost_packets;
+ lost_packets.insert(last_packet - 1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
+ .WillOnce(Return(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ ProcessAckPacket(&ack);
+
+ connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+
+ // Unblock the connection and verify that the RST_STREAM is sent and the
+ // second data packet or a retransmit is only sent on QUIC_VERSION_29 or
+ // later versions.
+ if (version() > QUIC_VERSION_28) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AtLeast(2));
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ }
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_EQ(1u, writer_->frame_count());
+ if (version() > QUIC_VERSION_28) {
+ EXPECT_EQ(0u, writer_->rst_stream_frames().size());
+ } else {
+ EXPECT_EQ(1u, writer_->rst_stream_frames().size());
+ EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
+ }
+}
+
TEST_P(QuicConnectionTest, DiscardRetransmit) {
QuicPacketNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
@@ -4551,24 +4669,17 @@
QuicConnectionPeer::GetFramer(&connection_)->set_version_for_tests(
QUIC_VERSION_UNSUPPORTED);
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.public_header.version_flag = true;
- header.packet_number = 12;
-
- QuicVersionVector supported_versions;
- for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
- supported_versions.push_back(kSupportedQuicVersions[i]);
- }
-
// Send a version negotiation packet.
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer_.BuildVersionNegotiationPacket(
- header.public_header, supported_versions));
+ framer_.BuildVersionNegotiationPacket(connection_id_,
+ QuicSupportedVersions()));
connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *encrypted);
// Now force another packet. The connection should transition into
// NEGOTIATED_VERSION state and tell the packet creator to StopSendingVersion.
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.packet_number = 12;
header.public_header.version_flag = false;
QuicFrames frames;
frames.push_back(QuicFrame(&frame1_));
@@ -4587,24 +4698,14 @@
}
TEST_P(QuicConnectionTest, BadVersionNegotiation) {
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.public_header.version_flag = true;
- header.packet_number = 12;
-
- QuicVersionVector supported_versions;
- for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
- supported_versions.push_back(kSupportedQuicVersions[i]);
- }
-
// Send a version negotiation packet with the version the client started with.
// It should be rejected.
EXPECT_CALL(visitor_,
OnConnectionClosed(QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
false));
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer_.BuildVersionNegotiationPacket(
- header.public_header, supported_versions));
+ framer_.BuildVersionNegotiationPacket(connection_id_,
+ QuicSupportedVersions()));
connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *encrypted);
}
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 98668e2..7783a257 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -155,10 +155,8 @@
QuicCryptoClientConfig::CachedState* cached =
crypto_config_->LookupOrCreate(server_id_);
QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
- server_config_update,
- session()->connection()->clock()->WallNow(),
- cached,
- &crypto_negotiated_params_,
+ server_config_update, session()->connection()->clock()->WallNow(),
+ session()->connection()->version(), cached, &crypto_negotiated_params_,
&error_details);
if (error != QUIC_NO_ERROR) {
@@ -370,8 +368,9 @@
stateless_reject_received_ = in->tag() == kSREJ;
string error_details;
QuicErrorCode error = crypto_config_->ProcessRejection(
- *in, session()->connection()->clock()->WallNow(), cached,
- &crypto_negotiated_params_, &error_details);
+ *in, session()->connection()->clock()->WallNow(),
+ session()->connection()->version(), cached, &crypto_negotiated_params_,
+ &error_details);
if (error != QUIC_NO_ERROR) {
next_state_ = STATE_NONE;
@@ -406,8 +405,8 @@
QuicAsyncStatus status = verifier->VerifyProof(
server_id_.host(), cached->server_config(), cached->certs(),
- cached->signature(), verify_context_.get(), &verify_error_details_,
- &verify_details_, proof_verify_callback);
+ cached->cert_sct(), cached->signature(), verify_context_.get(),
+ &verify_error_details_, &verify_details_, proof_verify_callback);
switch (status) {
case QUIC_PENDING:
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index eccf3392..8c88880 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -46,7 +46,8 @@
void CompleteCryptoHandshake() {
stream()->CryptoConnect();
- CryptoTestUtils::HandshakeWithFakeServer(&helper_, connection_, stream());
+ CryptoTestUtils::HandshakeWithFakeServer(&helper_, connection_, stream(),
+ server_options_);
}
void ConstructHandshakeMessage() {
@@ -63,6 +64,7 @@
CryptoHandshakeMessage message_;
scoped_ptr<QuicData> message_data_;
QuicCryptoClientConfig crypto_config_;
+ CryptoTestUtils::FakeServerOptions server_options_;
};
TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
@@ -195,6 +197,42 @@
/*offset=*/0, data->AsStringPiece()));
}
+TEST_F(QuicCryptoClientStreamTest, TokenBindingNegotiation) {
+ server_options_.token_binding_enabled = true;
+ crypto_config_.tb_key_params.push_back(kP256);
+
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
+ EXPECT_EQ(kP256,
+ stream()->crypto_negotiated_params().token_binding_key_param);
+}
+
+TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutServerSupport) {
+ crypto_config_.tb_key_params.push_back(kP256);
+
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
+ EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
+}
+
+TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutClientSupport) {
+ server_options_.token_binding_enabled = true;
+
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
+ EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
+}
+
+TEST_F(QuicCryptoClientStreamTest, TokenBindingNotNegotiated) {
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
+ EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
+}
+
class QuicCryptoClientStreamStatelessTest : public ::testing::Test {
public:
QuicCryptoClientStreamStatelessTest()
@@ -232,9 +270,10 @@
&server_connection_, &server_session);
CHECK(server_session);
server_session_.reset(server_session);
+ CryptoTestUtils::FakeServerOptions options;
CryptoTestUtils::SetupCryptoServerConfigForTest(
server_connection_->clock(), server_connection_->random_generator(),
- server_session_->config(), &server_crypto_config_);
+ server_session_->config(), &server_crypto_config_, options);
FLAGS_enable_quic_stateless_reject_support = true;
}
@@ -265,8 +304,8 @@
InitializeFakeStatelessRejectServer();
AdvanceHandshakeWithFakeServer();
- EXPECT_EQ(1, server_stream()->num_handshake_messages());
- EXPECT_EQ(0, server_stream()->num_handshake_messages_with_server_nonces());
+ EXPECT_EQ(1, server_stream()->NumHandshakeMessages());
+ EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces());
EXPECT_FALSE(client_session_->GetCryptoStream()->encryption_established());
EXPECT_FALSE(client_session_->GetCryptoStream()->handshake_confirmed());
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 30ba158..8e2e15a 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -32,7 +32,7 @@
QuicCryptoServerStream::QuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config,
QuicSession* session)
- : QuicCryptoStream(session),
+ : QuicCryptoServerStreamBase(session),
crypto_config_(crypto_config),
validate_client_hello_cb_(nullptr),
num_handshake_messages_(0),
@@ -57,7 +57,7 @@
void QuicCryptoServerStream::OnHandshakeMessage(
const CryptoHandshakeMessage& message) {
- QuicCryptoStream::OnHandshakeMessage(message);
+ QuicCryptoServerStreamBase::OnHandshakeMessage(message);
++num_handshake_messages_;
// Do not process handshake messages after the handshake is confirmed.
@@ -110,8 +110,8 @@
if (reply.tag() != kSHLO) {
if (reply.tag() == kSREJ) {
- DCHECK(use_stateless_rejects_if_peer_supported());
- DCHECK(peer_supports_stateless_rejects());
+ DCHECK(use_stateless_rejects_if_peer_supported_);
+ DCHECK(peer_supports_stateless_rejects_);
// Before sending the SREJ, cause the connection to save crypto packets
// so that they can be added to the time wait list manager and
// retransmitted.
@@ -120,8 +120,8 @@
SendHandshakeMessage(reply);
if (reply.tag() == kSREJ) {
- DCHECK(use_stateless_rejects_if_peer_supported());
- DCHECK(peer_supports_stateless_rejects());
+ DCHECK(use_stateless_rejects_if_peer_supported_);
+ DCHECK(peer_supports_stateless_rejects_);
DCHECK(!handshake_confirmed());
DVLOG(1) << "Closing connection "
<< session()->connection()->connection_id()
@@ -212,7 +212,37 @@
session()->connection()->OnHandshakeComplete();
}
-void QuicCryptoServerStream::set_previous_cached_network_params(
+uint8 QuicCryptoServerStream::NumHandshakeMessages() const {
+ return num_handshake_messages_;
+}
+
+uint8 QuicCryptoServerStream::NumHandshakeMessagesWithServerNonces() const {
+ return num_handshake_messages_with_server_nonces_;
+}
+
+int QuicCryptoServerStream::NumServerConfigUpdateMessagesSent() const {
+ return num_server_config_update_messages_sent_;
+}
+
+const CachedNetworkParameters*
+QuicCryptoServerStream::PreviousCachedNetworkParams() const {
+ return previous_cached_network_params_.get();
+}
+
+bool QuicCryptoServerStream::UseStatelessRejectsIfPeerSupported() const {
+ return use_stateless_rejects_if_peer_supported_;
+}
+
+bool QuicCryptoServerStream::PeerSupportsStatelessRejects() const {
+ return peer_supports_stateless_rejects_;
+}
+
+void QuicCryptoServerStream::SetPeerSupportsStatelessRejects(
+ bool peer_supports_stateless_rejects) {
+ peer_supports_stateless_rejects_ = peer_supports_stateless_rejects;
+}
+
+void QuicCryptoServerStream::SetPreviousCachedNetworkParams(
CachedNetworkParameters cached_network_params) {
previous_cached_network_params_.reset(
new CachedNetworkParameters(cached_network_params));
@@ -282,11 +312,6 @@
void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
}
-const CachedNetworkParameters*
-QuicCryptoServerStream::previous_cached_network_params() const {
- return previous_cached_network_params_.get();
-}
-
QuicCryptoServerStream::ValidateCallback::ValidateCallback(
QuicCryptoServerStream* parent) : parent_(parent) {
}
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index f3d9c92..b07cef40 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -18,7 +18,7 @@
class CachedNetworkParameters;
class CryptoHandshakeMessage;
class QuicCryptoServerConfig;
-class QuicCryptoServerStream;
+class QuicCryptoServerStreamBase;
class QuicSession;
namespace test {
@@ -30,7 +30,7 @@
// peer. At this point we disable HANDSHAKE_MODE in the sent packet manager.
class NET_EXPORT_PRIVATE ServerHelloNotifier : public QuicAckListenerInterface {
public:
- explicit ServerHelloNotifier(QuicCryptoServerStream* stream)
+ explicit ServerHelloNotifier(QuicCryptoServerStreamBase* stream)
: server_stream_(stream) {}
void OnPacketAcked(int acked_bytes,
@@ -41,65 +41,76 @@
private:
~ServerHelloNotifier() override {}
- QuicCryptoServerStream* server_stream_;
+ QuicCryptoServerStreamBase* server_stream_;
DISALLOW_COPY_AND_ASSIGN(ServerHelloNotifier);
};
-class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
+// TODO(alyssar) see what can be moved out of QuicCryptoServerStream with
+// various code and test refactoring.
+class NET_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream {
+ public:
+ // |crypto_config| must outlive the stream.
+ explicit QuicCryptoServerStreamBase(QuicSession* session)
+ : QuicCryptoStream(session) {}
+ ~QuicCryptoServerStreamBase() override {}
+
+ // Cancel any outstanding callbacks, such as asynchronous validation of client
+ // hello.
+ virtual void CancelOutstandingCallbacks() = 0;
+
+ // GetBase64SHA256ClientChannelID sets |*output| to the base64 encoded,
+ // SHA-256 hash of the client's ChannelID key and returns true, if the client
+ // presented a ChannelID. Otherwise it returns false.
+ virtual bool GetBase64SHA256ClientChannelID(std::string* output) const = 0;
+
+ virtual int NumServerConfigUpdateMessagesSent() const = 0;
+
+ // Sends the latest server config and source-address token to the client.
+ virtual void SendServerConfigUpdate(
+ const CachedNetworkParameters* cached_network_params) = 0;
+
+ // Called by the ServerHello AckNotifier once the SHLO has been ACKed by the
+ // client.
+ virtual void OnServerHelloAcked() = 0;
+
+ // These are all accessors and setters to their respective counters.
+ virtual uint8 NumHandshakeMessages() const = 0;
+ virtual uint8 NumHandshakeMessagesWithServerNonces() const = 0;
+ virtual bool UseStatelessRejectsIfPeerSupported() const = 0;
+ virtual bool PeerSupportsStatelessRejects() const = 0;
+ virtual void SetPeerSupportsStatelessRejects(bool set) = 0;
+ virtual const CachedNetworkParameters* PreviousCachedNetworkParams()
+ const = 0;
+ virtual void SetPreviousCachedNetworkParams(
+ CachedNetworkParameters cached_network_params) = 0;
+};
+
+class NET_EXPORT_PRIVATE QuicCryptoServerStream
+ : public QuicCryptoServerStreamBase {
public:
// |crypto_config| must outlive the stream.
QuicCryptoServerStream(const QuicCryptoServerConfig* crypto_config,
QuicSession* session);
~QuicCryptoServerStream() override;
- // Cancel any outstanding callbacks, such as asynchronous validation of client
- // hello.
- void CancelOutstandingCallbacks();
-
- // CryptoFramerVisitorInterface implementation
+ // From QuicCryptoServerStreamBase
+ void CancelOutstandingCallbacks() override;
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
-
- // GetBase64SHA256ClientChannelID sets |*output| to the base64 encoded,
- // SHA-256 hash of the client's ChannelID key and returns true, if the client
- // presented a ChannelID. Otherwise it returns false.
- bool GetBase64SHA256ClientChannelID(std::string* output) const;
-
- uint8 num_handshake_messages() const { return num_handshake_messages_; }
-
- uint8 num_handshake_messages_with_server_nonces() const {
- return num_handshake_messages_with_server_nonces_;
- }
-
- int num_server_config_update_messages_sent() const {
- return num_server_config_update_messages_sent_;
- }
-
- // Sends the latest server config and source-address token to the client.
- virtual void SendServerConfigUpdate(
- const CachedNetworkParameters* cached_network_params);
-
- // Called by the ServerHello AckNotifier once the SHLO has been ACKed by the
- // client.
- void OnServerHelloAcked();
-
- void set_previous_cached_network_params(
- CachedNetworkParameters cached_network_params);
-
- const CachedNetworkParameters* previous_cached_network_params() const;
-
- bool use_stateless_rejects_if_peer_supported() const {
- return use_stateless_rejects_if_peer_supported_;
- }
-
- bool peer_supports_stateless_rejects() const {
- return peer_supports_stateless_rejects_;
- }
-
- void set_peer_supports_stateless_rejects(
- bool peer_supports_stateless_rejects) {
- peer_supports_stateless_rejects_ = peer_supports_stateless_rejects;
- }
+ bool GetBase64SHA256ClientChannelID(std::string* output) const override;
+ void SendServerConfigUpdate(
+ const CachedNetworkParameters* cached_network_params) override;
+ void OnServerHelloAcked() override;
+ uint8 NumHandshakeMessages() const override;
+ uint8 NumHandshakeMessagesWithServerNonces() const override;
+ int NumServerConfigUpdateMessagesSent() const override;
+ const CachedNetworkParameters* PreviousCachedNetworkParams() const override;
+ bool UseStatelessRejectsIfPeerSupported() const override;
+ bool PeerSupportsStatelessRejects() const override;
+ void SetPeerSupportsStatelessRejects(
+ bool peer_supports_stateless_rejects) override;
+ void SetPreviousCachedNetworkParams(
+ CachedNetworkParameters cached_network_params) override;
protected:
virtual QuicErrorCode ProcessClientHello(
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index d9bbfe1c..a5bf553 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -105,9 +105,11 @@
&server_connection_, &server_session);
CHECK(server_session);
server_session_.reset(server_session);
+ CryptoTestUtils::FakeServerOptions options;
+ options.token_binding_enabled = true;
CryptoTestUtils::SetupCryptoServerConfigForTest(
server_connection_->clock(), server_connection_->random_generator(),
- server_session_->config(), &server_crypto_config_);
+ server_session_->config(), &server_crypto_config_, options);
}
QuicCryptoServerStream* server_stream() {
@@ -194,8 +196,8 @@
}
TEST_P(QuicCryptoServerStreamTest, NotInitiallySendingStatelessRejects) {
- EXPECT_FALSE(server_stream()->use_stateless_rejects_if_peer_supported());
- EXPECT_FALSE(server_stream()->peer_supports_stateless_rejects());
+ EXPECT_FALSE(server_stream()->UseStatelessRejectsIfPeerSupported());
+ EXPECT_FALSE(server_stream()->PeerSupportsStatelessRejects());
}
TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
@@ -251,8 +253,8 @@
// On the first round, encryption will not be established.
EXPECT_FALSE(server_stream()->encryption_established());
EXPECT_FALSE(server_stream()->handshake_confirmed());
- EXPECT_EQ(1, server_stream()->num_handshake_messages());
- EXPECT_EQ(0, server_stream()->num_handshake_messages_with_server_nonces());
+ EXPECT_EQ(1, server_stream()->NumHandshakeMessages());
+ EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces());
// Now check the client state.
QuicCryptoClientConfig::CachedState* client_state =
@@ -283,8 +285,8 @@
// On the second round, encryption will be established.
EXPECT_TRUE(server_stream()->encryption_established());
EXPECT_TRUE(server_stream()->handshake_confirmed());
- EXPECT_EQ(2, server_stream()->num_handshake_messages());
- EXPECT_EQ(1, server_stream()->num_handshake_messages_with_server_nonces());
+ EXPECT_EQ(2, server_stream()->NumHandshakeMessages());
+ EXPECT_EQ(1, server_stream()->NumHandshakeMessagesWithServerNonces());
}
TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) {
@@ -405,7 +407,7 @@
TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
// An attempt to send a SCUP before completing handshake should fail.
server_stream()->SendServerConfigUpdate(nullptr);
- EXPECT_EQ(0, server_stream()->num_server_config_update_messages_sent());
+ EXPECT_EQ(0, server_stream()->NumServerConfigUpdateMessagesSent());
}
TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) {
@@ -422,6 +424,24 @@
QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_));
}
+TEST_P(QuicCryptoServerStreamTest, TokenBindingNegotiated) {
+ client_options_.token_binding_enabled = true;
+ CompleteCryptoHandshake();
+ EXPECT_EQ(
+ kP256,
+ server_stream()->crypto_negotiated_params().token_binding_key_param);
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+}
+
+TEST_P(QuicCryptoServerStreamTest, NoTokenBindingWithoutClientSupport) {
+ CompleteCryptoHandshake();
+ EXPECT_EQ(
+ 0u, server_stream()->crypto_negotiated_params().token_binding_key_param);
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+}
+
} // namespace
} // namespace test
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index fc005c12..0c9baed 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -84,10 +84,6 @@
// Net.QuicSession.HeadersHOLBlockedTime.
bool FLAGS_quic_measure_headers_hol_blocking_time = true;
-// If true, skip a check for mismatched stream IDs inside
-// ReliableQuicStream::OnStreamFrame.
-bool FLAGS_quic_stop_checking_for_mismatch_ids = true;
-
// Disable QUIC's userspace pacing.
bool FLAGS_quic_disable_pacing = false;
@@ -119,3 +115,11 @@
// If true, QUIC connections will timeout when packets are not being recieved,
// even if they are being sent.
bool FLAGS_quic_use_new_idle_timeout = true;
+
+// If true, replace QuicFrameList with StreamSequencerBuffer as underlying data
+// structure for QuicStreamSequencer bufferring.
+bool FLAGS_quic_use_stream_sequencer_buffer = true;
+
+// If true, don't send QUIC packets if the send alarm is set.
+// Disabled until b/25638635 is resolved.
+bool FLAGS_respect_send_alarm = false;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index 1d48642..5cf76499 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -28,7 +28,6 @@
NET_EXPORT_PRIVATE extern bool FLAGS_allow_many_available_streams;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_read_packets_full_recvmmsg;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_measure_headers_hol_blocking_time;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_stop_checking_for_mismatch_ids;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_disable_pacing;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_fix_fin_accounting;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_implement_stop_reading;
@@ -37,5 +36,6 @@
NET_EXPORT_PRIVATE extern bool FLAGS_quic_packet_creator_prefetch;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_disable_non_nat_address_migration;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_new_idle_timeout;
-
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_stream_sequencer_buffer;
+NET_EXPORT_PRIVATE extern bool FLAGS_respect_send_alarm;
#endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc
index e2eaf3e..177f0a4 100644
--- a/net/quic/quic_flow_controller.cc
+++ b/net/quic/quic_flow_controller.cc
@@ -11,11 +11,6 @@
namespace net {
-namespace {
-const QuicByteCount kStreamReceiveWindowLimit = 16 * 1024 * 1024; // 16 MB
-const QuicByteCount kSessionReceiveWindowLimit = 24 * 1024 * 1024; // 24 MB
-}
-
#define ENDPOINT \
(perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 1d062fd7..45b9c67 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -477,11 +477,12 @@
return new QuicEncryptedPacket(buffer.release(), len, true);
}
+// static
QuicEncryptedPacket* QuicFramer::BuildVersionNegotiationPacket(
- const QuicPacketPublicHeader& header,
- const QuicVersionVector& supported_versions) {
- DCHECK(header.version_flag);
- size_t len = GetVersionNegotiationPacketSize(supported_versions.size());
+ QuicConnectionId connection_id,
+ const QuicVersionVector& versions) {
+ DCHECK(!versions.empty());
+ size_t len = GetVersionNegotiationPacketSize(versions.size());
scoped_ptr<char[]> buffer(new char[len]);
QuicDataWriter writer(len, buffer.get());
@@ -491,12 +492,12 @@
return nullptr;
}
- if (!writer.WriteUInt64(header.connection_id)) {
+ if (!writer.WriteUInt64(connection_id)) {
return nullptr;
}
- for (size_t i = 0; i < supported_versions.size(); ++i) {
- if (!writer.WriteUInt32(QuicVersionToQuicTag(supported_versions[i]))) {
+ for (QuicVersion version : versions) {
+ if (!writer.WriteUInt32(QuicVersionToQuicTag(version))) {
return nullptr;
}
}
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 0bc3299..53ca193 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -304,9 +304,10 @@
static QuicEncryptedPacket* BuildPublicResetPacket(
const QuicPublicResetPacket& packet);
- QuicEncryptedPacket* BuildVersionNegotiationPacket(
- const QuicPacketPublicHeader& header,
- const QuicVersionVector& supported_versions);
+ // Returns a new version negotiation packet, owned by the caller.
+ static QuicEncryptedPacket* BuildVersionNegotiationPacket(
+ QuicConnectionId connection_id,
+ const QuicVersionVector& versions);
// SetDecrypter sets the primary decrypter, replacing any that already exists,
// and takes ownership. If an alternative decrypter is in place then the
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 4a3d3be..4e284a4 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -40,6 +40,17 @@
const QuicPacketNumber kEpoch = UINT64_C(1) << 48;
const QuicPacketNumber kMask = kEpoch - 1;
+// Use fields in which each byte is distinct to ensure that every byte is
+// framed correctly. The values are otherwise arbitrary.
+const QuicConnectionId kConnectionId = UINT64_C(0xFEDCBA9876543210);
+const QuicPacketNumber kPacketNumber = UINT64_C(0x123456789ABC);
+const QuicPacketNumber kLargestObserved = UINT64_C(0x0123456789ABF);
+const QuicPacketNumber kMissingPacket = UINT64_C(0x0123456789ABE);
+const QuicPacketNumber kLeastUnacked = UINT64_C(0x0123456789AA0);
+const QuicStreamId kStreamId = UINT64_C(0x01020304);
+const QuicStreamOffset kStreamOffset = UINT64_C(0xBA98FEDC32107654);
+const QuicPublicResetNonceProof kNonceProof = UINT64_C(0xABCDEF0123456789);
+
// Index into the connection_id offset in the header.
const size_t kConnectionIdOffset = kPublicFlagsSize;
// Index into the version string in the header. (if present).
@@ -613,8 +624,7 @@
ASSERT_TRUE(visitor_.header_.get());
// Make sure we've parsed the packet header, so we can send an error.
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
// Make sure the correct error is propagated.
EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error());
}
@@ -637,16 +647,15 @@
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(0x00u, visitor_.header_->fec_group);
+ EXPECT_EQ(0u, visitor_.header_->fec_group);
// Now test framing boundaries.
for (size_t i = 0;
@@ -670,8 +679,7 @@
}
TEST_P(QuicFramerTest, PacketHeaderWith4ByteConnectionId) {
- QuicFramerPeer::SetLastSerializedConnectionId(
- &framer_, UINT64_C(0xFEDCBA9876543210));
+ QuicFramerPeer::SetLastSerializedConnectionId(&framer_, kConnectionId);
// clang-format off
unsigned char packet[] = {
@@ -690,16 +698,15 @@
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(0x00u, visitor_.header_->fec_group);
+ EXPECT_EQ(0u, visitor_.header_->fec_group);
// Now test framing boundaries.
for (size_t i = 0;
@@ -726,8 +733,7 @@
}
TEST_P(QuicFramerTest, PacketHeader1ByteConnectionId) {
- QuicFramerPeer::SetLastSerializedConnectionId(
- &framer_, UINT64_C(0xFEDCBA9876543210));
+ QuicFramerPeer::SetLastSerializedConnectionId(&framer_, kConnectionId);
// clang-format off
unsigned char packet[] = {
@@ -746,16 +752,15 @@
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(0x00u, visitor_.header_->fec_group);
+ EXPECT_EQ(0u, visitor_.header_->fec_group);
// Now test framing boundaries.
for (size_t i = 0;
@@ -782,8 +787,7 @@
}
TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
- QuicFramerPeer::SetLastSerializedConnectionId(
- &framer_, UINT64_C(0xFEDCBA9876543210));
+ QuicFramerPeer::SetLastSerializedConnectionId(&framer_, kConnectionId);
// clang-format off
unsigned char packet[] = {
@@ -802,16 +806,15 @@
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(0x00u, visitor_.header_->fec_group);
+ EXPECT_EQ(0u, visitor_.header_->fec_group);
// Now test framing boundaries.
for (size_t i = 0;
@@ -857,17 +860,16 @@
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_TRUE(visitor_.header_->public_header.version_flag);
EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(0x00u, visitor_.header_->fec_group);
+ EXPECT_EQ(0u, visitor_.header_->fec_group);
// Now test framing boundaries.
for (size_t i = 0;
@@ -893,7 +895,7 @@
}
TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) {
- QuicFramerPeer::SetLastPacketNumber(&framer_, UINT64_C(0x123456789ABA));
+ QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
// clang-format off
unsigned char packet[] = {
@@ -912,16 +914,15 @@
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(0x00u, visitor_.header_->fec_group);
+ EXPECT_EQ(0u, visitor_.header_->fec_group);
// Now test framing boundaries.
for (size_t i = 0;
@@ -947,7 +948,7 @@
}
TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) {
- QuicFramerPeer::SetLastPacketNumber(&framer_, UINT64_C(0x123456789ABA));
+ QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
// clang-format off
unsigned char packet[] = {
@@ -966,16 +967,15 @@
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(0x00u, visitor_.header_->fec_group);
+ EXPECT_EQ(0u, visitor_.header_->fec_group);
// Now test framing boundaries.
for (size_t i = 0;
@@ -1001,7 +1001,7 @@
}
TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) {
- QuicFramerPeer::SetLastPacketNumber(&framer_, UINT64_C(0x123456789ABA));
+ QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
// clang-format off
unsigned char packet[] = {
@@ -1020,16 +1020,15 @@
EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(0x00u, visitor_.header_->fec_group);
+ EXPECT_EQ(0u, visitor_.header_->fec_group);
// Now test framing boundaries.
for (size_t i = 0;
@@ -1274,10 +1273,9 @@
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(static_cast<uint64>(0x01020304),
- visitor_.stream_frames_[0]->stream_id);
+ EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1323,9 +1321,10 @@
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(UINT64_C(0x00020304), visitor_.stream_frames_[0]->stream_id);
+ // Stream ID should be the last 3 bytes of kStreamId.
+ EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1372,10 +1371,10 @@
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(static_cast<uint64>(0x00000304),
- visitor_.stream_frames_[0]->stream_id);
+ // Stream ID should be the last 2 bytes of kStreamId.
+ EXPECT_EQ(0x0000FFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1422,10 +1421,10 @@
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(static_cast<uint64>(0x00000004),
- visitor_.stream_frames_[0]->stream_id);
+ // Stream ID should be the last byte of kStreamId.
+ EXPECT_EQ(0x000000FF & kStreamId, visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1476,10 +1475,9 @@
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(static_cast<uint64>(0x01020304),
- visitor_.stream_frames_[0]->stream_id);
+ EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
// Now test framing boundaries.
@@ -1570,12 +1568,12 @@
// clang-format on
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = true;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
// Do not encrypt the payload because the revived payload is post-encryption.
@@ -1586,22 +1584,21 @@
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_EQ(1, visitor_.revived_packets_);
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
- visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_FALSE(visitor_.header_->public_header.version_flag);
EXPECT_TRUE(visitor_.header_->fec_flag);
EXPECT_TRUE(visitor_.header_->entropy_flag);
EXPECT_EQ(1 << (header.packet_number % 8), visitor_.header_->entropy_hash);
- EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(0x00u, visitor_.header_->fec_group);
+ EXPECT_EQ(0u, visitor_.header_->fec_group);
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(UINT64_C(0x01020304), visitor_.stream_frames_[0]->stream_id);
+ EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
}
@@ -1615,7 +1612,7 @@
0x98, 0xBA, 0xDC, 0xFE,
// packet number
0xBC, 0x9A, 0x78, 0x56,
- 0x12, 0x34,
+ 0x34, 0x12,
// private flags (fec group)
0x02,
// first fec protected packet offset
@@ -1644,7 +1641,7 @@
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
EXPECT_EQ(IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
- EXPECT_EQ(UINT64_C(0x341256789ABA), visitor_.header_->fec_group);
+ EXPECT_EQ(kPacketNumber - 2, visitor_.header_->fec_group);
const size_t fec_offset = GetStartOfFecProtectedData(
PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, PACKET_6BYTE_PACKET_NUMBER);
EXPECT_EQ(
@@ -1653,9 +1650,9 @@
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(UINT64_C(0x01020304), visitor_.stream_frames_[0]->stream_id);
+ EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id);
EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
}
@@ -1712,10 +1709,10 @@
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(UINT64_C(0x0123456789ABF), frame.largest_observed);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.missing_packets.NumPacketsSlow());
ASSERT_EQ(2u, frame.received_packet_times.size());
- EXPECT_EQ(UINT64_C(0x0123456789ABE), frame.missing_packets.Min());
+ EXPECT_EQ(kMissingPacket, frame.missing_packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset = kReceivedEntropyOffset +
@@ -1828,10 +1825,10 @@
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(UINT64_C(0x0123456789ABF), frame.largest_observed);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.missing_packets.NumPacketsSlow());
ASSERT_EQ(1u, frame.received_packet_times.size());
- EXPECT_EQ(UINT64_C(0x0123456789ABE), frame.missing_packets.Min());
+ EXPECT_EQ(kMissingPacket, frame.missing_packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset =
@@ -1930,9 +1927,9 @@
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(UINT64_C(0x0123456789ABF), frame.largest_observed);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.missing_packets.NumPacketsSlow());
- EXPECT_EQ(UINT64_C(0x0123456789ABE), frame.missing_packets.Min());
+ EXPECT_EQ(kMissingPacket, frame.missing_packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset = kReceivedEntropyOffset +
@@ -2028,9 +2025,9 @@
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& frame = *visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(UINT64_C(0x0123456789ABF), frame.largest_observed);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
ASSERT_EQ(1u, frame.missing_packets.NumPacketsSlow());
- EXPECT_EQ(UINT64_C(0x0123456789ABE), frame.missing_packets.Min());
+ EXPECT_EQ(kMissingPacket, frame.missing_packets.Min());
const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
const size_t kLargestObservedOffset = kReceivedEntropyOffset +
@@ -2120,7 +2117,7 @@
ASSERT_EQ(1u, visitor_.ack_frames_.size());
QuicAckFrame* frame = visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame->entropy_hash);
- EXPECT_EQ(UINT64_C(0x0123456789ABF), frame->largest_observed);
+ EXPECT_EQ(kLargestObserved, frame->largest_observed);
ASSERT_TRUE(frame->missing_packets.Empty());
// Verify that the packet re-serializes identically.
@@ -2185,11 +2182,11 @@
ASSERT_EQ(1u, visitor_.ack_frames_.size());
QuicAckFrame* frame = visitor_.ack_frames_[0];
EXPECT_EQ(0xBA, frame->entropy_hash);
- EXPECT_EQ(UINT64_C(0x0123456789ABF), frame->largest_observed);
+ EXPECT_EQ(kLargestObserved, frame->largest_observed);
EXPECT_EQ(0u, frame->latest_revived_packet);
ASSERT_EQ(500u, frame->missing_packets.NumPacketsSlow());
- EXPECT_EQ(UINT64_C(0x0123456789ABE) - 499, frame->missing_packets.Min());
- EXPECT_EQ(UINT64_C(0x0123456789ABE), frame->missing_packets.Max());
+ EXPECT_EQ(kMissingPacket - 499, frame->missing_packets.Min());
+ EXPECT_EQ(kMissingPacket, frame->missing_packets.Max());
// Verify that the packet re-serializes identically.
QuicFrames frames;
@@ -2238,7 +2235,7 @@
ASSERT_EQ(1u, visitor_.stop_waiting_frames_.size());
const QuicStopWaitingFrame& frame = *visitor_.stop_waiting_frames_[0];
EXPECT_EQ(0xAB, frame.entropy_hash);
- EXPECT_EQ(UINT64_C(0x0123456789AA0), frame.least_unacked);
+ EXPECT_EQ(kLeastUnacked, frame.least_unacked);
const size_t kSentEntropyOffset = kQuicFrameTypeSize;
const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize;
@@ -2278,8 +2275,8 @@
0x04, 0x03, 0x02, 0x01,
// sent byte offset
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
// error code
0x01, 0x00, 0x00, 0x00,
@@ -2293,10 +2290,9 @@
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
- EXPECT_EQ(UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id);
+ EXPECT_EQ(kStreamId, visitor_.rst_stream_frame_.stream_id);
EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code);
- EXPECT_EQ(UINT64_C(0x0807060504030201),
- visitor_.rst_stream_frame_.byte_offset);
+ EXPECT_EQ(kStreamOffset, visitor_.rst_stream_frame_.byte_offset);
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetRstStreamFrameSize();
@@ -2416,7 +2412,7 @@
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
- EXPECT_EQ(UINT64_C(0x01020304), visitor_.goaway_frame_.last_good_stream_id);
+ EXPECT_EQ(kStreamId, visitor_.goaway_frame_.last_good_stream_id);
EXPECT_EQ(0x9, visitor_.goaway_frame_.error_code);
EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase);
@@ -2460,8 +2456,8 @@
// stream id
0x04, 0x03, 0x02, 0x01,
// byte offset
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x0c,
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
};
// clang-format on
@@ -2473,9 +2469,8 @@
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
- EXPECT_EQ(UINT64_C(0x01020304), visitor_.window_update_frame_.stream_id);
- EXPECT_EQ(UINT64_C(0x0c0b0a0908070605),
- visitor_.window_update_frame_.byte_offset);
+ EXPECT_EQ(kStreamId, visitor_.window_update_frame_.stream_id);
+ EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset);
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize;
@@ -2523,7 +2518,7 @@
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
- EXPECT_EQ(UINT64_C(0x01020304), visitor_.blocked_frame_.stream_id);
+ EXPECT_EQ(kStreamId, visitor_.blocked_frame_.stream_id);
// Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetBlockedFrameSize();
@@ -2601,13 +2596,12 @@
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.public_reset_packet_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(kConnectionId,
visitor_.public_reset_packet_->public_header.connection_id);
EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
- EXPECT_EQ(UINT64_C(0xABCDEF0123456789),
- visitor_.public_reset_packet_->nonce_proof);
- EXPECT_EQ(UINT64_C(0x123456789ABC),
+ EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
+ EXPECT_EQ(kPacketNumber,
visitor_.public_reset_packet_->rejected_packet_number);
EXPECT_TRUE(
visitor_.public_reset_packet_->client_address.address().empty());
@@ -2709,13 +2703,12 @@
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.public_reset_packet_.get());
- EXPECT_EQ(UINT64_C(0xFEDCBA9876543210),
+ EXPECT_EQ(kConnectionId,
visitor_.public_reset_packet_->public_header.connection_id);
EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
- EXPECT_EQ(UINT64_C(0xABCDEF0123456789),
- visitor_.public_reset_packet_->nonce_proof);
- EXPECT_EQ(UINT64_C(0x123456789ABC),
+ EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
+ EXPECT_EQ(kPacketNumber,
visitor_.public_reset_packet_->rejected_packet_number);
EXPECT_EQ("4.31.198.44",
IPAddressToString(visitor_.public_reset_packet_->
@@ -2819,12 +2812,12 @@
TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicPaddingFrame padding_frame;
@@ -2867,13 +2860,13 @@
TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.public_header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicPaddingFrame padding_frame;
@@ -2915,13 +2908,13 @@
TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.public_header.packet_number_length = PACKET_2BYTE_PACKET_NUMBER;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicPaddingFrame padding_frame;
@@ -2963,13 +2956,13 @@
TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicPaddingFrame padding_frame;
@@ -3011,15 +3004,15 @@
TEST_P(QuicFramerTest, BuildStreamFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x77123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
- QuicStreamFrame stream_frame(0x01020304, true, UINT64_C(0xBA98FEDC32107654),
+ QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
StringPiece("hello world!"));
QuicFrames frames;
@@ -3062,16 +3055,16 @@
TEST_P(QuicFramerTest, BuildStreamFramePacketInFecGroup) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x77123456789ABC);
+ header.packet_number = kPacketNumber;
header.is_in_fec_group = IN_FEC_GROUP;
- header.fec_group = UINT64_C(0x77123456789ABC);
+ header.fec_group = kPacketNumber;
- QuicStreamFrame stream_frame(0x01020304, true, UINT64_C(0xBA98FEDC32107654),
+ QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
StringPiece("hello world!"));
QuicFrames frames;
@@ -3111,15 +3104,15 @@
TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = true;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x77123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
- QuicStreamFrame stream_frame(0x01020304, true, UINT64_C(0xBA98FEDC32107654),
+ QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
StringPiece("hello world!"));
QuicFrames frames;
@@ -3195,11 +3188,6 @@
}
TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
- QuicPacketPublicHeader header;
- header.connection_id = UINT64_C(0xFEDCBA9876543210);
- header.reset_flag = false;
- header.version_flag = true;
-
// clang-format off
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
@@ -3221,11 +3209,9 @@
};
// clang-format on
- QuicVersionVector versions;
- versions.push_back(GetParam());
- scoped_ptr<QuicEncryptedPacket> data(
- framer_.BuildVersionNegotiationPacket(header, versions));
-
+ QuicConnectionId connection_id = kConnectionId;
+ scoped_ptr<QuicEncryptedPacket> data(framer_.BuildVersionNegotiationPacket(
+ connection_id, SupportedVersions(GetParam())));
test::CompareCharArraysWithHexError("constructed packet", data->data(),
data->length(), AsChars(packet),
arraysize(packet));
@@ -3233,19 +3219,19 @@
TEST_P(QuicFramerTest, BuildAckFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x770123456789AA8);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicAckFrame ack_frame;
ack_frame.entropy_hash = 0x43;
- ack_frame.largest_observed = UINT64_C(0x770123456789ABF);
+ ack_frame.largest_observed = kLargestObserved;
ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
- ack_frame.missing_packets.Add(UINT64_C(0x770123456789ABE));
+ ack_frame.missing_packets.Add(kMissingPacket);
QuicFrames frames;
frames.push_back(QuicFrame(&ack_frame));
@@ -3257,7 +3243,7 @@
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
@@ -3296,12 +3282,12 @@
TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x770123456789AA8);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicAckFrame ack_frame;
@@ -3325,7 +3311,7 @@
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
@@ -3407,12 +3393,12 @@
TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x770123456789AA8);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicAckFrame ack_frame;
@@ -3436,7 +3422,7 @@
// connection_id
0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
// packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
@@ -3472,17 +3458,17 @@
TEST_P(QuicFramerTest, BuildStopWaitingPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x770123456789AA8);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicStopWaitingFrame stop_waiting_frame;
stop_waiting_frame.entropy_hash = 0x14;
- stop_waiting_frame.least_unacked = UINT64_C(0x770123456789AA0);
+ stop_waiting_frame.least_unacked = kLeastUnacked;
QuicFrames frames;
frames.push_back(QuicFrame(&stop_waiting_frame));
@@ -3495,8 +3481,7 @@
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet number
- 0xA8, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags (entropy)
0x01,
@@ -3505,7 +3490,7 @@
// entropy hash of sent packets till least awaiting - 1.
0x14,
// least packet number awaiting an ack, delta from packet number.
- 0x08, 0x00, 0x00, 0x00,
+ 0x1C, 0x00, 0x00, 0x00,
0x00, 0x00,
};
// clang-format on
@@ -3520,16 +3505,16 @@
TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicRstStreamFrame rst_frame;
- rst_frame.stream_id = 0x01020304;
+ rst_frame.stream_id = kStreamId;
rst_frame.error_code = static_cast<QuicRstStreamErrorCode>(0x05060708);
rst_frame.byte_offset = 0x0807060504030201;
@@ -3571,12 +3556,12 @@
TEST_P(QuicFramerTest, BuildCloseFramePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicConnectionCloseFrame close_frame;
@@ -3623,17 +3608,17 @@
TEST_P(QuicFramerTest, BuildGoAwayPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicGoAwayFrame goaway_frame;
goaway_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
- goaway_frame.last_good_stream_id = 0x01020304;
+ goaway_frame.last_good_stream_id = kStreamId;
goaway_frame.reason_phrase = "because I can";
QuicFrames frames;
@@ -3678,16 +3663,16 @@
TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicWindowUpdateFrame window_update_frame;
- window_update_frame.stream_id = 0x01020304;
+ window_update_frame.stream_id = kStreamId;
window_update_frame.byte_offset = 0x1122334455667788;
QuicFrames frames;
@@ -3726,16 +3711,16 @@
TEST_P(QuicFramerTest, BuildBlockedPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicBlockedFrame blocked_frame;
- blocked_frame.stream_id = 0x01020304;
+ blocked_frame.stream_id = kStreamId;
QuicFrames frames;
frames.push_back(QuicFrame(&blocked_frame));
@@ -3770,12 +3755,12 @@
TEST_P(QuicFramerTest, BuildPingPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicPingFrame ping_frame;
@@ -3812,12 +3797,12 @@
// Test that the MTU discovery packet is serialized correctly as a PING packet.
TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicMtuDiscoveryFrame mtu_discovery_frame;
@@ -3853,11 +3838,11 @@
TEST_P(QuicFramerTest, BuildPublicResetPacket) {
QuicPublicResetPacket reset_packet;
- reset_packet.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ reset_packet.public_header.connection_id = kConnectionId;
reset_packet.public_header.reset_flag = true;
reset_packet.public_header.version_flag = false;
- reset_packet.rejected_packet_number = UINT64_C(0x123456789ABC);
- reset_packet.nonce_proof = UINT64_C(0xABCDEF0123456789);
+ reset_packet.rejected_packet_number = kPacketNumber;
+ reset_packet.nonce_proof = kNonceProof;
// clang-format off
unsigned char packet[] = {
@@ -3898,11 +3883,11 @@
TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) {
QuicPublicResetPacket reset_packet;
- reset_packet.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ reset_packet.public_header.connection_id = kConnectionId;
reset_packet.public_header.reset_flag = true;
reset_packet.public_header.version_flag = false;
- reset_packet.rejected_packet_number = UINT64_C(0x123456789ABC);
- reset_packet.nonce_proof = UINT64_C(0xABCDEF0123456789);
+ reset_packet.rejected_packet_number = kPacketNumber;
+ reset_packet.nonce_proof = kNonceProof;
reset_packet.client_address = IPEndPoint(Loopback4(), 0x1234);
// clang-format off
@@ -3952,14 +3937,14 @@
TEST_P(QuicFramerTest, BuildFecPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = true;
header.entropy_flag = true;
- header.packet_number = (UINT64_C(0x123456789ABC));
+ header.packet_number = kPacketNumber;
header.is_in_fec_group = IN_FEC_GROUP;
- header.fec_group = UINT64_C(0x123456789ABB);
+ header.fec_group = kPacketNumber - 1;
string redundancy = "abcdefghijklmnop";
@@ -3995,7 +3980,7 @@
}
TEST_P(QuicFramerTest, EncryptPacket) {
- QuicPacketNumber packet_number = UINT64_C(0x123456789ABC);
+ QuicPacketNumber packet_number = kPacketNumber;
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
@@ -4031,7 +4016,7 @@
}
TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
- QuicPacketNumber packet_number = UINT64_C(0x123456789ABC);
+ QuicPacketNumber packet_number = kPacketNumber;
// clang-format off
unsigned char packet[] = {
// public flags (version, 8 byte connection_id)
@@ -4070,12 +4055,12 @@
TEST_P(QuicFramerTest, AckTruncationLargePacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
// Create a packet with just the ack.
@@ -4108,12 +4093,12 @@
TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = false;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
// Create a packet with just the ack.
@@ -4146,12 +4131,12 @@
TEST_P(QuicFramerTest, CleanTruncation) {
QuicPacketHeader header;
- header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210);
+ header.public_header.connection_id = kConnectionId;
header.public_header.reset_flag = false;
header.public_header.version_flag = false;
header.fec_flag = false;
header.entropy_flag = true;
- header.packet_number = UINT64_C(0x123456789ABC);
+ header.packet_number = kPacketNumber;
header.fec_group = 0;
QuicAckFrame ack_frame;
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index b5ca189..95c923df 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -10,6 +10,7 @@
#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "net/spdy/spdy_alt_svc_wire_format.h"
#include "net/spdy/spdy_protocol.h"
#include "net/spdy/spdy_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/quic/quic_multipath_transmissions_map.cc b/net/quic/quic_multipath_transmissions_map.cc
new file mode 100644
index 0000000..14655e37
--- /dev/null
+++ b/net/quic/quic_multipath_transmissions_map.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_multipath_transmissions_map.h"
+
+namespace net_quic {
+
+QuicMultipathTransmissionsMap::QuicMultipathTransmissionsMap() {}
+
+QuicMultipathTransmissionsMap::~QuicMultipathTransmissionsMap() {
+ for (std::pair<QuicPathIdPacketNumber, MultipathTransmissionsList*>
+ packet_transmissions : transmission_map_) {
+ packet_transmissions.second->pop_front();
+ if (packet_transmissions.second->empty()) {
+ delete packet_transmissions.second;
+ }
+ }
+}
+
+void QuicMultipathTransmissionsMap::OnPacketRetransmittedOnDifferentPath(
+ QuicPathIdPacketNumber original_path_id_packet_number,
+ QuicPathIdPacketNumber path_id_packet_number) {
+ MultipathTransmissionsList* across_paths_transmission_list = nullptr;
+ MultipathTransmissionsMap::iterator it =
+ transmission_map_.find(original_path_id_packet_number);
+ if (it != transmission_map_.end()) {
+ across_paths_transmission_list = it->second;
+ } else {
+ across_paths_transmission_list = new MultipathTransmissionsList();
+ across_paths_transmission_list->push_back(original_path_id_packet_number);
+ transmission_map_[original_path_id_packet_number] =
+ across_paths_transmission_list;
+ }
+
+ across_paths_transmission_list->push_back(path_id_packet_number);
+ transmission_map_[path_id_packet_number] = across_paths_transmission_list;
+}
+
+const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+QuicMultipathTransmissionsMap::MaybeGetTransmissionsOnOtherPaths(
+ QuicPathIdPacketNumber path_id_packet_number) const {
+ MultipathTransmissionsMap::const_iterator it =
+ transmission_map_.find(path_id_packet_number);
+ if (it == transmission_map_.end()) {
+ return nullptr;
+ }
+
+ return it->second;
+}
+
+void QuicMultipathTransmissionsMap::OnPacketHandled(
+ QuicPathIdPacketNumber path_id_packet_number) {
+ MultipathTransmissionsMap::iterator it =
+ transmission_map_.find(path_id_packet_number);
+ if (it == transmission_map_.end()) {
+ return;
+ }
+
+ MultipathTransmissionsList* transmission_list = it->second;
+ MultipathTransmissionsList::iterator transmission_it;
+ // Remove all across paths transmissions of this packet from the map.
+ for (QuicPathIdPacketNumber path_id_packet_number : *transmission_list) {
+ transmission_map_.erase(path_id_packet_number);
+ }
+ // Remove the multipath transmissions list.
+ delete transmission_list;
+}
+
+} // namespace net_quic
diff --git a/net/quic/quic_multipath_transmissions_map.h b/net/quic/quic_multipath_transmissions_map.h
new file mode 100644
index 0000000..121e63e
--- /dev/null
+++ b/net/quic/quic_multipath_transmissions_map.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A map manages packets which are transmitted across multiple paths.
+// For example, a packet is originally transmitted on path 1 with packet number
+// 1. Then this packet is retransmitted on path 2 with packet number 1. (1, 1)
+// and (2, 1) are inserted into this map. Suppose (2, 1) is detected lost and
+// gets retransmitted on path 2 with packet 2. (2, 2) will not be inserted
+// because this transmission does not "across" path compared to (2, 1).
+
+#ifndef NET_QUIC_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
+#define NET_QUIC_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
+
+#include <deque>
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net_quic {
+
+typedef std::pair<net::QuicPathId, net::QuicPacketNumber>
+ QuicPathIdPacketNumber;
+
+class NET_EXPORT_PRIVATE QuicMultipathTransmissionsMap {
+ public:
+ typedef std::deque<QuicPathIdPacketNumber> MultipathTransmissionsList;
+ typedef base::hash_map<QuicPathIdPacketNumber, MultipathTransmissionsList*>
+ MultipathTransmissionsMap;
+
+ QuicMultipathTransmissionsMap();
+ ~QuicMultipathTransmissionsMap();
+
+ // Called when a packet is retransmitted on a different path. Adds both
+ // |original_path_id_packet_number| (if not exists) and
+ // |path_id_packet_number| to |transmission_map_|.
+ void OnPacketRetransmittedOnDifferentPath(
+ QuicPathIdPacketNumber original_path_id_packet_number,
+ QuicPathIdPacketNumber path_id_packet_number);
+
+ // Returns all multipath transmissions list if |path_id_packet_number| has
+ // been transmitted across multiple paths, nullptr otherwise.
+ const MultipathTransmissionsList* MaybeGetTransmissionsOnOtherPaths(
+ QuicPathIdPacketNumber path_id_packet_number) const;
+
+ // Called after packet |path_id_packet_number| is received.
+ // If |path_id_packet_number| has been transmitted across multiple paths,
+ // clears all multipath transmissions list and removes each transmission from
+ // |transmission_map_|, does nothing otherwise.
+ void OnPacketHandled(QuicPathIdPacketNumber path_id_packet_number);
+
+ private:
+ // Keys of the map are QuicPathIdPacketNumber, and values are pointers to
+ // lists of multipath transmissions of the same packet. For example, if a
+ // packet has been transmitted as (1, 1) and (2, 1), two entries are added
+ // to this map and both values point to the same list: {(1, 1), (2, 1)}.
+ // The MultipathTransmissionsList is owned by the transmission which is
+ // received first (on any path).
+ MultipathTransmissionsMap transmission_map_;
+};
+
+} // namespace net_quic
+
+#endif // NET_QUIC_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
diff --git a/net/quic/quic_multipath_transmissions_map_test.cc b/net/quic/quic_multipath_transmissions_map_test.cc
new file mode 100644
index 0000000..fcae200
--- /dev/null
+++ b/net/quic/quic_multipath_transmissions_map_test.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_multipath_transmissions_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net_quic {
+namespace test {
+namespace {
+
+TEST(QuicAcrossPathsTransmissionMapTest, OnPacketRetransmittedOnDifferentPath) {
+ QuicMultipathTransmissionsMap transmission_map;
+ // Packet0's original transmission sent on path 1 with packet number 1.
+ QuicPathIdPacketNumber packet0_0(1, 1);
+ // Packet0's retransmission sent on path 2 with packet number 1.
+ QuicPathIdPacketNumber packet0_1(2, 1);
+ // packet0's 2nd retransmission sent on path 3 with packet number 1.
+ QuicPathIdPacketNumber packet0_2(3, 1);
+
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1);
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list1 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0);
+ EXPECT_EQ(packet0_0, (*transmission_list1)[0]);
+ EXPECT_EQ(packet0_1, (*transmission_list1)[1]);
+
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2);
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list2 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0);
+ EXPECT_EQ(packet0_0, (*transmission_list2)[0]);
+ EXPECT_EQ(packet0_1, (*transmission_list2)[1]);
+ EXPECT_EQ(packet0_2, (*transmission_list2)[2]);
+ // Make sure there is no memory leakage.
+}
+
+TEST(QuicAcrossPathsTransmissionMapTest, MaybeGetTransmissionsOnOtherPaths) {
+ QuicMultipathTransmissionsMap transmission_map;
+ // Packet0's original transmission sent on path 1 with packet number 1.
+ QuicPathIdPacketNumber packet0_0(1, 1);
+ // Packet0's retransmission sent on path 2 with packet number 1.
+ QuicPathIdPacketNumber packet0_1(2, 1);
+ // packet0's 2nd retransmission sent on path 3 with packet number 1.
+ QuicPathIdPacketNumber packet0_2(3, 1);
+
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1);
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2);
+
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list1 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0);
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list2 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_1);
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list3 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_2);
+ // Make sure all three pointers point to the same list.
+ EXPECT_EQ(transmission_list1, transmission_list2);
+ EXPECT_EQ(transmission_list2, transmission_list3);
+ EXPECT_EQ(packet0_0, (*transmission_list1)[0]);
+ EXPECT_EQ(packet0_1, (*transmission_list1)[1]);
+ EXPECT_EQ(packet0_2, (*transmission_list1)[2]);
+
+ // Packet1 which is not transmitted across path.
+ QuicPathIdPacketNumber packet1_0(1, 2);
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0));
+ // Make sure there is no memory leakage.
+}
+
+TEST(QuicAcrossPathsTransmissionMapTest, OnPacketHandled) {
+ QuicMultipathTransmissionsMap transmission_map;
+
+ // Packet's original transmission sent on path 1 with packet number 1.
+ QuicPathIdPacketNumber packet0_0(1, 1);
+ // Packet's retransmission sent on path 2 with packet number 1.
+ QuicPathIdPacketNumber packet0_1(2, 1);
+ // packet's 2nd retransmission sent on path 3 with packet number 1.
+ QuicPathIdPacketNumber packet0_2(3, 1);
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1);
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2);
+
+ // Packet1's original transmission sent on path 1 with packet number 2.
+ QuicPathIdPacketNumber packet1_0(1, 2);
+ // Packet1's retransmission sent on path 2 with packet number 2.
+ QuicPathIdPacketNumber packet1_1(2, 2);
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet1_0, packet1_1);
+
+ transmission_map.OnPacketHandled(packet0_0);
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0));
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_1));
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_2));
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0);
+ EXPECT_EQ(packet1_0, (*transmission_list)[0]);
+ EXPECT_EQ(packet1_1, (*transmission_list)[1]);
+ // Packet 1 is received on path 2.
+ transmission_map.OnPacketHandled(packet1_1);
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0));
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_1));
+ // Make sure there is no memory leakage.
+}
+
+} // namespace
+} // namespace test
+} // namespace net_quic
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index ccbf7e9..c2a400b 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -599,13 +599,8 @@
QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket(
const QuicVersionVector& supported_versions) {
DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective());
- QuicPacketPublicHeader header;
- header.connection_id = connection_id_;
- header.reset_flag = false;
- header.version_flag = true;
- header.versions = supported_versions;
- QuicEncryptedPacket* encrypted =
- framer_->BuildVersionNegotiationPacket(header, supported_versions);
+ QuicEncryptedPacket* encrypted = QuicFramer::BuildVersionNegotiationPacket(
+ connection_id_, supported_versions);
DCHECK(encrypted);
DCHECK_GE(max_packet_length_, encrypted->length());
return encrypted;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 1286b9a..fe4e8b7 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -41,6 +41,7 @@
typedef uint32 QuicStreamId;
typedef uint64 QuicStreamOffset;
typedef uint64 QuicPacketNumber;
+typedef uint8 QuicPathId;
typedef QuicPacketNumber QuicFecGroupNumber;
typedef uint64 QuicPublicResetNonceProof;
typedef uint8 QuicPacketEntropyHash;
@@ -73,6 +74,10 @@
// Minimum size of initial flow control window, for both stream and session.
const uint32 kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB
+// Maximum flow control receive window limits for connection and stream.
+const QuicByteCount kStreamReceiveWindowLimit = 16 * 1024 * 1024; // 16 MB
+const QuicByteCount kSessionReceiveWindowLimit = 24 * 1024 * 1024; // 24 MB
+
// Minimum size of the CWND, in packets, when doing bandwidth resumption.
const QuicPacketCount kMinCongestionWindowForBandwidthResumption = 10;
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 586d27a..20d357a 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -935,4 +935,19 @@
kInitialUnpacedBurst));
}
+void QuicSentPacketManager::OnConnectionMigration(PeerAddressChangeType type) {
+ if (type == UNKNOWN) {
+ return;
+ }
+
+ if (type == NAT_PORT_REBINDING || type == IPV4_SUBNET_REBINDING) {
+ // Rtt and cwnd do not need to be reset when the peer address change is
+ // considered to be caused by NATs.
+ return;
+ }
+
+ rtt_stats_.OnConnectionMigration();
+ send_algorithm_->OnConnectionMigration();
+}
+
} // namespace net
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index c37d3c3..73c695b 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -213,6 +213,9 @@
// Enables pacing if it has not already been enabled.
void EnablePacing();
+ // Called when peer address changes and the connection migrates.
+ void OnConnectionMigration(PeerAddressChangeType type);
+
bool using_pacing() const { return using_pacing_; }
void set_debug_delegate(DebugDelegate* debug_delegate) {
diff --git a/net/quic/quic_spdy_stream.cc b/net/quic/quic_spdy_stream.cc
index 746e96a8..775348f 100644
--- a/net/quic/quic_spdy_stream.cc
+++ b/net/quic/quic_spdy_stream.cc
@@ -14,6 +14,10 @@
namespace net {
+#define ENDPOINT \
+ (session()->perspective() == Perspective::IS_SERVER ? "Server: " : "Client:" \
+ " ")
+
namespace {
// This is somewhat arbitrary. It's possible, but unlikely, we will either fail
@@ -38,6 +42,29 @@
QuicSpdyStream::~QuicSpdyStream() {}
+void QuicSpdyStream::CloseWriteSide() {
+ if (version() > QUIC_VERSION_28 && !fin_received() && !rst_received() &&
+ sequencer()->ignore_read_data() && !rst_sent()) {
+ DCHECK(fin_sent());
+ // Tell the peer to stop sending further data.
+ DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id();
+ Reset(QUIC_STREAM_NO_ERROR);
+ }
+
+ ReliableQuicStream::CloseWriteSide();
+}
+
+void QuicSpdyStream::StopReading() {
+ if (version() > QUIC_VERSION_28 && !fin_received() && !rst_received() &&
+ write_side_closed() && !rst_sent()) {
+ DCHECK(fin_sent());
+ // Tell the peer to stop sending further data.
+ DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id();
+ Reset(QUIC_STREAM_NO_ERROR);
+ }
+ ReliableQuicStream::StopReading();
+}
+
size_t QuicSpdyStream::WriteHeaders(
const SpdyHeaderBlock& header_block,
bool fin,
diff --git a/net/quic/quic_spdy_stream.h b/net/quic/quic_spdy_stream.h
index 48e74b1..543e490 100644
--- a/net/quic/quic_spdy_stream.h
+++ b/net/quic/quic_spdy_stream.h
@@ -54,6 +54,11 @@
QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session);
~QuicSpdyStream() override;
+ // Override the base class to send QUIC_STREAM_NO_ERROR to the peer
+ // when the stream has not received all the data.
+ void CloseWriteSide() override;
+ void StopReading() override;
+
// ReliableQuicStream implementation
void OnClose() override;
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index f4467559..2012c95 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -1371,7 +1371,7 @@
cached->Initialize(server_info->state().server_config,
server_info->state().source_address_token,
- server_info->state().certs,
+ server_info->state().certs, "",
server_info->state().server_config_sig, clock_->WallNow());
}
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index 12fe8c7..b3f17dd 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -12,7 +12,9 @@
#include "net/quic/quic_clock.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_frame_list.h"
+#include "net/quic/quic_protocol.h"
#include "net/quic/reliable_quic_stream.h"
+#include "net/quic/stream_sequencer_buffer.h"
using std::min;
using std::numeric_limits;
@@ -23,14 +25,21 @@
QuicStreamSequencer::QuicStreamSequencer(ReliableQuicStream* quic_stream,
const QuicClock* clock)
: stream_(quic_stream),
- buffered_frames_(new QuicFrameList()),
close_offset_(numeric_limits<QuicStreamOffset>::max()),
blocked_(false),
num_frames_received_(0),
num_duplicate_frames_received_(0),
num_early_frames_received_(0),
clock_(clock),
- ignore_read_data_(false) {}
+ ignore_read_data_(false) {
+ if (FLAGS_quic_use_stream_sequencer_buffer) {
+ DVLOG(1) << "Use StreamSequencerBuffer for stream: " << stream_->id();
+ buffered_frames_.reset(
+ new StreamSequencerBuffer(kStreamReceiveWindowLimit));
+ } else {
+ buffered_frames_.reset(new QuicFrameList());
+ }
+}
QuicStreamSequencer::~QuicStreamSequencer() {}
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index aaf1d26..7a16115 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/rand_util.h"
#include "net/base/ip_endpoint.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_frame_list.h"
#include "net/quic/quic_utils.h"
#include "net/quic/reliable_quic_stream.h"
@@ -59,8 +60,13 @@
static const char kPayload[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-class QuicStreamSequencerTest : public ::testing::Test {
+class QuicStreamSequencerTest : public ::testing::TestWithParam<bool> {
public:
+ void SetUp() override {
+ FLAGS_quic_use_stream_sequencer_buffer = GetParam();
+ sequencer_.reset(new QuicStreamSequencer(&stream_, &clock_));
+ }
+
void ConsumeData(size_t num_bytes) {
char buffer[1024];
ASSERT_GT(arraysize(buffer), num_bytes);
@@ -74,39 +80,51 @@
QuicStreamSequencerTest()
: connection_(new MockConnection(&helper_, Perspective::IS_CLIENT)),
session_(connection_),
- stream_(&session_, 1),
- sequencer_(new QuicStreamSequencer(&stream_, &clock_)) {}
+ stream_(&session_, 1) {}
- bool VerifyReadableRegion(const char** expected) {
+ // Verify that the data in first region match with the expected[0].
+ bool VerifyReadableRegion(const vector<string>& expected) {
iovec iovecs[1];
- QuicTime timestamp = clock_.ApproximateNow();
- if (sequencer_->GetReadableRegion(iovecs, ×tamp)) {
- return (VerifyIovecs(iovecs, 1, expected, 1));
+ if (sequencer_->GetReadableRegions(iovecs, 1)) {
+ return (VerifyIovecs(iovecs, 1, vector<string>{expected[0]}));
}
return false;
}
- bool VerifyReadableRegions(const char** expected, size_t num_expected) {
+ // Verify that the data in each of currently readable regions match with each
+ // item given in |expected|.
+ bool VerifyReadableRegions(const vector<string>& expected) {
iovec iovecs[5];
size_t num_iovecs =
sequencer_->GetReadableRegions(iovecs, arraysize(iovecs));
return VerifyReadableRegion(expected) &&
- VerifyIovecs(iovecs, num_iovecs, expected, num_expected);
+ VerifyIovecs(iovecs, num_iovecs, expected);
}
bool VerifyIovecs(iovec* iovecs,
size_t num_iovecs,
- const char** expected,
- size_t num_expected) {
- if (num_expected != num_iovecs) {
- LOG(ERROR) << "Incorrect number of iovecs. Expected: " << num_expected
- << " Actual: " << num_iovecs;
- return false;
- }
- for (size_t i = 0; i < num_expected; ++i) {
- if (!VerifyIovec(iovecs[i], expected[i])) {
+ const vector<string>& expected) {
+ if (!FLAGS_quic_use_stream_sequencer_buffer) {
+ if (expected.size() != num_iovecs) {
+ LOG(ERROR) << "Incorrect number of iovecs. Expected: "
+ << expected.size() << " Actual: " << num_iovecs;
return false;
}
+
+ for (size_t i = 0; i < num_iovecs; ++i) {
+ if (!VerifyIovec(iovecs[i], expected[i])) {
+ return false;
+ }
+ }
+ } else {
+ int start_position = 0;
+ for (size_t i = 0; i < num_iovecs; ++i) {
+ if (!VerifyIovec(iovecs[i], expected[0].substr(start_position,
+ iovecs[i].iov_len))) {
+ return false;
+ }
+ start_position += iovecs[i].iov_len;
+ }
}
return true;
}
@@ -155,9 +173,13 @@
scoped_ptr<QuicStreamSequencer> sequencer_;
};
+INSTANTIATE_TEST_CASE_P(QuicStreamSequencerTests,
+ QuicStreamSequencerTest,
+ ::testing::Values(false, true));
+
// TODO(rch): reorder these tests so they build on each other.
-TEST_F(QuicStreamSequencerTest, RejectOldFrame) {
+TEST_P(QuicStreamSequencerTest, RejectOldFrame) {
EXPECT_CALL(stream_, OnDataAvailable())
.WillOnce(testing::Invoke(
CreateFunctor(this, &QuicStreamSequencerTest::ConsumeData, 3)));
@@ -173,7 +195,7 @@
EXPECT_EQ(0u, NumBufferedBytes());
}
-TEST_F(QuicStreamSequencerTest, RejectBufferedFrame) {
+TEST_P(QuicStreamSequencerTest, RejectBufferedFrame) {
EXPECT_CALL(stream_, OnDataAvailable());
OnFrame(0, "abc");
@@ -186,7 +208,7 @@
EXPECT_EQ(3u, NumBufferedBytes());
}
-TEST_F(QuicStreamSequencerTest, FullFrameConsumed) {
+TEST_P(QuicStreamSequencerTest, FullFrameConsumed) {
EXPECT_CALL(stream_, OnDataAvailable())
.WillOnce(testing::Invoke(
CreateFunctor(this, &QuicStreamSequencerTest::ConsumeData, 3)));
@@ -196,7 +218,7 @@
EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
}
-TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameConsumed) {
+TEST_P(QuicStreamSequencerTest, BlockedThenFullFrameConsumed) {
sequencer_->SetBlockedUntilFlush();
OnFrame(0, "abc");
@@ -218,7 +240,7 @@
EXPECT_TRUE(sequencer_->IsClosed());
}
-TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameAndFinConsumed) {
+TEST_P(QuicStreamSequencerTest, BlockedThenFullFrameAndFinConsumed) {
sequencer_->SetBlockedUntilFlush();
OnFinFrame(0, "abc");
@@ -235,7 +257,7 @@
EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
}
-TEST_F(QuicStreamSequencerTest, EmptyFrame) {
+TEST_P(QuicStreamSequencerTest, EmptyFrame) {
EXPECT_CALL(stream_,
CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME, _));
OnFrame(0, "");
@@ -243,14 +265,14 @@
EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
}
-TEST_F(QuicStreamSequencerTest, EmptyFinFrame) {
+TEST_P(QuicStreamSequencerTest, EmptyFinFrame) {
EXPECT_CALL(stream_, OnDataAvailable());
OnFinFrame(0, "");
EXPECT_EQ(0u, NumBufferedBytes());
EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
}
-TEST_F(QuicStreamSequencerTest, PartialFrameConsumed) {
+TEST_P(QuicStreamSequencerTest, PartialFrameConsumed) {
EXPECT_CALL(stream_, OnDataAvailable())
.WillOnce(testing::Invoke(
CreateFunctor(this, &QuicStreamSequencerTest::ConsumeData, 2)));
@@ -260,7 +282,7 @@
EXPECT_EQ(2u, sequencer_->NumBytesConsumed());
}
-TEST_F(QuicStreamSequencerTest, NextxFrameNotConsumed) {
+TEST_P(QuicStreamSequencerTest, NextxFrameNotConsumed) {
EXPECT_CALL(stream_, OnDataAvailable());
OnFrame(0, "abc");
@@ -269,14 +291,14 @@
EXPECT_EQ(0, sequencer_->num_early_frames_received());
}
-TEST_F(QuicStreamSequencerTest, FutureFrameNotProcessed) {
+TEST_P(QuicStreamSequencerTest, FutureFrameNotProcessed) {
OnFrame(3, "abc");
EXPECT_EQ(3u, NumBufferedBytes());
EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
EXPECT_EQ(1, sequencer_->num_early_frames_received());
}
-TEST_F(QuicStreamSequencerTest, OutOfOrderFrameProcessed) {
+TEST_P(QuicStreamSequencerTest, OutOfOrderFrameProcessed) {
// Buffer the first
OnFrame(6, "ghi");
EXPECT_EQ(3u, NumBufferedBytes());
@@ -300,7 +322,7 @@
EXPECT_EQ(0u, NumBufferedBytes());
}
-TEST_F(QuicStreamSequencerTest, BasicHalfCloseOrdered) {
+TEST_P(QuicStreamSequencerTest, BasicHalfCloseOrdered) {
InSequence s;
EXPECT_CALL(stream_, OnDataAvailable())
@@ -311,7 +333,7 @@
EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
}
-TEST_F(QuicStreamSequencerTest, BasicHalfCloseUnorderedWithFlush) {
+TEST_P(QuicStreamSequencerTest, BasicHalfCloseUnorderedWithFlush) {
OnFinFrame(6, "");
EXPECT_EQ(6u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
@@ -324,7 +346,7 @@
EXPECT_TRUE(sequencer_->IsClosed());
}
-TEST_F(QuicStreamSequencerTest, BasicHalfUnordered) {
+TEST_P(QuicStreamSequencerTest, BasicHalfUnordered) {
OnFinFrame(3, "");
EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
@@ -336,7 +358,7 @@
EXPECT_TRUE(sequencer_->IsClosed());
}
-TEST_F(QuicStreamSequencerTest, TerminateWithReadv) {
+TEST_P(QuicStreamSequencerTest, TerminateWithReadv) {
char buffer[3];
OnFinFrame(3, "");
@@ -353,7 +375,7 @@
EXPECT_TRUE(sequencer_->IsClosed());
}
-TEST_F(QuicStreamSequencerTest, MutipleOffsets) {
+TEST_P(QuicStreamSequencerTest, MutipleOffsets) {
OnFinFrame(3, "");
EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
@@ -410,7 +432,7 @@
// All frames are processed as soon as we have sequential data.
// Infinite buffering, so all frames are acked right away.
-TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingNoBackup) {
+TEST_P(QuicSequencerRandomTest, RandomFramesNoDroppingNoBackup) {
InSequence s;
EXPECT_CALL(stream_, OnDataAvailable())
.Times(AnyNumber())
@@ -429,7 +451,7 @@
EXPECT_EQ(kPayload, output_);
}
-TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingBackup) {
+TEST_P(QuicSequencerRandomTest, RandomFramesNoDroppingBackup) {
char buffer[10];
iovec iov[2];
iov[0].iov_base = &buffer[0];
@@ -475,7 +497,7 @@
}
// Same as above, just using a different method for reading.
-TEST_F(QuicStreamSequencerTest, MarkConsumed) {
+TEST_P(QuicStreamSequencerTest, MarkConsumed) {
InSequence s;
EXPECT_CALL(stream_, OnDataAvailable());
@@ -487,35 +509,50 @@
EXPECT_EQ(9u, sequencer_->NumBytesBuffered());
// Peek into the data.
- const char* expected[] = {"abc", "def", "ghi"};
- ASSERT_TRUE(VerifyReadableRegions(expected, arraysize(expected)));
+ vector<string> expected;
+ if (FLAGS_quic_use_stream_sequencer_buffer) {
+ expected = vector<string>{"abcdefghi"};
+ } else {
+ expected = vector<string>{"abc", "def", "ghi"};
+ }
+ ASSERT_TRUE(VerifyReadableRegions(expected));
// Consume 1 byte.
sequencer_->MarkConsumed(1);
EXPECT_EQ(1u, stream_.flow_controller()->bytes_consumed());
// Verify data.
- const char* expected2[] = {"bc", "def", "ghi"};
- ASSERT_TRUE(VerifyReadableRegions(expected2, arraysize(expected2)));
+ vector<string> expected2;
+ if (FLAGS_quic_use_stream_sequencer_buffer) {
+ expected2 = vector<string>{"bcdefghi"};
+ } else {
+ expected2 = vector<string>{"bc", "def", "ghi"};
+ }
+ ASSERT_TRUE(VerifyReadableRegions(expected2));
EXPECT_EQ(8u, sequencer_->NumBytesBuffered());
// Consume 2 bytes.
sequencer_->MarkConsumed(2);
EXPECT_EQ(3u, stream_.flow_controller()->bytes_consumed());
// Verify data.
- const char* expected3[] = {"def", "ghi"};
- ASSERT_TRUE(VerifyReadableRegions(expected3, arraysize(expected3)));
+ vector<string> expected3;
+ if (FLAGS_quic_use_stream_sequencer_buffer) {
+ expected3 = vector<string>{"defghi"};
+ } else {
+ expected3 = vector<string>{"def", "ghi"};
+ }
+ ASSERT_TRUE(VerifyReadableRegions(expected3));
EXPECT_EQ(6u, sequencer_->NumBytesBuffered());
// Consume 5 bytes.
sequencer_->MarkConsumed(5);
EXPECT_EQ(8u, stream_.flow_controller()->bytes_consumed());
// Verify data.
- const char* expected4[] = {"i"};
- ASSERT_TRUE(VerifyReadableRegions(expected4, arraysize(expected4)));
+ vector<string> expected4{"i"};
+ ASSERT_TRUE(VerifyReadableRegions(expected4));
EXPECT_EQ(1u, sequencer_->NumBytesBuffered());
}
-TEST_F(QuicStreamSequencerTest, MarkConsumedError) {
+TEST_P(QuicStreamSequencerTest, MarkConsumedError) {
EXPECT_CALL(stream_, OnDataAvailable());
OnFrame(0, "abc");
@@ -523,8 +560,8 @@
// Peek into the data. Only the first chunk should be readable because of the
// missing data.
- const char* expected[] = {"abc"};
- ASSERT_TRUE(VerifyReadableRegions(expected, arraysize(expected)));
+ vector<string> expected{"abc"};
+ ASSERT_TRUE(VerifyReadableRegions(expected));
// Now, attempt to mark consumed more data than was readable and expect the
// stream to be closed.
@@ -534,7 +571,7 @@
" expect to consume: 4, but not enough bytes available.");
}
-TEST_F(QuicStreamSequencerTest, MarkConsumedWithMissingPacket) {
+TEST_P(QuicStreamSequencerTest, MarkConsumedWithMissingPacket) {
InSequence s;
EXPECT_CALL(stream_, OnDataAvailable());
@@ -543,8 +580,13 @@
// Missing packet: 6, ghi.
OnFrame(9, "jkl");
- const char* expected[] = {"abc", "def"};
- ASSERT_TRUE(VerifyReadableRegions(expected, arraysize(expected)));
+ vector<string> expected;
+ if (FLAGS_quic_use_stream_sequencer_buffer) {
+ expected = vector<string>{"abcdef"};
+ } else {
+ expected = vector<string>{"abc", "def"};
+ }
+ ASSERT_TRUE(VerifyReadableRegions(expected));
sequencer_->MarkConsumed(6);
}
@@ -597,7 +639,7 @@
QuicStreamFrame(1, false, kBufferedOffset + kBufferedDataLength, data)));
}
-TEST_F(QuicStreamSequencerTest, DontAcceptOverlappingFrames) {
+TEST_P(QuicStreamSequencerTest, DontAcceptOverlappingFrames) {
// The peer should never send us non-identical stream frames which contain
// overlapping byte ranges - if they do, we close the connection.
@@ -610,7 +652,7 @@
sequencer_->OnStreamFrame(frame2);
}
-TEST_F(QuicStreamSequencerTest, InOrderTimestamps) {
+TEST_P(QuicStreamSequencerTest, InOrderTimestamps) {
// This test verifies that timestamps returned by
// GetReadableRegion() are in the correct sequence when frames
// arrive at the sequencer in order.
@@ -651,7 +693,7 @@
EXPECT_EQ(0u, sequencer_->NumBytesBuffered());
}
-TEST_F(QuicStreamSequencerTest, OutOfOrderTimestamps) {
+TEST_P(QuicStreamSequencerTest, OutOfOrderTimestamps) {
// This test verifies that timestamps returned by
// GetReadableRegion() are in the correct sequence when frames
// arrive at the sequencer out of order.
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index ab389ce..7481341 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -51,13 +51,7 @@
TransmissionInfo info(packet->retransmittable_frames,
packet->packet_number_length, transmission_type,
sent_time, bytes_sent, packet->is_fec_packet);
- if (old_packet_number == 0) {
- if (packet->retransmittable_frames != nullptr &&
- packet->retransmittable_frames->HasCryptoHandshake() == IS_HANDSHAKE) {
- ++pending_crypto_packet_count_;
- }
- info.ack_listeners.swap(packet->listeners);
- } else {
+ if (old_packet_number > 0) {
TransferRetransmissionInfo(old_packet_number, packet_number,
transmission_type, &info);
}
@@ -68,6 +62,15 @@
info.in_flight = true;
}
unacked_packets_.push_back(info);
+ // Swap the ack listeners after to avoid an extra list allocation.
+ // TODO(ianswett): Could use emplace_back when Chromium can.
+ if (old_packet_number == 0) {
+ if (packet->retransmittable_frames != nullptr &&
+ packet->retransmittable_frames->HasCryptoHandshake() == IS_HANDSHAKE) {
+ ++pending_crypto_packet_count_;
+ }
+ unacked_packets_.back().ack_listeners.swap(packet->listeners);
+ }
}
void QuicUnackedPacketMap::RemoveObsoletePackets() {
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index f4e9a8a..1efad19 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -100,11 +100,6 @@
}
}
- if (!FLAGS_quic_stop_checking_for_mismatch_ids && frame.stream_id != id_) {
- session_->connection()->SendConnectionClose(QUIC_INTERNAL_ERROR);
- return;
- }
-
if (frame.fin) {
fin_received_ = true;
if (fin_sent_) {
@@ -186,7 +181,6 @@
}
void ReliableQuicStream::Reset(QuicRstStreamErrorCode error) {
- DCHECK_NE(QUIC_STREAM_NO_ERROR, error);
stream_error_ = error;
// Sending a RstStream results in calling CloseStream.
session()->SendRstStream(id(), error, stream_bytes_written_);
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index a608c32..ab36df0 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -105,10 +105,16 @@
}
bool write_side_closed() const { return write_side_closed_; }
+ bool rst_received() { return rst_received_; }
+ bool rst_sent() { return rst_sent_; }
+ bool fin_received() { return fin_received_; }
+ bool fin_sent() { return fin_sent_; }
+
uint64 stream_bytes_read() const { return stream_bytes_read_; }
uint64 stream_bytes_written() const { return stream_bytes_written_; }
void set_fin_sent(bool fin_sent) { fin_sent_ = fin_sent; }
+ void set_fin_received(bool fin_received) { fin_received_ = fin_received; }
void set_rst_sent(bool rst_sent) { rst_sent_ = rst_sent; }
void set_fec_policy(FecPolicy fec_policy) { fec_policy_ = fec_policy; }
@@ -189,7 +195,7 @@
// Close the write side of the socket. Further writes will fail.
// Can be called by the subclass or internally.
// Does not send a FIN. May cause the stream to be closed.
- void CloseWriteSide();
+ virtual void CloseWriteSide();
// Helper method that returns FecProtection to use when writing.
FecProtection GetFecProtection();
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 6d8dae9..cb9ce7ce 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -58,51 +58,6 @@
vector<CryptoHandshakeMessage> messages_;
};
-// MovePackets parses crypto handshake messages from packet number
-// |*inout_packet_index| through to the last packet (or until a packet fails to
-// decrypt) and has |dest_stream| process them. |*inout_packet_index| is updated
-// with an index one greater than the last packet processed.
-void MovePackets(PacketSavingConnection* source_conn,
- size_t *inout_packet_index,
- QuicCryptoStream* dest_stream,
- PacketSavingConnection* dest_conn) {
- SimpleQuicFramer framer(source_conn->supported_versions());
- CryptoFramer crypto_framer;
- CryptoFramerVisitor crypto_visitor;
-
- // In order to properly test the code we need to perform encryption and
- // decryption so that the crypters latch when expected. The crypters are in
- // |dest_conn|, but we don't want to try and use them there. Instead we swap
- // them into |framer|, perform the decryption with them, and then swap them
- // back.
- QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
-
- crypto_framer.set_visitor(&crypto_visitor);
-
- size_t index = *inout_packet_index;
- for (; index < source_conn->encrypted_packets_.size(); index++) {
- if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) {
- // The framer will be unable to decrypt forward-secure packets sent after
- // the handshake is complete. Don't treat them as handshake packets.
- break;
- }
-
- for (const QuicStreamFrame& stream_frame : framer.stream_frames()) {
- ASSERT_TRUE(crypto_framer.ProcessInput(stream_frame.data));
- ASSERT_FALSE(crypto_visitor.error());
- }
- }
- *inout_packet_index = index;
-
- QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
-
- ASSERT_EQ(0u, crypto_framer.InputBytesRemaining());
-
- for (const CryptoHandshakeMessage& message : crypto_visitor.messages()) {
- dest_stream->OnHandshakeMessage(message);
- }
-}
-
// HexChar parses |c| as a hex character. If valid, it sets |*value| to the
// value of the hex character and returns true. Otherwise it returns false.
bool HexChar(char c, uint8* value) {
@@ -166,14 +121,20 @@
} // anonymous namespace
+CryptoTestUtils::FakeServerOptions::FakeServerOptions()
+ : token_binding_enabled(false) {}
+
CryptoTestUtils::FakeClientOptions::FakeClientOptions()
- : channel_id_enabled(false), channel_id_source_async(false) {}
+ : channel_id_enabled(false),
+ channel_id_source_async(false),
+ token_binding_enabled(false) {}
// static
int CryptoTestUtils::HandshakeWithFakeServer(
MockConnectionHelper* helper,
PacketSavingConnection* client_conn,
- QuicCryptoClientStream* client) {
+ QuicCryptoClientStream* client,
+ const FakeServerOptions& options) {
PacketSavingConnection* server_conn = new PacketSavingConnection(
helper, Perspective::IS_SERVER, client_conn->supported_versions());
@@ -183,7 +144,7 @@
ProofSourceForTesting());
SetupCryptoServerConfigForTest(server_conn->clock(),
server_conn->random_generator(), &config,
- &crypto_config);
+ &crypto_config, options);
TestQuicSpdyServerSession server_session(server_conn, config, &crypto_config);
@@ -220,6 +181,9 @@
}
crypto_config.SetChannelIDSource(source);
}
+ if (options.token_binding_enabled) {
+ crypto_config.tb_key_params.push_back(kP256);
+ }
TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
server_id, &crypto_config);
@@ -252,9 +216,11 @@
const QuicClock* clock,
QuicRandom* rand,
QuicConfig* config,
- QuicCryptoServerConfig* crypto_config) {
+ QuicCryptoServerConfig* crypto_config,
+ const FakeServerOptions& fake_options) {
QuicCryptoServerConfig::ConfigOptions options;
options.channel_id_enabled = true;
+ options.token_binding_enabled = fake_options.token_binding_enabled;
scoped_ptr<CryptoHandshakeMessage> scfg(
crypto_config->AddDefaultConfig(rand, clock, options));
}
@@ -608,5 +574,47 @@
return *parsed;
}
+// static
+void CryptoTestUtils::MovePackets(PacketSavingConnection* source_conn,
+ size_t* inout_packet_index,
+ QuicCryptoStream* dest_stream,
+ PacketSavingConnection* dest_conn) {
+ SimpleQuicFramer framer(source_conn->supported_versions());
+ CryptoFramer crypto_framer;
+ CryptoFramerVisitor crypto_visitor;
+
+ // In order to properly test the code we need to perform encryption and
+ // decryption so that the crypters latch when expected. The crypters are in
+ // |dest_conn|, but we don't want to try and use them there. Instead we swap
+ // them into |framer|, perform the decryption with them, and then swap ther
+ // back.
+ QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
+
+ crypto_framer.set_visitor(&crypto_visitor);
+
+ size_t index = *inout_packet_index;
+ for (; index < source_conn->encrypted_packets_.size(); index++) {
+ if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) {
+ // The framer will be unable to decrypt forward-secure packets sent after
+ // the handshake is complete. Don't treat them as handshake packets.
+ break;
+ }
+
+ for (const QuicStreamFrame& stream_frame : framer.stream_frames()) {
+ ASSERT_TRUE(crypto_framer.ProcessInput(stream_frame.data));
+ ASSERT_FALSE(crypto_visitor.error());
+ }
+ }
+ *inout_packet_index = index;
+
+ QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
+
+ ASSERT_EQ(0u, crypto_framer.InputBytesRemaining());
+
+ for (const CryptoHandshakeMessage& message : crypto_visitor.messages()) {
+ dest_stream->OnHandshakeMessage(message);
+ }
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h
index b881b457..b823c61 100644
--- a/net/quic/test_tools/crypto_test_utils.h
+++ b/net/quic/test_tools/crypto_test_utils.h
@@ -54,6 +54,16 @@
virtual void RunPendingCallbacks() = 0;
};
+ // FakeServerOptions bundles together a number of options for configuring the
+ // server in HandshakeWithFakeServer.
+ struct FakeServerOptions {
+ FakeServerOptions();
+
+ // If token_binding_enabled is true, then the server will attempt to
+ // negotiate Token Binding.
+ bool token_binding_enabled;
+ };
+
// FakeClientOptions bundles together a number of options for configuring
// HandshakeWithFakeClient.
struct FakeClientOptions {
@@ -66,12 +76,17 @@
// If channel_id_source_async is true then the client will use an async
// ChannelIDSource for testing. Ignored if channel_id_enabled is false.
bool channel_id_source_async;
+
+ // If token_binding_enabled is true, then the client will attempt to
+ // negotiate Token Binding.
+ bool token_binding_enabled;
};
// returns: the number of client hellos that the client sent.
static int HandshakeWithFakeServer(MockConnectionHelper* helper,
PacketSavingConnection* client_conn,
- QuicCryptoClientStream* client);
+ QuicCryptoClientStream* client,
+ const FakeServerOptions& options);
// returns: the number of client hellos that the client sent.
static int HandshakeWithFakeClient(MockConnectionHelper* helper,
@@ -86,7 +101,8 @@
const QuicClock* clock,
QuicRandom* rand,
QuicConfig* config,
- QuicCryptoServerConfig* crypto_config);
+ QuicCryptoServerConfig* crypto_config,
+ const FakeServerOptions& options);
// CommunicateHandshakeMessages moves messages from |a| to |b| and back until
// |a|'s handshake has completed.
@@ -165,6 +181,15 @@
// method never returns QUIC_PENDING.
static ChannelIDSource* ChannelIDSourceForTesting();
+ // MovePackets parses crypto handshake messages from packet number
+ // |*inout_packet_index| through to the last packet (or until a packet fails
+ // to decrypt) and has |dest_stream| process them. |*inout_packet_index| is
+ // updated with an index one greater than the last packet processed.
+ static void MovePackets(PacketSavingConnection* source_conn,
+ size_t* inout_packet_index,
+ QuicCryptoStream* dest_stream,
+ PacketSavingConnection* dest_conn);
+
private:
static void CompareClientAndServerKeys(QuicCryptoClientStream* client,
QuicCryptoServerStream* server);
diff --git a/net/quic/test_tools/crypto_test_utils_chromium.cc b/net/quic/test_tools/crypto_test_utils_chromium.cc
index 9978d72c..f6171442 100644
--- a/net/quic/test_tools/crypto_test_utils_chromium.cc
+++ b/net/quic/test_tools/crypto_test_utils_chromium.cc
@@ -137,6 +137,7 @@
QuicAsyncStatus VerifyProof(const std::string& hostname,
const std::string& server_config,
const std::vector<std::string>& certs,
+ const std::string& cert_sct,
const std::string& signature,
const ProofVerifyContext* verify_context,
std::string* error_details,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index d5fdec2..8e1df7ad 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -545,6 +545,7 @@
QuicByteCount,
HasRetransmittableData));
MOCK_METHOD1(OnRetransmissionTimeout, void(bool));
+ MOCK_METHOD0(OnConnectionMigration, void());
MOCK_METHOD0(RevertRetransmissionTimeout, void());
MOCK_CONST_METHOD3(TimeUntilSend,
QuicTime::Delta(QuicTime now,
@@ -691,7 +692,7 @@
QuicPacketNumber,
EncryptionLevel,
TransmissionType,
- const QuicEncryptedPacket&,
+ size_t encrypted_length,
QuicTime));
MOCK_METHOD3(OnPacketReceived,
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index ed5491a..3003929 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -147,30 +147,51 @@
// to do 0-RTT across incompatible versions. Chromium only supports
// a single version at a time anyway. :)
QuicVersionVector all_supported_versions = QuicSupportedVersions();
- QuicVersionVector client_version_buckets[2];
+ QuicVersionVector version_buckets[2];
for (const QuicVersion version : all_supported_versions) {
if (version <= QUIC_VERSION_25) {
// SPDY/4
- client_version_buckets[0].push_back(version);
+ version_buckets[0].push_back(version);
} else {
// QUIC_VERSION_26 changes the kdf in a way that is incompatible with
// version negotiation across the version 26 boundary.
- client_version_buckets[1].push_back(version);
+ version_buckets[1].push_back(version);
}
}
vector<TestParams> params;
- // TODO(rtenneti): Add kTBBR after BBR code is checked in.
- // for (const QuicTag congestion_control_tag : {kRENO, kTBBR, kQBIC}) {
- for (const QuicTag congestion_control_tag : {kRENO, kQBIC}) {
- for (const bool use_fec : {false, true}) {
- for (const QuicVersionVector& client_versions : client_version_buckets) {
- // A number of end to end tests fail when stateless rejects are enabled
- // *and* there are more than two QUIC versions.
- for (bool client_supports_stateless_rejects : {true, false}) {
- for (bool server_uses_stateless_rejects_if_peer_supported :
- {true, false}) {
- for (bool auto_tune_flow_control_window : {true, false}) {
+ for (bool server_uses_stateless_rejects_if_peer_supported : {true, false}) {
+ for (bool client_supports_stateless_rejects : {true, false}) {
+ // TODO(rtenneti): Add kTBBR after BBR code is checked in.
+ for (const QuicTag congestion_control_tag : {kRENO, kQBIC}) {
+ for (bool auto_tune_flow_control_window : {true, false}) {
+ for (const bool use_fec : {false, true}) {
+ const int kMaxEnabledOptions = 5;
+ int enabled_options = 0;
+ if (congestion_control_tag != kQBIC) {
+ ++enabled_options;
+ }
+ if (use_fec) {
+ ++enabled_options;
+ }
+ if (auto_tune_flow_control_window) {
+ ++enabled_options;
+ }
+ if (client_supports_stateless_rejects) {
+ ++enabled_options;
+ }
+ if (server_uses_stateless_rejects_if_peer_supported) {
+ ++enabled_options;
+ }
+ CHECK_GE(kMaxEnabledOptions, 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());
// Add an entry for server and client supporting all versions.
params.push_back(TestParams(
@@ -179,10 +200,10 @@
client_supports_stateless_rejects,
server_uses_stateless_rejects_if_peer_supported,
congestion_control_tag, auto_tune_flow_control_window));
- if (client_supports_stateless_rejects &&
- server_uses_stateless_rejects_if_peer_supported) {
- // TODO(b/23745998) Make stateless reject work with version
- // negotiation.
+
+ // 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;
}
@@ -1050,6 +1071,28 @@
EXPECT_EQ(QUIC_INVALID_STREAM_ID, client_->connection_error());
}
+TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) {
+ ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ string large_body;
+ GenerateBody(&large_body, 1024 * 1024);
+
+ HTTPMessage request(HttpConstants::HTTP_1_1, HttpConstants::POST, "/foo");
+ request.AddBody(large_body, false);
+
+ // Insert an invalid content_length field in request to trigger an early
+ // response from server.
+ request.AddHeader("content-length", "-3");
+
+ request.set_skip_message_validation(true);
+ client_->SendCustomSynchronousRequest(request);
+ EXPECT_EQ("bad", client_->response_body());
+ EXPECT_EQ(500u, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(QUIC_STREAM_NO_ERROR, client_->stream_error());
+ EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
+}
+
// TODO(rch): this test seems to cause net_unittests timeouts :|
TEST_P(EndToEndTest, DISABLED_MultipleTermination) {
ASSERT_TRUE(Initialize());
@@ -1776,14 +1819,9 @@
// Send the version negotiation packet.
QuicConnectionId incorrect_connection_id =
client_->client()->session()->connection()->connection_id() + 1;
- QuicVersionNegotiationPacket header;
- header.connection_id = incorrect_connection_id;
- header.reset_flag = true;
- header.version_flag = true;
- QuicFramer framer(server_supported_versions_, QuicTime::Zero(),
- Perspective::IS_SERVER);
scoped_ptr<QuicEncryptedPacket> packet(
- framer.BuildVersionNegotiationPacket(header, server_supported_versions_));
+ QuicFramer::BuildVersionNegotiationPacket(incorrect_connection_id,
+ server_supported_versions_));
testing::NiceMock<MockQuicConnectionDebugVisitor> visitor;
client_->client()->session()->connection()->set_debug_visitor(&visitor);
EXPECT_CALL(visitor, OnIncorrectConnectionId(incorrect_connection_id))
@@ -2064,6 +2102,17 @@
// Receive the response and let the server close writing.
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()->GetStream(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);
@@ -2074,13 +2123,14 @@
// (This is OK despite already waiting for a response.)
client_->WaitForResponse();
// There should be no buffered data to write in the client's stream.
- ReliableQuicStream* stream = client_->client()->session()->GetStream(5);
+ ReliableQuicStream* stream =
+ client_->client()->session()->GetStream(kClientDataStreamId1);
EXPECT_FALSE(stream != nullptr && stream->HasBufferedData());
} else {
// Run the client for 0.1 second to let any buffered data be sent.
// Must have a timeout, as the stream will not close and cause a return.
// (This is OK despite already waiting for a response.)
- client_->WaitForResponseForMs(static_cast<int64>(100));
+ client_->WaitForResponseForMs(100);
// There will be buffered data to write in the client's stream.
ReliableQuicStream* stream = client_->client()->session()->GetStream(5);
EXPECT_TRUE(stream != nullptr && stream->HasBufferedData());
diff --git a/net/tools/quic/quic_client_bin.cc b/net/tools/quic/quic_client_bin.cc
index 5b214a86..e5cc288 100644
--- a/net/tools/quic/quic_client_bin.cc
+++ b/net/tools/quic/quic_client_bin.cc
@@ -19,7 +19,7 @@
// quic_client https://www.google.com --port=443 --host=${IP}
//
// Use a specific version:
-// quic_client http://www.google.com --version=23 --host=${IP}
+// quic_client http://www.google.com --quic_version=23 --host=${IP}
//
// Send a POST instead of a GET:
// quic_client http://www.google.com --body="this is a POST body" --host=${IP}
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 7ae923bf..67718c1a 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -62,7 +62,9 @@
session_->CryptoConnect();
QuicCryptoClientStream* stream =
static_cast<QuicCryptoClientStream*>(session_->GetCryptoStream());
- CryptoTestUtils::HandshakeWithFakeServer(&helper_, connection_, stream);
+ CryptoTestUtils::FakeServerOptions options;
+ CryptoTestUtils::HandshakeWithFakeServer(&helper_, connection_, stream,
+ options);
}
QuicCryptoClientConfig crypto_config_;
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index efe6acc..ba110dd 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -64,10 +64,12 @@
crypto_stream_ = crypto_stream;
}
- QuicCryptoServerStream* GetCryptoStream() override { return crypto_stream_; }
+ QuicCryptoServerStreamBase* GetCryptoStream() override {
+ return crypto_stream_;
+ }
private:
- QuicCryptoServerStream* crypto_stream_;
+ QuicCryptoServerStreamBase* crypto_stream_;
DISALLOW_COPY_AND_ASSIGN(TestQuicSpdyServerSession);
};
@@ -408,7 +410,7 @@
session1_->SetCryptoStream(crypto_stream1_);
crypto_stream1_->set_handshake_confirmed_for_testing(
GetParam().crypto_handshake_successful);
- crypto_stream1_->set_peer_supports_stateless_rejects(
+ crypto_stream1_->SetPeerSupportsStatelessRejects(
GetParam().client_supports_statelesss_rejects);
return session1_;
}
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 33d7cef..423b99b 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -35,7 +35,7 @@
QuicSpdySession::Initialize();
}
-QuicCryptoServerStream* QuicServerSession::CreateQuicCryptoServerStream(
+QuicCryptoServerStreamBase* QuicServerSession::CreateQuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config) {
return new QuicCryptoServerStream(crypto_config, this);
}
@@ -51,7 +51,7 @@
// region, then pass it to the sent packet manager in preparation for possible
// bandwidth resumption.
const CachedNetworkParameters* cached_network_params =
- crypto_stream_->previous_cached_network_params();
+ crypto_stream_->PreviousCachedNetworkParams();
const bool last_bandwidth_resumption =
ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
const bool max_bandwidth_resumption =
@@ -210,7 +210,7 @@
return nullptr;
}
-QuicCryptoServerStream* QuicServerSession::GetCryptoStream() {
+QuicCryptoServerStreamBase* QuicServerSession::GetCryptoStream() {
return crypto_stream_.get();
}
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index 654d1ce8..bce73a72 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -70,7 +70,7 @@
void Initialize() override;
- const QuicCryptoServerStream* crypto_stream() const {
+ const QuicCryptoServerStreamBase* crypto_stream() const {
return crypto_stream_.get();
}
@@ -81,14 +81,14 @@
if (GetCryptoStream() == nullptr) {
return false;
}
- return GetCryptoStream()->use_stateless_rejects_if_peer_supported();
+ return GetCryptoStream()->UseStatelessRejectsIfPeerSupported();
}
bool PeerSupportsStatelessRejects() {
if (GetCryptoStream() == nullptr) {
return false;
}
- return GetCryptoStream()->peer_supports_stateless_rejects();
+ return GetCryptoStream()->PeerSupportsStatelessRejects();
}
void set_serving_region(const std::string& serving_region) {
@@ -99,21 +99,23 @@
// QuicSession methods:
QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override;
QuicSpdyStream* CreateOutgoingDynamicStream() override;
- QuicCryptoServerStream* GetCryptoStream() override;
+ QuicCryptoServerStreamBase* GetCryptoStream() override;
// If we should create an incoming stream, returns true. Otherwise
// does error handling, including communicating the error to the client and
// possibly closing the connection, and returns false.
virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id);
- virtual QuicCryptoServerStream* CreateQuicCryptoServerStream(
+ virtual QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config);
+ const QuicCryptoServerConfig* crypto_config() { return crypto_config_; }
+
private:
friend class test::QuicServerSessionPeer;
const QuicCryptoServerConfig* crypto_config_;
- scoped_ptr<QuicCryptoServerStream> crypto_stream_;
+ scoped_ptr<QuicCryptoServerStreamBase> crypto_stream_;
QuicServerSessionVisitor* visitor_;
// Whether bandwidth resumption is enabled for this connection.
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 2b1b961..173ea53 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -455,21 +455,21 @@
CachedNetworkParameters cached_network_params;
cached_network_params.set_bandwidth_estimate_bytes_per_second(1);
cached_network_params.set_serving_region("different serving region");
- crypto_stream->set_previous_cached_network_params(cached_network_params);
+ crypto_stream->SetPreviousCachedNetworkParams(cached_network_params);
EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0);
session_->OnConfigNegotiated();
// Same serving region, but timestamp is too old, should have no effect.
cached_network_params.set_serving_region(kTestServingRegion);
cached_network_params.set_timestamp(0);
- crypto_stream->set_previous_cached_network_params(cached_network_params);
+ crypto_stream->SetPreviousCachedNetworkParams(cached_network_params);
EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0);
session_->OnConfigNegotiated();
// Same serving region, and timestamp is recent: estimate is stored.
cached_network_params.set_timestamp(
connection_->clock()->WallNow().ToUNIXSeconds());
- crypto_stream->set_previous_cached_network_params(cached_network_params);
+ crypto_stream->SetPreviousCachedNetworkParams(cached_network_params);
EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(1);
session_->OnConfigNegotiated();
}
diff --git a/net/tools/quic/quic_simple_client_bin.cc b/net/tools/quic/quic_simple_client_bin.cc
index 69e68ad..aec114db 100644
--- a/net/tools/quic/quic_simple_client_bin.cc
+++ b/net/tools/quic/quic_simple_client_bin.cc
@@ -19,7 +19,7 @@
// quic_client https://www.google.com --port=443 --host=${IP}
//
// Use a specific version:
-// quic_client http://www.google.com --version=23 --host=${IP}
+// quic_client http://www.google.com --quic_version=23 --host=${IP}
//
// Send a POST instead of a GET:
// quic_client http://www.google.com --body="this is a POST body" --host=${IP}
diff --git a/net/tools/quic/quic_spdy_server_stream_test.cc b/net/tools/quic/quic_spdy_server_stream_test.cc
index dedb272..3ff6fe7 100644
--- a/net/tools/quic/quic_spdy_server_stream_test.cc
+++ b/net/tools/quic/quic_spdy_server_stream_test.cc
@@ -77,11 +77,13 @@
namespace {
-class QuicSpdyServerStreamTest : public ::testing::Test {
+class QuicSpdyServerStreamTest : public ::testing::TestWithParam<QuicVersion> {
public:
QuicSpdyServerStreamTest()
: connection_(
- new StrictMock<MockConnection>(&helper_, Perspective::IS_SERVER)),
+ new StrictMock<MockConnection>(&helper_,
+ Perspective::IS_SERVER,
+ SupportedVersions(GetParam()))),
session_(connection_),
body_("hello world") {
SpdyHeaderBlock request_headers;
@@ -144,7 +146,11 @@
return QuicConsumedData(data.total_length, fin);
}
-TEST_F(QuicSpdyServerStreamTest, TestFraming) {
+INSTANTIATE_TEST_CASE_P(Tests,
+ QuicSpdyServerStreamTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicSpdyServerStreamTest, TestFraming) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
WillRepeatedly(Invoke(ConsumeAllData));
stream_->OnStreamHeaders(headers_string_);
@@ -157,7 +163,7 @@
EXPECT_EQ(body_, StreamBody());
}
-TEST_F(QuicSpdyServerStreamTest, TestFramingOnePacket) {
+TEST_P(QuicSpdyServerStreamTest, TestFramingOnePacket) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
WillRepeatedly(Invoke(ConsumeAllData));
@@ -171,12 +177,32 @@
EXPECT_EQ(body_, StreamBody());
}
-TEST_F(QuicSpdyServerStreamTest, TestFramingExtraData) {
+TEST_P(QuicSpdyServerStreamTest, SendQuicRstStreamNoErrorInStopReading) {
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke(ConsumeAllData));
+
+ EXPECT_FALSE(stream_->fin_received());
+ EXPECT_FALSE(stream_->rst_received());
+
+ 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);
+ }
+ stream_->StopReading();
+}
+
+TEST_P(QuicSpdyServerStreamTest, TestFramingExtraData) {
string large_body = "hello world!!!!!!";
// We'll automatically write out an error (headers + body)
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
WillRepeatedly(Invoke(ConsumeAllData));
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
stream_->OnStreamHeaders(headers_string_);
stream_->OnStreamHeadersComplete(false, headers_string_.size());
@@ -185,13 +211,13 @@
// Content length is still 11. This will register as an error and we won't
// accept the bytes.
stream_->OnStreamFrame(
- QuicStreamFrame(stream_->id(), /*fin=*/false, body_.size(), large_body));
+ QuicStreamFrame(stream_->id(), /*fin=*/true, body_.size(), large_body));
EXPECT_EQ("11", StreamHeadersValue("content-length"));
EXPECT_EQ("/", StreamHeadersValue(":path"));
EXPECT_EQ("POST", StreamHeadersValue(":method"));
}
-TEST_F(QuicSpdyServerStreamTest, TestSendResponse) {
+TEST_P(QuicSpdyServerStreamTest, TestSendResponse) {
SpdyHeaderBlock* request_headers = stream_->mutable_headers();
(*request_headers)[":path"] = "/foo";
(*request_headers)[":authority"] = "";
@@ -201,6 +227,7 @@
response_headers_[":version"] = "HTTP/1.1";
response_headers_[":status"] = "200 OK";
response_headers_["content-length"] = "3";
+ stream_->set_fin_received(true);
InSequence s;
EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, 0, false, _, nullptr));
@@ -217,10 +244,13 @@
EXPECT_TRUE(stream_->write_side_closed());
}
-TEST_F(QuicSpdyServerStreamTest, TestSendErrorResponse) {
+TEST_P(QuicSpdyServerStreamTest, TestSendErrorResponse) {
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
+
response_headers_[":version"] = "HTTP/1.1";
response_headers_[":status"] = "500 Server Error";
response_headers_["content-length"] = "3";
+ stream_->set_fin_received(true);
InSequence s;
EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, 0, false, _, nullptr));
@@ -237,7 +267,9 @@
EXPECT_TRUE(stream_->write_side_closed());
}
-TEST_F(QuicSpdyServerStreamTest, InvalidMultipleContentLength) {
+TEST_P(QuicSpdyServerStreamTest, InvalidMultipleContentLength) {
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
+
SpdyHeaderBlock request_headers;
// \000 is a way to write the null byte when followed by a literal digit.
request_headers["content-length"] = StringPiece("11\00012", 5);
@@ -247,20 +279,17 @@
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
.Times(AnyNumber())
.WillRepeatedly(Invoke(ConsumeAllData));
-
stream_->OnStreamHeaders(headers_string_);
- stream_->OnStreamHeadersComplete(false, headers_string_.size());
+ stream_->OnStreamHeadersComplete(true, headers_string_.size());
- if (!FLAGS_quic_implement_stop_reading) {
- EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream_));
- } else {
- EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
- }
+ EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream_));
EXPECT_TRUE(stream_->reading_stopped());
EXPECT_TRUE(stream_->write_side_closed());
}
-TEST_F(QuicSpdyServerStreamTest, InvalidLeadingNullContentLength) {
+TEST_P(QuicSpdyServerStreamTest, InvalidLeadingNullContentLength) {
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
+
SpdyHeaderBlock request_headers;
// \000 is a way to write the null byte when followed by a literal digit.
request_headers["content-length"] = StringPiece("\00012", 3);
@@ -270,20 +299,15 @@
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
.Times(AnyNumber())
.WillRepeatedly(Invoke(ConsumeAllData));
-
stream_->OnStreamHeaders(headers_string_);
- stream_->OnStreamHeadersComplete(false, headers_string_.size());
+ stream_->OnStreamHeadersComplete(true, headers_string_.size());
- if (!FLAGS_quic_implement_stop_reading) {
- EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream_));
- } else {
- EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
- }
+ EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream_));
EXPECT_TRUE(stream_->reading_stopped());
EXPECT_TRUE(stream_->write_side_closed());
}
-TEST_F(QuicSpdyServerStreamTest, ValidMultipleContentLength) {
+TEST_P(QuicSpdyServerStreamTest, ValidMultipleContentLength) {
SpdyHeaderBlock request_headers;
// \000 is a way to write the null byte when followed by a literal digit.
request_headers["content-length"] = StringPiece("11\00011", 5);
@@ -299,7 +323,46 @@
EXPECT_FALSE(stream_->write_side_closed());
}
-TEST_F(QuicSpdyServerStreamTest, InvalidHeadersWithFin) {
+TEST_P(QuicSpdyServerStreamTest, SendQuicRstStreamNoErrorWithEarlyResponse) {
+ response_headers_[":version"] = "HTTP/1.1";
+ response_headers_[":status"] = "500 Server Error";
+ response_headers_["content-length"] = "3";
+
+ InSequence s;
+
+ EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, 0, false, _, nullptr));
+ 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_FALSE(stream_->fin_received());
+ QuicSpdyServerStreamPeer::SendErrorResponse(stream_);
+ EXPECT_TRUE(stream_->reading_stopped());
+ EXPECT_TRUE(stream_->write_side_closed());
+}
+
+TEST_P(QuicSpdyServerStreamTest, DoNotSendQuicRstStreamNoErrorWithRstReceived) {
+ response_headers_[":version"] = "HTTP/1.1";
+ response_headers_[":status"] = "500 Server Error";
+ response_headers_["content-length"] = "3";
+
+ InSequence s;
+ EXPECT_FALSE(stream_->reading_stopped());
+
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)).Times(1);
+ QuicRstStreamFrame rst_frame(stream_->id(), QUIC_STREAM_CANCELLED, 1234);
+ stream_->OnStreamReset(rst_frame);
+
+ EXPECT_TRUE(stream_->reading_stopped());
+ EXPECT_TRUE(stream_->write_side_closed());
+}
+
+TEST_P(QuicSpdyServerStreamTest, InvalidHeadersWithFin) {
char arr[] = {
0x3a, 0x68, 0x6f, 0x73, // :hos
0x74, 0x00, 0x00, 0x00, // t...
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 276daae..b6f1768 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -46,6 +46,7 @@
QuicAsyncStatus VerifyProof(const string& hostname,
const string& server_config,
const vector<string>& certs,
+ const string& cert_sct,
const string& signature,
const ProofVerifyContext* context,
string* error_details,
@@ -71,13 +72,18 @@
// }
//
// common_name_ = cert->subject().GetDisplayName();
+ cert_sct_ = cert_sct;
+
return QUIC_SUCCESS;
}
const string& common_name() const { return common_name_; }
+ const string& cert_sct() const { return cert_sct_; }
+
private:
string common_name_;
+ string cert_sct_;
};
} // anonymous namespace
@@ -387,6 +393,11 @@
->common_name();
}
+const string& QuicTestClient::cert_sct() const {
+ return reinterpret_cast<RecordingProofVerifier*>(client_->proof_verifier())
+ ->cert_sct();
+}
+
QuicTagValueMap QuicTestClient::GetServerConfig() const {
QuicCryptoClientConfig* config = client_->crypto_config();
QuicCryptoClientConfig::CachedState* state =
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index 0bf9baa..4d54f18 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -161,6 +161,10 @@
// or the empty string if no certificate was presented.
const std::string& cert_common_name() const;
+ // cert_sct returns the signed timestamp of the server's certificate,
+ // or the empty string if no signed timestamp was presented.
+ const std::string& cert_sct() const;
+
// Get the server config map.
QuicTagValueMap GetServerConfig() const;
diff --git a/net/tools/quic/test_tools/quic_test_server.cc b/net/tools/quic/test_tools/quic_test_server.cc
index 8d5bd487..baf33af 100644
--- a/net/tools/quic/test_tools/quic_test_server.cc
+++ b/net/tools/quic/test_tools/quic_test_server.cc
@@ -28,23 +28,38 @@
class CustomStreamSession : public QuicServerSession {
public:
- CustomStreamSession(const QuicConfig& config,
- QuicConnection* connection,
- QuicServerSessionVisitor* visitor,
- const QuicCryptoServerConfig* crypto_config,
- QuicTestServer::StreamFactory* factory)
+ CustomStreamSession(
+ const QuicConfig& config,
+ QuicConnection* connection,
+ QuicServerSessionVisitor* visitor,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicTestServer::StreamFactory* factory,
+ QuicTestServer::CryptoStreamFactory* crypto_stream_factory)
: QuicServerSession(config, connection, visitor, crypto_config),
- stream_factory_(factory) {}
+ stream_factory_(factory),
+ crypto_stream_factory_(crypto_stream_factory) {}
QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override {
if (!ShouldCreateIncomingDynamicStream(id)) {
return nullptr;
}
- return stream_factory_->CreateStream(id, this);
+ if (stream_factory_) {
+ return stream_factory_->CreateStream(id, this);
+ }
+ return QuicServerSession::CreateIncomingDynamicStream(id);
+ }
+
+ QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
+ const QuicCryptoServerConfig* crypto_config) override {
+ if (crypto_stream_factory_) {
+ return crypto_stream_factory_->CreateCryptoStream(crypto_config, this);
+ }
+ return QuicServerSession::CreateQuicCryptoServerStream(crypto_config);
}
private:
- QuicTestServer::StreamFactory* stream_factory_; // Not owned.
+ QuicTestServer::StreamFactory* stream_factory_; // Not owned.
+ QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned.
};
class QuicTestDispatcher : public QuicDispatcher {
@@ -56,11 +71,13 @@
QuicConnectionHelperInterface* helper)
: QuicDispatcher(config, crypto_config, versions, factory, helper),
session_factory_(nullptr),
- stream_factory_(nullptr) {}
+ stream_factory_(nullptr),
+ crypto_stream_factory_(nullptr) {}
QuicServerSession* CreateQuicSession(QuicConnectionId id,
const IPEndPoint& client) override {
- if (session_factory_ == nullptr && stream_factory_ == nullptr) {
+ if (session_factory_ == nullptr && stream_factory_ == nullptr &&
+ crypto_stream_factory_ == nullptr) {
return QuicDispatcher::CreateQuicSession(id, client);
}
QuicConnection* connection = new QuicConnection(
@@ -68,9 +85,10 @@
/* owns_writer= */ true, Perspective::IS_SERVER, supported_versions());
QuicServerSession* session = nullptr;
- if (stream_factory_ != nullptr) {
- session = new CustomStreamSession(config(), connection, this,
- crypto_config(), stream_factory_);
+ if (stream_factory_ != nullptr || crypto_stream_factory_ != nullptr) {
+ session =
+ new CustomStreamSession(config(), connection, this, crypto_config(),
+ stream_factory_, crypto_stream_factory_);
} else {
session = session_factory_->CreateSession(config(), connection, this,
crypto_config());
@@ -82,6 +100,7 @@
void set_session_factory(QuicTestServer::SessionFactory* factory) {
DCHECK(session_factory_ == nullptr);
DCHECK(stream_factory_ == nullptr);
+ DCHECK(crypto_stream_factory_ == nullptr);
session_factory_ = factory;
}
@@ -91,13 +110,20 @@
stream_factory_ = factory;
}
+ void set_crypto_stream_factory(QuicTestServer::CryptoStreamFactory* factory) {
+ DCHECK(session_factory_ == nullptr);
+ DCHECK(crypto_stream_factory_ == nullptr);
+ crypto_stream_factory_ = factory;
+ }
+
QuicTestServer::SessionFactory* session_factory() { return session_factory_; }
QuicTestServer::StreamFactory* stream_factory() { return stream_factory_; }
private:
- QuicTestServer::SessionFactory* session_factory_; // Not owned.
- QuicTestServer::StreamFactory* stream_factory_; // Not owned.
+ QuicTestServer::SessionFactory* session_factory_; // Not owned.
+ QuicTestServer::StreamFactory* stream_factory_; // Not owned.
+ QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned.
};
QuicTestServer::QuicTestServer(ProofSource* proof_source)
@@ -124,6 +150,11 @@
static_cast<QuicTestDispatcher*>(dispatcher())->set_stream_factory(factory);
}
+void QuicTestServer::SetCryptoStreamFactory(CryptoStreamFactory* factory) {
+ static_cast<QuicTestDispatcher*>(dispatcher())
+ ->set_crypto_stream_factory(factory);
+}
+
/////////////////////////// TEST SESSIONS ///////////////////////////////
ImmediateGoAwaySession::ImmediateGoAwaySession(
diff --git a/net/tools/quic/test_tools/quic_test_server.h b/net/tools/quic/test_tools/quic_test_server.h
index 6a027632..da97ccdb 100644
--- a/net/tools/quic/test_tools/quic_test_server.h
+++ b/net/tools/quic/test_tools/quic_test_server.h
@@ -49,6 +49,16 @@
QuicSpdySession* session) = 0;
};
+ class CryptoStreamFactory {
+ public:
+ virtual ~CryptoStreamFactory() {}
+
+ // Returns a new QuicCryptoServerStreamBase owned by the caller
+ virtual QuicCryptoServerStreamBase* CreateCryptoStream(
+ const QuicCryptoServerConfig* crypto_config,
+ QuicSpdySession* session) = 0;
+ };
+
explicit QuicTestServer(ProofSource* proof_source);
QuicTestServer(ProofSource* proof_source,
const QuicConfig& config,
@@ -58,12 +68,17 @@
QuicDispatcher* CreateQuicDispatcher() override;
// Sets a custom session factory, owned by the caller, for easy custom
- // session logic. This is incompatible with setting a stream factory.
+ // session logic. This is incompatible with setting a stream factory or a
+ // crypto stream factory.
void SetSessionFactory(SessionFactory* factory);
// Sets a custom stream factory, owned by the caller, for easy custom
// stream logic. This is incompatible with setting a session factory.
void SetSpdyStreamFactory(StreamFactory* factory);
+
+ // Sets a custom crypto stream factory, owned by the caller, for easy custom
+ // crypto logic. This is incompatible with setting a session factory.
+ void SetCryptoStreamFactory(CryptoStreamFactory* factory);
};
// Useful test sessions for the QuicTestServer.