diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-07-31 15:50:41 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-08-30 12:35:23 +0000 |
commit | 7b2ffa587235a47d4094787d72f38102089f402a (patch) | |
tree | 30e82af9cbab08a7fa028bb18f4f2987a3f74dfa /chromium/net/third_party | |
parent | d94af01c90575348c4e81a418257f254b6f8d225 (diff) | |
download | qtwebengine-chromium-7b2ffa587235a47d4094787d72f38102089f402a.tar.gz |
BASELINE: Update Chromium to 76.0.3809.94
Change-Id: I321c3f5f929c105aec0f98c5091ef6108822e647
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/net/third_party')
320 files changed, 13747 insertions, 10003 deletions
diff --git a/chromium/net/third_party/nist-pkits/generate_tests.py b/chromium/net/third_party/nist-pkits/generate_tests.py index b2c42c2a059..2da0c120d7f 100644 --- a/chromium/net/third_party/nist-pkits/generate_tests.py +++ b/chromium/net/third_party/nist-pkits/generate_tests.py @@ -200,6 +200,8 @@ def parse_cert_path_lines(lines): if "is composed of the following objects:" in line: continue + if "See the introduction to Section 4.4 for more information." in line: + continue if not line or PAGE_NUMBER_MATCHER.match(line): continue @@ -1182,6 +1184,12 @@ def main(): output = open(output_path, 'w') output.write('// Autogenerated by %s, do not edit\n\n' % sys.argv[0]) + output.write(""" +// This file intentionally does not have header guards, it's intended to +// be inlined in another header file. The following line silences a +// presubmit warning that would otherwise be triggered by this: +// no-include-guard-because-multiply-included +// NOLINT(build/header_guard)\n\n""") output.write('// Hack to allow disabling type parameterized test cases.\n' '// See https://github.com/google/googletest/issues/389\n') output.write('#define WRAPPED_TYPED_TEST_P(CaseName, TestName) ' diff --git a/chromium/net/third_party/nist-pkits/pkits_testcases-inl.h b/chromium/net/third_party/nist-pkits/pkits_testcases-inl.h index f83c0a244ed..6fee9585417 100644 --- a/chromium/net/third_party/nist-pkits/pkits_testcases-inl.h +++ b/chromium/net/third_party/nist-pkits/pkits_testcases-inl.h @@ -1,5 +1,11 @@ // Autogenerated by generate_tests.py, do not edit +// This file intentionally does not have header guards, it's intended to +// be inlined in another header file. The following line silences a +// presubmit warning that would otherwise be triggered by this: +// no-include-guard-because-multiply-included +// NOLINT(build/header_guard) + // Hack to allow disabling type parameterized test cases. // See https://github.com/google/googletest/issues/389 #define WRAPPED_TYPED_TEST_P(CaseName, TestName) \ @@ -556,8 +562,7 @@ WRAPPED_TYPED_TEST_P(PkitsTest04BasicCertificateRevocationTests, Section4Invalidpre2000CRLnextUpdateTest12) { const char* const certs[] = {"TrustAnchorRootCertificate", "pre2000CRLnextUpdateCACert", - "Invalidpre2000CRLnextUpdateTest12EESeetheintrod" - "uctiontoSection4.4formoreinformation."}; + "Invalidpre2000CRLnextUpdateTest12EE"}; const char* const crls[] = {"TrustAnchorRootCRL", "pre2000CRLnextUpdateCACRL"}; PkitsTestInfo info; diff --git a/chromium/net/third_party/quiche/OWNERS b/chromium/net/third_party/quiche/OWNERS new file mode 100644 index 00000000000..e2c377d23b0 --- /dev/null +++ b/chromium/net/third_party/quiche/OWNERS @@ -0,0 +1,3 @@ +file://net/quic/OWNERS + +# COMPONENT: Internals>Network>QUIC diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_logging.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_logging.h new file mode 100644 index 00000000000..15f5bf3fbc5 --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_logging.h @@ -0,0 +1,6 @@ +#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_LOGGING_H_ +#define QUICHE_COMMON_PLATFORM_API_QUICHE_LOGGING_H_ + +#include "net/quiche/common/platform/impl/quiche_logging_impl.h" + +#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_LOGGING_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h new file mode 100644 index 00000000000..26b152bd47f --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h @@ -0,0 +1,21 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_PTR_UTIL_H_ +#define QUICHE_COMMON_PLATFORM_API_QUICHE_PTR_UTIL_H_ + +#include <memory> + +#include "net/quiche/common/platform/impl/quiche_ptr_util_impl.h" + +namespace quiche { + +template <typename T, typename... Args> +std::unique_ptr<T> QuicheMakeUnique(Args&&... args) { + return QuicheMakeUniqueImpl<T>(std::forward<Args>(args)...); +} + +} // namespace quiche + +#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_PTR_UTIL_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_test.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_test.h new file mode 100644 index 00000000000..f51c85e63a0 --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_test.h @@ -0,0 +1,10 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_TEST_H_ +#define QUICHE_COMMON_PLATFORM_API_QUICHE_TEST_H_ + +#include "net/quiche/common/platform/impl/quiche_test_impl.h" + +#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_TEST_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_unordered_containers.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_unordered_containers.h new file mode 100644 index 00000000000..583f97eba65 --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_unordered_containers.h @@ -0,0 +1,24 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_UNORDERED_CONTAINERS_H_ +#define QUICHE_COMMON_PLATFORM_API_QUICHE_UNORDERED_CONTAINERS_H_ + +#include "net/quiche/common/platform/impl/quiche_unordered_containers_impl.h" + +namespace quiche { + +// The default hasher used by hash tables. +template <typename Key> +using QuicheDefaultHasher = QuicheDefaultHasherImpl<Key>; + +// A general-purpose unordered map. +template <typename Key, + typename Value, + typename Hash = QuicheDefaultHasher<Key>> +using QuicheUnorderedMap = QuicheUnorderedMapImpl<Key, Value, Hash>; + +} // namespace quiche + +#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_UNORDERED_CONTAINERS_H_ diff --git a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h b/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h new file mode 100644 index 00000000000..c99585e2092 --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h @@ -0,0 +1,246 @@ +// Copyright (c) 2019 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. + +// This is a simplistic insertion-ordered map. It behaves similarly to an STL +// map, but only implements a small subset of the map's methods. Internally, we +// just keep a map and a list going in parallel. +// +// This class provides no thread safety guarantees, beyond what you would +// normally see with std::list. +// +// Iterators point into the list and should be stable in the face of +// mutations, except for an iterator pointing to an element that was just +// deleted. + +#ifndef QUICHE_COMMON_SIMPLE_LINKED_HASH_MAP_H_ +#define QUICHE_COMMON_SIMPLE_LINKED_HASH_MAP_H_ + +#include <list> +#include <tuple> +#include <type_traits> +#include <utility> + +#include "net/third_party/quiche/src/common/platform/api/quiche_logging.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_unordered_containers.h" + +namespace quiche { + +// This holds a list of pair<Key, Value> items. This list is what gets +// traversed, and it's iterators from this list that we return from +// begin/end/find. +// +// We also keep a set<list::iterator> for find. Since std::list is a +// doubly-linked list, the iterators should remain stable. + +template <class Key, class Value, class Hash = std::hash<Key>> +class SimpleLinkedHashMap { + private: + typedef std::list<std::pair<Key, Value>> ListType; + typedef QuicheUnorderedMap<Key, typename ListType::iterator, Hash> MapType; + + public: + typedef typename ListType::iterator iterator; + typedef typename ListType::reverse_iterator reverse_iterator; + typedef typename ListType::const_iterator const_iterator; + typedef typename ListType::const_reverse_iterator const_reverse_iterator; + typedef typename MapType::key_type key_type; + typedef typename ListType::value_type value_type; + typedef typename ListType::size_type size_type; + + SimpleLinkedHashMap() = default; + explicit SimpleLinkedHashMap(size_type bucket_count) : map_(bucket_count) {} + + SimpleLinkedHashMap(const SimpleLinkedHashMap& other) = delete; + SimpleLinkedHashMap& operator=(const SimpleLinkedHashMap& other) = delete; + SimpleLinkedHashMap(SimpleLinkedHashMap&& other) = default; + SimpleLinkedHashMap& operator=(SimpleLinkedHashMap&& other) = default; + + // Returns an iterator to the first (insertion-ordered) element. Like a map, + // this can be dereferenced to a pair<Key, Value>. + iterator begin() { return list_.begin(); } + const_iterator begin() const { return list_.begin(); } + + // Returns an iterator beyond the last element. + iterator end() { return list_.end(); } + const_iterator end() const { return list_.end(); } + + // Returns an iterator to the last (insertion-ordered) element. Like a map, + // this can be dereferenced to a pair<Key, Value>. + reverse_iterator rbegin() { return list_.rbegin(); } + const_reverse_iterator rbegin() const { return list_.rbegin(); } + + // Returns an iterator beyond the first element. + reverse_iterator rend() { return list_.rend(); } + const_reverse_iterator rend() const { return list_.rend(); } + + // Front and back accessors common to many stl containers. + + // Returns the earliest-inserted element + const value_type& front() const { return list_.front(); } + + // Returns the earliest-inserted element. + value_type& front() { return list_.front(); } + + // Returns the most-recently-inserted element. + const value_type& back() const { return list_.back(); } + + // Returns the most-recently-inserted element. + value_type& back() { return list_.back(); } + + // Clears the map of all values. + void clear() { + map_.clear(); + list_.clear(); + } + + // Returns true iff the map is empty. + bool empty() const { return list_.empty(); } + + // Removes the first element from the list. + void pop_front() { erase(begin()); } + + // Erases values with the provided key. Returns the number of elements + // erased. In this implementation, this will be 0 or 1. + size_type erase(const Key& key) { + typename MapType::iterator found = map_.find(key); + if (found == map_.end()) { + return 0; + } + + list_.erase(found->second); + map_.erase(found); + + return 1; + } + + // Erases the item that 'position' points to. Returns an iterator that points + // to the item that comes immediately after the deleted item in the list, or + // end(). + // If the provided iterator is invalid or there is inconsistency between the + // map and list, a CHECK() error will occur. + iterator erase(iterator position) { + typename MapType::iterator found = map_.find(position->first); + CHECK(found->second == position) + << "Inconsisent iterator for map and list, or the iterator is invalid."; + + map_.erase(found); + return list_.erase(position); + } + + // Erases all the items in the range [first, last). Returns an iterator that + // points to the item that comes immediately after the last deleted item in + // the list, or end(). + iterator erase(iterator first, iterator last) { + while (first != last && first != end()) { + first = erase(first); + } + return first; + } + + // Finds the element with the given key. Returns an iterator to the + // value found, or to end() if the value was not found. Like a map, this + // iterator points to a pair<Key, Value>. + iterator find(const Key& key) { + typename MapType::iterator found = map_.find(key); + if (found == map_.end()) { + return end(); + } + return found->second; + } + + const_iterator find(const Key& key) const { + typename MapType::const_iterator found = map_.find(key); + if (found == map_.end()) { + return end(); + } + return found->second; + } + + bool contains(const Key& key) const { return find(key) != end(); } + + // Returns the value mapped to key, or an inserted iterator to that position + // in the map. + Value& operator[](const key_type& key) { + return (*((this->insert(std::make_pair(key, Value()))).first)).second; + } + + // Inserts an element into the map + std::pair<iterator, bool> insert(const std::pair<Key, Value>& pair) { + // First make sure the map doesn't have a key with this value. If it does, + // return a pair with an iterator to it, and false indicating that we + // didn't insert anything. + typename MapType::iterator found = map_.find(pair.first); + if (found != map_.end()) { + return std::make_pair(found->second, false); + } + + // Otherwise, insert into the list first. + list_.push_back(pair); + + // Obtain an iterator to the newly added element. We do -- instead of - + // since list::iterator doesn't implement operator-(). + typename ListType::iterator last = list_.end(); + --last; + + CHECK(map_.insert(std::make_pair(pair.first, last)).second) + << "Map and list are inconsistent"; + + return std::make_pair(last, true); + } + + // Inserts an element into the map + std::pair<iterator, bool> insert(std::pair<Key, Value>&& pair) { + // First make sure the map doesn't have a key with this value. If it does, + // return a pair with an iterator to it, and false indicating that we + // didn't insert anything. + typename MapType::iterator found = map_.find(pair.first); + if (found != map_.end()) { + return std::make_pair(found->second, false); + } + + // Otherwise, insert into the list first. + list_.push_back(std::move(pair)); + + // Obtain an iterator to the newly added element. We do -- instead of - + // since list::iterator doesn't implement operator-(). + typename ListType::iterator last = list_.end(); + --last; + + CHECK(map_.insert(std::make_pair(pair.first, last)).second) + << "Map and list are inconsistent"; + return std::make_pair(last, true); + } + + size_type size() const { return list_.size(); } + + template <typename... Args> + std::pair<iterator, bool> emplace(Args&&... args) { + ListType node_donor; + auto node_pos = + node_donor.emplace(node_donor.end(), std::forward<Args>(args)...); + const auto& k = node_pos->first; + auto ins = map_.insert({k, node_pos}); + if (!ins.second) { + return {ins.first->second, false}; + } + list_.splice(list_.end(), node_donor, node_pos); + return {ins.first->second, true}; + } + + void swap(SimpleLinkedHashMap& other) { + map_.swap(other.map_); + list_.swap(other.list_); + } + + private: + // The map component, used for speedy lookups + MapType map_; + + // The list component, used for maintaining insertion order + ListType list_; +}; + +} // namespace quiche + +#endif // QUICHE_COMMON_SIMPLE_LINKED_HASH_MAP_H_ diff --git a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map_test.cc b/chromium/net/third_party/quiche/src/common/simple_linked_hash_map_test.cc new file mode 100644 index 00000000000..0ea7d8a015d --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/simple_linked_hash_map_test.cc @@ -0,0 +1,396 @@ +// Copyright (c) 2019 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. + +// Tests SimpleLinkedHashMap. + +#include "net/third_party/quiche/src/common/simple_linked_hash_map.h" + +#include <memory> +#include <utility> + +#include "net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_test.h" + +using testing::Pair; +using testing::Pointee; +using testing::UnorderedElementsAre; + +namespace quiche { +namespace test { + +// Tests that move constructor works. +TEST(LinkedHashMapTest, Move) { + // Use unique_ptr as an example of a non-copyable type. + SimpleLinkedHashMap<int, std::unique_ptr<int>> m; + m[2] = QuicheMakeUnique<int>(12); + m[3] = QuicheMakeUnique<int>(13); + SimpleLinkedHashMap<int, std::unique_ptr<int>> n = std::move(m); + EXPECT_THAT(n, + UnorderedElementsAre(Pair(2, Pointee(12)), Pair(3, Pointee(13)))); +} + +TEST(LinkedHashMapTest, CanEmplaceMoveOnly) { + SimpleLinkedHashMap<int, std::unique_ptr<int>> m; + struct Data { + int k, v; + }; + const Data data[] = {{1, 123}, {3, 345}, {2, 234}, {4, 456}}; + for (const auto& kv : data) { + m.emplace(std::piecewise_construct, std::make_tuple(kv.k), + std::make_tuple(new int{kv.v})); + } + EXPECT_TRUE(m.contains(2)); + auto found = m.find(2); + ASSERT_TRUE(found != m.end()); + EXPECT_EQ(234, *found->second); +} + +struct NoCopy { + explicit NoCopy(int x) : x(x) {} + NoCopy(const NoCopy&) = delete; + NoCopy& operator=(const NoCopy&) = delete; + NoCopy(NoCopy&&) = delete; + NoCopy& operator=(NoCopy&&) = delete; + int x; +}; + +TEST(LinkedHashMapTest, CanEmplaceNoMoveNoCopy) { + SimpleLinkedHashMap<int, NoCopy> m; + struct Data { + int k, v; + }; + const Data data[] = {{1, 123}, {3, 345}, {2, 234}, {4, 456}}; + for (const auto& kv : data) { + m.emplace(std::piecewise_construct, std::make_tuple(kv.k), + std::make_tuple(kv.v)); + } + EXPECT_TRUE(m.contains(2)); + auto found = m.find(2); + ASSERT_TRUE(found != m.end()); + EXPECT_EQ(234, found->second.x); +} + +TEST(LinkedHashMapTest, ConstKeys) { + SimpleLinkedHashMap<int, int> m; + m.insert(std::make_pair(1, 2)); + // Test that keys are const in iteration. + std::pair<int, int>& p = *m.begin(); + EXPECT_EQ(1, p.first); +} + +// Tests that iteration from begin() to end() works +TEST(LinkedHashMapTest, Iteration) { + SimpleLinkedHashMap<int, int> m; + EXPECT_TRUE(m.begin() == m.end()); + + m.insert(std::make_pair(2, 12)); + m.insert(std::make_pair(1, 11)); + m.insert(std::make_pair(3, 13)); + + SimpleLinkedHashMap<int, int>::iterator i = m.begin(); + ASSERT_TRUE(m.begin() == i); + ASSERT_TRUE(m.end() != i); + EXPECT_EQ(2, i->first); + EXPECT_EQ(12, i->second); + + ++i; + ASSERT_TRUE(m.end() != i); + EXPECT_EQ(1, i->first); + EXPECT_EQ(11, i->second); + + ++i; + ASSERT_TRUE(m.end() != i); + EXPECT_EQ(3, i->first); + EXPECT_EQ(13, i->second); + + ++i; // Should be the end of the line. + ASSERT_TRUE(m.end() == i); +} + +// Tests that reverse iteration from rbegin() to rend() works +TEST(LinkedHashMapTest, ReverseIteration) { + SimpleLinkedHashMap<int, int> m; + EXPECT_TRUE(m.rbegin() == m.rend()); + + m.insert(std::make_pair(2, 12)); + m.insert(std::make_pair(1, 11)); + m.insert(std::make_pair(3, 13)); + + SimpleLinkedHashMap<int, int>::reverse_iterator i = m.rbegin(); + ASSERT_TRUE(m.rbegin() == i); + ASSERT_TRUE(m.rend() != i); + EXPECT_EQ(3, i->first); + EXPECT_EQ(13, i->second); + + ++i; + ASSERT_TRUE(m.rend() != i); + EXPECT_EQ(1, i->first); + EXPECT_EQ(11, i->second); + + ++i; + ASSERT_TRUE(m.rend() != i); + EXPECT_EQ(2, i->first); + EXPECT_EQ(12, i->second); + + ++i; // Should be the end of the line. + ASSERT_TRUE(m.rend() == i); +} + +// Tests that clear() works +TEST(LinkedHashMapTest, Clear) { + SimpleLinkedHashMap<int, int> m; + m.insert(std::make_pair(2, 12)); + m.insert(std::make_pair(1, 11)); + m.insert(std::make_pair(3, 13)); + + ASSERT_EQ(3u, m.size()); + + m.clear(); + + EXPECT_EQ(0u, m.size()); + + m.clear(); // Make sure we can call it on an empty map. + + EXPECT_EQ(0u, m.size()); +} + +// Tests that size() works. +TEST(LinkedHashMapTest, Size) { + SimpleLinkedHashMap<int, int> m; + EXPECT_EQ(0u, m.size()); + m.insert(std::make_pair(2, 12)); + EXPECT_EQ(1u, m.size()); + m.insert(std::make_pair(1, 11)); + EXPECT_EQ(2u, m.size()); + m.insert(std::make_pair(3, 13)); + EXPECT_EQ(3u, m.size()); + m.clear(); + EXPECT_EQ(0u, m.size()); +} + +// Tests empty() +TEST(LinkedHashMapTest, Empty) { + SimpleLinkedHashMap<int, int> m; + ASSERT_TRUE(m.empty()); + m.insert(std::make_pair(2, 12)); + ASSERT_FALSE(m.empty()); + m.clear(); + ASSERT_TRUE(m.empty()); +} + +TEST(LinkedHashMapTest, Erase) { + SimpleLinkedHashMap<int, int> m; + ASSERT_EQ(0u, m.size()); + EXPECT_EQ(0u, m.erase(2)); // Nothing to erase yet + + m.insert(std::make_pair(2, 12)); + ASSERT_EQ(1u, m.size()); + EXPECT_EQ(1u, m.erase(2)); + EXPECT_EQ(0u, m.size()); + + EXPECT_EQ(0u, m.erase(2)); // Make sure nothing bad happens if we repeat. + EXPECT_EQ(0u, m.size()); +} + +TEST(LinkedHashMapTest, Erase2) { + SimpleLinkedHashMap<int, int> m; + ASSERT_EQ(0u, m.size()); + EXPECT_EQ(0u, m.erase(2)); // Nothing to erase yet + + m.insert(std::make_pair(2, 12)); + m.insert(std::make_pair(1, 11)); + m.insert(std::make_pair(3, 13)); + m.insert(std::make_pair(4, 14)); + ASSERT_EQ(4u, m.size()); + + // Erase middle two + EXPECT_EQ(1u, m.erase(1)); + EXPECT_EQ(1u, m.erase(3)); + + EXPECT_EQ(2u, m.size()); + + // Make sure we can still iterate over everything that's left. + SimpleLinkedHashMap<int, int>::iterator it = m.begin(); + ASSERT_TRUE(it != m.end()); + EXPECT_EQ(12, it->second); + ++it; + ASSERT_TRUE(it != m.end()); + EXPECT_EQ(14, it->second); + ++it; + ASSERT_TRUE(it == m.end()); + + EXPECT_EQ(0u, m.erase(1)); // Make sure nothing bad happens if we repeat. + ASSERT_EQ(2u, m.size()); + + EXPECT_EQ(1u, m.erase(2)); + EXPECT_EQ(1u, m.erase(4)); + ASSERT_EQ(0u, m.size()); + + EXPECT_EQ(0u, m.erase(1)); // Make sure nothing bad happens if we repeat. + ASSERT_EQ(0u, m.size()); +} + +// Test that erase(iter,iter) and erase(iter) compile and work. +TEST(LinkedHashMapTest, Erase3) { + SimpleLinkedHashMap<int, int> m; + + m.insert(std::make_pair(1, 11)); + m.insert(std::make_pair(2, 12)); + m.insert(std::make_pair(3, 13)); + m.insert(std::make_pair(4, 14)); + + // Erase middle two + SimpleLinkedHashMap<int, int>::iterator it2 = m.find(2); + SimpleLinkedHashMap<int, int>::iterator it4 = m.find(4); + EXPECT_EQ(m.erase(it2, it4), m.find(4)); + EXPECT_EQ(2u, m.size()); + + // Make sure we can still iterate over everything that's left. + SimpleLinkedHashMap<int, int>::iterator it = m.begin(); + ASSERT_TRUE(it != m.end()); + EXPECT_EQ(11, it->second); + ++it; + ASSERT_TRUE(it != m.end()); + EXPECT_EQ(14, it->second); + ++it; + ASSERT_TRUE(it == m.end()); + + // Erase first one using an iterator. + EXPECT_EQ(m.erase(m.begin()), m.find(4)); + + // Only the last element should be left. + it = m.begin(); + ASSERT_TRUE(it != m.end()); + EXPECT_EQ(14, it->second); + ++it; + ASSERT_TRUE(it == m.end()); +} + +TEST(LinkedHashMapTest, Insertion) { + SimpleLinkedHashMap<int, int> m; + ASSERT_EQ(0u, m.size()); + std::pair<SimpleLinkedHashMap<int, int>::iterator, bool> result; + + result = m.insert(std::make_pair(2, 12)); + ASSERT_EQ(1u, m.size()); + EXPECT_TRUE(result.second); + EXPECT_EQ(2, result.first->first); + EXPECT_EQ(12, result.first->second); + + result = m.insert(std::make_pair(1, 11)); + ASSERT_EQ(2u, m.size()); + EXPECT_TRUE(result.second); + EXPECT_EQ(1, result.first->first); + EXPECT_EQ(11, result.first->second); + + result = m.insert(std::make_pair(3, 13)); + SimpleLinkedHashMap<int, int>::iterator result_iterator = result.first; + ASSERT_EQ(3u, m.size()); + EXPECT_TRUE(result.second); + EXPECT_EQ(3, result.first->first); + EXPECT_EQ(13, result.first->second); + + result = m.insert(std::make_pair(3, 13)); + EXPECT_EQ(3u, m.size()); + EXPECT_FALSE(result.second) << "No insertion should have occurred."; + EXPECT_TRUE(result_iterator == result.first) + << "Duplicate insertion should have given us the original iterator."; +} + +static std::pair<int, int> Pair(int i, int j) { + return {i, j}; +} + +// Test front accessors. +TEST(LinkedHashMapTest, Front) { + SimpleLinkedHashMap<int, int> m; + + m.insert(std::make_pair(2, 12)); + m.insert(std::make_pair(1, 11)); + m.insert(std::make_pair(3, 13)); + + EXPECT_EQ(3u, m.size()); + EXPECT_EQ(Pair(2, 12), m.front()); + m.pop_front(); + EXPECT_EQ(2u, m.size()); + EXPECT_EQ(Pair(1, 11), m.front()); + m.pop_front(); + EXPECT_EQ(1u, m.size()); + EXPECT_EQ(Pair(3, 13), m.front()); + m.pop_front(); + EXPECT_TRUE(m.empty()); +} + +TEST(LinkedHashMapTest, Find) { + SimpleLinkedHashMap<int, int> m; + + EXPECT_TRUE(m.end() == m.find(1)) + << "We shouldn't find anything in an empty map."; + + m.insert(std::make_pair(2, 12)); + EXPECT_TRUE(m.end() == m.find(1)) + << "We shouldn't find an element that doesn't exist in the map."; + + std::pair<SimpleLinkedHashMap<int, int>::iterator, bool> result = + m.insert(std::make_pair(1, 11)); + ASSERT_TRUE(result.second); + ASSERT_TRUE(m.end() != result.first); + EXPECT_TRUE(result.first == m.find(1)) + << "We should have found an element we know exists in the map."; + EXPECT_EQ(11, result.first->second); + + // Check that a follow-up insertion doesn't affect our original + m.insert(std::make_pair(3, 13)); + SimpleLinkedHashMap<int, int>::iterator it = m.find(1); + ASSERT_TRUE(m.end() != it); + EXPECT_EQ(11, it->second); + + m.clear(); + EXPECT_TRUE(m.end() == m.find(1)) + << "We shouldn't find anything in a map that we've cleared."; +} + +TEST(LinkedHashMapTest, Contains) { + SimpleLinkedHashMap<int, int> m; + + EXPECT_FALSE(m.contains(1)) << "An empty map shouldn't contain anything."; + + m.insert(std::make_pair(2, 12)); + EXPECT_FALSE(m.contains(1)) + << "The map shouldn't contain an element that doesn't exist."; + + m.insert(std::make_pair(1, 11)); + EXPECT_TRUE(m.contains(1)) + << "The map should contain an element that we know exists."; + + m.clear(); + EXPECT_FALSE(m.contains(1)) + << "A map that we've cleared shouldn't contain anything."; +} + +TEST(LinkedHashMapTest, Swap) { + SimpleLinkedHashMap<int, int> m1; + SimpleLinkedHashMap<int, int> m2; + m1.insert(std::make_pair(1, 1)); + m1.insert(std::make_pair(2, 2)); + m2.insert(std::make_pair(3, 3)); + ASSERT_EQ(2u, m1.size()); + ASSERT_EQ(1u, m2.size()); + m1.swap(m2); + ASSERT_EQ(1u, m1.size()); + ASSERT_EQ(2u, m2.size()); +} + +TEST(LinkedHashMapTest, CustomHashAndEquality) { + struct CustomIntHash { + size_t operator()(int x) const { return x; } + }; + SimpleLinkedHashMap<int, int, CustomIntHash> m; + m.insert(std::make_pair(1, 1)); + EXPECT_TRUE(m.contains(1)); + EXPECT_EQ(1, m[1]); +} + +} // namespace test +} // namespace quiche diff --git a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h index 470311a4088..cd5bd3a8808 100644 --- a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h +++ b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h @@ -8,8 +8,7 @@ #include <stddef.h> #include <stdint.h> -#include <unordered_map> -#include <unordered_set> +#include <map> #include "net/third_party/quiche/src/epoll_server/platform/api/epoll_export.h" #include "net/third_party/quiche/src/epoll_server/simple_epoll_server.h" @@ -57,7 +56,7 @@ class EPOLL_EXPORT_PRIVATE FakeTimeSimpleEpollServer class EPOLL_EXPORT_PRIVATE FakeSimpleEpollServer : public FakeTimeSimpleEpollServer { public: // type definitions - using EventQueue = std::unordered_multimap<int64_t, struct epoll_event>; + using EventQueue = std::multimap<int64_t, struct epoll_event>; FakeSimpleEpollServer(); FakeSimpleEpollServer(const FakeSimpleEpollServer&) = delete; diff --git a/chromium/net/third_party/quiche/src/epoll_server/platform/api/epoll_time.h b/chromium/net/third_party/quiche/src/epoll_server/platform/api/epoll_time.h index 95f04079a97..3d263848b5c 100644 --- a/chromium/net/third_party/quiche/src/epoll_server/platform/api/epoll_time.h +++ b/chromium/net/third_party/quiche/src/epoll_server/platform/api/epoll_time.h @@ -9,7 +9,7 @@ namespace epoll_server { -int64_t WallTimeNowInUsec() { return WallTimeNowInUsecImpl(); } +inline int64_t WallTimeNowInUsec() { return WallTimeNowInUsecImpl(); } } // namespace epoll_server diff --git a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc index 7c024f1d562..dbc3292f96d 100644 --- a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc +++ b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc @@ -164,7 +164,10 @@ class RecordingCB : public EpollCallbackInterface { if (event->in_events & EPOLLIN) { const int kLength = 1024; char buf[kLength]; - read(fd, &buf, kLength); + int data_read; + do { + data_read = read(fd, &buf, kLength); + } while (data_read > 0); } } @@ -258,7 +261,7 @@ class EpollFunctionTest : public EpollTest { int pipe_fds[2]; if (pipe(pipe_fds) < 0) { - PLOG(FATAL) << "pipe() failed"; + EPOLL_PLOG(FATAL) << "pipe() failed"; } fd_ = pipe_fds[0]; fd2_ = pipe_fds[1]; @@ -1004,7 +1007,7 @@ TEST(SimpleEpollServerTest, TestRepeatAlarms) { alarm.Reset(); // Make sure the alarm is called one final time. - EXPECT_EQ(1, ep.GetNumPendingAlarmsForTest()); + EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); ep.set_timeout_in_us(alarm_time * 1000 * 2); WaitForAlarm(&ep, alarm); @@ -1481,18 +1484,18 @@ TEST(SimpleEpollServerTest, TestMultipleFDs) { EXPECT_EQ(2u, records_one->size()); EXPECT_EQ(2u, records_two->size()); - write(pipe_one[1], &data, 1); + EXPECT_EQ(1, write(pipe_one[1], &data, 1)); ep.WaitForEventsAndExecuteCallbacks(); EXPECT_EQ(3u, records_one->size()); EXPECT_EQ(2u, records_two->size()); - write(pipe_two[1], &data, 1); + EXPECT_EQ(1, write(pipe_two[1], &data, 1)); ep.WaitForEventsAndExecuteCallbacks(); EXPECT_EQ(3u, records_one->size()); EXPECT_EQ(3u, records_two->size()); - write(pipe_one[1], &data, 1); - write(pipe_two[1], &data, 1); + EXPECT_EQ(1, write(pipe_one[1], &data, 1)); + EXPECT_EQ(1, write(pipe_two[1], &data, 1)); ep.WaitForEventsAndExecuteCallbacks(); EXPECT_EQ(4u, records_one->size()); EXPECT_EQ(4u, records_two->size()); @@ -1724,7 +1727,7 @@ class EpollReader: public EpollCallbackInterface { void TestPipe(char *test_message, int len) { int pipe_fds[2]; if (pipe(pipe_fds) < 0) { - PLOG(FATAL) << "pipe failed()"; + EPOLL_PLOG(FATAL) << "pipe failed()"; } int reader_pipe = pipe_fds[0]; int writer_pipe = pipe_fds[1]; @@ -1744,14 +1747,14 @@ void TestPipe(char *test_message, int len) { } } if (len > 0) { - PLOG(FATAL) << "write() failed"; + EPOLL_PLOG(FATAL) << "write() failed"; } close(writer_pipe); _exit(0); } case -1: - PLOG(FATAL) << "fork() failed"; + EPOLL_PLOG(FATAL) << "fork() failed"; break; default: { // Parent will receive message. close(writer_pipe); @@ -1925,7 +1928,7 @@ class EdgeTriggerCB : public EpollCallbackInterface { // Since we can only get on the ready list once, wait till we confirm both // read and write side continuation state and set the correct event mask // for the ready list. - event->out_ready_mask = can_read_ ? EPOLLIN : 0; + event->out_ready_mask = can_read_ ? static_cast<int>(EPOLLIN) : 0; if (can_write_) { event->out_ready_mask |= EPOLLOUT; } diff --git a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc index 4ce5d8caccb..ec3a899b8bd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc +++ b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc @@ -5,8 +5,10 @@ #include "net/third_party/quiche/src/quic/core/chlo_extractor.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" @@ -35,6 +37,9 @@ class ChloFramerVisitor : public QuicFramerVisitorInterface, void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override {} + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override {} bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override; bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override {} @@ -60,8 +65,8 @@ class ChloFramerVisitor : public QuicFramerVisitorInterface, bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override; bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override; bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override; - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override; - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override; + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override; + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override; bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; bool OnBlockedFrame(const QuicBlockedFrame& frame) override; bool OnPaddingFrame(const QuicPaddingFrame& frame) override; @@ -113,6 +118,23 @@ bool ChloFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version, bool ChloFramerVisitor::OnUnauthenticatedPublicHeader( const QuicPacketHeader& header) { connection_id_ = header.destination_connection_id; + // QuicFramer creates a NullEncrypter and NullDecrypter at level + // ENCRYPTION_INITIAL, which are the correct ones to use with the QUIC Crypto + // handshake. When the TLS handshake is used, the IETF-style initial crypters + // are used instead, so those need to be created and installed. + if (header.version.handshake_protocol == PROTOCOL_TLS1_3) { + CrypterPair crypters; + CryptoUtils::CreateTlsInitialCrypters( + Perspective::IS_SERVER, header.version.transport_version, + header.destination_connection_id, &crypters); + framer_->SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter)); + if (framer_->version().KnowsWhichDecrypterToUse()) { + framer_->InstallDecrypter(ENCRYPTION_INITIAL, + std::move(crypters.decrypter)); + } else { + framer_->SetDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter)); + } + } return true; } bool ChloFramerVisitor::OnUnauthenticatedHeader( @@ -129,8 +151,8 @@ bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) { return false; } QuicStringPiece data(frame.data_buffer, frame.data_length); - if (frame.stream_id == - QuicUtils::GetCryptoStreamId(framer_->transport_version()) && + if (QuicUtils::IsCryptoStreamId(framer_->transport_version(), + frame.stream_id) && frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) { return OnHandshakeData(data); } @@ -263,12 +285,12 @@ bool ChloFramerVisitor::IsValidStatelessResetToken(QuicUint128 token) const { return false; } -bool ChloFramerVisitor::OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) { +bool ChloFramerVisitor::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) { return true; } -bool ChloFramerVisitor::OnStreamIdBlockedFrame( - const QuicStreamIdBlockedFrame& frame) { +bool ChloFramerVisitor::OnStreamsBlockedFrame( + const QuicStreamsBlockedFrame& frame) { return true; } diff --git a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc index cea445dabaa..258e141fe34 100644 --- a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor_test.cc @@ -70,6 +70,14 @@ class ChloExtractorTest : public QuicTest { } QuicFramer framer(SupportedVersions(header_.version), QuicTime::Zero(), Perspective::IS_CLIENT, kQuicDefaultConnectionIdLength); + if (version.handshake_protocol == PROTOCOL_TLS1_3) { + CrypterPair crypters; + CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_CLIENT, + version.transport_version, + TestConnectionId(), &crypters); + framer.SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter)); + framer.SetDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter)); + } if (!QuicVersionUsesCryptoFrames(version.transport_version) || munge_stream_id) { QuicStreamId stream_id = @@ -133,11 +141,15 @@ TEST_F(ChloExtractorTest, FindsValidChlo) { } TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) { + ParsedQuicVersion version = AllSupportedVersions()[0]; + if (QuicVersionUsesCryptoFrames(version.transport_version)) { + return; + } CryptoHandshakeMessage client_hello; client_hello.set_tag(kCHLO); std::string client_hello_str(client_hello.GetSerialized().AsStringPiece()); - MakePacket(AllSupportedVersions()[0], client_hello_str, + MakePacket(version, client_hello_str, /*munge_offset*/ false, /*munge_stream_id*/ true); EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_, @@ -157,7 +169,11 @@ TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) { } TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) { - MakePacket(AllSupportedVersions()[0], "foo", /*munge_offset*/ false, + ParsedQuicVersion version = AllSupportedVersions()[0]; + if (QuicVersionUsesCryptoFrames(version.transport_version)) { + return; + } + MakePacket(version, "foo", /*munge_offset*/ false, /*munge_stream_id*/ true); EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_, diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc index 1c0d274fe1d..5844987b3cb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc @@ -30,7 +30,7 @@ const float kDefaultHighGain = 2.885f; // The newly derived gain for STARTUP, equal to 4 * ln(2) const float kDerivedHighGain = 2.773f; // The newly derived CWND gain for STARTUP, 2. -const float kDerivedHighCWNDGain = 2.773f; +const float kDerivedHighCWNDGain = 2.0f; // The gain used in STARTUP after loss has been detected. // 1.5 is enough to allow for 25% exogenous loss and still observe a 25% growth // in measured bandwidth. @@ -329,11 +329,6 @@ void BbrSender::SetFromConfig(const QuicConfig& config, QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_slower_startup3, 3, 4); enable_ack_aggregation_during_startup_ = true; } - if (GetQuicReloadableFlag(quic_bbr_slower_startup3) && - config.HasClientRequestedIndependentOption(kBBQ4, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_slower_startup3, 4, 4); - set_drain_gain(kModerateProbeRttMultiplier); - } if (GetQuicReloadableFlag(quic_bbr_slower_startup4) && config.HasClientRequestedIndependentOption(kBBQ5, perspective)) { QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_slower_startup4); @@ -345,13 +340,43 @@ void BbrSender::SetFromConfig(const QuicConfig& config, } void BbrSender::AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) { + QuicTime::Delta rtt, + bool allow_cwnd_to_decrease) { if (!bandwidth.IsZero()) { max_bandwidth_.Update(bandwidth, round_trip_count_); } if (!rtt.IsZero() && (min_rtt_ > rtt || min_rtt_.IsZero())) { min_rtt_ = rtt; } + if (GetQuicReloadableFlag(quic_fix_bbr_cwnd_in_bandwidth_resumption) && + mode_ == STARTUP) { + if (bandwidth.IsZero()) { + // Ignore bad bandwidth samples. + QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_bbr_cwnd_in_bandwidth_resumption, 3, + 3); + return; + } + const QuicByteCount new_cwnd = + std::max(kMinInitialCongestionWindow * kDefaultTCPMSS, + std::min(kMaxInitialCongestionWindow * kDefaultTCPMSS, + bandwidth * rtt_stats_->SmoothedOrInitialRtt())); + if (new_cwnd > congestion_window_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_bbr_cwnd_in_bandwidth_resumption, 1, + 3); + } else { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_bbr_cwnd_in_bandwidth_resumption, 2, + 3); + } + if (new_cwnd < congestion_window_ && !allow_cwnd_to_decrease) { + // Only decrease cwnd if allow_cwnd_to_decrease is true. + return; + } + // Decreases cwnd gain and pacing gain. Please note, if pacing_rate_ has + // been calculated, it cannot decrease in STARTUP phase. + set_high_gain(kDerivedHighCWNDGain); + set_high_cwnd_gain(kDerivedHighCWNDGain); + congestion_window_ = new_cwnd; + } } void BbrSender::OnCongestionEvent(bool /*rtt_updated*/, diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h index d01dbfe4dc2..a49a5efd579 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h @@ -108,7 +108,8 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { Perspective perspective) override; void AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) override; + QuicTime::Delta rtt, + bool allow_cwnd_to_decrease) override; void SetNumEmulatedConnections(int num_connections) override {} void SetInitialCongestionWindowInPackets( QuicPacketCount congestion_window) override; @@ -164,6 +165,10 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { drain_gain_ = drain_gain; } + // Returns the current estimate of the RTT of the connection. Outside of the + // edge cases, this is minimum RTT. + QuicTime::Delta GetMinRtt() const; + DebugState ExportDebugState() const; private: @@ -179,9 +184,6 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { QuicRoundTripCount> MaxAckHeightFilter; - // Returns the current estimate of the RTT of the connection. Outside of the - // edge cases, this is minimum RTT. - QuicTime::Delta GetMinRtt() const; // Returns whether the connection has achieved full bandwidth required to exit // the slow start. bool IsAtFullBandwidth() const; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc index 3d40e0a2217..be4f291406b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -161,7 +162,7 @@ class BbrSenderTest : public QuicTest { 0.5 * kTestBdp); bbr_sender_link_ = QuicMakeUnique<simulator::SymmetricLink>( &bbr_sender_, switch_->port(1), kLocalLinkBandwidth, - kTestPropagationDelay); + kLocalPropagationDelay); receiver_link_ = QuicMakeUnique<simulator::SymmetricLink>( &receiver_, switch_->port(2), kTestLinkBandwidth, kTestPropagationDelay); @@ -217,8 +218,8 @@ class BbrSenderTest : public QuicTest { ASSERT_FALSE(sender_->ExportDebugState().is_at_full_bandwidth); DoSimpleTransfer(1024 * 1024, QuicTime::Delta::FromSeconds(15)); EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); - ExpectApproxEq(kTestLinkBandwidth, - sender_->ExportDebugState().max_bandwidth, 0.02f); + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.02f); } // Send |bytes|-sized bursts of data |number_of_bursts| times, waiting for @@ -276,8 +277,8 @@ TEST_F(BbrSenderTest, SimpleTransfer) { // Verify that pacing rate is based on the initial RTT. QuicBandwidth expected_pacing_rate = QuicBandwidth::FromBytesAndTimeDelta( 2.885 * kDefaultWindowTCP, rtt_stats_->initial_rtt()); - ExpectApproxEq(expected_pacing_rate.ToBitsPerSecond(), - sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); + EXPECT_APPROX_EQ(expected_pacing_rate.ToBitsPerSecond(), + sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); ASSERT_GE(kTestBdp, kDefaultWindowTCP + kDefaultTCPMSS); @@ -288,7 +289,7 @@ TEST_F(BbrSenderTest, SimpleTransfer) { // The margin here is quite high, since there exists a possibility that the // connection just exited high gain cycle. - ExpectApproxEq(kTestRtt, rtt_stats_->smoothed_rtt(), 0.2f); + EXPECT_APPROX_EQ(kTestRtt, rtt_stats_->smoothed_rtt(), 0.2f); } // Test a simple transfer in a situation when the buffer is less than BDP. @@ -297,10 +298,14 @@ TEST_F(BbrSenderTest, SimpleTransferSmallBuffer) { DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(30)); EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); - ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, - 0.01f); + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); EXPECT_GE(bbr_sender_.connection()->GetStats().packets_lost, 0u); EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); + + // The margin here is quite high, since there exists a possibility that the + // connection just exited high gain cycle. + EXPECT_APPROX_EQ(kTestRtt, sender_->GetMinRtt(), 0.2f); } TEST_F(BbrSenderTest, SimpleTransferEarlyPacketLoss) { @@ -363,7 +368,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) { // The margin here is high, because the aggregation greatly increases // smoothed rtt. EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt()); - ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.2f); + EXPECT_APPROX_EQ(kTestRtt, rtt_stats_->min_rtt(), 0.2f); } // Test a simple long data transfer with 2 rtts of aggregation. @@ -398,7 +403,7 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { // The margin here is high, because the aggregation greatly increases // smoothed rtt. EXPECT_GE(kTestRtt * 2, rtt_stats_->smoothed_rtt()); - ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.1f); + EXPECT_APPROX_EQ(kTestRtt, rtt_stats_->min_rtt(), 0.1f); } // Test a simple long data transfer with 2 rtts of aggregation. @@ -425,7 +430,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { // The margin here is high, because the aggregation greatly increases // smoothed rtt. EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt()); - ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.12f); + EXPECT_APPROX_EQ(kTestRtt, rtt_stats_->min_rtt(), 0.12f); } // Test a simple long data transfer with 2 rtts of aggregation. @@ -452,7 +457,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) { // The margin here is high, because the aggregation greatly increases // smoothed rtt. EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt()); - ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.12f); + EXPECT_APPROX_EQ(kTestRtt, rtt_stats_->min_rtt(), 0.12f); } // Test the number of losses incurred by the startup phase in a situation when @@ -467,15 +472,23 @@ TEST_F(BbrSenderTest, PacketLossOnSmallBufferStartup) { EXPECT_LE(loss_rate, 0.31); } +// Test the number of losses incurred by the startup phase in a situation when +// the buffer is less than BDP, with a STARTUP CWND gain of 2. +TEST_F(BbrSenderTest, PacketLossOnSmallBufferStartupDerivedCWNDGain) { + SetQuicReloadableFlag(quic_bbr_slower_startup3, true); + CreateSmallBufferSetup(); + + SetConnectionOption(kBBQ2); + DriveOutOfStartup(); + float loss_rate = + static_cast<float>(bbr_sender_.connection()->GetStats().packets_lost) / + bbr_sender_.connection()->GetStats().packets_sent; + EXPECT_LE(loss_rate, 0.1); +} + // Ensures the code transitions loss recovery states correctly (NOT_IN_RECOVERY // -> CONSERVATION -> GROWTH -> NOT_IN_RECOVERY). TEST_F(BbrSenderTest, RecoveryStates) { - // Set seed to the position where the gain cycling causes the sender go - // into conservation upon entering PROBE_BW. - // - // TODO(vasilvv): there should be a better way to test this. - random_.set_seed(UINT64_C(14719894707049085006)); - const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); bool simulator_result; CreateSmallBufferSetup(); @@ -509,7 +522,6 @@ TEST_F(BbrSenderTest, RecoveryStates) { }, timeout); - ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); ASSERT_EQ(BbrSender::NOT_IN_RECOVERY, sender_->ExportDebugState().recovery_state); ASSERT_TRUE(simulator_result); @@ -525,8 +537,8 @@ TEST_F(BbrSenderTest, ApplicationLimitedBursts) { SendBursts(20, 512, QuicTime::Delta::FromSeconds(3)); EXPECT_TRUE(sender_->ExportDebugState().last_sample_is_app_limited); - ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, - 0.01f); + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); } // Verify the behavior of the algorithm in the case when the connection sends @@ -538,8 +550,8 @@ TEST_F(BbrSenderTest, ApplicationLimitedBurstsWithoutPrior) { EXPECT_TRUE(sender_->ExportDebugState().last_sample_is_app_limited); DriveOutOfStartup(); - ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, - 0.01f); + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); } @@ -566,8 +578,8 @@ TEST_F(BbrSenderTest, Drain) { timeout); ASSERT_TRUE(simulator_result); ASSERT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); - ExpectApproxEq(sender_->BandwidthEstimate() * (1 / 2.885f), - sender_->PacingRate(0), 0.01f); + EXPECT_APPROX_EQ(sender_->BandwidthEstimate() * (1 / 2.885f), + sender_->PacingRate(0), 0.01f); // BBR uses CWND gain of 2.88 during STARTUP, hence it will fill the buffer // with approximately 1.88 BDPs. Here, we use 1.5 to give some margin for // error. @@ -576,7 +588,7 @@ TEST_F(BbrSenderTest, Drain) { // Observe increased RTT due to bufferbloat. const QuicTime::Delta queueing_delay = kTestLinkBandwidth.TransferTime(queue->bytes_queued()); - ExpectApproxEq(kTestRtt + queueing_delay, rtt_stats_->latest_rtt(), 0.1f); + EXPECT_APPROX_EQ(kTestRtt + queueing_delay, rtt_stats_->latest_rtt(), 0.1f); // Transition to the drain phase and verify that it makes the queue // have at most a BDP worth of packets. @@ -602,18 +614,17 @@ TEST_F(BbrSenderTest, Drain) { ASSERT_TRUE(simulator_result); // Observe the bufferbloat go away. - ExpectApproxEq(kTestRtt, rtt_stats_->smoothed_rtt(), 0.1f); + EXPECT_APPROX_EQ(kTestRtt, rtt_stats_->smoothed_rtt(), 0.1f); } +// TODO(wub): Re-enable this test once default drain_gain changed to 0.75. // Verify that the DRAIN phase works correctly. -TEST_F(BbrSenderTest, ShallowDrain) { +TEST_F(BbrSenderTest, DISABLED_ShallowDrain) { SetQuicReloadableFlag(quic_bbr_slower_startup3, true); // Disable Ack Decimation on the receiver, because it can increase srtt. QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); - // BBQ4 increases the pacing gain in DRAIN to 0.75 - SetConnectionOption(kBBQ4); const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); // Get the queue at the bottleneck, which is the outgoing queue at the port to // which the receiver is connected. @@ -641,7 +652,7 @@ TEST_F(BbrSenderTest, ShallowDrain) { // Observe increased RTT due to bufferbloat. const QuicTime::Delta queueing_delay = kTestLinkBandwidth.TransferTime(queue->bytes_queued()); - ExpectApproxEq(kTestRtt + queueing_delay, rtt_stats_->latest_rtt(), 0.1f); + EXPECT_APPROX_EQ(kTestRtt + queueing_delay, rtt_stats_->latest_rtt(), 0.1f); // Transition to the drain phase and verify that it makes the queue // have at most a BDP worth of packets. @@ -667,7 +678,7 @@ TEST_F(BbrSenderTest, ShallowDrain) { ASSERT_TRUE(simulator_result); // Observe the bufferbloat go away. - ExpectApproxEq(kTestRtt, rtt_stats_->smoothed_rtt(), 0.1f); + EXPECT_APPROX_EQ(kTestRtt, rtt_stats_->smoothed_rtt(), 0.1f); } // Verify that the connection enters and exits PROBE_RTT correctly. @@ -834,8 +845,8 @@ TEST_F(BbrSenderTest, InFlightAwareGainCycling) { SendBursts(5, target_bandwidth * burst_interval, burst_interval); EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); EXPECT_EQ(0, sender_->ExportDebugState().gain_cycle_index); - ExpectApproxEq(kTestLinkBandwidth, - sender_->ExportDebugState().max_bandwidth, 0.01f); + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); } // Now that in-flight is almost zero and the pacing gain is still above 1, @@ -1170,8 +1181,8 @@ TEST_F(BbrSenderTest, DerivedPacingGainStartup) { // Verify that pacing rate is based on the initial RTT. QuicBandwidth expected_pacing_rate = QuicBandwidth::FromBytesAndTimeDelta( 2.773 * kDefaultWindowTCP, rtt_stats_->initial_rtt()); - ExpectApproxEq(expected_pacing_rate.ToBitsPerSecond(), - sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); + EXPECT_APPROX_EQ(expected_pacing_rate.ToBitsPerSecond(), + sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); // Run until the full bandwidth is reached and check how many rounds it was. bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); @@ -1181,15 +1192,15 @@ TEST_F(BbrSenderTest, DerivedPacingGainStartup) { ASSERT_TRUE(simulator_result); EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain); - ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, - 0.01f); + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); } TEST_F(BbrSenderTest, DerivedCWNDGainStartup) { SetQuicReloadableFlag(quic_bbr_slower_startup3, true); - CreateDefaultSetup(); + CreateSmallBufferSetup(); SetConnectionOption(kBBQ2); EXPECT_EQ(3u, sender_->num_startup_rtts()); @@ -1198,8 +1209,8 @@ TEST_F(BbrSenderTest, DerivedCWNDGainStartup) { // Verify that pacing rate is based on the initial RTT. QuicBandwidth expected_pacing_rate = QuicBandwidth::FromBytesAndTimeDelta( 2.885 * kDefaultWindowTCP, rtt_stats_->initial_rtt()); - ExpectApproxEq(expected_pacing_rate.ToBitsPerSecond(), - sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); + EXPECT_APPROX_EQ(expected_pacing_rate.ToBitsPerSecond(), + sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); // Run until the full bandwidth is reached and check how many rounds it was. bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); @@ -1209,9 +1220,12 @@ TEST_F(BbrSenderTest, DerivedCWNDGainStartup) { ASSERT_TRUE(simulator_result); EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain); - ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, - 0.01f); - EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); + float loss_rate = + static_cast<float>(bbr_sender_.connection()->GetStats().packets_lost) / + bbr_sender_.connection()->GetStats().packets_sent; + EXPECT_LT(loss_rate, 0.15f); EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); // Expect an SRTT less than 2.7 * Min RTT on exit from STARTUP. EXPECT_GT(kTestRtt * 2.7, rtt_stats_->smoothed_rtt()); @@ -1231,8 +1245,8 @@ TEST_F(BbrSenderTest, AckAggregationInStartup) { // Verify that pacing rate is based on the initial RTT. QuicBandwidth expected_pacing_rate = QuicBandwidth::FromBytesAndTimeDelta( 2.885 * kDefaultWindowTCP, rtt_stats_->initial_rtt()); - ExpectApproxEq(expected_pacing_rate.ToBitsPerSecond(), - sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); + EXPECT_APPROX_EQ(expected_pacing_rate.ToBitsPerSecond(), + sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); // Run until the full bandwidth is reached and check how many rounds it was. bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); @@ -1242,8 +1256,8 @@ TEST_F(BbrSenderTest, AckAggregationInStartup) { ASSERT_TRUE(simulator_result); EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain); - ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, - 0.01f); + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); } @@ -1278,10 +1292,10 @@ TEST_F(BbrSenderTest, ResumeConnectionState) { CreateDefaultSetup(); bbr_sender_.connection()->AdjustNetworkParameters(kTestLinkBandwidth, - kTestRtt); + kTestRtt, false); EXPECT_EQ(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth); EXPECT_EQ(kTestLinkBandwidth, sender_->BandwidthEstimate()); - ExpectApproxEq(kTestRtt, sender_->ExportDebugState().min_rtt, 0.01f); + EXPECT_APPROX_EQ(kTestRtt, sender_->ExportDebugState().min_rtt, 0.01f); DriveOutOfStartup(); } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.cc index 45e8bae6fdc..0968935492d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.cc @@ -99,6 +99,7 @@ void PacingSender::OnPacketSent( if (GetQuicReloadableFlag(quic_no_lumpy_pacing_at_low_bw) && sender_->BandwidthEstimate() < QuicBandwidth::FromKBitsPerSecond(1200)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_no_lumpy_pacing_at_low_bw); // Below 1.2Mbps, send 1 packet at once, because one full-sized packet // is about 10ms of queueing. lumpy_tokens_ = 1u; @@ -121,6 +122,13 @@ void PacingSender::OnApplicationLimited() { pacing_limited_ = false; } +void PacingSender::SetBurstTokens(uint32_t burst_tokens) { + initial_burst_size_ = burst_tokens; + burst_tokens_ = std::min( + initial_burst_size_, + static_cast<uint32_t>(sender_->GetCongestionWindow() / kDefaultTCPMSS)); +} + QuicTime::Delta PacingSender::TimeUntilSend( QuicTime now, QuicByteCount bytes_in_flight) const { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h index 8420c7f1650..781a9211951 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h @@ -66,6 +66,9 @@ class QUIC_EXPORT_PRIVATE PacingSender { // making up for lost time. void OnApplicationLimited(); + // Set burst_tokens_ and initial_burst_size_. + void SetBurstTokens(uint32_t burst_tokens); + QuicTime::Delta TimeUntilSend(QuicTime now, QuicByteCount bytes_in_flight) const; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc index ea9debf302d..4e4c401229d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/pacing_sender_test.cc @@ -388,8 +388,8 @@ TEST_F(PacingSenderTest, CwndLimited) { TEST_F(PacingSenderTest, LumpyPacingWithInitialBurstToken) { // Set lumpy size to be 3, and cwnd faction to 0.5 - SetQuicFlag(&FLAGS_quic_lumpy_pacing_size, 3); - SetQuicFlag(&FLAGS_quic_lumpy_pacing_cwnd_fraction, 0.5f); + SetQuicFlag(FLAGS_quic_lumpy_pacing_size, 3); + SetQuicFlag(FLAGS_quic_lumpy_pacing_cwnd_fraction, 0.5f); // Configure pacing rate of 1 packet per 1 ms. InitPacingRate( 10, QuicBandwidth::FromBytesAndTimeDelta( @@ -442,8 +442,8 @@ TEST_F(PacingSenderTest, LumpyPacingWithInitialBurstToken) { TEST_F(PacingSenderTest, NoLumpyPacingForLowBandwidthFlows) { // Set lumpy size to be 3, and cwnd faction to 0.5 - SetQuicFlag(&FLAGS_quic_lumpy_pacing_size, 3); - SetQuicFlag(&FLAGS_quic_lumpy_pacing_cwnd_fraction, 0.5f); + SetQuicFlag(FLAGS_quic_lumpy_pacing_size, 3); + SetQuicFlag(FLAGS_quic_lumpy_pacing_cwnd_fraction, 0.5f); SetQuicReloadableFlag(quic_no_lumpy_pacing_at_low_bw, true); // Configure pacing rate of 1 packet per 100 ms. diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h index 620b23f879d..9db67b5abd1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h @@ -120,7 +120,8 @@ class QUIC_EXPORT_PRIVATE SendAlgorithmInterface { // measurement or prediction. Either |bandwidth| or |rtt| may be zero if no // sample is available. virtual void AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) = 0; + QuicTime::Delta rtt, + bool allow_cwnd_to_decrease) = 0; // Retrieves debugging information about the current state of the // send algorithm. diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc index fde8d750101..7cbf332ffcd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.cc @@ -105,8 +105,10 @@ void TcpCubicSenderBytes::SetFromConfig(const QuicConfig& config, } } -void TcpCubicSenderBytes::AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) { +void TcpCubicSenderBytes::AdjustNetworkParameters( + QuicBandwidth bandwidth, + QuicTime::Delta rtt, + bool /*allow_cwnd_to_decrease*/) { if (bandwidth.IsZero() || rtt.IsZero()) { return; } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h index a437426ae5e..dd8be128be3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h @@ -47,7 +47,8 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public SendAlgorithmInterface { void SetFromConfig(const QuicConfig& config, Perspective perspective) override; void AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) override; + QuicTime::Delta rtt, + bool allow_cwnd_to_decrease) override; void SetNumEmulatedConnections(int num_connections) override; void SetInitialCongestionWindowInPackets( QuicPacketCount congestion_window) override; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc index 5eb6226b33e..32451a51020 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc @@ -677,11 +677,11 @@ TEST_F(TcpCubicSenderBytesTest, BandwidthResumption) { const QuicBandwidth kBandwidthEstimate = QuicBandwidth::FromBytesPerSecond(kNumberOfPackets * kDefaultTCPMSS); const QuicTime::Delta kRttEstimate = QuicTime::Delta::FromSeconds(1); - sender_->AdjustNetworkParameters(kBandwidthEstimate, kRttEstimate); + sender_->AdjustNetworkParameters(kBandwidthEstimate, kRttEstimate, false); EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow()); // Resume with an illegal value of 0 and verify the server ignores it. - sender_->AdjustNetworkParameters(QuicBandwidth::Zero(), kRttEstimate); + sender_->AdjustNetworkParameters(QuicBandwidth::Zero(), kRttEstimate, false); EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow()); // Resumed CWND is limited to be in a sensible range. @@ -689,7 +689,7 @@ TEST_F(TcpCubicSenderBytesTest, BandwidthResumption) { QuicBandwidth::FromBytesPerSecond((kMaxCongestionWindowPackets + 1) * kDefaultTCPMSS); sender_->AdjustNetworkParameters(kUnreasonableBandwidth, - QuicTime::Delta::FromSeconds(1)); + QuicTime::Delta::FromSeconds(1), false); EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS, sender_->GetCongestionWindow()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc index 33b93930db2..1fe346534e3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc @@ -31,12 +31,17 @@ class UberLossAlgorithmTest : public QuicTest { void SendPacket(uint64_t packet_number, EncryptionLevel encryption_level) { QuicStreamFrame frame; - frame.stream_id = - encryption_level == ENCRYPTION_INITIAL - ? QuicUtils::GetCryptoStreamId( - CurrentSupportedVersions()[0].transport_version) - : QuicUtils::GetHeadersStreamId( - CurrentSupportedVersions()[0].transport_version); + QuicTransportVersion version = + CurrentSupportedVersions()[0].transport_version; + frame.stream_id = QuicUtils::GetHeadersStreamId(version); + if (encryption_level == ENCRYPTION_INITIAL) { + if (QuicVersionUsesCryptoFrames(version)) { + frame.stream_id = QuicUtils::GetFirstBidirectionalStreamId( + version, Perspective::IS_CLIENT); + } else { + frame.stream_id = QuicUtils::GetCryptoStreamId(version); + } + } SerializedPacket packet(QuicPacketNumber(packet_number), PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, false, false); diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter_test.cc index d9f3655d203..30387e062db 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/windowed_filter_test.cc @@ -32,11 +32,11 @@ class WindowedFilterTest : public QuicTest { QuicTime::Delta rtt_sample = QuicTime::Delta::FromMilliseconds(10); for (int i = 0; i < 5; ++i) { windowed_min_rtt_.Update(rtt_sample, now); - VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds() - << " mins: " - << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " " - << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " " - << windowed_min_rtt_.GetThirdBest().ToMilliseconds(); + QUIC_VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds() + << " mins: " + << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " " + << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " " + << windowed_min_rtt_.GetThirdBest().ToMilliseconds(); now = now + QuicTime::Delta::FromMilliseconds(25); rtt_sample = rtt_sample + QuicTime::Delta::FromMilliseconds(10); } @@ -57,11 +57,11 @@ class WindowedFilterTest : public QuicTest { QuicBandwidth bw_sample = QuicBandwidth::FromBitsPerSecond(1000); for (int i = 0; i < 5; ++i) { windowed_max_bw_.Update(bw_sample, now); - VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond() - << " maxs: " - << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " " - << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " " - << windowed_max_bw_.GetThirdBest().ToBitsPerSecond(); + QUIC_VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond() + << " maxs: " + << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " " + << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " " + << windowed_max_bw_.GetThirdBest().ToBitsPerSecond(); now = now + QuicTime::Delta::FromMilliseconds(25); bw_sample = bw_sample - QuicBandwidth::FromBitsPerSecond(100); } @@ -120,11 +120,11 @@ TEST_F(WindowedFilterTest, MonotonicallyIncreasingMin) { now = now + QuicTime::Delta::FromMilliseconds(25); rtt_sample = rtt_sample + QuicTime::Delta::FromMilliseconds(10); windowed_min_rtt_.Update(rtt_sample, now); - VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds() - << " mins: " - << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " " - << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " " - << windowed_min_rtt_.GetThirdBest().ToMilliseconds(); + QUIC_VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds() + << " mins: " + << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " " + << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " " + << windowed_min_rtt_.GetThirdBest().ToMilliseconds(); if (i < 3) { EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), windowed_min_rtt_.GetBest()); @@ -150,11 +150,11 @@ TEST_F(WindowedFilterTest, MonotonicallyDecreasingMax) { now = now + QuicTime::Delta::FromMilliseconds(25); bw_sample = bw_sample - QuicBandwidth::FromBitsPerSecond(100); windowed_max_bw_.Update(bw_sample, now); - VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond() - << " maxs: " - << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " " - << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " " - << windowed_max_bw_.GetThirdBest().ToBitsPerSecond(); + QUIC_VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond() + << " maxs: " + << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " " + << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " " + << windowed_max_bw_.GetThirdBest().ToBitsPerSecond(); if (i < 3) { EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(1000), windowed_max_bw_.GetBest()); @@ -371,8 +371,8 @@ TEST_F(WindowedFilterTest, ExpireCounterBasedMax) { EXPECT_EQ(kBest, max_filter.GetBest()); UpdateWithIrrelevantSamples(&max_filter, 20, 3); EXPECT_EQ(kBest, max_filter.GetBest()); - VLOG(0) << max_filter.GetSecondBest(); - VLOG(0) << max_filter.GetThirdBest(); + QUIC_VLOG(0) << max_filter.GetSecondBest(); + QUIC_VLOG(0) << max_filter.GetThirdBest(); // Insert 20000 at t = 4. 50000 at t = 1 expires, so 40000 becomes the new // maximum. diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_base_encrypter.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_base_encrypter.cc index 49fc71d4602..cdb21b85a43 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/aes_base_encrypter.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/aes_base_encrypter.cc @@ -11,7 +11,7 @@ namespace quic { bool AesBaseEncrypter::SetHeaderProtectionKey(QuicStringPiece key) { if (key.size() != GetKeySize()) { - QUIC_BUG << "Invalid key size for header protection"; + QUIC_BUG << "Invalid key size for header protection: " << key.size(); return false; } if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key.data()), diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/channel_id.h b/chromium/net/third_party/quiche/src/quic/core/crypto/channel_id.h index 309aaf207d8..8719394ce47 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/channel_id.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/channel_id.h @@ -14,54 +14,6 @@ namespace quic { -// ChannelIDKey is an interface that supports signing with and serializing a -// ChannelID key. -class QUIC_EXPORT_PRIVATE ChannelIDKey { - public: - virtual ~ChannelIDKey() {} - - // Sign signs |signed_data| using the ChannelID private key and puts the - // signature into |out_signature|. It returns true on success. - virtual bool Sign(QuicStringPiece signed_data, - std::string* out_signature) const = 0; - - // SerializeKey returns the serialized ChannelID public key. - virtual std::string SerializeKey() const = 0; -}; - -// ChannelIDSourceCallback provides a generic mechanism for a ChannelIDSource -// to call back after an asynchronous GetChannelIDKey operation. -class ChannelIDSourceCallback { - public: - virtual ~ChannelIDSourceCallback() {} - - // Run is called on the original thread to mark the completion of an - // asynchonous GetChannelIDKey operation. If |*channel_id_key| is not nullptr - // then the channel ID lookup is successful. |Run| may take ownership of - // |*channel_id_key| by calling |release| on it. - virtual void Run(std::unique_ptr<ChannelIDKey>* channel_id_key) = 0; -}; - -// ChannelIDSource is an abstract interface by which a QUIC client can obtain -// a ChannelIDKey for a given hostname. -class QUIC_EXPORT_PRIVATE ChannelIDSource { - public: - virtual ~ChannelIDSource() {} - - // GetChannelIDKey looks up the ChannelIDKey for |hostname|. On success it - // returns QUIC_SUCCESS and stores the ChannelIDKey in |*channel_id_key|, - // which the caller takes ownership of. On failure, it returns QUIC_FAILURE. - // - // This function may also return QUIC_PENDING, in which case the - // ChannelIDSource will call back, on the original thread, via |callback| - // when complete. In this case, the ChannelIDSource will take ownership of - // |callback|. - virtual QuicAsyncStatus GetChannelIDKey( - const std::string& hostname, - std::unique_ptr<ChannelIDKey>* channel_id_key, - ChannelIDSourceCallback* callback) = 0; -}; - // ChannelIDVerifier verifies ChannelID signatures. class QUIC_EXPORT_PRIVATE ChannelIDVerifier { public: diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/channel_id_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/channel_id_test.cc index 99a84dd5909..d3673826d27 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/channel_id_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/channel_id_test.cc @@ -282,40 +282,5 @@ TEST_F(ChannelIDTest, VerifyKnownAnswerTest) { } } -TEST_F(ChannelIDTest, SignAndVerify) { - std::unique_ptr<ChannelIDSource> source( - crypto_test_utils::ChannelIDSourceForTesting()); - - const std::string signed_data = "signed data"; - const std::string hostname = "foo.example.com"; - std::unique_ptr<ChannelIDKey> channel_id_key; - QuicAsyncStatus status = - source->GetChannelIDKey(hostname, &channel_id_key, nullptr); - ASSERT_EQ(QUIC_SUCCESS, status); - - std::string signature; - ASSERT_TRUE(channel_id_key->Sign(signed_data, &signature)); - - std::string key = channel_id_key->SerializeKey(); - EXPECT_TRUE(ChannelIDVerifier::Verify(key, signed_data, signature)); - - EXPECT_FALSE(ChannelIDVerifier::Verify("a" + key, signed_data, signature)); - EXPECT_FALSE(ChannelIDVerifier::Verify(key, "a" + signed_data, signature)); - - std::unique_ptr<char[]> bad_key(new char[key.size()]); - memcpy(bad_key.get(), key.data(), key.size()); - bad_key[1] ^= 0x80; - EXPECT_FALSE(ChannelIDVerifier::Verify(std::string(bad_key.get(), key.size()), - signed_data, signature)); - - std::unique_ptr<char[]> bad_signature(new char[signature.size()]); - memcpy(bad_signature.get(), signature.data(), signature.size()); - bad_signature[1] ^= 0x80; - EXPECT_FALSE(ChannelIDVerifier::Verify( - key, signed_data, std::string(bad_signature.get(), signature.size()))); - - EXPECT_FALSE(ChannelIDVerifier::Verify(key, "wrong signed data", signature)); -} - } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_framer.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_framer.h index f20f0407bd9..5dcc81a87fe 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_framer.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_framer.h @@ -14,7 +14,6 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_message_parser.h" -#include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc index 1bbed745bd0..457d0fb054e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.cc @@ -274,7 +274,8 @@ std::string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const { case kCFCW: case kSFCW: case kIRTT: - case kMIDS: + case kMIUS: + case kMIBS: case kSCLS: case kTCID: // uint32_t value @@ -285,16 +286,6 @@ std::string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const { done = true; } break; - case kRCID: - // uint64_t value - if (it->second.size() == 8) { - uint64_t value; - memcpy(&value, it->second.data(), sizeof(value)); - value = QuicEndian::NetToHost64(value); - ret += QuicTextUtils::Uint64ToString(value); - done = true; - } - break; case kTBKP: case kKEXS: case kAEAD: diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message_test.cc index fc5298036a9..f595581601f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message_test.cc @@ -93,37 +93,11 @@ TEST(CryptoHandshakeMessageTest, DebugStringWithTagVector) { EXPECT_EQ(str, message5.DebugString()); } -TEST(CryptoHandshakeMessageTest, ServerDesignatedConnectionId) { - const char* str = "SREJ<\n RCID: 18364758544493064720\n>"; - - CryptoHandshakeMessage message; - message.set_tag(kSREJ); - message.SetValue(kRCID, - QuicEndian::NetToHost64(UINT64_C(18364758544493064720))); - EXPECT_EQ(str, message.DebugString()); - - // Test copy - CryptoHandshakeMessage message2(message); - EXPECT_EQ(str, message2.DebugString()); - - // Test move - CryptoHandshakeMessage message3(std::move(message)); - EXPECT_EQ(str, message3.DebugString()); - - // Test assign - CryptoHandshakeMessage message4 = message3; - EXPECT_EQ(str, message4.DebugString()); - - // Test move-assign - CryptoHandshakeMessage message5 = std::move(message3); - EXPECT_EQ(str, message5.DebugString()); -} - TEST(CryptoHandshakeMessageTest, HasStringPiece) { CryptoHandshakeMessage message; - EXPECT_FALSE(message.HasStringPiece(kRCID)); - message.SetStringPiece(kRCID, "foo"); - EXPECT_TRUE(message.HasStringPiece(kRCID)); + EXPECT_FALSE(message.HasStringPiece(kALPN)); + message.SetStringPiece(kALPN, "foo"); + EXPECT_TRUE(message.HasStringPiece(kALPN)); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc index c680290bcb4..ecbcab82e53 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_message_printer_bin.cc @@ -10,7 +10,6 @@ #include <iostream> #include <string> -#include "base/init_google.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" @@ -37,13 +36,19 @@ class CryptoMessagePrinter : public ::quic::CryptoFramerVisitorInterface { } // namespace quic int main(int argc, char* argv[]) { - InitGoogle(argv[0], &argc, &argv, true); + const char* usage = "Usage: crypto_message_printer <hex>"; + std::vector<std::string> messages = + quic::QuicParseCommandLineFlags(usage, argc, argv); + if (messages.size() != 1) { + quic::QuicPrintCommandLineFlagHelp(usage); + exit(0); + } quic::CryptoMessagePrinter printer; quic::CryptoFramer framer; framer.set_visitor(&printer); framer.set_process_truncated_messages(true); - std::string input = quic::QuicTextUtils::HexDecode(argv[1]); + std::string input = quic::QuicTextUtils::HexDecode(messages[0]); if (!framer.ProcessInput(input)) { return 1; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h index d9a1ebce3b5..e63224a38ed 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h @@ -26,12 +26,14 @@ namespace quic { typedef std::string ServerConfigID; +// The following tags have been deprecated and should not be reused: +// "BBQ4", "RCID", "SREJ" + // clang-format off const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello const QuicTag kSHLO = TAG('S', 'H', 'L', 'O'); // Server hello const QuicTag kSCFG = TAG('S', 'C', 'F', 'G'); // Server config const QuicTag kREJ = TAG('R', 'E', 'J', '\0'); // Reject -const QuicTag kSREJ = TAG('S', 'R', 'E', 'J'); // Stateless reject const QuicTag kCETV = TAG('C', 'E', 'T', 'V'); // Client encrypted tag-value // pairs const QuicTag kPRST = TAG('P', 'R', 'S', 'T'); // Public reset @@ -112,7 +114,6 @@ const QuicTag kBBQ2 = TAG('B', 'B', 'Q', '2'); // BBR with lower 2.0 STARTUP // CWND gain. const QuicTag kBBQ3 = TAG('B', 'B', 'Q', '3'); // BBR with ack aggregation // compensation in STARTUP. -const QuicTag kBBQ4 = TAG('B', 'B', 'Q', '4'); // Drain gain of 0.75. const QuicTag kBBQ5 = TAG('B', 'B', 'Q', '5'); // Expire ack aggregation upon // bandwidth increase in // STARTUP. @@ -188,6 +189,9 @@ const QuicTag kBWRE = TAG('B', 'W', 'R', 'E'); // Bandwidth resumption. const QuicTag kBWMX = TAG('B', 'W', 'M', 'X'); // Max bandwidth resumption. const QuicTag kBWRS = TAG('B', 'W', 'R', 'S'); // Server bandwidth resumption. const QuicTag kBWS2 = TAG('B', 'W', 'S', '2'); // Server bw resumption v2. +const QuicTag kBWS3 = TAG('B', 'W', 'S', '3'); // QUIC Initial CWND - Control. +const QuicTag kBWS4 = TAG('B', 'W', 'S', '4'); // QUIC Initial CWND - Enabled. +const QuicTag kBWS5 = TAG('B', 'W', 'S', '5'); // QUIC Initial CWND up and down // Enable path MTU discovery experiment. const QuicTag kMTUH = TAG('M', 'T', 'U', 'H'); // High-target MTU discovery. @@ -213,7 +217,8 @@ const QuicTag kCOPT = TAG('C', 'O', 'P', 'T'); // Connection options const QuicTag kCLOP = TAG('C', 'L', 'O', 'P'); // Client connection options const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle network timeout const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout -const QuicTag kMIDS = TAG('M', 'I', 'D', 'S'); // Max incoming dynamic streams +const QuicTag kMIBS = TAG('M', 'I', 'D', 'S'); // Max incoming bidi streams +const QuicTag kMIUS = TAG('M', 'I', 'U', 'S'); // Max incoming unidi streams const QuicTag kIRTT = TAG('I', 'R', 'T', 'T'); // Estimated initial RTT in us. const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name // indication @@ -239,9 +244,7 @@ const QuicTag kTB10 = TAG('T', 'B', '1', '0'); // TB draft 10 with P256. // Rejection tags const QuicTag kRREJ = TAG('R', 'R', 'E', 'J'); // Reasons for server sending -// Stateless Reject tags -const QuicTag kRCID = TAG('R', 'C', 'I', 'D'); // Server-designated - // connection ID + // Server hello tags const QuicTag kCADR = TAG('C', 'A', 'D', 'R'); // Client IP address and port const QuicTag kASAD = TAG('A', 'S', 'A', 'D'); // Alternate Server IP address diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.cc index 40f69df0013..c44cbb9d7ed 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.cc @@ -55,7 +55,7 @@ void CryptoSecretBoxer::SetKeys(const std::vector<std::string>& keys) { key.size(), EVP_AEAD_DEFAULT_TAG_LENGTH)); if (!ctx) { ERR_clear_error(); - LOG(DFATAL) << "EVP_AEAD_CTX_init failed"; + QUIC_LOG(DFATAL) << "EVP_AEAD_CTX_init failed"; return; } @@ -94,7 +94,7 @@ std::string CryptoSecretBoxer::Box(QuicRandom* rand, reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size(), nullptr, 0)) { ERR_clear_error(); - LOG(DFATAL) << "EVP_AEAD_CTX_seal failed"; + QUIC_LOG(DFATAL) << "EVP_AEAD_CTX_seal failed"; return ""; } } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc index 4d080c700d2..306a28b8ebf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc @@ -57,29 +57,15 @@ const char kOldConfigId[] = "old-config-id"; } // namespace struct TestParams { - TestParams(bool enable_stateless_rejects, - bool use_stateless_rejects, - ParsedQuicVersionVector supported_versions) - : enable_stateless_rejects(enable_stateless_rejects), - use_stateless_rejects(use_stateless_rejects), - supported_versions(std::move(supported_versions)) {} + TestParams(ParsedQuicVersionVector supported_versions) + : supported_versions(std::move(supported_versions)) {} friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { - os << " enable_stateless_rejects: " << p.enable_stateless_rejects - << std::endl; - os << " use_stateless_rejects: " << p.use_stateless_rejects << std::endl; os << " versions: " << ParsedQuicVersionVectorToString(p.supported_versions) << " }"; return os; } - // This only enables the stateless reject feature via the feature-flag. - // It does not force the crypto server to emit stateless rejects. - bool enable_stateless_rejects; - // If true, this forces the server to send a stateless reject when - // rejecting messages. This should be a no-op if - // enable_stateless_rejects is false. - bool use_stateless_rejects; // Versions supported by client and server. ParsedQuicVersionVector supported_versions; }; @@ -87,18 +73,14 @@ struct TestParams { // Constructs various test permutations. std::vector<TestParams> GetTestParams() { std::vector<TestParams> params; - static const bool kTrueFalse[] = {true, false}; - for (bool enable_stateless_rejects : kTrueFalse) { - for (bool use_stateless_rejects : kTrueFalse) { - // Start with all versions, remove highest on each iteration. - ParsedQuicVersionVector supported_versions = AllSupportedVersions(); - while (!supported_versions.empty()) { - params.push_back(TestParams(enable_stateless_rejects, - use_stateless_rejects, supported_versions)); - supported_versions.erase(supported_versions.begin()); - } - } + + // Start with all versions, remove highest on each iteration. + ParsedQuicVersionVector supported_versions = AllSupportedVersions(); + while (!supported_versions.empty()) { + params.push_back(TestParams(supported_versions)); + supported_versions.erase(supported_versions.begin()); } + return params; } @@ -124,10 +106,6 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { client_version_ = supported_versions_.front(); client_version_string_ = ParsedQuicVersionToString(client_version_); - - SetQuicReloadableFlag(enable_quic_stateless_reject_support, - GetParam().enable_stateless_rejects); - use_stateless_rejects_ = GetParam().use_stateless_rejects; } void SetUp() override { @@ -169,7 +147,6 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); - CheckForServerDesignatedConnectionId(); QuicStringPiece srct; ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct)); @@ -320,8 +297,8 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { result, /*reject_only=*/false, /*connection_id=*/TestConnectionId(1), server_address, client_address_, supported_versions_.front(), supported_versions_, - use_stateless_rejects_, server_designated_connection_id, &clock_, rand_, - &compressed_certs_cache_, params_, signed_config_, + /*use_stateless_rejects=*/false, server_designated_connection_id, + &clock_, rand_, &compressed_certs_cache_, params_, signed_config_, /*total_framing_overhead=*/50, chlo_packet_size_, QuicMakeUnique<ProcessCallback>(result, should_succeed, error_substr, &called, &out_)); @@ -352,36 +329,8 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { } } - // If the server is rejecting statelessly, make sure it contains a - // server-designated connection id. Once the check is complete, - // allow the random id-generator to move to the next value. - void CheckForServerDesignatedConnectionId() { - uint64_t server_designated_connection_id; - if (!RejectsAreStateless()) { - EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, - out_.GetUint64(kRCID, &server_designated_connection_id)); - } else { - ASSERT_EQ(QUIC_NO_ERROR, - out_.GetUint64(kRCID, &server_designated_connection_id)); - server_designated_connection_id = - QuicEndian::NetToHost64(server_designated_connection_id); - EXPECT_EQ(rand_for_id_generation_.RandUint64(), - server_designated_connection_id); - } - rand_for_id_generation_.ChangeValue(); - } - void CheckRejectTag() { - if (RejectsAreStateless()) { - ASSERT_EQ(kSREJ, out_.tag()) << QuicTagToString(out_.tag()); - } else { - ASSERT_EQ(kREJ, out_.tag()) << QuicTagToString(out_.tag()); - } - } - - bool RejectsAreStateless() { - return GetParam().enable_stateless_rejects && - GetParam().use_stateless_rejects; + ASSERT_EQ(kREJ, out_.tag()) << QuicTagToString(out_.tag()); } std::string XlctHexString() { @@ -406,7 +355,6 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_; CryptoHandshakeMessage out_; uint8_t orbit_[kOrbitSize]; - bool use_stateless_rejects_; size_t chlo_packet_size_; // These strings contain hex escaped values from the server suitable for using diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc index 724f245fb7c..be12ad42034 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc @@ -76,10 +76,14 @@ void CryptoUtils::SetKeyAndIV(const EVP_MD* prf, prf, pp_secret, "quic key", crypter->GetKeySize()); std::vector<uint8_t> iv = CryptoUtils::HkdfExpandLabel( prf, pp_secret, "quic iv", crypter->GetIVSize()); + std::vector<uint8_t> pn = CryptoUtils::HkdfExpandLabel( + prf, pp_secret, "quic hp", crypter->GetKeySize()); crypter->SetKey( QuicStringPiece(reinterpret_cast<char*>(key.data()), key.size())); crypter->SetIV( QuicStringPiece(reinterpret_cast<char*>(iv.data()), iv.size())); + crypter->SetHeaderProtectionKey( + QuicStringPiece(reinterpret_cast<char*>(pn.data()), pn.size())); } namespace { @@ -97,6 +101,10 @@ void CryptoUtils::CreateTlsInitialCrypters(Perspective perspective, QuicTransportVersion version, QuicConnectionId connection_id, CrypterPair* crypters) { + QUIC_DLOG(INFO) << "Creating " + << (perspective == Perspective::IS_CLIENT ? "client" + : "server") + << " TLS crypters for " << connection_id; QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(connection_id, version)) << "CreateTlsInitialCrypters: attempted to use connection ID " << connection_id << " which is invalid with version " @@ -224,15 +232,23 @@ bool CryptoUtils::DeriveKeys(QuicStringPiece premaster_secret, if (perspective == Perspective::IS_SERVER) { if (!crypters->encrypter->SetKey(hkdf.server_write_key()) || !crypters->encrypter->SetNoncePrefix(hkdf.server_write_iv()) || + !crypters->encrypter->SetHeaderProtectionKey( + hkdf.server_hp_key()) || !crypters->decrypter->SetKey(hkdf.client_write_key()) || - !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv())) { + !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv()) || + !crypters->decrypter->SetHeaderProtectionKey( + hkdf.client_hp_key())) { return false; } } else { if (!crypters->encrypter->SetKey(hkdf.client_write_key()) || !crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) || + !crypters->encrypter->SetHeaderProtectionKey( + hkdf.client_hp_key()) || !crypters->decrypter->SetKey(hkdf.server_write_key()) || - !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) { + !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv()) || + !crypters->decrypter->SetHeaderProtectionKey( + hkdf.server_hp_key())) { return false; } } @@ -246,8 +262,10 @@ bool CryptoUtils::DeriveKeys(QuicStringPiece premaster_secret, if (!crypters->encrypter->SetKey(hkdf.client_write_key()) || !crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) || + !crypters->encrypter->SetHeaderProtectionKey(hkdf.client_hp_key()) || !crypters->decrypter->SetPreliminaryKey(hkdf.server_write_key()) || - !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) { + !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv()) || + !crypters->decrypter->SetHeaderProtectionKey(hkdf.server_hp_key())) { return false; } break; @@ -265,8 +283,10 @@ bool CryptoUtils::DeriveKeys(QuicStringPiece premaster_secret, &nonce_prefix); if (!crypters->decrypter->SetKey(hkdf.client_write_key()) || !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv()) || + !crypters->decrypter->SetHeaderProtectionKey(hkdf.client_hp_key()) || !crypters->encrypter->SetKey(key) || - !crypters->encrypter->SetNoncePrefix(nonce_prefix)) { + !crypters->encrypter->SetNoncePrefix(nonce_prefix) || + !crypters->encrypter->SetHeaderProtectionKey(hkdf.server_hp_key())) { return false; } break; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h index cc777c7b3cd..fd890987d5d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h @@ -10,7 +10,7 @@ #include <vector> #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h" -#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h index e6605bb0961..38e978a2d6f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_verifier.h @@ -9,8 +9,8 @@ #include <string> #include <vector> -#include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" @@ -103,6 +103,8 @@ class QUIC_EXPORT_PRIVATE ProofVerifier { virtual QuicAsyncStatus VerifyCertChain( const std::string& hostname, const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, const ProofVerifyContext* context, std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc index 39838369e93..4fca4bb00a3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc @@ -11,7 +11,6 @@ #include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h" #include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter.h" -#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h" #include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" @@ -517,7 +516,6 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( const CachedState* cached, QuicWallTime now, QuicRandom* rand, - const ChannelIDKey* channel_id_key, QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, CryptoHandshakeMessage* out, std::string* error_details) const { @@ -643,65 +641,6 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( } out->SetValue(kXLCT, CryptoUtils::ComputeLeafCertHash(certs[0])); - if (channel_id_key) { - // In order to calculate the encryption key for the CETV block we need to - // serialise the client hello as it currently is (i.e. without the CETV - // block). For this, the client hello is serialized without padding. - const size_t orig_min_size = out->minimum_size(); - out->set_minimum_size(0); - - CryptoHandshakeMessage cetv; - cetv.set_tag(kCETV); - - std::string hkdf_input; - const QuicData& client_hello_serialized = out->GetSerialized(); - hkdf_input.append(QuicCryptoConfig::kCETVLabel, - strlen(QuicCryptoConfig::kCETVLabel) + 1); - hkdf_input.append(connection_id.data(), connection_id.length()); - hkdf_input.append(client_hello_serialized.data(), - client_hello_serialized.length()); - hkdf_input.append(cached->server_config()); - - std::string key = channel_id_key->SerializeKey(); - std::string signature; - if (!channel_id_key->Sign(hkdf_input, &signature)) { - *error_details = "Channel ID signature failed"; - return QUIC_INVALID_CHANNEL_ID_SIGNATURE; - } - - cetv.SetStringPiece(kCIDK, key); - cetv.SetStringPiece(kCIDS, signature); - - CrypterPair crypters; - if (!CryptoUtils::DeriveKeys(out_params->initial_premaster_secret, - out_params->aead, out_params->client_nonce, - out_params->server_nonce, pre_shared_key_, - hkdf_input, Perspective::IS_CLIENT, - CryptoUtils::Diversification::Never(), - &crypters, nullptr /* subkey secret */)) { - *error_details = "Symmetric key setup failed"; - return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; - } - - const QuicData& cetv_plaintext = cetv.GetSerialized(); - const size_t encrypted_len = - crypters.encrypter->GetCiphertextSize(cetv_plaintext.length()); - std::unique_ptr<char[]> output(new char[encrypted_len]); - size_t output_size = 0; - if (!crypters.encrypter->EncryptPacket( - 0 /* packet number */, QuicStringPiece() /* associated data */, - cetv_plaintext.AsStringPiece(), output.get(), &output_size, - encrypted_len)) { - *error_details = "Packet encryption failed"; - return QUIC_ENCRYPTION_FAILURE; - } - - out->SetStringPiece(kCETV, QuicStringPiece(output.get(), output_size)); - out->MarkDirty(); - - out->set_minimum_size(orig_min_size); - } - // Derive the symmetric keys and set up the encrypters and decrypters. // Set the following members of out_params: // out_params->hkdf_input_suffix @@ -822,8 +761,8 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection( std::string* error_details) { DCHECK(error_details != nullptr); - if ((rej.tag() != kREJ) && (rej.tag() != kSREJ)) { - *error_details = "Message is not REJ or SREJ"; + if (rej.tag() != kREJ) { + *error_details = "Message is not REJ"; return QUIC_CRYPTO_INTERNAL_ERROR; } @@ -839,30 +778,6 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection( out_params->server_nonce = std::string(nonce); } - if (rej.tag() == kSREJ) { - QuicConnectionId connection_id; - - QuicStringPiece connection_id_bytes; - if (!rej.GetStringPiece(kRCID, &connection_id_bytes)) { - *error_details = "Missing kRCID"; - return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; - } - connection_id = QuicConnectionId(connection_id_bytes.data(), - connection_id_bytes.length()); - if (!QuicUtils::IsConnectionIdValidForVersion(connection_id, version)) { - QUIC_PEER_BUG << "Received server-designated connection ID " - << connection_id << " which is invalid with version " - << QuicVersionToString(version); - *error_details = "Bad kRCID length"; - return QUIC_CRYPTO_INTERNAL_ERROR; - } - cached->add_server_designated_connection_id(connection_id); - if (!nonce.empty()) { - cached->add_server_nonce(std::string(nonce)); - } - return QUIC_NO_ERROR; - } - return QUIC_NO_ERROR; } @@ -951,19 +866,10 @@ ProofVerifier* QuicCryptoClientConfig::proof_verifier() const { return proof_verifier_.get(); } -ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const { - return channel_id_source_.get(); -} - SSL_CTX* QuicCryptoClientConfig::ssl_ctx() const { return ssl_ctx_.get(); } -void QuicCryptoClientConfig::SetChannelIDSource( - std::unique_ptr<ChannelIDSource> source) { - channel_id_source_ = std::move(source); -} - void QuicCryptoClientConfig::InitializeFrom( const QuicServerId& server_id, const QuicServerId& canonical_server_id, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h index f4293c0c85e..2918a23bb13 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h @@ -22,8 +22,6 @@ namespace quic { -class ChannelIDKey; -class ChannelIDSource; class CryptoHandshakeMessage; class ProofVerifier; class ProofVerifyDetails; @@ -258,7 +256,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { const CachedState* cached, QuicWallTime now, QuicRandom* rand, - const ChannelIDKey* channel_id_key, QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, CryptoHandshakeMessage* out, std::string* error_details) const; @@ -312,15 +309,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { ProofVerifier* proof_verifier() const; - ChannelIDSource* channel_id_source() const; - SSL_CTX* ssl_ctx() const; - // SetChannelIDSource sets a ChannelIDSource that will be called, when the - // server supports channel IDs, to obtain a channel ID for signing a message - // proving possession of the channel ID. - void SetChannelIDSource(std::unique_ptr<ChannelIDSource> source); - // Initialize the CachedState from |canonical_crypto_config| for the // |canonical_server_id| as the initial CachedState for |server_id|. We will // copy config data only if |canonical_crypto_config| has valid proof. @@ -397,7 +387,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { std::vector<std::string> canonical_suffixes_; std::unique_ptr<ProofVerifier> proof_verifier_; - std::unique_ptr<ChannelIDSource> channel_id_source_; bssl::UniquePtr<SSL_CTX> ssl_ctx_; // The |user_agent_id_| passed in QUIC's CHLO message. diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc index 2158cd3859e..563c7f1cc80 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc @@ -323,7 +323,6 @@ TEST_F(QuicCryptoClientConfigTest, FillClientHello) { QuicServerId server_id("www.google.com", 443, false); config.FillClientHello(server_id, kConnectionId, QuicVersionMax(), &state, QuicWallTime::Zero(), &rand, - nullptr, // channel_id_key params, &chlo, &error_details); // Verify that the version label has been set correctly in the CHLO. @@ -346,7 +345,6 @@ TEST_F(QuicCryptoClientConfigTest, FillClientHelloNoPadding) { QuicServerId server_id("www.google.com", 443, false); config.FillClientHello(server_id, kConnectionId, QuicVersionMax(), &state, QuicWallTime::Zero(), &rand, - nullptr, // channel_id_key params, &chlo, &error_details); // Verify that the version label has been set correctly in the CHLO. @@ -537,7 +535,7 @@ TEST_F(QuicCryptoClientConfigTest, ClearCachedStates) { TEST_F(QuicCryptoClientConfigTest, ProcessReject) { CryptoHandshakeMessage rej; - crypto_test_utils::FillInDummyReject(&rej, /* stateless */ false); + crypto_test_utils::FillInDummyReject(&rej); // Now process the rejection. QuicCryptoClientConfig::CachedState cached; @@ -556,7 +554,7 @@ TEST_F(QuicCryptoClientConfigTest, ProcessReject) { TEST_F(QuicCryptoClientConfigTest, ProcessRejectWithLongTTL) { CryptoHandshakeMessage rej; - crypto_test_utils::FillInDummyReject(&rej, /* stateless */ false); + crypto_test_utils::FillInDummyReject(&rej); QuicTime::Delta one_week = QuicTime::Delta::FromSeconds(kNumSecondsPerWeek); int64_t long_ttl = 3 * one_week.ToSeconds(); rej.SetValue(kSTTL, long_ttl); @@ -580,55 +578,6 @@ TEST_F(QuicCryptoClientConfigTest, ProcessRejectWithLongTTL) { QuicWallTime::FromUNIXSeconds(one_week.ToSeconds() - 1))); } -TEST_F(QuicCryptoClientConfigTest, ProcessStatelessReject) { - // Create a dummy reject message and mark it as stateless. - CryptoHandshakeMessage rej; - crypto_test_utils::FillInDummyReject(&rej, /* stateless */ true); - const QuicConnectionId kConnectionId = TestConnectionId(0xdeadbeef); - const std::string server_nonce = "SERVER_NONCE"; - const uint64_t kConnectionId64 = TestConnectionIdToUInt64(kConnectionId); - rej.SetValue(kRCID, kConnectionId64); - rej.SetStringPiece(kServerNonceTag, server_nonce); - - // Now process the rejection. - QuicCryptoClientConfig::CachedState cached; - QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( - new QuicCryptoNegotiatedParameters); - std::string error; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), - TlsClientHandshaker::CreateSslCtx()); - EXPECT_EQ(QUIC_NO_ERROR, - config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), - AllSupportedTransportVersions().front(), "", - &cached, out_params, &error)); - EXPECT_TRUE(cached.has_server_designated_connection_id()); - EXPECT_EQ(TestConnectionId(QuicEndian::NetToHost64( - TestConnectionIdToUInt64(kConnectionId))), - cached.GetNextServerDesignatedConnectionId()); - EXPECT_EQ(server_nonce, cached.GetNextServerNonce()); -} - -TEST_F(QuicCryptoClientConfigTest, BadlyFormattedStatelessReject) { - // Create a dummy reject message and mark it as stateless. Do not - // add an server-designated connection-id. - CryptoHandshakeMessage rej; - crypto_test_utils::FillInDummyReject(&rej, /* stateless */ true); - - // Now process the rejection. - QuicCryptoClientConfig::CachedState cached; - QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( - new QuicCryptoNegotiatedParameters); - std::string error; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), - TlsClientHandshaker::CreateSslCtx()); - EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, - config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), - AllSupportedTransportVersions().front(), "", - &cached, out_params, &error)); - EXPECT_FALSE(cached.has_server_designated_connection_id()); - EXPECT_EQ("Missing kRCID", error); -} - TEST_F(QuicCryptoClientConfigTest, ServerNonceinSHLO) { // Test that the server must include a nonce in the SHLO. CryptoHandshakeMessage msg; diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc index 88875beb5a2..54d4bf48fec 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc @@ -205,7 +205,7 @@ QuicCryptoServerConfig::ConfigOptions::~ConfigOptions() {} QuicCryptoServerConfig::ProcessClientHelloContext:: ~ProcessClientHelloContext() { if (done_cb_ != nullptr) { - LOG(WARNING) + QUIC_LOG(WARNING) << "Deleting ProcessClientHelloContext with a pending callback."; } } @@ -341,10 +341,6 @@ QuicServerConfigProtobuf QuicCryptoServerConfig::GenerateConfig( msg.SetVector(kPDMD, QuicTagVector{kCHID}); } - if (!options.token_binding_params.empty()) { - msg.SetVector(kTBKP, options.token_binding_params); - } - 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. @@ -1441,28 +1437,8 @@ void QuicCryptoServerConfig::BuildRejection( const std::vector<uint32_t>& reject_reasons, CryptoHandshakeMessage* out) const { const QuicWallTime now = context.clock()->WallNow(); - if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) && - context.use_stateless_rejects()) { - QUIC_DVLOG(1) << "QUIC Crypto server config returning stateless reject " - << "with server-designated connection ID " - << context.server_designated_connection_id(); - out->set_tag(kSREJ); - if (!QuicUtils::IsConnectionIdValidForVersion( - context.server_designated_connection_id(), - context.transport_version())) { - QUIC_BUG << "Tried to send server designated connection ID " - << context.server_designated_connection_id() - << " which is invalid with version " - << QuicVersionToString(context.transport_version()); - return; - } - out->SetStringPiece( - kRCID, - QuicStringPiece(context.server_designated_connection_id().data(), - context.server_designated_connection_id().length())); - } else { - out->set_tag(kREJ); - } + + out->set_tag(kREJ); out->SetStringPiece(kSCFG, config.serialized); out->SetStringPiece( kSourceAddressTokenTag, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h index 7f3f947a313..039da84bf6c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h @@ -191,9 +191,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { // channel_id_enabled controls whether the server config will indicate // support for ChannelIDs. bool channel_id_enabled; - // token_binding_params contains the list of Token Binding params (e.g. - // P256, TB10) that the server config will include. - QuicTagVector token_binding_params; // id contains the server config id for the resulting config. If empty, a // random id is generated. std::string id; @@ -341,6 +338,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { const QuicSocketAddress& client_address, ParsedQuicVersion version, const ParsedQuicVersionVector& supported_versions, + // TODO(wub): Deprecate use_stateless_rejects and + // server_designated_connection_id. bool use_stateless_rejects, QuicConnectionId server_designated_connection_id, const QuicClock* clock, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.cc index 3754cab89c2..1bd9ad54c2b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.cc @@ -39,8 +39,8 @@ QuicHKDF::QuicHKDF(QuicStringPiece secret, size_t server_iv_bytes_to_generate, size_t subkey_secret_bytes_to_generate) { const size_t material_length = - client_key_bytes_to_generate + client_iv_bytes_to_generate + - server_key_bytes_to_generate + server_iv_bytes_to_generate + + 2 * client_key_bytes_to_generate + client_iv_bytes_to_generate + + 2 * server_key_bytes_to_generate + server_iv_bytes_to_generate + subkey_secret_bytes_to_generate; DCHECK_LT(material_length, kMaxKeyMaterialSize); @@ -85,6 +85,19 @@ QuicHKDF::QuicHKDF(QuicStringPiece secret, if (subkey_secret_bytes_to_generate) { subkey_secret_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]), subkey_secret_bytes_to_generate); + j += subkey_secret_bytes_to_generate; + } + // Repeat client and server key bytes for header protection keys. + if (client_key_bytes_to_generate) { + client_hp_key_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]), + client_key_bytes_to_generate); + j += client_key_bytes_to_generate; + } + + if (server_key_bytes_to_generate) { + server_hp_key_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]), + server_key_bytes_to_generate); + j += server_key_bytes_to_generate; } } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h index fb80f7bd1ad..c57b894b52c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h @@ -54,6 +54,8 @@ class QUIC_EXPORT QuicHKDF { QuicStringPiece server_write_key() const { return server_write_key_; } QuicStringPiece server_write_iv() const { return server_write_iv_; } QuicStringPiece subkey_secret() const { return subkey_secret_; } + QuicStringPiece client_hp_key() const { return client_hp_key_; } + QuicStringPiece server_hp_key() const { return server_hp_key_; } private: std::vector<uint8_t> output_; @@ -63,6 +65,8 @@ class QUIC_EXPORT QuicHKDF { QuicStringPiece client_write_iv_; QuicStringPiece server_write_iv_; QuicStringPiece subkey_secret_; + QuicStringPiece client_hp_key_; + QuicStringPiece server_hp_key_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc index 60fb22c09f7..ee0ebf094a4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc @@ -4,184 +4,535 @@ #include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" +#include <cstdint> +#include <cstring> + #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_data_reader.h" +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" namespace quic { -namespace { +// Values of the TransportParameterId enum as defined in the +// "Transport Parameter Encoding" section of draft-ietf-quic-transport. +// When parameters are encoded, one of these enum values is used to indicate +// which parameter is encoded. The supported draft version is noted in +// transport_parameters.h. +enum TransportParameters::TransportParameterId : uint16_t { + kOriginalConnectionId = 0, + kIdleTimeout = 1, + kStatelessResetToken = 2, + kMaxPacketSize = 3, + kInitialMaxData = 4, + kInitialMaxStreamDataBidiLocal = 5, + kInitialMaxStreamDataBidiRemote = 6, + kInitialMaxStreamDataUni = 7, + kInitialMaxStreamsBidi = 8, + kInitialMaxStreamsUni = 9, + kAckDelayExponent = 0xa, + kMaxAckDelay = 0xb, + kDisableMigration = 0xc, + kPreferredAddress = 0xd, -// Values of the TransportParameterId enum as defined in -// draft-ietf-quic-transport-08 section 7.4. When parameters are encoded, one of -// these enum values is used to indicate which parameter is encoded. -enum TransportParameterId : uint16_t { - kInitialMaxStreamDataId = 0, - kInitialMaxDataId = 1, - kInitialMaxBidiStreamsId = 2, - kIdleTimeoutId = 3, - kMaxOutgoingPacketSizeId = 5, - kStatelessResetTokenId = 6, - kAckDelayExponentId = 7, - kInitialMaxUniStreamsId = 8, - - kMaxKnownParameterId = 9, + kGoogleQuicParam = 18257, // Used for non-standard Google-specific params. + kGoogleQuicVersion = + 18258, // Used to transmit version and supported_versions. }; -// Value for the TransportParameterId to use for non-standard Google QUIC params -// in Transport Parameters. -const uint16_t kGoogleQuicParamId = 18257; +namespace { // The following constants define minimum and maximum allowed values for some of -// the parameters. These come from draft-ietf-quic-transport-08 section 7.4.1. -const uint16_t kMaxAllowedIdleTimeout = 600; -const uint16_t kMinAllowedMaxPacketSize = 1200; -const uint16_t kMaxAllowedMaxPacketSize = 65527; -const uint8_t kMaxAllowedAckDelayExponent = 20; - -static_assert(kMaxKnownParameterId <= 32, "too many parameters to bit pack"); - -// The initial_max_stream_data, initial_max_data, and idle_timeout parameters -// are always required to be present. When parsing the extension, a bitmask is -// used to keep track of which parameter have been seen so far, and that bitmask -// will be compared to this mask to check that all of the required parameters -// were present. -static constexpr uint16_t kRequiredParamsMask = (1 << kInitialMaxStreamDataId) | - (1 << kInitialMaxDataId) | - (1 << kIdleTimeoutId); +// the parameters. These come from the "Transport Parameter Definitions" +// section of draft-ietf-quic-transport. +const uint64_t kMinMaxPacketSizeTransportParam = 1200; +const uint64_t kDefaultMaxPacketSizeTransportParam = 65527; +const uint64_t kMaxAckDelayExponentTransportParam = 20; +const uint64_t kDefaultAckDelayExponentTransportParam = 3; +const uint64_t kMaxMaxAckDelayTransportParam = 16383; +const uint64_t kDefaultMaxAckDelayTransportParam = 25; +const size_t kStatelessResetTokenLength = 16; + +std::string TransportParameterIdToString( + TransportParameters::TransportParameterId param_id) { + switch (param_id) { + case kOriginalConnectionId: + return "original_connection_id"; + case kIdleTimeout: + return "idle_timeout"; + case kStatelessResetToken: + return "stateless_reset_token"; + case kMaxPacketSize: + return "max_packet_size"; + case kInitialMaxData: + return "initial_max_data"; + case kInitialMaxStreamDataBidiLocal: + return "initial_max_stream_data_bidi_local"; + case kInitialMaxStreamDataBidiRemote: + return "initial_max_stream_data_bidi_remote"; + case kInitialMaxStreamDataUni: + return "initial_max_stream_data_uni"; + case kInitialMaxStreamsBidi: + return "initial_max_streams_bidi"; + case kInitialMaxStreamsUni: + return "initial_max_streams_uni"; + case kAckDelayExponent: + return "ack_delay_exponent"; + case kMaxAckDelay: + return "max_ack_delay"; + case kDisableMigration: + return "disable_migration"; + case kPreferredAddress: + return "preferred_address"; + case kGoogleQuicParam: + return "google"; + case kGoogleQuicVersion: + return "google-version"; + } + return "Unknown(" + QuicTextUtils::Uint64ToString(param_id) + ")"; +} } // namespace -TransportParameters::TransportParameters() = default; +TransportParameters::IntegerParameter::IntegerParameter( + TransportParameters::TransportParameterId param_id, + uint64_t default_value, + uint64_t min_value, + uint64_t max_value) + : param_id_(param_id), + value_(default_value), + default_value_(default_value), + min_value_(min_value), + max_value_(max_value), + has_been_read_from_cbs_(false) { + DCHECK_LE(min_value, default_value); + DCHECK_LE(default_value, max_value); + DCHECK_LE(max_value, kVarInt62MaxValue); +} -TransportParameters::~TransportParameters() = default; +TransportParameters::IntegerParameter::IntegerParameter( + TransportParameters::TransportParameterId param_id) + : TransportParameters::IntegerParameter::IntegerParameter( + param_id, + 0, + 0, + kVarInt62MaxValue) {} -bool TransportParameters::is_valid() const { - if (perspective == Perspective::IS_CLIENT && !stateless_reset_token.empty()) { +void TransportParameters::IntegerParameter::set_value(uint64_t value) { + value_ = value; +} + +uint64_t TransportParameters::IntegerParameter::value() const { + return value_; +} + +bool TransportParameters::IntegerParameter::IsValid() const { + return min_value_ <= value_ && value_ <= max_value_; +} + +bool TransportParameters::IntegerParameter::WriteToCbb(CBB* parent_cbb) const { + DCHECK(IsValid()); + if (value_ == default_value_) { + // Do not write if the value is default. + return true; + } + uint8_t encoded_data[sizeof(uint64_t)] = {}; + QuicDataWriter writer(sizeof(encoded_data), + reinterpret_cast<char*>(encoded_data)); + writer.WriteVarInt62(value_); + const uint16_t value_length = writer.length(); + DCHECK_LE(value_length, sizeof(encoded_data)); + const bool ok = CBB_add_u16(parent_cbb, param_id_) && + CBB_add_u16(parent_cbb, value_length) && + CBB_add_bytes(parent_cbb, encoded_data, value_length); + QUIC_BUG_IF(!ok) << "Failed to write " << this; + return ok; +} + +bool TransportParameters::IntegerParameter::ReadFromCbs(CBS* const value_cbs) { + if (has_been_read_from_cbs_) { + QUIC_DLOG(ERROR) << "Received a second " + << TransportParameterIdToString(param_id_); + return false; + } + has_been_read_from_cbs_ = true; + QuicDataReader reader(reinterpret_cast<const char*>(CBS_data(value_cbs)), + CBS_len(value_cbs)); + QuicVariableLengthIntegerLength value_length = reader.PeekVarInt62Length(); + if (value_length == 0 || !reader.ReadVarInt62(&value_)) { + QUIC_DLOG(ERROR) << "Failed to parse value for " + << TransportParameterIdToString(param_id_); return false; } - if (perspective == Perspective::IS_SERVER && - stateless_reset_token.size() != 16) { + if (!reader.IsDoneReading()) { + QUIC_DLOG(ERROR) << "Received unexpected " << reader.BytesRemaining() + << " bytes after parsing " << this; return false; } - if (idle_timeout > kMaxAllowedIdleTimeout || - (max_packet_size.present && - (max_packet_size.value > kMaxAllowedMaxPacketSize || - max_packet_size.value < kMinAllowedMaxPacketSize)) || - (ack_delay_exponent.present && - ack_delay_exponent.value > kMaxAllowedAckDelayExponent)) { + if (!CBS_skip(value_cbs, value_length)) { + QUIC_BUG << "Failed to advance CBS past value for " << this; return false; } return true; } +std::string TransportParameters::IntegerParameter::ToString( + bool for_use_in_list) const { + if (for_use_in_list && value_ == default_value_) { + return ""; + } + std::string rv = for_use_in_list ? " " : ""; + rv += TransportParameterIdToString(param_id_) + " "; + rv += QuicTextUtils::Uint64ToString(value_); + if (!IsValid()) { + rv += " (Invalid)"; + } + return rv; +} + +std::ostream& operator<<(std::ostream& os, + const TransportParameters::IntegerParameter& param) { + os << param.ToString(/*for_use_in_list=*/false); + return os; +} + +TransportParameters::PreferredAddress::PreferredAddress() + : ipv4_socket_address(QuicIpAddress::Any4(), 0), + ipv6_socket_address(QuicIpAddress::Any6(), 0), + connection_id(EmptyQuicConnectionId()), + stateless_reset_token(kStatelessResetTokenLength, 0) {} + +TransportParameters::PreferredAddress::~PreferredAddress() {} + +std::ostream& operator<<( + std::ostream& os, + const TransportParameters::PreferredAddress& preferred_address) { + os << preferred_address.ToString(); + return os; +} + +std::string TransportParameters::PreferredAddress::ToString() const { + return "[" + ipv4_socket_address.ToString() + " " + + ipv6_socket_address.ToString() + " connection_id " + + connection_id.ToString() + " stateless_reset_token " + + QuicTextUtils::HexEncode( + reinterpret_cast<const char*>(stateless_reset_token.data()), + stateless_reset_token.size()) + + "]"; +} + +std::ostream& operator<<(std::ostream& os, const TransportParameters& params) { + os << params.ToString(); + return os; +} + +std::string TransportParameters::ToString() const { + std::string rv = "["; + if (perspective == Perspective::IS_SERVER) { + rv += "Server"; + } else { + rv += "Client"; + } + if (version != 0) { + rv += " version " + QuicVersionLabelToString(version); + } + if (!supported_versions.empty()) { + rv += " supported_versions " + + QuicVersionLabelVectorToString(supported_versions); + } + if (!original_connection_id.IsEmpty()) { + rv += " " + TransportParameterIdToString(kOriginalConnectionId) + " " + + original_connection_id.ToString(); + } + rv += idle_timeout_milliseconds.ToString(/*for_use_in_list=*/true); + if (!stateless_reset_token.empty()) { + rv += " " + TransportParameterIdToString(kStatelessResetToken) + " " + + QuicTextUtils::HexEncode( + reinterpret_cast<const char*>(stateless_reset_token.data()), + stateless_reset_token.size()); + } + rv += max_packet_size.ToString(/*for_use_in_list=*/true); + rv += initial_max_data.ToString(/*for_use_in_list=*/true); + rv += initial_max_stream_data_bidi_local.ToString(/*for_use_in_list=*/true); + rv += initial_max_stream_data_bidi_remote.ToString(/*for_use_in_list=*/true); + rv += initial_max_stream_data_uni.ToString(/*for_use_in_list=*/true); + rv += initial_max_streams_bidi.ToString(/*for_use_in_list=*/true); + rv += initial_max_streams_uni.ToString(/*for_use_in_list=*/true); + rv += ack_delay_exponent.ToString(/*for_use_in_list=*/true); + rv += max_ack_delay.ToString(/*for_use_in_list=*/true); + if (disable_migration) { + rv += " " + TransportParameterIdToString(kDisableMigration); + } + if (preferred_address) { + rv += " " + TransportParameterIdToString(kPreferredAddress) + " " + + preferred_address->ToString(); + } + if (google_quic_params) { + rv += " " + TransportParameterIdToString(kGoogleQuicParam); + } + rv += "]"; + return rv; +} + +TransportParameters::TransportParameters() + : version(0), + original_connection_id(EmptyQuicConnectionId()), + idle_timeout_milliseconds(kIdleTimeout), + max_packet_size(kMaxPacketSize, + kDefaultMaxPacketSizeTransportParam, + kMinMaxPacketSizeTransportParam, + kVarInt62MaxValue), + initial_max_data(kInitialMaxData), + initial_max_stream_data_bidi_local(kInitialMaxStreamDataBidiLocal), + initial_max_stream_data_bidi_remote(kInitialMaxStreamDataBidiRemote), + initial_max_stream_data_uni(kInitialMaxStreamDataUni), + initial_max_streams_bidi(kInitialMaxStreamsBidi), + initial_max_streams_uni(kInitialMaxStreamsUni), + ack_delay_exponent(kAckDelayExponent, + kDefaultAckDelayExponentTransportParam, + 0, + kMaxAckDelayExponentTransportParam), + max_ack_delay(kMaxAckDelay, + kDefaultMaxAckDelayTransportParam, + 0, + kMaxMaxAckDelayTransportParam), + disable_migration(false) +// Important note: any new transport parameters must be added +// to TransportParameters::AreValid, SerializeTransportParameters and +// ParseTransportParameters. +{} + +bool TransportParameters::AreValid() const { + DCHECK(perspective == Perspective::IS_CLIENT || + perspective == Perspective::IS_SERVER); + if (perspective == Perspective::IS_CLIENT && !stateless_reset_token.empty()) { + QUIC_DLOG(ERROR) << "Client cannot send stateless reset token"; + return false; + } + if (perspective == Perspective::IS_CLIENT && + !original_connection_id.IsEmpty()) { + QUIC_DLOG(ERROR) << "Client cannot send original connection ID"; + return false; + } + if (!stateless_reset_token.empty() && + stateless_reset_token.size() != kStatelessResetTokenLength) { + QUIC_DLOG(ERROR) << "Stateless reset token has bad length " + << stateless_reset_token.size(); + return false; + } + if (perspective == Perspective::IS_CLIENT && preferred_address) { + QUIC_DLOG(ERROR) << "Client cannot send preferred address"; + return false; + } + if (preferred_address && preferred_address->stateless_reset_token.size() != + kStatelessResetTokenLength) { + QUIC_DLOG(ERROR) + << "Preferred address stateless reset token has bad length " + << preferred_address->stateless_reset_token.size(); + return false; + } + if (preferred_address && + (!preferred_address->ipv4_socket_address.host().IsIPv4() || + !preferred_address->ipv6_socket_address.host().IsIPv6())) { + QUIC_BUG << "Preferred address family failure"; + return false; + } + const bool ok = idle_timeout_milliseconds.IsValid() && + max_packet_size.IsValid() && initial_max_data.IsValid() && + initial_max_stream_data_bidi_local.IsValid() && + initial_max_stream_data_bidi_remote.IsValid() && + initial_max_stream_data_uni.IsValid() && + initial_max_streams_bidi.IsValid() && + initial_max_streams_uni.IsValid() && + ack_delay_exponent.IsValid() && max_ack_delay.IsValid(); + if (!ok) { + QUIC_DLOG(ERROR) << "Invalid transport parameters " << *this; + } + return ok; +} + +TransportParameters::~TransportParameters() = default; + bool SerializeTransportParameters(const TransportParameters& in, std::vector<uint8_t>* out) { - if (!in.is_valid()) { + if (!in.AreValid()) { + QUIC_DLOG(ERROR) << "Not serializing invalid transport parameters " << in; + return false; + } + if (in.version == 0 || (in.perspective == Perspective::IS_SERVER && + in.supported_versions.empty())) { + QUIC_DLOG(ERROR) << "Refusing to serialize without versions"; return false; } + bssl::ScopedCBB cbb; - // 28 is the minimum size that the serialized TransportParameters can be, - // which is when it is for a client and only the required parameters are - // present. The CBB will grow to fit larger serializations. - if (!CBB_init(cbb.get(), 28) || !CBB_add_u32(cbb.get(), in.version)) { + // Empirically transport parameters generally fit within 128 bytes. + // The CBB will grow to fit larger serializations if required. + if (!CBB_init(cbb.get(), 128)) { + QUIC_BUG << "Failed to initialize CBB for " << in; return false; } - CBB versions; - if (in.perspective == Perspective::IS_SERVER) { - if (!CBB_add_u8_length_prefixed(cbb.get(), &versions)) { + + CBB params; + // Add length of the transport parameters list. + if (!CBB_add_u16_length_prefixed(cbb.get(), ¶ms)) { + QUIC_BUG << "Failed to write parameter length for " << in; + return false; + } + + // original_connection_id + CBB original_connection_id_param; + if (!in.original_connection_id.IsEmpty()) { + DCHECK_EQ(Perspective::IS_SERVER, in.perspective); + if (!CBB_add_u16(¶ms, kOriginalConnectionId) || + !CBB_add_u16_length_prefixed(¶ms, &original_connection_id_param) || + !CBB_add_bytes( + &original_connection_id_param, + reinterpret_cast<const uint8_t*>(in.original_connection_id.data()), + in.original_connection_id.length())) { + QUIC_BUG << "Failed to write original_connection_id " + << in.original_connection_id << " for " << in; return false; } - for (QuicVersionLabel version : in.supported_versions) { - if (!CBB_add_u32(&versions, version)) { - return false; - } - } } - CBB params, initial_max_stream_data_param, initial_max_data_param, - idle_timeout_param; - // required parameters - if (!CBB_add_u16_length_prefixed(cbb.get(), ¶ms) || - // initial_max_stream_data - !CBB_add_u16(¶ms, kInitialMaxStreamDataId) || - !CBB_add_u16_length_prefixed(¶ms, &initial_max_stream_data_param) || - !CBB_add_u32(&initial_max_stream_data_param, - in.initial_max_stream_data) || - // initial_max_data - !CBB_add_u16(¶ms, kInitialMaxDataId) || - !CBB_add_u16_length_prefixed(¶ms, &initial_max_data_param) || - !CBB_add_u32(&initial_max_data_param, in.initial_max_data) || - // idle_timeout - !CBB_add_u16(¶ms, kIdleTimeoutId) || - !CBB_add_u16_length_prefixed(¶ms, &idle_timeout_param) || - !CBB_add_u16(&idle_timeout_param, in.idle_timeout)) { + if (!in.idle_timeout_milliseconds.WriteToCbb(¶ms)) { + QUIC_BUG << "Failed to write idle_timeout for " << in; return false; } + // stateless_reset_token CBB stateless_reset_token_param; if (!in.stateless_reset_token.empty()) { - if (!CBB_add_u16(¶ms, kStatelessResetTokenId) || + DCHECK_EQ(kStatelessResetTokenLength, in.stateless_reset_token.size()); + DCHECK_EQ(Perspective::IS_SERVER, in.perspective); + if (!CBB_add_u16(¶ms, kStatelessResetToken) || !CBB_add_u16_length_prefixed(¶ms, &stateless_reset_token_param) || !CBB_add_bytes(&stateless_reset_token_param, in.stateless_reset_token.data(), in.stateless_reset_token.size())) { + QUIC_BUG << "Failed to write stateless_reset_token of length " + << in.stateless_reset_token.size() << " for " << in; return false; } } - CBB initial_max_bidi_streams_param; - if (in.initial_max_bidi_streams.present) { - if (!CBB_add_u16(¶ms, kInitialMaxBidiStreamsId) || - !CBB_add_u16_length_prefixed(¶ms, - &initial_max_bidi_streams_param) || - !CBB_add_u16(&initial_max_bidi_streams_param, - in.initial_max_bidi_streams.value)) { - return false; - } + if (!in.max_packet_size.WriteToCbb(¶ms) || + !in.initial_max_data.WriteToCbb(¶ms) || + !in.initial_max_stream_data_bidi_local.WriteToCbb(¶ms) || + !in.initial_max_stream_data_bidi_remote.WriteToCbb(¶ms) || + !in.initial_max_stream_data_uni.WriteToCbb(¶ms) || + !in.initial_max_streams_bidi.WriteToCbb(¶ms) || + !in.initial_max_streams_uni.WriteToCbb(¶ms) || + !in.ack_delay_exponent.WriteToCbb(¶ms) || + !in.max_ack_delay.WriteToCbb(¶ms)) { + QUIC_BUG << "Failed to write integers for " << in; + return false; } - CBB initial_max_uni_streams_param; - if (in.initial_max_uni_streams.present) { - if (!CBB_add_u16(¶ms, kInitialMaxUniStreamsId) || - !CBB_add_u16_length_prefixed(¶ms, &initial_max_uni_streams_param) || - !CBB_add_u16(&initial_max_uni_streams_param, - in.initial_max_uni_streams.value)) { + + // disable_migration + if (in.disable_migration) { + if (!CBB_add_u16(¶ms, kDisableMigration) || + !CBB_add_u16(¶ms, 0u)) { // 0 is the length of this parameter. + QUIC_BUG << "Failed to write disable_migration for " << in; return false; } } - CBB max_packet_size_param; - if (in.max_packet_size.present) { - if (!CBB_add_u16(¶ms, kMaxOutgoingPacketSizeId) || - !CBB_add_u16_length_prefixed(¶ms, &max_packet_size_param) || - !CBB_add_u16(&max_packet_size_param, in.max_packet_size.value)) { + + // preferred_address + CBB preferred_address_params, preferred_address_connection_id_param; + if (in.preferred_address) { + std::string v4_address_bytes = + in.preferred_address->ipv4_socket_address.host().ToPackedString(); + std::string v6_address_bytes = + in.preferred_address->ipv6_socket_address.host().ToPackedString(); + if (v4_address_bytes.length() != 4 || v6_address_bytes.length() != 16 || + in.preferred_address->stateless_reset_token.size() != + kStatelessResetTokenLength) { + QUIC_BUG << "Bad lengths " << *in.preferred_address; return false; } - } - CBB ack_delay_exponent_param; - if (in.ack_delay_exponent.present) { - if (!CBB_add_u16(¶ms, kAckDelayExponentId) || - !CBB_add_u16_length_prefixed(¶ms, &ack_delay_exponent_param) || - !CBB_add_u8(&ack_delay_exponent_param, in.ack_delay_exponent.value)) { + if (!CBB_add_u16(¶ms, kPreferredAddress) || + !CBB_add_u16_length_prefixed(¶ms, &preferred_address_params) || + !CBB_add_bytes( + &preferred_address_params, + reinterpret_cast<const uint8_t*>(v4_address_bytes.data()), + v4_address_bytes.length()) || + !CBB_add_u16(&preferred_address_params, + in.preferred_address->ipv4_socket_address.port()) || + !CBB_add_bytes( + &preferred_address_params, + reinterpret_cast<const uint8_t*>(v6_address_bytes.data()), + v6_address_bytes.length()) || + !CBB_add_u16(&preferred_address_params, + in.preferred_address->ipv6_socket_address.port()) || + !CBB_add_u8_length_prefixed(&preferred_address_params, + &preferred_address_connection_id_param) || + !CBB_add_bytes(&preferred_address_connection_id_param, + reinterpret_cast<const uint8_t*>( + in.preferred_address->connection_id.data()), + in.preferred_address->connection_id.length()) || + !CBB_add_bytes(&preferred_address_params, + in.preferred_address->stateless_reset_token.data(), + in.preferred_address->stateless_reset_token.size())) { + QUIC_BUG << "Failed to write preferred_address for " << in; return false; } } + + // Google-specific non-standard parameter. CBB google_quic_params; if (in.google_quic_params) { const QuicData& serialized_google_quic_params = in.google_quic_params->GetSerialized(); - if (!CBB_add_u16(¶ms, kGoogleQuicParamId) || + if (!CBB_add_u16(¶ms, kGoogleQuicParam) || !CBB_add_u16_length_prefixed(¶ms, &google_quic_params) || !CBB_add_bytes(&google_quic_params, reinterpret_cast<const uint8_t*>( serialized_google_quic_params.data()), serialized_google_quic_params.length())) { + QUIC_BUG << "Failed to write Google params of length " + << serialized_google_quic_params.length() << " for " << in; + return false; + } + } + + // Google-specific version extension. + CBB google_version_params; + if (!CBB_add_u16(¶ms, kGoogleQuicVersion) || + !CBB_add_u16_length_prefixed(¶ms, &google_version_params) || + !CBB_add_u32(&google_version_params, in.version)) { + QUIC_BUG << "Failed to write Google version extension for " << in; + return false; + } + CBB versions; + if (in.perspective == Perspective::IS_SERVER) { + if (!CBB_add_u8_length_prefixed(&google_version_params, &versions)) { + QUIC_BUG << "Failed to write versions length for " << in; return false; } + for (QuicVersionLabel version : in.supported_versions) { + if (!CBB_add_u32(&versions, version)) { + QUIC_BUG << "Failed to write supported version for " << in; + return false; + } + } } + if (!CBB_flush(cbb.get())) { + QUIC_BUG << "Failed to flush CBB for " << in; return false; } out->resize(CBB_len(cbb.get())); memcpy(out->data(), CBB_data(cbb.get()), CBB_len(cbb.get())); + QUIC_DLOG(INFO) << "Serialized " << in << " as " << CBB_len(cbb.get()) + << " bytes"; return true; } @@ -189,114 +540,205 @@ bool ParseTransportParameters(const uint8_t* in, size_t in_len, Perspective perspective, TransportParameters* out) { + out->perspective = perspective; CBS cbs; CBS_init(&cbs, in, in_len); - if (!CBS_get_u32(&cbs, &out->version)) { - return false; - } - if (perspective == Perspective::IS_SERVER) { - CBS versions; - if (!CBS_get_u8_length_prefixed(&cbs, &versions) || - CBS_len(&versions) % 4 != 0) { - return false; - } - while (CBS_len(&versions) > 0) { - QuicVersionLabel version; - if (!CBS_get_u32(&versions, &version)) { - return false; - } - out->supported_versions.push_back(version); - } - } - out->perspective = perspective; - uint32_t present_params = 0; - bool has_google_quic_params = false; CBS params; if (!CBS_get_u16_length_prefixed(&cbs, ¶ms)) { + QUIC_DLOG(ERROR) << "Failed to parse the number of transport parameters"; return false; } + while (CBS_len(¶ms) > 0) { - uint16_t param_id; + TransportParameters::TransportParameterId param_id; CBS value; - if (!CBS_get_u16(¶ms, ¶m_id) || - !CBS_get_u16_length_prefixed(¶ms, &value)) { + static_assert(sizeof(param_id) == sizeof(uint16_t), "bad size"); + if (!CBS_get_u16(¶ms, reinterpret_cast<uint16_t*>(¶m_id))) { + QUIC_DLOG(ERROR) << "Failed to parse transport parameter ID"; return false; } - if (param_id < kMaxKnownParameterId) { - uint16_t mask = 1 << param_id; - if (present_params & mask) { - return false; - } - present_params |= mask; + if (!CBS_get_u16_length_prefixed(¶ms, &value)) { + QUIC_DLOG(ERROR) << "Failed to parse length of transport parameter " + << TransportParameterIdToString(param_id); + return false; } + bool parse_success = true; switch (param_id) { - case kInitialMaxStreamDataId: - if (!CBS_get_u32(&value, &out->initial_max_stream_data) || - CBS_len(&value) != 0) { + case kOriginalConnectionId: + if (!out->original_connection_id.IsEmpty()) { + QUIC_DLOG(ERROR) << "Received a second original connection ID"; return false; } - break; - case kInitialMaxDataId: - if (!CBS_get_u32(&value, &out->initial_max_data) || - CBS_len(&value) != 0) { + if (CBS_len(&value) > static_cast<size_t>(kQuicMaxConnectionIdLength)) { + QUIC_DLOG(ERROR) << "Received original connection ID of " + << "invalid length " << CBS_len(&value); return false; } - break; - case kInitialMaxBidiStreamsId: - if (!CBS_get_u16(&value, &out->initial_max_bidi_streams.value) || - CBS_len(&value) != 0) { - return false; + if (CBS_len(&value) != 0) { + out->original_connection_id.set_length(CBS_len(&value)); + memcpy(out->original_connection_id.mutable_data(), CBS_data(&value), + CBS_len(&value)); } - out->initial_max_bidi_streams.present = true; break; - case kIdleTimeoutId: - if (!CBS_get_u16(&value, &out->idle_timeout) || CBS_len(&value) != 0) { - return false; - } + case kIdleTimeout: + parse_success = out->idle_timeout_milliseconds.ReadFromCbs(&value); break; - case kMaxOutgoingPacketSizeId: - if (!CBS_get_u16(&value, &out->max_packet_size.value) || - CBS_len(&value) != 0) { + case kStatelessResetToken: + if (!out->stateless_reset_token.empty()) { + QUIC_DLOG(ERROR) << "Received a second stateless reset token"; return false; } - out->max_packet_size.present = true; - break; - case kStatelessResetTokenId: - if (CBS_len(&value) == 0) { + if (CBS_len(&value) != kStatelessResetTokenLength) { + QUIC_DLOG(ERROR) << "Received stateless reset token of " + << "invalid length " << CBS_len(&value); return false; } out->stateless_reset_token.assign(CBS_data(&value), CBS_data(&value) + CBS_len(&value)); break; - case kAckDelayExponentId: - if (!CBS_get_u8(&value, &out->ack_delay_exponent.value) || - CBS_len(&value) != 0) { + case kMaxPacketSize: + parse_success = out->max_packet_size.ReadFromCbs(&value); + break; + case kInitialMaxData: + parse_success = out->initial_max_data.ReadFromCbs(&value); + break; + case kInitialMaxStreamDataBidiLocal: + parse_success = + out->initial_max_stream_data_bidi_local.ReadFromCbs(&value); + break; + case kInitialMaxStreamDataBidiRemote: + parse_success = + out->initial_max_stream_data_bidi_remote.ReadFromCbs(&value); + break; + case kInitialMaxStreamDataUni: + parse_success = out->initial_max_stream_data_uni.ReadFromCbs(&value); + break; + case kInitialMaxStreamsBidi: + parse_success = out->initial_max_streams_bidi.ReadFromCbs(&value); + break; + case kInitialMaxStreamsUni: + parse_success = out->initial_max_streams_uni.ReadFromCbs(&value); + break; + case kAckDelayExponent: + parse_success = out->ack_delay_exponent.ReadFromCbs(&value); + break; + case kMaxAckDelay: + parse_success = out->max_ack_delay.ReadFromCbs(&value); + break; + case kDisableMigration: + if (out->disable_migration) { + QUIC_DLOG(ERROR) << "Received a second disable migration"; return false; } - out->ack_delay_exponent.present = true; - break; - case kInitialMaxUniStreamsId: - if (!CBS_get_u16(&value, &out->initial_max_uni_streams.value) || - CBS_len(&value) != 0) { + if (CBS_len(&value) != 0) { + QUIC_DLOG(ERROR) << "Received disable migration of invalid length " + << CBS_len(&value); return false; } - out->initial_max_uni_streams.present = true; + out->disable_migration = true; break; - case kGoogleQuicParamId: - if (has_google_quic_params) { + case kPreferredAddress: { + uint16_t ipv4_port, ipv6_port; + in_addr ipv4_address; + in6_addr ipv6_address; + if (!CBS_copy_bytes(&value, reinterpret_cast<uint8_t*>(&ipv4_address), + sizeof(ipv4_address)) || + !CBS_get_u16(&value, &ipv4_port) || + !CBS_copy_bytes(&value, reinterpret_cast<uint8_t*>(&ipv6_address), + sizeof(ipv6_address)) || + !CBS_get_u16(&value, &ipv6_port)) { + QUIC_DLOG(ERROR) << "Failed to parse preferred address IPs and ports"; + return false; + } + TransportParameters::PreferredAddress preferred_address; + preferred_address.ipv4_socket_address = + QuicSocketAddress(QuicIpAddress(ipv4_address), ipv4_port); + preferred_address.ipv6_socket_address = + QuicSocketAddress(QuicIpAddress(ipv6_address), ipv6_port); + if (!preferred_address.ipv4_socket_address.host().IsIPv4() || + !preferred_address.ipv6_socket_address.host().IsIPv6()) { + QUIC_DLOG(ERROR) << "Received preferred addresses of bad families " + << preferred_address; + return false; + } + CBS connection_id_cbs; + if (!CBS_get_u8_length_prefixed(&value, &connection_id_cbs)) { + QUIC_DLOG(ERROR) + << "Failed to parse length of preferred address connection ID"; + return false; + } + if (CBS_len(&connection_id_cbs) > kQuicMaxConnectionIdLength) { + QUIC_DLOG(ERROR) << "Bad preferred address connection ID length"; + return false; + } + preferred_address.connection_id.set_length(CBS_len(&connection_id_cbs)); + if (preferred_address.connection_id.length() > 0 && + !CBS_copy_bytes(&connection_id_cbs, + reinterpret_cast<uint8_t*>( + preferred_address.connection_id.mutable_data()), + preferred_address.connection_id.length())) { + QUIC_DLOG(ERROR) << "Failed to read preferred address connection ID"; + return false; + } + if (CBS_len(&value) != kStatelessResetTokenLength) { + QUIC_DLOG(ERROR) << "Received preferred address with " + << "invalid remaining length " << CBS_len(&value); + return false; + } + preferred_address.stateless_reset_token.assign( + CBS_data(&value), CBS_data(&value) + CBS_len(&value)); + out->preferred_address = + QuicMakeUnique<TransportParameters::PreferredAddress>( + preferred_address); + } break; + case kGoogleQuicParam: { + if (out->google_quic_params) { + QUIC_DLOG(ERROR) << "Received a second Google parameter"; return false; } - has_google_quic_params = true; QuicStringPiece serialized_params( reinterpret_cast<const char*>(CBS_data(&value)), CBS_len(&value)); out->google_quic_params = CryptoFramer::ParseMessage(serialized_params); + } break; + case kGoogleQuicVersion: { + if (!CBS_get_u32(&value, &out->version)) { + QUIC_DLOG(ERROR) << "Failed to parse Google version extension"; + return false; + } + if (perspective == Perspective::IS_SERVER) { + CBS versions; + if (!CBS_get_u8_length_prefixed(&value, &versions) || + CBS_len(&versions) % 4 != 0) { + QUIC_DLOG(ERROR) + << "Failed to parse Google supported versions length"; + return false; + } + while (CBS_len(&versions) > 0) { + QuicVersionLabel version; + if (!CBS_get_u32(&versions, &version)) { + QUIC_DLOG(ERROR) << "Failed to parse Google supported version"; + return false; + } + out->supported_versions.push_back(version); + } + } + } break; + } + if (!parse_success) { + return false; } } - if ((present_params & kRequiredParamsMask) != kRequiredParamsMask) { - return false; + + const bool ok = out->AreValid(); + if (ok) { + QUIC_DLOG(INFO) << "Parsed transport parameters " << *out << " from " + << in_len << " bytes"; + } else { + QUIC_DLOG(ERROR) << "Transport parameter validity check failed " << *out + << " from " << in_len << " bytes"; } - return out->is_valid(); + return ok; } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h index b8abc0ba7f6..27b5fe77e38 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h @@ -8,71 +8,178 @@ #include <memory> #include <vector> +#include "third_party/boringssl/src/include/openssl/bytestring.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" namespace quic { // TransportParameters contains parameters for QUIC's transport layer that are -// indicated during the TLS handshake. This struct is a mirror of the struct in -// section 6.4 of draft-ietf-quic-transport-11. +// exchanged during the TLS handshake. This struct is a mirror of the struct in +// the "Transport Parameter Encoding" section of draft-ietf-quic-transport. +// This struct currently uses the values from draft 20. struct QUIC_EXPORT_PRIVATE TransportParameters { + // The identifier used to differentiate transport parameters. + enum TransportParameterId : uint16_t; + // Represents an individual QUIC transport parameter that only encodes a + // variable length integer. Can only be created inside the constructor for + // TransportParameters. + class QUIC_EXPORT_PRIVATE IntegerParameter { + public: + // Forbid constructing and copying apart from TransportParameters. + IntegerParameter() = delete; + IntegerParameter(const IntegerParameter&) = delete; + IntegerParameter& operator=(const IntegerParameter&) = delete; + // Sets the value of this transport parameter. + void set_value(uint64_t value); + // Gets the value of this transport parameter. + uint64_t value() const; + // Validates whether the current value is valid. + bool IsValid() const; + // Writes to a crypto byte buffer, used during serialization. Does not write + // anything if the value is equal to the parameter's default value. + // Returns whether the write was successful. + bool WriteToCbb(CBB* parent_cbb) const; + // Reads from a crypto byte string, used during parsing. + // Returns whether the read was successful. + bool ReadFromCbs(CBS* const value_cbs); + // operator<< allows easily logging integer transport parameters. + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const IntegerParameter& param); + + private: + friend struct TransportParameters; + // Constructors for initial setup used by TransportParameters only. + // This constructor sets |default_value| and |min_value| to 0, and + // |max_value| to kVarInt62MaxValue. + explicit IntegerParameter(TransportParameterId param_id); + IntegerParameter(TransportParameterId param_id, + uint64_t default_value, + uint64_t min_value, + uint64_t max_value); + // Human-readable string representation. + std::string ToString(bool for_use_in_list) const; + + // Number used to indicate this transport parameter. + TransportParameterId param_id_; + // Current value of the transport parameter. + uint64_t value_; + // Default value of this transport parameter, as per IETF specification. + const uint64_t default_value_; + // Minimum value of this transport parameter, as per IETF specification. + const uint64_t min_value_; + // Maximum value of this transport parameter, as per IETF specification. + const uint64_t max_value_; + // Ensures this parameter is not parsed twice in the same message. + bool has_been_read_from_cbs_; + }; + + // Represents the preferred_address transport parameter that a server can + // send to clients. + struct QUIC_EXPORT_PRIVATE PreferredAddress { + PreferredAddress(); + ~PreferredAddress(); + + QuicSocketAddress ipv4_socket_address; + QuicSocketAddress ipv6_socket_address; + QuicConnectionId connection_id; + std::vector<uint8_t> stateless_reset_token; + + // Allows easily logging. + std::string ToString() const; + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const TransportParameters& params); + }; + TransportParameters(); ~TransportParameters(); - // When |perspective| is Perspective::IS_CLIENT, this struct is being used in - // the client_hello handshake message; when it is Perspective::IS_SERVER, it - // is being used in the encrypted_extensions handshake message. + // Represents the sender of the transport parameters. When |perspective| is + // Perspective::IS_CLIENT, this struct is being used in the client_hello + // handshake message; when it is Perspective::IS_SERVER, it is being used in + // the encrypted_extensions handshake message. Perspective perspective; // When Perspective::IS_CLIENT, |version| is the initial version offered by // the client (before any version negotiation packets) for this connection. // When Perspective::IS_SERVER, |version| is the version that is in use. - QuicVersionLabel version = 0; - - // Server-only parameters: + QuicVersionLabel version; // |supported_versions| contains a list of all versions that the server would // send in a version negotiation packet. It is not used if |perspective == // Perspective::IS_CLIENT|. QuicVersionLabelVector supported_versions; - // See section 6.4.1 of draft-ietf-quic-transport-11 for definition. + // The value of the Destination Connection ID field from the first + // Initial packet sent by the client. + QuicConnectionId original_connection_id; + + // Idle timeout expressed in milliseconds. + IntegerParameter idle_timeout_milliseconds; + + // Stateless reset token used in verifying stateless resets. std::vector<uint8_t> stateless_reset_token; - // Required parameters. See section 6.4.1 of draft-ietf-quic-transport-11 for - // definitions. - uint32_t initial_max_stream_data = 0; - uint32_t initial_max_data = 0; - uint16_t idle_timeout = 0; + // Limits the size of packets that the endpoint is willing to receive. + // This indicates that packets larger than this limit will be dropped. + IntegerParameter max_packet_size; - template <typename T> - struct OptionalParam { - bool present = false; - T value; - }; + // Contains the initial value for the maximum amount of data that can + // be sent on the connection. + IntegerParameter initial_max_data; + + // Initial flow control limit for locally-initiated bidirectional streams. + IntegerParameter initial_max_stream_data_bidi_local; - // Optional parameters. See section 6.4.1 of draft-ietf-quic-transport-11 for - // definitions. - OptionalParam<uint16_t> initial_max_bidi_streams; - OptionalParam<uint16_t> initial_max_uni_streams; - OptionalParam<uint16_t> max_packet_size; - OptionalParam<uint8_t> ack_delay_exponent; + // Initial flow control limit for peer-initiated bidirectional streams. + IntegerParameter initial_max_stream_data_bidi_remote; + + // Initial flow control limit for unidirectional streams. + IntegerParameter initial_max_stream_data_uni; + + // Initial maximum number of bidirectional streams the peer may initiate. + IntegerParameter initial_max_streams_bidi; + + // Initial maximum number of unidirectional streams the peer may initiate. + IntegerParameter initial_max_streams_uni; + + // Exponent used to decode the ACK Delay field in ACK frames. + IntegerParameter ack_delay_exponent; + + // Maximum amount of time in milliseconds by which the endpoint will + // delay sending acknowledgments. + IntegerParameter max_ack_delay; + + // Indicates lack of support for connection migration. + bool disable_migration; + + // Used to effect a change in server address at the end of the handshake. + std::unique_ptr<PreferredAddress> preferred_address; // Transport parameters used by Google QUIC but not IETF QUIC. This is // serialized into a TransportParameter struct with a TransportParameterId of - // 18257. + // kGoogleQuicParamId. std::unique_ptr<CryptoHandshakeMessage> google_quic_params; - // Returns true if the contents of this struct are valid. - bool is_valid() const; + // Validates whether transport parameters are valid according to + // the specification. + bool AreValid() const; + + // Allows easily logging transport parameters. + std::string ToString() const; + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const TransportParameters& params); }; // Serializes a TransportParameters struct into the format for sending it in a -// TLS extension. The serialized bytes are put in |*out|, and this function -// returns true on success or false if |TransportParameters::is_valid| returns -// false. +// TLS extension. The serialized bytes are written to |*out|. Returns if the +// parameters are valid and serialization succeeded. QUIC_EXPORT_PRIVATE bool SerializeTransportParameters( const TransportParameters& in, std::vector<uint8_t>* out); @@ -80,8 +187,7 @@ QUIC_EXPORT_PRIVATE bool SerializeTransportParameters( // Parses bytes from the quic_transport_parameters TLS extension and writes the // parsed parameters into |*out|. Input is read from |in| for |in_len| bytes. // |perspective| indicates whether the input came from a client or a server. -// This method returns true if the input was successfully parsed, and false if -// it could not be parsed. +// This method returns true if the input was successfully parsed. // TODO(nharper): Write fuzz tests for this method. QUIC_EXPORT_PRIVATE bool ParseTransportParameters(const uint8_t* in, size_t in_len, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc index 23b18e54bbc..7776af14b13 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc @@ -4,31 +4,98 @@ #include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" +#include <cstring> + #include "third_party/boringssl/src/include/openssl/mem.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" namespace quic { namespace test { +namespace { +const QuicVersionLabel kFakeVersionLabel = 0x01234567; +const QuicVersionLabel kFakeVersionLabel2 = 0x89ABCDEF; +const QuicConnectionId kFakeOriginalConnectionId = TestConnectionId(0x1337); +const uint64_t kFakeIdleTimeoutMilliseconds = 12012; +const uint8_t kFakeStatelessResetTokenData[16] = { + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F}; +const std::vector<uint8_t> kFakeStatelessResetToken( + kFakeStatelessResetTokenData, + kFakeStatelessResetTokenData + sizeof(kFakeStatelessResetTokenData)); +const uint64_t kFakeMaxPacketSize = 9001; +const uint64_t kFakeInitialMaxData = 101; +const uint64_t kFakeInitialMaxStreamDataBidiLocal = 2001; +const uint64_t kFakeInitialMaxStreamDataBidiRemote = 2002; +const uint64_t kFakeInitialMaxStreamDataUni = 3000; +const uint64_t kFakeInitialMaxStreamsBidi = 21; +const uint64_t kFakeInitialMaxStreamsUni = 22; +const uint64_t kFakeAckDelayExponent = 10; +const uint64_t kFakeMaxAckDelay = 51; +const bool kFakeDisableMigration = true; +const QuicConnectionId kFakePreferredConnectionId = TestConnectionId(0xBEEF); +const uint8_t kFakePreferredStatelessResetTokenData[16] = { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F}; +const std::vector<uint8_t> kFakePreferredStatelessResetToken( + kFakePreferredStatelessResetTokenData, + kFakePreferredStatelessResetTokenData + + sizeof(kFakeStatelessResetTokenData)); + +QuicSocketAddress CreateFakeV4SocketAddress() { + QuicIpAddress ipv4_address; + if (!ipv4_address.FromString("65.66.67.68")) { // 0x41, 0x42, 0x43, 0x44 + QUIC_LOG(FATAL) << "Failed to create IPv4 address"; + return QuicSocketAddress(); + } + return QuicSocketAddress(ipv4_address, 0x4884); +} + +QuicSocketAddress CreateFakeV6SocketAddress() { + QuicIpAddress ipv6_address; + if (!ipv6_address.FromString("6061:6263:6465:6667:6869:6A6B:6C6D:6E6F")) { + QUIC_LOG(FATAL) << "Failed to create IPv6 address"; + return QuicSocketAddress(); + } + return QuicSocketAddress(ipv6_address, 0x6336); +} + +std::unique_ptr<TransportParameters::PreferredAddress> +CreateFakePreferredAddress() { + TransportParameters::PreferredAddress preferred_address; + preferred_address.ipv4_socket_address = CreateFakeV4SocketAddress(); + preferred_address.ipv6_socket_address = CreateFakeV6SocketAddress(); + preferred_address.connection_id = kFakePreferredConnectionId; + preferred_address.stateless_reset_token = kFakePreferredStatelessResetToken; + return QuicMakeUnique<TransportParameters::PreferredAddress>( + preferred_address); +} + +} // namespace class TransportParametersTest : public QuicTest {}; TEST_F(TransportParametersTest, RoundTripClient) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; - orig_params.initial_max_stream_data = 12; - orig_params.initial_max_data = 34; - orig_params.idle_timeout = 56; - orig_params.initial_max_bidi_streams.present = true; - orig_params.initial_max_bidi_streams.value = 2000; - orig_params.initial_max_uni_streams.present = true; - orig_params.initial_max_uni_streams.value = 3000; - orig_params.max_packet_size.present = true; - orig_params.max_packet_size.value = 9001; - orig_params.ack_delay_exponent.present = true; - orig_params.ack_delay_exponent.value = 10; - orig_params.version = 0xff000005; + orig_params.version = kFakeVersionLabel; + orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + orig_params.max_packet_size.set_value(kFakeMaxPacketSize); + orig_params.initial_max_data.set_value(kFakeInitialMaxData); + orig_params.initial_max_stream_data_bidi_local.set_value( + kFakeInitialMaxStreamDataBidiLocal); + orig_params.initial_max_stream_data_bidi_remote.set_value( + kFakeInitialMaxStreamDataBidiRemote); + orig_params.initial_max_stream_data_uni.set_value( + kFakeInitialMaxStreamDataUni); + orig_params.initial_max_streams_bidi.set_value(kFakeInitialMaxStreamsBidi); + orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); + orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent); + orig_params.max_ack_delay.set_value(kFakeMaxAckDelay); + orig_params.disable_migration = kFakeDisableMigration; std::vector<uint8_t> serialized; ASSERT_TRUE(SerializeTransportParameters(orig_params, &serialized)); @@ -37,35 +104,53 @@ TEST_F(TransportParametersTest, RoundTripClient) { ASSERT_TRUE(ParseTransportParameters(serialized.data(), serialized.size(), Perspective::IS_CLIENT, &new_params)); - EXPECT_EQ(new_params.initial_max_stream_data, - orig_params.initial_max_stream_data); - EXPECT_EQ(new_params.initial_max_data, orig_params.initial_max_data); - EXPECT_EQ(new_params.idle_timeout, orig_params.idle_timeout); - EXPECT_EQ(new_params.version, orig_params.version); - EXPECT_TRUE(new_params.initial_max_bidi_streams.present); - EXPECT_EQ(new_params.initial_max_bidi_streams.value, - orig_params.initial_max_bidi_streams.value); - EXPECT_TRUE(new_params.initial_max_uni_streams.present); - EXPECT_EQ(new_params.initial_max_uni_streams.value, - orig_params.initial_max_uni_streams.value); - EXPECT_TRUE(new_params.max_packet_size.present); - EXPECT_EQ(new_params.max_packet_size.value, - orig_params.max_packet_size.value); - EXPECT_TRUE(new_params.ack_delay_exponent.present); - EXPECT_EQ(new_params.ack_delay_exponent.value, - orig_params.ack_delay_exponent.value); + EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective); + EXPECT_EQ(kFakeVersionLabel, new_params.version); + EXPECT_TRUE(new_params.supported_versions.empty()); + EXPECT_EQ(EmptyQuicConnectionId(), new_params.original_connection_id); + EXPECT_EQ(kFakeIdleTimeoutMilliseconds, + new_params.idle_timeout_milliseconds.value()); + EXPECT_TRUE(new_params.stateless_reset_token.empty()); + EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); + EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, + new_params.initial_max_stream_data_bidi_local.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote, + new_params.initial_max_stream_data_bidi_remote.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataUni, + new_params.initial_max_stream_data_uni.value()); + EXPECT_EQ(kFakeInitialMaxStreamsBidi, + new_params.initial_max_streams_bidi.value()); + EXPECT_EQ(kFakeInitialMaxStreamsUni, + new_params.initial_max_streams_uni.value()); + EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value()); + EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value()); + EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration); } TEST_F(TransportParametersTest, RoundTripServer) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_SERVER; - orig_params.initial_max_stream_data = 12; - orig_params.initial_max_data = 34; - orig_params.idle_timeout = 56; - orig_params.stateless_reset_token.resize(16); - orig_params.version = 0xff000005; - orig_params.supported_versions.push_back(0xff000005); - orig_params.supported_versions.push_back(0xff000004); + orig_params.version = kFakeVersionLabel; + orig_params.supported_versions.push_back(kFakeVersionLabel); + orig_params.supported_versions.push_back(kFakeVersionLabel2); + orig_params.original_connection_id = kFakeOriginalConnectionId; + orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + orig_params.stateless_reset_token = kFakeStatelessResetToken; + orig_params.max_packet_size.set_value(kFakeMaxPacketSize); + orig_params.initial_max_data.set_value(kFakeInitialMaxData); + orig_params.initial_max_stream_data_bidi_local.set_value( + kFakeInitialMaxStreamDataBidiLocal); + orig_params.initial_max_stream_data_bidi_remote.set_value( + kFakeInitialMaxStreamDataBidiRemote); + orig_params.initial_max_stream_data_uni.set_value( + kFakeInitialMaxStreamDataUni); + orig_params.initial_max_streams_bidi.set_value(kFakeInitialMaxStreamsBidi); + orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); + orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent); + orig_params.max_ack_delay.set_value(kFakeMaxAckDelay); + orig_params.disable_migration = kFakeDisableMigration; + orig_params.preferred_address = CreateFakePreferredAddress(); std::vector<uint8_t> serialized; ASSERT_TRUE(SerializeTransportParameters(orig_params, &serialized)); @@ -74,107 +159,177 @@ TEST_F(TransportParametersTest, RoundTripServer) { ASSERT_TRUE(ParseTransportParameters(serialized.data(), serialized.size(), Perspective::IS_SERVER, &new_params)); - EXPECT_EQ(new_params.initial_max_stream_data, - orig_params.initial_max_stream_data); - EXPECT_EQ(new_params.initial_max_data, orig_params.initial_max_data); - EXPECT_EQ(new_params.idle_timeout, orig_params.idle_timeout); - EXPECT_EQ(new_params.stateless_reset_token, - orig_params.stateless_reset_token); - EXPECT_EQ(new_params.version, orig_params.version); - ASSERT_EQ(new_params.supported_versions, orig_params.supported_versions); + EXPECT_EQ(Perspective::IS_SERVER, new_params.perspective); + EXPECT_EQ(kFakeVersionLabel, new_params.version); + EXPECT_EQ(2u, new_params.supported_versions.size()); + EXPECT_EQ(kFakeVersionLabel, new_params.supported_versions[0]); + EXPECT_EQ(kFakeVersionLabel2, new_params.supported_versions[1]); + EXPECT_EQ(kFakeOriginalConnectionId, new_params.original_connection_id); + EXPECT_EQ(kFakeIdleTimeoutMilliseconds, + new_params.idle_timeout_milliseconds.value()); + EXPECT_EQ(kFakeStatelessResetToken, new_params.stateless_reset_token); + EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); + EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, + new_params.initial_max_stream_data_bidi_local.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote, + new_params.initial_max_stream_data_bidi_remote.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataUni, + new_params.initial_max_stream_data_uni.value()); + EXPECT_EQ(kFakeInitialMaxStreamsBidi, + new_params.initial_max_streams_bidi.value()); + EXPECT_EQ(kFakeInitialMaxStreamsUni, + new_params.initial_max_streams_uni.value()); + EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value()); + EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value()); + EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration); + ASSERT_NE(nullptr, new_params.preferred_address.get()); + EXPECT_EQ(CreateFakeV4SocketAddress(), + new_params.preferred_address->ipv4_socket_address); + EXPECT_EQ(CreateFakeV6SocketAddress(), + new_params.preferred_address->ipv6_socket_address); + EXPECT_EQ(kFakePreferredConnectionId, + new_params.preferred_address->connection_id); + EXPECT_EQ(kFakePreferredStatelessResetToken, + new_params.preferred_address->stateless_reset_token); } TEST_F(TransportParametersTest, IsValid) { - TransportParameters empty_params; - empty_params.perspective = Perspective::IS_CLIENT; - EXPECT_TRUE(empty_params.is_valid()); - { TransportParameters params; params.perspective = Perspective::IS_CLIENT; - EXPECT_TRUE(params.is_valid()); - params.idle_timeout = 600; - EXPECT_TRUE(params.is_valid()); - params.idle_timeout = 601; - EXPECT_FALSE(params.is_valid()); + EXPECT_TRUE(params.AreValid()); } { TransportParameters params; params.perspective = Perspective::IS_CLIENT; - EXPECT_TRUE(params.is_valid()); - params.max_packet_size.present = true; - params.max_packet_size.value = 0; - EXPECT_FALSE(params.is_valid()); - params.max_packet_size.value = 1200; - EXPECT_TRUE(params.is_valid()); - params.max_packet_size.value = 65527; - EXPECT_TRUE(params.is_valid()); - params.max_packet_size.value = 65535; - EXPECT_FALSE(params.is_valid()); + EXPECT_TRUE(params.AreValid()); + params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + EXPECT_TRUE(params.AreValid()); + params.idle_timeout_milliseconds.set_value(601000); + EXPECT_TRUE(params.AreValid()); } { TransportParameters params; params.perspective = Perspective::IS_CLIENT; - EXPECT_TRUE(params.is_valid()); - params.ack_delay_exponent.present = true; - params.ack_delay_exponent.value = 0; - EXPECT_TRUE(params.is_valid()); - params.ack_delay_exponent.value = 20; - EXPECT_TRUE(params.is_valid()); - params.ack_delay_exponent.value = 21; - EXPECT_FALSE(params.is_valid()); + EXPECT_TRUE(params.AreValid()); + params.max_packet_size.set_value(0); + EXPECT_FALSE(params.AreValid()); + params.max_packet_size.set_value(1199); + EXPECT_FALSE(params.AreValid()); + params.max_packet_size.set_value(1200); + EXPECT_TRUE(params.AreValid()); + params.max_packet_size.set_value(65535); + EXPECT_TRUE(params.AreValid()); + params.max_packet_size.set_value(9999999); + EXPECT_TRUE(params.AreValid()); + } + { + TransportParameters params; + params.perspective = Perspective::IS_CLIENT; + EXPECT_TRUE(params.AreValid()); + params.ack_delay_exponent.set_value(0); + EXPECT_TRUE(params.AreValid()); + params.ack_delay_exponent.set_value(20); + EXPECT_TRUE(params.AreValid()); + params.ack_delay_exponent.set_value(21); + EXPECT_FALSE(params.AreValid()); } -} - -TEST_F(TransportParametersTest, NoServerParamsWithoutStatelessResetToken) { - TransportParameters orig_params; - orig_params.perspective = Perspective::IS_SERVER; - orig_params.initial_max_stream_data = 12; - orig_params.initial_max_data = 34; - orig_params.idle_timeout = 56; - orig_params.version = 0xff000005; - orig_params.supported_versions.push_back(0xff000005); - orig_params.supported_versions.push_back(0xff000004); - - std::vector<uint8_t> out; - ASSERT_FALSE(SerializeTransportParameters(orig_params, &out)); } TEST_F(TransportParametersTest, NoClientParamsWithStatelessResetToken) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; - orig_params.initial_max_stream_data = 12; - orig_params.initial_max_data = 34; - orig_params.idle_timeout = 56; - orig_params.stateless_reset_token.resize(16); - orig_params.version = 0xff000005; + orig_params.version = kFakeVersionLabel; + orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + orig_params.stateless_reset_token = kFakeStatelessResetToken; + orig_params.max_packet_size.set_value(kFakeMaxPacketSize); std::vector<uint8_t> out; - ASSERT_FALSE(SerializeTransportParameters(orig_params, &out)); + EXPECT_FALSE(SerializeTransportParameters(orig_params, &out)); } TEST_F(TransportParametersTest, ParseClientParams) { + // clang-format off const uint8_t kClientParams[] = { - 0xff, 0x00, 0x00, 0x05, // initial version - 0x00, 0x16, // length parameters array that follows - // initial_max_stream_data - 0x00, 0x00, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x0c, // value - // initial_max_data - 0x00, 0x01, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x22, // value + 0x00, 0x44, // length of the parameters array that follows // idle_timeout + 0x00, 0x01, // parameter id + 0x00, 0x02, // length + 0x6e, 0xec, // value + // max_packet_size 0x00, 0x03, // parameter id 0x00, 0x02, // length - 0x00, 0x38, // value + 0x63, 0x29, // value + // initial_max_data + 0x00, 0x04, // parameter id + 0x00, 0x02, // length + 0x40, 0x65, // value + // initial_max_stream_data_bidi_local + 0x00, 0x05, // parameter id + 0x00, 0x02, // length + 0x47, 0xD1, // value + // initial_max_stream_data_bidi_remote + 0x00, 0x06, // parameter id + 0x00, 0x02, // length + 0x47, 0xD2, // value + // initial_max_stream_data_uni + 0x00, 0x07, // parameter id + 0x00, 0x02, // length + 0x4B, 0xB8, // value + // initial_max_streams_bidi + 0x00, 0x08, // parameter id + 0x00, 0x01, // length + 0x15, // value + // initial_max_streams_uni + 0x00, 0x09, // parameter id + 0x00, 0x01, // length + 0x16, // value + // ack_delay_exponent + 0x00, 0x0a, // parameter id + 0x00, 0x01, // length + 0x0a, // value + // max_ack_delay + 0x00, 0x0b, // parameter id + 0x00, 0x01, // length + 0x33, // value + // disable_migration + 0x00, 0x0c, // parameter id + 0x00, 0x00, // length + // Google version extension + 0x47, 0x52, // parameter id + 0x00, 0x04, // length + 0x01, 0x23, 0x45, 0x67, // initial version }; + // clang-format on - TransportParameters out_params; + TransportParameters new_params; ASSERT_TRUE(ParseTransportParameters(kClientParams, QUIC_ARRAYSIZE(kClientParams), - Perspective::IS_CLIENT, &out_params)); + Perspective::IS_CLIENT, &new_params)); + + EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective); + EXPECT_EQ(kFakeVersionLabel, new_params.version); + EXPECT_TRUE(new_params.supported_versions.empty()); + EXPECT_EQ(EmptyQuicConnectionId(), new_params.original_connection_id); + EXPECT_EQ(kFakeIdleTimeoutMilliseconds, + new_params.idle_timeout_milliseconds.value()); + EXPECT_TRUE(new_params.stateless_reset_token.empty()); + EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); + EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, + new_params.initial_max_stream_data_bidi_local.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote, + new_params.initial_max_stream_data_bidi_remote.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataUni, + new_params.initial_max_stream_data_uni.value()); + EXPECT_EQ(kFakeInitialMaxStreamsBidi, + new_params.initial_max_streams_bidi.value()); + EXPECT_EQ(kFakeInitialMaxStreamsUni, + new_params.initial_max_streams_uni.value()); + EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value()); + EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value()); + EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration); } TEST_F(TransportParametersTest, ParseClientParamsFailsWithStatelessResetToken) { @@ -182,234 +337,237 @@ TEST_F(TransportParametersTest, ParseClientParamsFailsWithStatelessResetToken) { // clang-format off const uint8_t kClientParamsWithFullToken[] = { - 0xff, 0x00, 0x00, 0x05, // initial version - 0x00, 0x2a, // length parameters array that follows - // initial_max_stream_data - 0x00, 0x00, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x0c, // value - // initial_max_data - 0x00, 0x01, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x22, // value + 0x00, 0x26, // length parameters array that follows // idle_timeout - 0x00, 0x03, // parameter id + 0x00, 0x01, // parameter id 0x00, 0x02, // length - 0x00, 0x38, // value + 0x6e, 0xec, // value // stateless_reset_token - 0x00, 0x06, // parameter id - 0x00, 0x10, // length - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x02, + 0x00, 0x10, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + // max_packet_size + 0x00, 0x03, // parameter id + 0x00, 0x02, // length + 0x63, 0x29, // value + // initial_max_data + 0x00, 0x04, // parameter id + 0x00, 0x02, // length + 0x40, 0x65, // value }; // clang-format on - ASSERT_FALSE(ParseTransportParameters( + EXPECT_FALSE(ParseTransportParameters( kClientParamsWithFullToken, QUIC_ARRAYSIZE(kClientParamsWithFullToken), Perspective::IS_CLIENT, &out_params)); + // clang-format off const uint8_t kClientParamsWithEmptyToken[] = { - 0xff, 0x00, 0x00, 0x05, // initial version - 0x00, 0x1a, // length parameters array that follows - // initial_max_stream_data - 0x00, 0x00, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x0c, // value - // initial_max_data - 0x00, 0x01, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x22, // value + 0x00, 0x16, // length parameters array that follows // idle_timeout - 0x00, 0x03, // parameter id + 0x00, 0x01, // parameter id 0x00, 0x02, // length - 0x00, 0x38, // value + 0x6e, 0xec, // value // stateless_reset_token - 0x00, 0x06, // parameter id - 0x00, 0x00, // length + 0x00, 0x02, + 0x00, 0x00, + // max_packet_size + 0x00, 0x03, // parameter id + 0x00, 0x02, // length + 0x63, 0x29, // value + // initial_max_data + 0x00, 0x04, // parameter id + 0x00, 0x02, // length + 0x40, 0x65, // value }; + // clang-format on - ASSERT_FALSE(ParseTransportParameters( + EXPECT_FALSE(ParseTransportParameters( kClientParamsWithEmptyToken, QUIC_ARRAYSIZE(kClientParamsWithEmptyToken), Perspective::IS_CLIENT, &out_params)); } -TEST_F(TransportParametersTest, ParseClientParametersWithInvalidParams) { - TransportParameters out_params; - +TEST_F(TransportParametersTest, ParseClientParametersRepeated) { + // clang-format off const uint8_t kClientParamsRepeated[] = { - 0xff, 0x00, 0x00, 0x05, // initial version - 0x00, 0x1c, // length parameters array that follows - // initial_max_stream_data - 0x00, 0x00, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x0c, // value - // initial_max_data - 0x00, 0x01, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x22, // value + 0x00, 0x16, // length parameters array that follows // idle_timeout - 0x00, 0x03, // parameter id + 0x00, 0x01, // parameter id 0x00, 0x02, // length - 0x00, 0x38, // value - // idle_timeout (repeat) + 0x6e, 0xec, // value + // stateless_reset_token + 0x00, 0x02, + 0x00, 0x00, + // max_packet_size 0x00, 0x03, // parameter id 0x00, 0x02, // length - 0x00, 0x38, // value + 0x63, 0x29, // value + // idle_timeout (repeated) + 0x00, 0x01, // parameter id + 0x00, 0x02, // length + 0x6e, 0xec, // value }; - ASSERT_FALSE(ParseTransportParameters(kClientParamsRepeated, + // clang-format on + TransportParameters out_params; + EXPECT_FALSE(ParseTransportParameters(kClientParamsRepeated, QUIC_ARRAYSIZE(kClientParamsRepeated), Perspective::IS_CLIENT, &out_params)); - - const uint8_t kClientParamsMissing[] = { - 0xff, 0x00, 0x00, 0x05, // initial version - 0x00, 0x10, // length parameters array that follows - // initial_max_stream_data - 0x00, 0x00, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x0c, // value - // initial_max_data - 0x00, 0x01, // parameter id - 0x00, 0x04, // length - 0x00, 0x00, 0x00, 0x22, // value - }; - ASSERT_FALSE(ParseTransportParameters(kClientParamsMissing, - QUIC_ARRAYSIZE(kClientParamsMissing), - Perspective::IS_CLIENT, &out_params)); } TEST_F(TransportParametersTest, ParseServerParams) { // clang-format off const uint8_t kServerParams[] = { - 0xff, 0x00, 0x00, 0x05, // negotiated_version - 0x08, // length of supported versions array - 0xff, 0x00, 0x00, 0x05, - 0xff, 0x00, 0x00, 0x04, - 0x00, 0x2a, // length of parameters array that follows - // initial_max_stream_data - 0x00, 0x00, - 0x00, 0x04, - 0x00, 0x00, 0x00, 0x0c, - // initial_max_data - 0x00, 0x01, - 0x00, 0x04, - 0x00, 0x00, 0x00, 0x22, + 0x00, 0xa2, // length of parameters array that follows + // original_connection_id + 0x00, 0x00, // parameter id + 0x00, 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, // idle_timeout - 0x00, 0x03, - 0x00, 0x02, - 0x00, 0x38, + 0x00, 0x01, // parameter id + 0x00, 0x02, // length + 0x6e, 0xec, // value // stateless_reset_token - 0x00, 0x06, + 0x00, 0x02, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + // max_packet_size + 0x00, 0x03, // parameter id + 0x00, 0x02, // length + 0x63, 0x29, // value + // initial_max_data + 0x00, 0x04, // parameter id + 0x00, 0x02, // length + 0x40, 0x65, // value + // initial_max_stream_data_bidi_local + 0x00, 0x05, // parameter id + 0x00, 0x02, // length + 0x47, 0xD1, // value + // initial_max_stream_data_bidi_remote + 0x00, 0x06, // parameter id + 0x00, 0x02, // length + 0x47, 0xD2, // value + // initial_max_stream_data_uni + 0x00, 0x07, // parameter id + 0x00, 0x02, // length + 0x4B, 0xB8, // value + // initial_max_streams_bidi + 0x00, 0x08, // parameter id + 0x00, 0x01, // length + 0x15, // value + // initial_max_streams_uni + 0x00, 0x09, // parameter id + 0x00, 0x01, // length + 0x16, // value + // ack_delay_exponent + 0x00, 0x0a, // parameter id + 0x00, 0x01, // length + 0x0a, // value + // max_ack_delay + 0x00, 0x0b, // parameter id + 0x00, 0x01, // length + 0x33, // value + // disable_migration + 0x00, 0x0c, // parameter id + 0x00, 0x00, // length + // preferred_address + 0x00, 0x0d, // parameter id + 0x00, 0x31, // length + 0x41, 0x42, 0x43, 0x44, // IPv4 address + 0x48, 0x84, // IPv4 port + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // IPv6 address + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x63, 0x36, // IPv6 port + 0x08, // connection ID length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xEF, // connection ID + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, // stateless reset token + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + // Google version extension + 0x47, 0x52, // parameter id + 0x00, 0x0d, // length + 0x01, 0x23, 0x45, 0x67, // negotiated_version + 0x08, // length of supported versions array + 0x01, 0x23, 0x45, 0x67, + 0x89, 0xab, 0xcd, 0xef, }; // clang-format on - TransportParameters out_params; + TransportParameters new_params; ASSERT_TRUE(ParseTransportParameters(kServerParams, QUIC_ARRAYSIZE(kServerParams), - Perspective::IS_SERVER, &out_params)); -} - -TEST_F(TransportParametersTest, ParseServerParamsWithoutToken) { - // clang-format off - const uint8_t kServerParams[] = { - 0xff, 0x00, 0x00, 0x05, // negotiated_version - 0x08, // length of supported versions array - 0xff, 0x00, 0x00, 0x05, - 0xff, 0x00, 0x00, 0x04, - 0x00, 0x16, // length of parameters array that follows - // initial_max_stream_data - 0x00, 0x00, - 0x00, 0x04, - 0x00, 0x00, 0x00, 0x0c, - // initial_max_data - 0x00, 0x01, - 0x00, 0x04, - 0x00, 0x00, 0x00, 0x22, - // idle_timeout - 0x00, 0x03, - 0x00, 0x02, - 0x00, 0x38, - }; - // clang-format on + Perspective::IS_SERVER, &new_params)); - TransportParameters out_params; - ASSERT_FALSE(ParseTransportParameters(kServerParams, - QUIC_ARRAYSIZE(kServerParams), - Perspective::IS_SERVER, &out_params)); + EXPECT_EQ(Perspective::IS_SERVER, new_params.perspective); + EXPECT_EQ(kFakeVersionLabel, new_params.version); + EXPECT_EQ(2u, new_params.supported_versions.size()); + EXPECT_EQ(kFakeVersionLabel, new_params.supported_versions[0]); + EXPECT_EQ(kFakeVersionLabel2, new_params.supported_versions[1]); + EXPECT_EQ(kFakeOriginalConnectionId, new_params.original_connection_id); + EXPECT_EQ(kFakeIdleTimeoutMilliseconds, + new_params.idle_timeout_milliseconds.value()); + EXPECT_EQ(kFakeStatelessResetToken, new_params.stateless_reset_token); + EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); + EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, + new_params.initial_max_stream_data_bidi_local.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote, + new_params.initial_max_stream_data_bidi_remote.value()); + EXPECT_EQ(kFakeInitialMaxStreamDataUni, + new_params.initial_max_stream_data_uni.value()); + EXPECT_EQ(kFakeInitialMaxStreamsBidi, + new_params.initial_max_streams_bidi.value()); + EXPECT_EQ(kFakeInitialMaxStreamsUni, + new_params.initial_max_streams_uni.value()); + EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value()); + EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value()); + EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration); + ASSERT_NE(nullptr, new_params.preferred_address.get()); + EXPECT_EQ(CreateFakeV4SocketAddress(), + new_params.preferred_address->ipv4_socket_address); + EXPECT_EQ(CreateFakeV6SocketAddress(), + new_params.preferred_address->ipv6_socket_address); + EXPECT_EQ(kFakePreferredConnectionId, + new_params.preferred_address->connection_id); + EXPECT_EQ(kFakePreferredStatelessResetToken, + new_params.preferred_address->stateless_reset_token); } -TEST_F(TransportParametersTest, ParseServerParametersWithInvalidParams) { - TransportParameters out_params; - +TEST_F(TransportParametersTest, ParseServerParametersRepeated) { // clang-format off const uint8_t kServerParamsRepeated[] = { - 0xff, 0x00, 0x00, 0x05, // negotiated_version - 0x08, // length of supported versions array - 0xff, 0x00, 0x00, 0x05, - 0xff, 0x00, 0x00, 0x04, - 0x00, 0x30, // length of parameters array that follows - // initial_max_stream_data - 0x00, 0x00, - 0x00, 0x04, - 0x00, 0x00, 0x00, 0x0c, - // initial_max_data - 0x00, 0x01, - 0x00, 0x04, - 0x00, 0x00, 0x00, 0x22, + 0x00, 0x2c, // length of parameters array that follows + // original_connection_id + 0x00, 0x00, // parameter id + 0x00, 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, // idle_timeout - 0x00, 0x03, - 0x00, 0x02, - 0x00, 0x38, - // idle_timeout (repeat) - 0x00, 0x03, - 0x00, 0x02, - 0x00, 0x38, + 0x00, 0x01, // parameter id + 0x00, 0x02, // length + 0x6e, 0xec, // value // stateless_reset_token - 0x00, 0x06, + 0x00, 0x02, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + // idle_timeout (repeated) + 0x00, 0x01, // parameter id + 0x00, 0x02, // length + 0x6e, 0xec, // value }; // clang-format on - ASSERT_FALSE(ParseTransportParameters(kServerParamsRepeated, - QUIC_ARRAYSIZE(kServerParamsRepeated), - Perspective::IS_SERVER, &out_params)); - // clang-format off - const uint8_t kServerParamsMissing[] = { - 0xff, 0x00, 0x00, 0x05, // negotiated_version - 0x08, // length of supported versions array - 0xff, 0x00, 0x00, 0x05, - 0xff, 0x00, 0x00, 0x04, - 0x00, 0x24, // length of parameters array that follows - // initial_max_stream_data - 0x00, 0x00, - 0x00, 0x04, - 0x00, 0x00, 0x00, 0x0c, - // initial_max_data - 0x00, 0x01, - 0x00, 0x04, - 0x00, 0x00, 0x00, 0x22, - // stateless_reset_token - 0x00, 0x06, - 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - // clang-format on - ASSERT_FALSE(ParseTransportParameters(kServerParamsMissing, - QUIC_ARRAYSIZE(kServerParamsMissing), + TransportParameters out_params; + EXPECT_FALSE(ParseTransportParameters(kServerParamsRepeated, + QUIC_ARRAYSIZE(kServerParamsRepeated), Perspective::IS_SERVER, &out_params)); } TEST_F(TransportParametersTest, CryptoHandshakeMessageRoundtrip) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; - orig_params.initial_max_stream_data = 12; - orig_params.initial_max_data = 34; - orig_params.idle_timeout = 56; + orig_params.version = kFakeVersionLabel; + orig_params.max_packet_size.set_value(kFakeMaxPacketSize); orig_params.google_quic_params = QuicMakeUnique<CryptoHandshakeMessage>(); const std::string kTestString = "test string"; @@ -434,6 +592,8 @@ TEST_F(TransportParametersTest, CryptoHandshakeMessageRoundtrip) { EXPECT_EQ(new_params.google_quic_params->GetUint32(1337, &test_value), QUIC_NO_ERROR); EXPECT_EQ(test_value, kTestValue); + EXPECT_EQ(kFakeVersionLabel, new_params.version); + EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc index baffa9d941b..3587ebd063f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.cc @@ -4,6 +4,8 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h" +#include <memory> + namespace quic { QuicConnectionCloseFrame::QuicConnectionCloseFrame() @@ -48,11 +50,13 @@ std::ostream& operator<<( << ", error_code: " << ((connection_close_frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) - ? connection_close_frame.transport_error_code + ? static_cast<uint16_t>( + connection_close_frame.transport_error_code) : ((connection_close_frame.close_type == IETF_QUIC_APPLICATION_CONNECTION_CLOSE) ? connection_close_frame.application_error_code - : connection_close_frame.quic_error_code)) + : static_cast<uint16_t>( + connection_close_frame.quic_error_code))) << ", extracted_error_code: " << connection_close_frame.extracted_error_code << ", error_details: '" << connection_close_frame.error_details diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc index 95fee41f6bf..0f3e7344cc2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc @@ -51,10 +51,10 @@ QuicFrame::QuicFrame(QuicNewConnectionIdFrame* frame) QuicFrame::QuicFrame(QuicRetireConnectionIdFrame* frame) : type(RETIRE_CONNECTION_ID_FRAME), retire_connection_id_frame(frame) {} -QuicFrame::QuicFrame(QuicMaxStreamIdFrame frame) : max_stream_id_frame(frame) {} +QuicFrame::QuicFrame(QuicMaxStreamsFrame frame) : max_streams_frame(frame) {} -QuicFrame::QuicFrame(QuicStreamIdBlockedFrame frame) - : stream_id_blocked_frame(frame) {} +QuicFrame::QuicFrame(QuicStreamsBlockedFrame frame) + : streams_blocked_frame(frame) {} QuicFrame::QuicFrame(QuicPathResponseFrame* frame) : type(PATH_RESPONSE_FRAME), path_response_frame(frame) {} @@ -84,9 +84,9 @@ void DeleteFrame(QuicFrame* frame) { case PADDING_FRAME: case MTU_DISCOVERY_FRAME: case PING_FRAME: - case MAX_STREAM_ID_FRAME: + case MAX_STREAMS_FRAME: case STOP_WAITING_FRAME: - case STREAM_ID_BLOCKED_FRAME: + case STREAMS_BLOCKED_FRAME: case STREAM_FRAME: break; case ACK_FRAME: @@ -154,8 +154,8 @@ bool IsControlFrame(QuicFrameType type) { case GOAWAY_FRAME: case WINDOW_UPDATE_FRAME: case BLOCKED_FRAME: - case STREAM_ID_BLOCKED_FRAME: - case MAX_STREAM_ID_FRAME: + case STREAMS_BLOCKED_FRAME: + case MAX_STREAMS_FRAME: case PING_FRAME: case STOP_SENDING_FRAME: return true; @@ -174,10 +174,10 @@ QuicControlFrameId GetControlFrameId(const QuicFrame& frame) { return frame.window_update_frame->control_frame_id; case BLOCKED_FRAME: return frame.blocked_frame->control_frame_id; - case STREAM_ID_BLOCKED_FRAME: - return frame.stream_id_blocked_frame.control_frame_id; - case MAX_STREAM_ID_FRAME: - return frame.max_stream_id_frame.control_frame_id; + case STREAMS_BLOCKED_FRAME: + return frame.streams_blocked_frame.control_frame_id; + case MAX_STREAMS_FRAME: + return frame.max_streams_frame.control_frame_id; case PING_FRAME: return frame.ping_frame.control_frame_id; case STOP_SENDING_FRAME: @@ -204,11 +204,11 @@ void SetControlFrameId(QuicControlFrameId control_frame_id, QuicFrame* frame) { case PING_FRAME: frame->ping_frame.control_frame_id = control_frame_id; return; - case STREAM_ID_BLOCKED_FRAME: - frame->stream_id_blocked_frame.control_frame_id = control_frame_id; + case STREAMS_BLOCKED_FRAME: + frame->streams_blocked_frame.control_frame_id = control_frame_id; return; - case MAX_STREAM_ID_FRAME: - frame->max_stream_id_frame.control_frame_id = control_frame_id; + case MAX_STREAMS_FRAME: + frame->max_streams_frame.control_frame_id = control_frame_id; return; case STOP_SENDING_FRAME: frame->stop_sending_frame->control_frame_id = control_frame_id; @@ -240,11 +240,11 @@ QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame) { case STOP_SENDING_FRAME: copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame)); break; - case STREAM_ID_BLOCKED_FRAME: - copy = QuicFrame(QuicStreamIdBlockedFrame(frame.stream_id_blocked_frame)); + case STREAMS_BLOCKED_FRAME: + copy = QuicFrame(QuicStreamsBlockedFrame(frame.streams_blocked_frame)); break; - case MAX_STREAM_ID_FRAME: - copy = QuicFrame(QuicMaxStreamIdFrame(frame.max_stream_id_frame)); + case MAX_STREAMS_FRAME: + copy = QuicFrame(QuicMaxStreamsFrame(frame.max_streams_frame)); break; default: QUIC_BUG << "Try to copy a non-retransmittable control frame: " << frame; @@ -297,6 +297,10 @@ std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) { os << "type { PING_FRAME } " << frame.ping_frame; break; } + case CRYPTO_FRAME: { + os << "type { CRYPTO_FRAME } " << frame.crypto_frame; + break; + } case MTU_DISCOVERY_FRAME: { os << "type { MTU_DISCOVERY_FRAME } "; break; @@ -308,11 +312,11 @@ std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) { os << "type { RETIRE_CONNECTION_ID } " << *(frame.retire_connection_id_frame); break; - case MAX_STREAM_ID_FRAME: - os << "type { MAX_STREAM_ID } " << frame.max_stream_id_frame; + case MAX_STREAMS_FRAME: + os << "type { MAX_STREAMS } " << frame.max_streams_frame; break; - case STREAM_ID_BLOCKED_FRAME: - os << "type { STREAM_ID_BLOCKED } " << frame.stream_id_blocked_frame; + case STREAMS_BLOCKED_FRAME: + os << "type { STREAMS_BLOCKED } " << frame.streams_blocked_frame; break; case PATH_RESPONSE_FRAME: os << "type { PATH_RESPONSE } " << *(frame.path_response_frame); diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h index c452bf41303..caa5fcecf36 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h @@ -13,7 +13,7 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h" -#include "net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_message_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_mtu_discovery_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h" @@ -27,7 +27,7 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_stop_waiting_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" -#include "net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" @@ -41,9 +41,9 @@ struct QUIC_EXPORT_PRIVATE QuicFrame { explicit QuicFrame(QuicPaddingFrame padding_frame); explicit QuicFrame(QuicMtuDiscoveryFrame frame); explicit QuicFrame(QuicPingFrame frame); - explicit QuicFrame(QuicMaxStreamIdFrame frame); + explicit QuicFrame(QuicMaxStreamsFrame frame); explicit QuicFrame(QuicStopWaitingFrame frame); - explicit QuicFrame(QuicStreamIdBlockedFrame frame); + explicit QuicFrame(QuicStreamsBlockedFrame frame); explicit QuicFrame(QuicStreamFrame stream_frame); explicit QuicFrame(QuicAckFrame* frame); @@ -72,9 +72,9 @@ struct QUIC_EXPORT_PRIVATE QuicFrame { QuicPaddingFrame padding_frame; QuicMtuDiscoveryFrame mtu_discovery_frame; QuicPingFrame ping_frame; - QuicMaxStreamIdFrame max_stream_id_frame; + QuicMaxStreamsFrame max_streams_frame; QuicStopWaitingFrame stop_waiting_frame; - QuicStreamIdBlockedFrame stream_id_blocked_frame; + QuicStreamsBlockedFrame streams_blocked_frame; QuicStreamFrame stream_frame; // Out of line frames. diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc index c432657a442..bf60b7b8917 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc @@ -101,33 +101,37 @@ TEST_F(QuicFramesTest, StopSendingFrameToString) { EXPECT_TRUE(IsControlFrame(frame.type)); } -TEST_F(QuicFramesTest, StreamIdBlockedFrameToString) { - QuicStreamIdBlockedFrame stream_id_blocked; - QuicFrame frame(stream_id_blocked); +TEST_F(QuicFramesTest, StreamsBlockedFrameToString) { + QuicStreamsBlockedFrame streams_blocked; + QuicFrame frame(streams_blocked); SetControlFrameId(1, &frame); EXPECT_EQ(1u, GetControlFrameId(frame)); - // QuicStreamIdBlocked is copied into a QuicFrame (as opposed to putting a + // QuicStreamsBlocked is copied into a QuicFrame (as opposed to putting a // pointer to it into QuicFrame) so need to work with the copy in |frame| and - // not the original one, stream_id_blocked. - frame.stream_id_blocked_frame.stream_id = 321; + // not the original one, streams_blocked. + frame.streams_blocked_frame.stream_count = 321; + frame.streams_blocked_frame.unidirectional = false; std::ostringstream stream; - stream << frame.stream_id_blocked_frame; - EXPECT_EQ("{ control_frame_id: 1, stream id: 321 }\n", stream.str()); + stream << frame.streams_blocked_frame; + EXPECT_EQ("{ control_frame_id: 1, stream count: 321, bidirectional }\n", + stream.str()); EXPECT_TRUE(IsControlFrame(frame.type)); } -TEST_F(QuicFramesTest, MaxStreamIdFrameToString) { - QuicMaxStreamIdFrame max_stream_id; - QuicFrame frame(max_stream_id); +TEST_F(QuicFramesTest, MaxStreamsFrameToString) { + QuicMaxStreamsFrame max_streams; + QuicFrame frame(max_streams); SetControlFrameId(1, &frame); EXPECT_EQ(1u, GetControlFrameId(frame)); - // QuicMaxStreamId is copied into a QuicFrame (as opposed to putting a + // QuicMaxStreams is copied into a QuicFrame (as opposed to putting a // pointer to it into QuicFrame) so need to work with the copy in |frame| and - // not the original one, max_stream_id. - frame.max_stream_id_frame.max_stream_id = 321; + // not the original one, max_streams. + frame.max_streams_frame.stream_count = 321; + frame.max_streams_frame.unidirectional = true; std::ostringstream stream; - stream << frame.max_stream_id_frame; - EXPECT_EQ("{ control_frame_id: 1, stream_id: 321 }\n", stream.str()); + stream << frame.max_streams_frame; + EXPECT_EQ("{ control_frame_id: 1, stream_count: 321, unidirectional }\n", + stream.str()); EXPECT_TRUE(IsControlFrame(frame.type)); } diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.cc deleted file mode 100644 index 19270e8e23e..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.h" - -namespace quic { - -QuicMaxStreamIdFrame::QuicMaxStreamIdFrame() - : QuicInlinedFrame(MAX_STREAM_ID_FRAME), - control_frame_id(kInvalidControlFrameId) {} - -QuicMaxStreamIdFrame::QuicMaxStreamIdFrame(QuicControlFrameId control_frame_id, - QuicStreamId max_stream_id) - : QuicInlinedFrame(MAX_STREAM_ID_FRAME), - control_frame_id(control_frame_id), - max_stream_id(max_stream_id) {} - -std::ostream& operator<<(std::ostream& os, const QuicMaxStreamIdFrame& frame) { - os << "{ control_frame_id: " << frame.control_frame_id - << ", stream_id: " << frame.max_stream_id << " }\n"; - return os; -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.h deleted file mode 100644 index 6177687d44e..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAM_ID_FRAME_H_ -#define QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAM_ID_FRAME_H_ - -#include <ostream> - -#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" - -namespace quic { - -// IETF format MAX_STREAM_ID frame. -// This frame is used by the sender to inform the peer of the largest -// stream id that the peer may open and that the sender will accept. -struct QUIC_EXPORT_PRIVATE QuicMaxStreamIdFrame - : public QuicInlinedFrame<QuicMaxStreamIdFrame> { - QuicMaxStreamIdFrame(); - QuicMaxStreamIdFrame(QuicControlFrameId control_frame_id, - QuicStreamId max_stream_id); - - friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( - std::ostream& os, - const QuicMaxStreamIdFrame& frame); - - // A unique identifier of this control frame. 0 when this frame is received, - // and non-zero when sent. - QuicControlFrameId control_frame_id; - - // The maximum stream id to support. - QuicStreamId max_stream_id; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAM_ID_FRAME_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc new file mode 100644 index 00000000000..21dce5bf706 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2019 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/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h" + +namespace quic { + +QuicMaxStreamsFrame::QuicMaxStreamsFrame() + : QuicInlinedFrame(MAX_STREAMS_FRAME), + control_frame_id(kInvalidControlFrameId), + unidirectional(false) {} + +QuicMaxStreamsFrame::QuicMaxStreamsFrame(QuicControlFrameId control_frame_id, + QuicStreamCount stream_count, + bool unidirectional) + : QuicInlinedFrame(MAX_STREAMS_FRAME), + control_frame_id(control_frame_id), + stream_count(stream_count), + unidirectional(unidirectional) {} + +std::ostream& operator<<(std::ostream& os, const QuicMaxStreamsFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", stream_count: " << frame.stream_count + << ((frame.unidirectional) ? ", unidirectional }\n" + : ", bidirectional }\n"); + return os; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h new file mode 100644 index 00000000000..f8c78f9afd4 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h @@ -0,0 +1,43 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAMS_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAMS_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// IETF format MAX_STREAMS frame. +// This frame is used by the sender to inform the peer of the number of +// streams that the peer may open and that the sender will accept. +struct QUIC_EXPORT_PRIVATE QuicMaxStreamsFrame + : public QuicInlinedFrame<QuicMaxStreamsFrame> { + QuicMaxStreamsFrame(); + QuicMaxStreamsFrame(QuicControlFrameId control_frame_id, + QuicStreamCount stream_count, + bool unidirectional); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicMaxStreamsFrame& frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + // The number of streams that may be opened. + QuicStreamCount stream_count; + // Whether uni- or bi-directional streams + bool unidirectional; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAMS_FRAME_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.cc deleted file mode 100644 index 627ad2a93ce..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.h" - -namespace quic { - -QuicStreamIdBlockedFrame::QuicStreamIdBlockedFrame() - : QuicInlinedFrame(STREAM_ID_BLOCKED_FRAME), - control_frame_id(kInvalidControlFrameId) {} - -QuicStreamIdBlockedFrame::QuicStreamIdBlockedFrame( - QuicControlFrameId control_frame_id, - QuicStreamId stream_id) - : QuicInlinedFrame(STREAM_ID_BLOCKED_FRAME), - control_frame_id(control_frame_id), - stream_id(stream_id) {} - -std::ostream& operator<<(std::ostream& os, - const QuicStreamIdBlockedFrame& frame) { - os << "{ control_frame_id: " << frame.control_frame_id - << ", stream id: " << frame.stream_id << " }\n"; - return os; -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.h deleted file mode 100644 index f9ccca2d8b1..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_ID_BLOCKED_FRAME_H_ -#define QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_ID_BLOCKED_FRAME_H_ - -#include <ostream> - -#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_constants.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" - -namespace quic { - -// IETF format STREAM_ID_BLOCKED frame. -// The sender uses this to inform the peer that the sender wished to -// open a new stream but was blocked from doing so due due to the -// maximum stream ID limit set by the peer (via a MAX_STREAM_ID frame) -struct QUIC_EXPORT_PRIVATE QuicStreamIdBlockedFrame - : public QuicInlinedFrame<QuicStreamIdBlockedFrame> { - QuicStreamIdBlockedFrame(); - QuicStreamIdBlockedFrame(QuicControlFrameId control_frame_id, - QuicStreamId stream_id); - - friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( - std::ostream& os, - const QuicStreamIdBlockedFrame& frame); - - // A unique identifier of this control frame. 0 when this frame is received, - // and non-zero when sent. - QuicControlFrameId control_frame_id; - - QuicStreamId stream_id; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_ID_BLOCKED_FRAME_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc new file mode 100644 index 00000000000..f0579c55b68 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2019 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/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h" + +namespace quic { + +QuicStreamsBlockedFrame::QuicStreamsBlockedFrame() + : QuicInlinedFrame(STREAMS_BLOCKED_FRAME), + control_frame_id(kInvalidControlFrameId), + unidirectional(false) {} + +QuicStreamsBlockedFrame::QuicStreamsBlockedFrame( + QuicControlFrameId control_frame_id, + QuicStreamCount stream_count, + bool unidirectional) + : QuicInlinedFrame(STREAMS_BLOCKED_FRAME), + control_frame_id(control_frame_id), + stream_count(stream_count), + unidirectional(unidirectional) {} + +std::ostream& operator<<(std::ostream& os, + const QuicStreamsBlockedFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", stream count: " << frame.stream_count + << ((frame.unidirectional) ? ", unidirectional }\n" + : ", bidirectional }\n"); + + return os; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h new file mode 100644 index 00000000000..ff7c7f44621 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h @@ -0,0 +1,44 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STREAMS_BLOCKED_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_STREAMS_BLOCKED_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// IETF format STREAMS_BLOCKED frame. +// The sender uses this to inform the peer that the sender wished to +// open a new stream, exceeding the limit on the number of streams. +struct QUIC_EXPORT_PRIVATE QuicStreamsBlockedFrame + : public QuicInlinedFrame<QuicStreamsBlockedFrame> { + QuicStreamsBlockedFrame(); + QuicStreamsBlockedFrame(QuicControlFrameId control_frame_id, + QuicStreamCount stream_count, + bool unidirectional); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicStreamsBlockedFrame& frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + // The number of streams that the sender wishes to exceed + QuicStreamCount stream_count; + + // Whether uni- or bi-directional streams + bool unidirectional; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_STREAMS_BLOCKED_FRAME_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc index e537c735377..0a0326ce437 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc @@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h" #include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" @@ -83,18 +84,11 @@ struct TestParams { TestParams(const ParsedQuicVersionVector& client_supported_versions, const ParsedQuicVersionVector& server_supported_versions, ParsedQuicVersion negotiated_version, - bool client_supports_stateless_rejects, - bool server_uses_stateless_rejects_if_peer_supported, - QuicTag congestion_control_tag, - bool use_cheap_stateless_reject) + QuicTag congestion_control_tag) : client_supported_versions(client_supported_versions), server_supported_versions(server_supported_versions), negotiated_version(negotiated_version), - client_supports_stateless_rejects(client_supports_stateless_rejects), - server_uses_stateless_rejects_if_peer_supported( - server_uses_stateless_rejects_if_peer_supported), - congestion_control_tag(congestion_control_tag), - use_cheap_stateless_reject(use_cheap_stateless_reject) {} + congestion_control_tag(congestion_control_tag) {} friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { os << "{ server_supported_versions: " @@ -103,29 +97,19 @@ struct TestParams { << ParsedQuicVersionVectorToString(p.client_supported_versions); os << " negotiated_version: " << ParsedQuicVersionToString(p.negotiated_version); - os << " client_supports_stateless_rejects: " - << p.client_supports_stateless_rejects; - os << " server_uses_stateless_rejects_if_peer_supported: " - << p.server_uses_stateless_rejects_if_peer_supported; os << " congestion_control_tag: " - << QuicTagToString(p.congestion_control_tag); - os << " use_cheap_stateless_reject: " << p.use_cheap_stateless_reject - << " }"; + << QuicTagToString(p.congestion_control_tag) << " }"; return os; } ParsedQuicVersionVector client_supported_versions; ParsedQuicVersionVector server_supported_versions; ParsedQuicVersion negotiated_version; - bool client_supports_stateless_rejects; - bool server_uses_stateless_rejects_if_peer_supported; QuicTag congestion_control_tag; - bool use_cheap_stateless_reject; }; // Constructs various test permutations. -std::vector<TestParams> GetTestParams(bool use_tls_handshake, - bool test_stateless_rejects) { +std::vector<TestParams> GetTestParams(bool use_tls_handshake) { QuicFlagSaver flags; // Divide the versions into buckets in which the intra-frame format // is compatible. When clients encounter QUIC version negotiation @@ -135,7 +119,7 @@ std::vector<TestParams> GetTestParams(bool use_tls_handshake, // handshake protocol). So these tests need to ensure that clients are never // attempting to do 0-RTT across incompatible versions. Chromium only // supports a single version at a time anyway. :) - FLAGS_quic_supports_tls_handshake = use_tls_handshake; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, use_tls_handshake); ParsedQuicVersionVector all_supported_versions = FilterSupportedVersions(AllSupportedVersions()); @@ -157,92 +141,35 @@ std::vector<TestParams> GetTestParams(bool use_tls_handshake, } } - // This must be kept in sync with the number of nested for-loops below as it - // is used to prune the number of tests that are run. - const int kMaxEnabledOptions = 4; - int max_enabled_options = 0; std::vector<TestParams> params; for (const QuicTag congestion_control_tag : {kRENO, kTBBR, kQBIC, kTPCC}) { - for (bool server_uses_stateless_rejects_if_peer_supported : {true, false}) { - for (bool client_supports_stateless_rejects : {true, false}) { - for (bool use_cheap_stateless_reject : {true, false}) { - int enabled_options = 0; - if (congestion_control_tag != kQBIC) { - ++enabled_options; - } - if (client_supports_stateless_rejects) { - ++enabled_options; - } - if (server_uses_stateless_rejects_if_peer_supported) { - ++enabled_options; - } - if (use_cheap_stateless_reject) { - ++enabled_options; - } - CHECK_GE(kMaxEnabledOptions, enabled_options); - if (enabled_options > max_enabled_options) { - max_enabled_options = enabled_options; - } - - // Run tests with no options, a single option, or all the - // options enabled to avoid a combinatorial explosion. - if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) { - continue; - } - - // There are many stateless reject combinations, so don't test them - // unless requested. - if ((server_uses_stateless_rejects_if_peer_supported || - client_supports_stateless_rejects || - use_cheap_stateless_reject) && - !test_stateless_rejects) { - continue; - } - - for (const ParsedQuicVersionVector& client_versions : - version_buckets) { - if (FilterSupportedVersions(client_versions).empty()) { - continue; - } - // Add an entry for server and client supporting all - // versions. - params.push_back(TestParams( - client_versions, all_supported_versions, - client_versions.front(), client_supports_stateless_rejects, - server_uses_stateless_rejects_if_peer_supported, - congestion_control_tag, use_cheap_stateless_reject)); - - // Run version negotiation tests tests with no options, or - // all the options enabled to avoid a combinatorial - // explosion. - if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) { - continue; - } - - // Test client supporting all versions and server supporting - // 1 version. Simulate an old server and exercise version - // downgrade in the client. Protocol negotiation should - // occur. Skip the i = 0 case because it is essentially the - // same as the default case. - for (size_t i = 1; i < client_versions.size(); ++i) { - ParsedQuicVersionVector server_supported_versions; - server_supported_versions.push_back(client_versions[i]); - if (FilterSupportedVersions(server_supported_versions).empty()) { - continue; - } - params.push_back(TestParams( - client_versions, server_supported_versions, - server_supported_versions.front(), - client_supports_stateless_rejects, - server_uses_stateless_rejects_if_peer_supported, - congestion_control_tag, use_cheap_stateless_reject)); - } // End of inner version loop. - } // End of outer version loop. - } // End of use_cheap_stateless_reject loop. - } // End of client_supports_stateless_rejects loop. - } // End of server_uses_stateless_rejects_if_peer_supported loop. - } // End of congestion_control_tag loop. - CHECK_EQ(kMaxEnabledOptions, max_enabled_options); + for (const ParsedQuicVersionVector& client_versions : version_buckets) { + if (FilterSupportedVersions(client_versions).empty()) { + continue; + } + // Add an entry for server and client supporting all versions. + params.push_back(TestParams(client_versions, all_supported_versions, + client_versions.front(), + congestion_control_tag)); + + // Test client supporting all versions and server supporting + // 1 version. Simulate an old server and exercise version + // downgrade in the client. Protocol negotiation should + // occur. Skip the i = 0 case because it is essentially the + // same as the default case. + for (size_t i = 1; i < client_versions.size(); ++i) { + ParsedQuicVersionVector server_supported_versions; + server_supported_versions.push_back(client_versions[i]); + if (FilterSupportedVersions(server_supported_versions).empty()) { + continue; + } + params.push_back(TestParams(client_versions, server_supported_versions, + server_supported_versions.front(), + congestion_control_tag)); + } // End of inner version loop. + } // End of outer version loop. + } // End of congestion_control_tag loop. + return params; } @@ -284,9 +211,9 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { chlo_multiplier_(0), stream_factory_(nullptr), support_server_push_(false), - override_connection_id_(nullptr), - expected_connection_id_length_(kQuicDefaultConnectionIdLength) { - FLAGS_quic_supports_tls_handshake = true; + override_server_connection_id_(nullptr), + expected_server_connection_id_length_(kQuicDefaultConnectionIdLength) { + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, true); SetQuicReloadableFlag(quic_no_client_conn_ver_negotiation, true); client_supported_versions_ = GetParam().client_supported_versions; @@ -332,8 +259,8 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { if (!pre_shared_key_client_.empty()) { client->client()->SetPreSharedKey(pre_shared_key_client_); } - if (override_connection_id_ != nullptr) { - client->UseConnectionId(*override_connection_id_); + if (override_server_connection_id_ != nullptr) { + client->UseConnectionId(*override_server_connection_id_); } client->Connect(); return client; @@ -406,9 +333,6 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { copt.push_back(kTPCC); } - if (GetParam().client_supports_stateless_rejects) { - copt.push_back(kSREJ); - } client_config_.SetConnectionOptionsToSend(copt); // Start the server first, because CreateQuicClient() attempts @@ -448,13 +372,10 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { } void StartServer() { - SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, - GetParam().use_cheap_stateless_reject); - auto* test_server = new QuicTestServer( crypto_test_utils::ProofSourceForTesting(), server_config_, server_supported_versions_, &memory_cache_backend_, - expected_connection_id_length_); + expected_server_connection_id_length_); server_thread_ = QuicMakeUnique<ServerThread>(test_server, server_address_); if (chlo_multiplier_ != 0) { server_thread_->server()->SetChloMultiplier(chlo_multiplier_); @@ -467,10 +388,6 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { QuicServerPeer::GetDispatcher(server_thread_->server()); QuicDispatcherPeer::UseWriter(dispatcher, server_writer_); - SetQuicReloadableFlag( - enable_quic_stateless_reject_support, - GetParam().server_uses_stateless_rejects_if_peer_supported); - server_writer_->Initialize(QuicDispatcherPeer::GetHelper(dispatcher), QuicDispatcherPeer::GetAlarmFactory(dispatcher), QuicMakeUnique<ServerDelegate>(dispatcher)); @@ -524,13 +441,10 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { EXPECT_EQ(0u, client_stats.packets_lost); } EXPECT_EQ(0u, client_stats.packets_discarded); - // When doing 0-RTT with stateless rejects, the encrypted requests cause - // a retranmission of the SREJ packets which are dropped by the client. // When client starts with an unsupported version, the version negotiation // packet sent by server for the old connection (respond for the connection // close packet) will be dropped by the client. - if (!BothSidesSupportStatelessRejects() && - !ServerSendsVersionNegotiation()) { + if (!ServerSendsVersionNegotiation()) { EXPECT_EQ(0u, client_stats.packets_dropped); } if (!ClientSupportsIetfQuicNotSupportedByServer()) { @@ -542,13 +456,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { EXPECT_EQ(client_stats.packets_received, client_stats.packets_processed); } - const int num_expected_stateless_rejects = - (BothSidesSupportStatelessRejects() && - client_->client()->client_session()->GetNumSentClientHellos() > 0) - ? 1 - : 0; - EXPECT_EQ(num_expected_stateless_rejects, - client_->client()->num_stateless_rejects_received()); + EXPECT_EQ(0, client_->client()->num_stateless_rejects_received()); server_thread_->Pause(); QuicConnectionStats server_stats = GetServerConnection()->GetStats(); @@ -562,15 +470,9 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { server_thread_->Resume(); } - bool BothSidesSupportStatelessRejects() { - return (GetParam().server_uses_stateless_rejects_if_peer_supported && - GetParam().client_supports_stateless_rejects); - } - // Client supports IETF QUIC, while it is not supported by server. bool ClientSupportsIetfQuicNotSupportedByServer() { - return GetParam().client_supported_versions[0].transport_version > - QUIC_VERSION_43 && + return client_supported_versions_[0].transport_version > QUIC_VERSION_43 && FilterSupportedVersions(GetParam().server_supported_versions)[0] .transport_version <= QUIC_VERSION_43; } @@ -579,8 +481,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { // closes connection when version negotiation is received. bool ServerSendsVersionNegotiation() { return GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation) && - GetParam().client_supported_versions[0] != - GetParam().negotiated_version; + client_supported_versions_[0] != GetParam().negotiated_version; } bool SupportsIetfQuicWithTls(ParsedQuicVersion version) { @@ -637,26 +538,20 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { bool support_server_push_; std::string pre_shared_key_client_; std::string pre_shared_key_server_; - QuicConnectionId* override_connection_id_; - uint8_t expected_connection_id_length_; + QuicConnectionId* override_server_connection_id_; + uint8_t expected_server_connection_id_length_; }; // Run all end to end tests with all supported versions. INSTANTIATE_TEST_SUITE_P(EndToEndTests, EndToEndTest, - ::testing::ValuesIn(GetTestParams(false, false))); + ::testing::ValuesIn(GetTestParams(false))); class EndToEndTestWithTls : public EndToEndTest {}; INSTANTIATE_TEST_SUITE_P(EndToEndTestsWithTls, EndToEndTestWithTls, - ::testing::ValuesIn(GetTestParams(true, false))); - -class EndToEndTestWithStatelessReject : public EndToEndTest {}; - -INSTANTIATE_TEST_SUITE_P(WithStatelessReject, - EndToEndTestWithStatelessReject, - ::testing::ValuesIn(GetTestParams(false, true))); + ::testing::ValuesIn(GetTestParams(true))); TEST_P(EndToEndTestWithTls, HandshakeSuccessful) { ASSERT_TRUE(Initialize()); @@ -680,7 +575,7 @@ TEST_P(EndToEndTestWithTls, HandshakeSuccessful) { EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); } -TEST_P(EndToEndTestWithStatelessReject, SimpleRequestResponseStatless) { +TEST_P(EndToEndTest, SimpleRequestResponse) { ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -688,35 +583,28 @@ TEST_P(EndToEndTestWithStatelessReject, SimpleRequestResponseStatless) { int expected_num_client_hellos = 2; if (ServerSendsVersionNegotiation()) { ++expected_num_client_hellos; - if (BothSidesSupportStatelessRejects()) { - ++expected_num_client_hellos; - } } EXPECT_EQ(expected_num_client_hellos, client_->client()->GetNumSentClientHellos()); } -TEST_P(EndToEndTest, SimpleRequestResponse) { +TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) { + client_supported_versions_.insert(client_supported_versions_.begin(), + QuicVersionReservedForNegotiation()); ASSERT_TRUE(Initialize()); + ASSERT_TRUE(ServerSendsVersionNegotiation()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); EXPECT_EQ("200", client_->response_headers()->find(":status")->second); - int expected_num_client_hellos = 2; - if (ServerSendsVersionNegotiation()) { - ++expected_num_client_hellos; - if (BothSidesSupportStatelessRejects()) { - ++expected_num_client_hellos; - } - } - EXPECT_EQ(expected_num_client_hellos, - client_->client()->GetNumSentClientHellos()); + + EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); } TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) { QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId( GetParam().negotiated_version.transport_version); - override_connection_id_ = &connection_id; - expected_connection_id_length_ = connection_id.length(); + override_server_connection_id_ = &connection_id; + expected_server_connection_id_length_ = connection_id.length(); ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -724,9 +612,6 @@ TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) { int expected_num_client_hellos = 2; if (ServerSendsVersionNegotiation()) { ++expected_num_client_hellos; - if (BothSidesSupportStatelessRejects()) { - ++expected_num_client_hellos; - } } EXPECT_EQ(expected_num_client_hellos, client_->client()->GetNumSentClientHellos()); @@ -743,8 +628,35 @@ TEST_P(EndToEndTest, BadConnectionIdLength) { } QuicConnectionId connection_id = TestConnectionIdNineBytesLong(UINT64_C(0xBADbadBADbad)); - override_connection_id_ = &connection_id; + override_server_connection_id_ = &connection_id; + ASSERT_TRUE(Initialize()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + EXPECT_EQ(kQuicDefaultConnectionIdLength, client_->client() + ->client_session() + ->connection() + ->connection_id() + .length()); +} + +TEST_P(EndToEndTest, ForcedVersionNegotiationAndBadConnectionIdLength) { + if (!GetQuicRestartFlag( + quic_allow_variable_length_connection_id_for_negotiation)) { + ASSERT_TRUE(Initialize()); + return; + } + if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( + GetParam().negotiated_version.transport_version)) { + ASSERT_TRUE(Initialize()); + return; + } + client_supported_versions_.insert(client_supported_versions_.begin(), + QuicVersionReservedForNegotiation()); + QuicConnectionId connection_id = + TestConnectionIdNineBytesLong(UINT64_C(0xBADbadBADbad)); + override_server_connection_id_ = &connection_id; ASSERT_TRUE(Initialize()); + ASSERT_TRUE(ServerSendsVersionNegotiation()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); EXPECT_EQ("200", client_->response_headers()->find(":status")->second); EXPECT_EQ(kQuicDefaultConnectionIdLength, client_->client() @@ -764,9 +676,9 @@ TEST_P(EndToEndTest, MixGoodAndBadConnectionIdLengths) { // Start client_ which will use a bad connection ID length. QuicConnectionId connection_id = TestConnectionIdNineBytesLong(UINT64_C(0xBADbadBADbad)); - override_connection_id_ = &connection_id; + override_server_connection_id_ = &connection_id; ASSERT_TRUE(Initialize()); - override_connection_id_ = nullptr; + override_server_connection_id_ = nullptr; // Start client2 which will use a good connection ID length. std::unique_ptr<QuicTestClient> client2(CreateQuicClient(nullptr)); @@ -819,6 +731,22 @@ TEST_P(EndToEndTestWithTls, SimpleRequestResponsev6) { EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } +TEST_P(EndToEndTestWithTls, NoUndecryptablePackets) { + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + QuicConnectionStats client_stats = + client_->client()->client_session()->connection()->GetStats(); + EXPECT_EQ(0u, client_stats.undecryptable_packets_received); + + server_thread_->Pause(); + QuicConnectionStats server_stats = GetServerConnection()->GetStats(); + EXPECT_EQ(0u, server_stats.undecryptable_packets_received); + server_thread_->Resume(); +} + TEST_P(EndToEndTestWithTls, SeparateFinPacket) { ASSERT_TRUE(Initialize()); @@ -855,8 +783,8 @@ TEST_P(EndToEndTestWithTls, MultipleRequestResponse) { TEST_P(EndToEndTest, MultipleRequestResponseZeroConnectionID) { QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId( GetParam().negotiated_version.transport_version); - override_connection_id_ = &connection_id; - expected_connection_id_length_ = connection_id.length(); + override_server_connection_id_ = &connection_id; + expected_server_connection_id_length_ = connection_id.length(); ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -1000,14 +928,10 @@ TEST_P(EndToEndTest, LargePostNoPacketLoss1sRTT) { } TEST_P(EndToEndTest, LargePostWithPacketLoss) { - if (!BothSidesSupportStatelessRejects()) { - // Connect with lower fake packet loss than we'd like to test. - // Until b/10126687 is fixed, losing handshake packets is pretty - // brutal. - // TODO(jokulik): Until we support redundant SREJ packets, don't - // drop handshake packets for stateless rejects. - SetPacketLossPercentage(5); - } + // Connect with lower fake packet loss than we'd like to test. + // Until b/10126687 is fixed, losing handshake packets is pretty + // brutal. + SetPacketLossPercentage(5); ASSERT_TRUE(Initialize()); // Wait for the server SHLO before upping the packet loss. @@ -1059,13 +983,9 @@ TEST_P(EndToEndTest, LargePostWithPacketLossAndAlwaysBundleWindowUpdates) { } TEST_P(EndToEndTest, LargePostWithPacketLossAndBlockedSocket) { - if (!BothSidesSupportStatelessRejects()) { - // Connect with lower fake packet loss than we'd like to test. Until - // b/10126687 is fixed, losing handshake packets is pretty brutal. - // TODO(jokulik): Until we support redundant SREJ packets, don't - // drop handshake packets for stateless rejects. - SetPacketLossPercentage(5); - } + // Connect with lower fake packet loss than we'd like to test. Until + // b/10126687 is fixed, losing handshake packets is pretty brutal. + SetPacketLossPercentage(5); ASSERT_TRUE(Initialize()); // Wait for the server SHLO before upping the packet loss. @@ -1119,17 +1039,9 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) { EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(headers, body)); - // In the non-stateless case, the same session is used for both - // hellos, so the number of hellos sent on that session is 2. In - // the stateless case, the first client session will be completely - // torn down after the reject. The number of hellos on the latest - // session is 1. - const int expected_num_hellos_latest_session = - (BothSidesSupportStatelessRejects() && !ServerSendsVersionNegotiation()) - ? 1 - : 2; - EXPECT_EQ(expected_num_hellos_latest_session, - client_->client()->client_session()->GetNumSentClientHellos()); + // The same session is used for both hellos, so the number of hellos sent on + // that session is 2. + EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos()); if (ServerSendsVersionNegotiation()) { EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); } else { @@ -1164,13 +1076,9 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) { ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(headers, body)); - // In the non-stateless case, the same session is used for both - // hellos, so the number of hellos sent on that session is 2. In - // the stateless case, the first client session will be completely - // torn down after the reject. The number of hellos sent on the - // latest session is 1. - EXPECT_EQ(expected_num_hellos_latest_session, - client_->client()->client_session()->GetNumSentClientHellos()); + // The same session is used for both hellos, so the number of hellos sent on + // that session is 2. + EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos()); if (ServerSendsVersionNegotiation()) { EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); } else { @@ -1186,17 +1094,9 @@ TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) { ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); - // In the non-stateless case, the same session is used for both - // hellos, so the number of hellos sent on that session is 2. In - // the stateless case, the first client session will be completely - // torn down after the reject. The number of hellos on that second - // latest session is 1. - const int expected_num_hellos_latest_session = - (BothSidesSupportStatelessRejects() && !ServerSendsVersionNegotiation()) - ? 1 - : 2; - EXPECT_EQ(expected_num_hellos_latest_session, - client_->client()->client_session()->GetNumSentClientHellos()); + // The same session is used for both hellos, so the number of hellos sent on + // that session is 2. + EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos()); if (ServerSendsVersionNegotiation()) { EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); } else { @@ -1229,13 +1129,8 @@ TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) { EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); - // In the non-stateless case, the same session is used for both - // hellos, so the number of hellos sent on that session is 2. In - // the stateless case, the first client session will be completely - // torn down after the reject. The number of hellos sent on the - // latest session is 1. - EXPECT_EQ(expected_num_hellos_latest_session, - client_->client()->client_session()->GetNumSentClientHellos()); + + EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos()); if (ServerSendsVersionNegotiation()) { EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); } else { @@ -1259,17 +1154,9 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) { EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(headers, body)); - // In the non-stateless case, the same session is used for both - // hellos, so the number of hellos sent on that session is 2. In - // the stateless case, the first client session will be completely - // torn down after the reject. The number of hellos on the latest - // session is 1. - const int expected_num_hellos_latest_session = - (BothSidesSupportStatelessRejects() && !ServerSendsVersionNegotiation()) - ? 1 - : 2; - EXPECT_EQ(expected_num_hellos_latest_session, - client_->client()->client_session()->GetNumSentClientHellos()); + // The same session is used for both hellos, so the number of hellos sent on + // that session is 2. + EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos()); if (ServerSendsVersionNegotiation()) { EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); } else { @@ -1304,13 +1191,8 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) { ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(headers, body)); - // In the non-stateless case, the same session is used for both - // hellos, so the number of hellos sent on that session is 2. In - // the stateless case, the first client session will be completely - // torn down after the reject. The number of hellos sent on the - // latest session is 1. - EXPECT_EQ(expected_num_hellos_latest_session, - client_->client()->client_session()->GetNumSentClientHellos()); + + EXPECT_EQ(2, client_->client()->client_session()->GetNumSentClientHellos()); if (ServerSendsVersionNegotiation()) { EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); } else { @@ -1320,9 +1202,9 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) { VerifyCleanConnection(false); } -TEST_P(EndToEndTest, StatelessRejectWithPacketLoss) { +TEST_P(EndToEndTest, RejectWithPacketLoss) { // In this test, we intentionally drop the first packet from the - // server, which corresponds with the initial REJ/SREJ response from + // server, which corresponds with the initial REJ response from // the server. server_writer_->set_fake_drop_first_n_packets(1); ASSERT_TRUE(Initialize()); @@ -1461,8 +1343,17 @@ TEST_P(EndToEndTest, LargeHeaders) { headers["key3"] = std::string(15 * 1024, 'a'); client_->SendCustomSynchronousRequest(headers, body); - EXPECT_EQ(QUIC_HEADERS_TOO_LARGE, client_->stream_error()); - EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + + if (VersionUsesQpack(client_->client() + ->client_session() + ->connection() + ->transport_version())) { + EXPECT_EQ(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, + client_->connection_error()); + } else { + EXPECT_EQ(QUIC_HEADERS_TOO_LARGE, client_->stream_error()); + EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + } } TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) { @@ -1524,12 +1415,18 @@ TEST_P(EndToEndTestWithTls, MaxIncomingDynamicStreamsLimitRespected) { // Set a limit on maximum number of incoming dynamic streams. // Make sure the limit is respected. const uint32_t kServerMaxIncomingDynamicStreams = 1; - server_config_.SetMaxIncomingDynamicStreamsToSend( + server_config_.SetMaxIncomingBidirectionalStreamsToSend( kServerMaxIncomingDynamicStreams); ASSERT_TRUE(Initialize()); + if (GetParam().negotiated_version.transport_version == QUIC_VERSION_99) { + // Do not run this test for version 99/IETF QUIC. Note that the test needs + // to be here, after calling Initialize(), because all tests end up calling + // EndToEndTest::TearDown(), which asserts that Initialize has been called + // and then proceeds to tear things down -- which fails if they are not + // properly set up. + return; + } EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); - QuicConnection* client_connection = - client_->client()->client_session()->connection(); // Make the client misbehave after negotiation. const int kServerMaxStreams = kMaxStreamsMinimumIncrement + 1; @@ -1549,35 +1446,43 @@ TEST_P(EndToEndTestWithTls, MaxIncomingDynamicStreamsLimitRespected) { client_->SendMessage(headers, "", /*fin=*/false); } client_->WaitForResponse(); - if (client_connection->transport_version() != QUIC_VERSION_99) { - EXPECT_TRUE(client_->connected()); - EXPECT_EQ(QUIC_REFUSED_STREAM, client_->stream_error()); - EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); - } else { - // Version 99 disconnects the connection if we exceed the stream limit. - EXPECT_FALSE(client_->connected()); - EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error()); - EXPECT_EQ(QUIC_INVALID_STREAM_ID, client_->connection_error()); - } + + EXPECT_TRUE(client_->connected()); + EXPECT_EQ(QUIC_REFUSED_STREAM, client_->stream_error()); + EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); } TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) { // Each endpoint can set max incoming dynamic streams independently. const uint32_t kClientMaxIncomingDynamicStreams = 2; const uint32_t kServerMaxIncomingDynamicStreams = 1; - client_config_.SetMaxIncomingDynamicStreamsToSend( + client_config_.SetMaxIncomingBidirectionalStreamsToSend( + kClientMaxIncomingDynamicStreams); + server_config_.SetMaxIncomingBidirectionalStreamsToSend( + kServerMaxIncomingDynamicStreams); + client_config_.SetMaxIncomingUnidirectionalStreamsToSend( kClientMaxIncomingDynamicStreams); - server_config_.SetMaxIncomingDynamicStreamsToSend( + server_config_.SetMaxIncomingUnidirectionalStreamsToSend( kServerMaxIncomingDynamicStreams); + ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); // The client has received the server's limit and vice versa. QuicSpdyClientSession* client_session = client_->client()->client_session(); + // The value returned by max_allowed... includes the Crypto and Header + // stream (created as a part of initialization). The config. values, + // above, are treated as "number of requests/responses" - that is, they do + // not include the static Crypto and Header streams. Reduce the value + // returned by max_allowed... by 2 to remove the static streams from the + // count. size_t client_max_open_outgoing_bidirectional_streams = client_session->connection()->transport_version() == QUIC_VERSION_99 ? QuicSessionPeer::v99_streamid_manager(client_session) - ->max_allowed_outgoing_bidirectional_streams() + ->max_allowed_outgoing_bidirectional_streams() - + QuicSessionPeer::v99_bidirectional_stream_id_manager( + client_session) + ->outgoing_static_stream_count() : QuicSessionPeer::GetStreamIdManager(client_session) ->max_open_outgoing_streams(); size_t client_max_open_outgoing_unidirectional_streams = @@ -1757,6 +1662,11 @@ TEST_P(EndToEndTest, MinInitialRTT) { } TEST_P(EndToEndTest, 0ByteConnectionId) { + if (GetParam().negotiated_version.transport_version > QUIC_VERSION_43) { + // SetBytesForConnectionIdToSend only applies to Google QUIC encoding. + ASSERT_TRUE(Initialize()); + return; + } client_config_.SetBytesForConnectionIdToSend(0); ASSERT_TRUE(Initialize()); @@ -1766,10 +1676,19 @@ TEST_P(EndToEndTest, 0ByteConnectionId) { client_->client()->client_session()->connection(); QuicPacketHeader* header = QuicConnectionPeer::GetLastHeader(client_connection); - EXPECT_EQ(CONNECTION_ID_ABSENT, header->destination_connection_id_included); + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + EXPECT_EQ(CONNECTION_ID_ABSENT, header->destination_connection_id_included); + } else { + EXPECT_EQ(CONNECTION_ID_ABSENT, header->source_connection_id_included); + } } TEST_P(EndToEndTestWithTls, 8ByteConnectionId) { + if (GetParam().negotiated_version.transport_version > QUIC_VERSION_43) { + // SetBytesForConnectionIdToSend only applies to Google QUIC encoding. + ASSERT_TRUE(Initialize()); + return; + } client_config_.SetBytesForConnectionIdToSend(8); ASSERT_TRUE(Initialize()); @@ -1779,15 +1698,15 @@ TEST_P(EndToEndTestWithTls, 8ByteConnectionId) { client_->client()->client_session()->connection(); QuicPacketHeader* header = QuicConnectionPeer::GetLastHeader(client_connection); - if (client_connection->transport_version() > QUIC_VERSION_43) { - EXPECT_EQ(CONNECTION_ID_ABSENT, header->destination_connection_id_included); - } else { - EXPECT_EQ(CONNECTION_ID_PRESENT, - header->destination_connection_id_included); - } + EXPECT_EQ(CONNECTION_ID_PRESENT, header->destination_connection_id_included); } TEST_P(EndToEndTestWithTls, 15ByteConnectionId) { + if (GetParam().negotiated_version.transport_version > QUIC_VERSION_43) { + // SetBytesForConnectionIdToSend only applies to Google QUIC encoding. + ASSERT_TRUE(Initialize()); + return; + } client_config_.SetBytesForConnectionIdToSend(15); ASSERT_TRUE(Initialize()); @@ -1798,12 +1717,7 @@ TEST_P(EndToEndTestWithTls, 15ByteConnectionId) { client_->client()->client_session()->connection(); QuicPacketHeader* header = QuicConnectionPeer::GetLastHeader(client_connection); - if (client_connection->transport_version() > QUIC_VERSION_43) { - EXPECT_EQ(CONNECTION_ID_ABSENT, header->destination_connection_id_included); - } else { - EXPECT_EQ(CONNECTION_ID_PRESENT, - header->destination_connection_id_included); - } + EXPECT_EQ(CONNECTION_ID_PRESENT, header->destination_connection_id_included); } TEST_P(EndToEndTestWithTls, ResetConnection) { @@ -1820,13 +1734,9 @@ TEST_P(EndToEndTestWithTls, ResetConnection) { // TODO(nharper): Needs to get turned back to EndToEndTestWithTls // when we figure out why the test doesn't work on chrome. TEST_P(EndToEndTest, MaxStreamsUberTest) { - if (!BothSidesSupportStatelessRejects()) { - // Connect with lower fake packet loss than we'd like to test. Until - // b/10126687 is fixed, losing handshake packets is pretty brutal. - // TODO(jokulik): Until we support redundant SREJ packets, don't - // drop handshake packets for stateless rejects. - SetPacketLossPercentage(1); - } + // Connect with lower fake packet loss than we'd like to test. Until + // b/10126687 is fixed, losing handshake packets is pretty brutal. + SetPacketLossPercentage(1); ASSERT_TRUE(Initialize()); std::string large_body(10240, 'a'); int max_streams = 100; @@ -2086,10 +1996,9 @@ TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) { client_->client()->client_session()); // In v47 and later, the crypto handshake (sent in CRYPTO frames) is not // subject to flow control. - if (!QuicVersionUsesCryptoFrames(client_->client() - ->client_session() - ->connection() - ->transport_version())) { + const QuicTransportVersion transport_version = + client_->client()->client_session()->connection()->transport_version(); + if (!QuicVersionUsesCryptoFrames(transport_version)) { EXPECT_LT(QuicFlowControllerPeer::SendWindowSize( crypto_stream->flow_controller()), kStreamIFCW); @@ -2102,6 +2011,11 @@ TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) { // has not been affected. EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + // No headers stream in IETF QUIC. + if (VersionUsesQpack(transport_version)) { + return; + } + QuicHeadersStream* headers_stream = QuicSpdySessionPeer::GetHeadersStream( client_->client()->client_session()); EXPECT_LT( @@ -2135,11 +2049,16 @@ TEST_P(EndToEndTest, FlowControlsSynced) { auto* server_session = static_cast<QuicSpdySession*>(GetServerSession()); ExpectFlowControlsSynced(client_session->flow_controller(), server_session->flow_controller()); - ExpectFlowControlsSynced( - QuicSessionPeer::GetMutableCryptoStream(client_session) - ->flow_controller(), - QuicSessionPeer::GetMutableCryptoStream(server_session) - ->flow_controller()); + if (!QuicVersionUsesCryptoFrames(client_->client() + ->client_session() + ->connection() + ->transport_version())) { + ExpectFlowControlsSynced( + QuicSessionPeer::GetMutableCryptoStream(client_session) + ->flow_controller(), + QuicSessionPeer::GetMutableCryptoStream(server_session) + ->flow_controller()); + } SpdyFramer spdy_framer(SpdyFramer::ENABLE_COMPRESSION); SpdySettingsIR settings_frame; settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, @@ -2243,11 +2162,8 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) { // socket, an AckNotifierDelegate will get informed that the data it is // interested in has been ACKed. This tests end-to-end ACK notification, and // demonstrates that retransmissions do not break this functionality. - if (!BothSidesSupportStatelessRejects()) { - // TODO(jokulik): Until we support redundant SREJ packets, don't - // drop handshake packets for stateless rejects. - SetPacketLossPercentage(5); - } + + SetPacketLossPercentage(5); ASSERT_TRUE(Initialize()); // Wait for the server SHLO before upping the packet loss. @@ -2264,6 +2180,29 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) { client_->SendMessage(headers, "", /*fin=*/false); + // Size of headers on the request stream. Zero if headers are sent on the + // header stream. + size_t header_size = 0; + if (VersionUsesQpack(client_->client() + ->client_session() + ->connection() + ->transport_version())) { + // Determine size of compressed headers. + NoopDecoderStreamErrorDelegate decoder_stream_error_delegate; + NoopEncoderStreamSenderDelegate encoder_stream_sender_delegate; + QpackEncoder qpack_encoder(&decoder_stream_error_delegate, + &encoder_stream_sender_delegate); + auto progressive_encoder = + qpack_encoder.EncodeHeaderList(/* stream_id = */ 0, &headers); + std::string encoded_headers; + while (progressive_encoder->HasNext()) { + progressive_encoder->Next( + /* max_encoded_bytes = */ std::numeric_limits<size_t>::max(), + &encoded_headers); + } + header_size = encoded_headers.size(); + } + // Test the AckNotifier's ability to track multiple packets by making the // request body exceed the size of a single packet. std::string request_string = "a request body bigger than one packet" + @@ -2271,7 +2210,7 @@ TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) { // The TestAckListener will cause a failure if not notified. QuicReferenceCountedPointer<TestAckListener> ack_listener( - new TestAckListener(request_string.length())); + new TestAckListener(header_size + request_string.length())); // Send the request, and register the delegate for ACKs. client_->SendData(request_string, true, ack_listener); @@ -2437,7 +2376,7 @@ TEST_P(EndToEndTestWithTls, TestConnectionIdToUInt64(client_connection->connection_id()) + 1); std::unique_ptr<QuicEncryptedPacket> packet( QuicFramer::BuildVersionNegotiationPacket( - incorrect_connection_id, + incorrect_connection_id, EmptyQuicConnectionId(), client_connection->transport_version() > QUIC_VERSION_43, server_supported_versions_)); testing::NiceMock<MockQuicConnectionDebugVisitor> visitor; @@ -2863,8 +2802,10 @@ class EndToEndTestServerPush : public EndToEndTest { const size_t kNumMaxStreams = 10; EndToEndTestServerPush() : EndToEndTest() { - client_config_.SetMaxIncomingDynamicStreamsToSend(kNumMaxStreams); - server_config_.SetMaxIncomingDynamicStreamsToSend(kNumMaxStreams); + client_config_.SetMaxIncomingBidirectionalStreamsToSend(kNumMaxStreams); + server_config_.SetMaxIncomingBidirectionalStreamsToSend(kNumMaxStreams); + client_config_.SetMaxIncomingUnidirectionalStreamsToSend(kNumMaxStreams); + server_config_.SetMaxIncomingUnidirectionalStreamsToSend(kNumMaxStreams); support_server_push_ = true; } @@ -2911,7 +2852,7 @@ class EndToEndTestServerPush : public EndToEndTest { // Run all server push end to end tests with all supported versions. INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush, EndToEndTestServerPush, - ::testing::ValuesIn(GetTestParams(false, false))); + ::testing::ValuesIn(GetTestParams(false))); TEST_P(EndToEndTestServerPush, ServerPush) { ASSERT_TRUE(Initialize()); @@ -3206,10 +3147,7 @@ TEST_P(EndToEndTest, DISABLED_TestHugeResponseWithPacketLoss) { SetPacketLossPercentage(1); client_->SendRequest("/huge_response"); client_->WaitForResponse(); - // TODO(fayang): Fix this test to work with stateless rejects. - if (!BothSidesSupportStatelessRejects()) { - VerifyCleanConnection(true); - } + VerifyCleanConnection(true); } // Regression test for b/111515567 @@ -3348,7 +3286,8 @@ TEST_P(EndToEndTest, EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); if (client_->client()->client_session()->connection()->transport_version() > - QUIC_VERSION_43) { + QUIC_VERSION_43 || + GetQuicReloadableFlag(quic_terminate_gquic_connection_as_ietf)) { EXPECT_EQ(QUIC_HANDSHAKE_FAILED, client_->connection_error()); } else { EXPECT_EQ(QUIC_PUBLIC_RESET, client_->connection_error()); @@ -3629,7 +3568,7 @@ class EndToEndPacketReorderingTest : public EndToEndTest { INSTANTIATE_TEST_SUITE_P(EndToEndPacketReorderingTests, EndToEndPacketReorderingTest, - testing::ValuesIn(GetTestParams(false, false))); + testing::ValuesIn(GetTestParams(false))); TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) { ASSERT_TRUE(Initialize()); @@ -3883,7 +3822,6 @@ class BadShloPacketWriter2 : public QuicPacketWriterWrapper { TEST_P(EndToEndTest, ForwardSecureConnectionClose) { // This test ensures ZERO_RTT_PROTECTED connection close is sent to a client // which has ZERO_RTT_PROTECTED encryption level. - SetQuicReloadableFlag(quic_fix_termination_packets, true); connect_to_server_on_initialize_ = negotiated_version_.transport_version <= QUIC_VERSION_43; ASSERT_TRUE(Initialize()); @@ -3910,6 +3848,37 @@ TEST_P(EndToEndTest, ForwardSecureConnectionClose) { EXPECT_EQ(QUIC_PACKET_WRITE_ERROR, client_->connection_error()); } +// Test that the stream id manager closes the connection if a stream +// in excess of the allowed maximum. +TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) { + // Has to be before version test, see EndToEndTest::TearDown() + ASSERT_TRUE(Initialize()); + if (negotiated_version_.transport_version != QUIC_VERSION_99) { + // Only runs for IETF QUIC. + return; + } + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + std::string body(kMaxOutgoingPacketSize, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + // Force the client to write with a stream ID that exceeds the limit. + QuicSpdySession* session = client_->client()->client_session(); + QuicStreamIdManager* stream_id_manager = + QuicSessionPeer::v99_bidirectional_stream_id_manager(session); + QuicStreamCount max_number_of_streams = + stream_id_manager->outgoing_max_streams(); + QuicSessionPeer::SetNextOutgoingBidirectionalStreamId( + session, GetNthClientInitiatedBidirectionalId(max_number_of_streams + 1)); + client_->SendCustomSynchronousRequest(headers, body); + EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error()); + EXPECT_EQ(QUIC_INVALID_STREAM_ID, client_->connection_error()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc index ec0062a0dd0..c59e8b0699b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.cc @@ -24,8 +24,6 @@ uint8_t ExtractBits(uint8_t flags, uint8_t num_bits, uint8_t offset) { return (flags >> offset) & GetMaskFromNumBits(num_bits); } -// Length of the type field of HTTP/3 frames. -static const QuicByteCount kFrameTypeLength = 1; // Length of the weight field of a priority frame. static const size_t kPriorityWeightLength = 1; // Length of a priority frame's first byte. @@ -35,12 +33,14 @@ static const size_t kPriorityFirstByteLength = 1; HttpDecoder::HttpDecoder() : visitor_(nullptr), - state_(STATE_READING_FRAME_LENGTH), + state_(STATE_READING_FRAME_TYPE), current_frame_type_(0), - current_length_field_size_(0), + current_length_field_length_(0), remaining_length_field_length_(0), current_frame_length_(0), remaining_frame_length_(0), + current_type_field_length_(0), + remaining_type_field_length_(0), error_(QUIC_NO_ERROR), error_detail_("") {} @@ -51,12 +51,12 @@ QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) { while (error_ == QUIC_NO_ERROR && (reader.BytesRemaining() != 0 || state_ == STATE_FINISH_PARSING)) { switch (state_) { - case STATE_READING_FRAME_LENGTH: - ReadFrameLength(&reader); - break; case STATE_READING_FRAME_TYPE: ReadFrameType(&reader); break; + case STATE_READING_FRAME_LENGTH: + ReadFrameLength(&reader); + break; case STATE_READING_FRAME_PAYLOAD: ReadFramePayload(&reader); break; @@ -77,29 +77,83 @@ QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) { return len - reader.BytesRemaining(); } -void HttpDecoder::ReadFrameLength(QuicDataReader* reader) { +void HttpDecoder::ReadFrameType(QuicDataReader* reader) { DCHECK_NE(0u, reader->BytesRemaining()); - BufferFrameLength(reader); - if (remaining_length_field_length_ != 0) { - return; - } - QuicDataReader length_reader(length_buffer_.data(), - current_length_field_size_); - if (!length_reader.ReadVarInt62(¤t_frame_length_)) { - RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length"); - visitor_->OnError(this); - return; + if (current_type_field_length_ == 0) { + // A new frame is coming. + current_type_field_length_ = reader->PeekVarInt62Length(); + if (current_type_field_length_ == 0) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame type length"); + visitor_->OnError(this); + return; + } + if (current_type_field_length_ <= reader->BytesRemaining()) { + // The reader has all type data needed, so no need to buffer. + if (!reader->ReadVarInt62(¤t_frame_type_)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame type"); + return; + } + } else { + // Buffer a new type field. + remaining_type_field_length_ = current_type_field_length_; + BufferFrameType(reader); + return; + } + } else { + // Buffer the existing type field. + BufferFrameType(reader); + // The frame is still not buffered completely. + if (remaining_type_field_length_ != 0) { + return; + } + QuicDataReader type_reader(type_buffer_.data(), current_type_field_length_); + if (!type_reader.ReadVarInt62(¤t_frame_type_)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read buffered frame type"); + visitor_->OnError(this); + return; + } } - state_ = STATE_READING_FRAME_TYPE; - remaining_frame_length_ = current_frame_length_; + state_ = STATE_READING_FRAME_LENGTH; } -void HttpDecoder::ReadFrameType(QuicDataReader* reader) { +void HttpDecoder::ReadFrameLength(QuicDataReader* reader) { DCHECK_NE(0u, reader->BytesRemaining()); - if (!reader->ReadUInt8(¤t_frame_type_)) { - RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame type"); - return; + if (current_length_field_length_ == 0) { + // A new frame is coming. + current_length_field_length_ = reader->PeekVarInt62Length(); + if (current_length_field_length_ == 0) { + RaiseError(QUIC_INTERNAL_ERROR, + "Unable to read the length of frame length"); + visitor_->OnError(this); + return; + } + if (current_length_field_length_ <= reader->BytesRemaining()) { + // The reader has all length data needed, so no need to buffer. + if (!reader->ReadVarInt62(¤t_frame_length_)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length"); + return; + } + } else { + // Buffer a new length field. + remaining_length_field_length_ = current_length_field_length_; + BufferFrameLength(reader); + return; + } + } else { + // Buffer the existing length field. + BufferFrameLength(reader); + // The frame is still not buffered completely. + if (remaining_length_field_length_ != 0) { + return; + } + QuicDataReader length_reader(length_buffer_.data(), + current_length_field_length_); + if (!length_reader.ReadVarInt62(¤t_frame_length_)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read buffered frame length"); + visitor_->OnError(this); + return; + } } if (current_frame_length_ > MaxFrameLength(current_frame_type_)) { @@ -112,15 +166,19 @@ void HttpDecoder::ReadFrameType(QuicDataReader* reader) { // frame payload. if (current_frame_type_ == 0x0) { visitor_->OnDataFrameStart(Http3FrameLengths( - current_length_field_size_ + kFrameTypeLength, current_frame_length_)); + current_length_field_length_ + current_type_field_length_, + current_frame_length_)); } else if (current_frame_type_ == 0x1) { visitor_->OnHeadersFrameStart(Http3FrameLengths( - current_length_field_size_ + kFrameTypeLength, current_frame_length_)); + current_length_field_length_ + current_type_field_length_, + current_frame_length_)); } else if (current_frame_type_ == 0x4) { visitor_->OnSettingsFrameStart(Http3FrameLengths( - current_length_field_size_ + kFrameTypeLength, current_frame_length_)); + current_length_field_length_ + current_type_field_length_, + current_frame_length_)); } + remaining_frame_length_ = current_frame_length_; state_ = (remaining_frame_length_ == 0) ? STATE_FINISH_PARSING : STATE_READING_FRAME_PAYLOAD; } @@ -233,6 +291,7 @@ void HttpDecoder::ReadFramePayload(QuicDataReader* reader) { QUIC_FALLTHROUGH_INTENDED; default: DiscardFramePayload(reader); + return; } if (remaining_frame_length_ == 0) { @@ -274,10 +333,6 @@ void HttpDecoder::FinishParsing() { break; } case 0x4: { // SETTINGS - // TODO(rch): Handle overly large SETTINGS frames. Either: - // 1. Impose a limit on SETTINGS frame size, and close the connection if - // exceeded - // 2. Implement a streaming parsing mode. SettingsFrame frame; QuicDataReader reader(buffer_.data(), current_frame_length_); if (!ParseSettingsFrame(&reader, &frame)) { @@ -330,8 +385,9 @@ void HttpDecoder::FinishParsing() { } } - current_length_field_size_ = 0; - state_ = STATE_READING_FRAME_LENGTH; + current_length_field_length_ = 0; + current_type_field_length_ = 0; + state_ = STATE_READING_FRAME_TYPE; } void HttpDecoder::DiscardFramePayload(QuicDataReader* reader) { @@ -344,8 +400,9 @@ void HttpDecoder::DiscardFramePayload(QuicDataReader* reader) { } remaining_frame_length_ -= payload.length(); if (remaining_frame_length_ == 0) { - state_ = STATE_READING_FRAME_LENGTH; - current_length_field_size_ = 0; + state_ = STATE_READING_FRAME_TYPE; + current_length_field_length_ = 0; + current_type_field_length_ = 0; } } @@ -366,31 +423,37 @@ void HttpDecoder::BufferFramePayload(QuicDataReader* reader) { } void HttpDecoder::BufferFrameLength(QuicDataReader* reader) { - if (current_length_field_size_ == 0) { - current_length_field_size_ = reader->PeekVarInt62Length(); - if (current_length_field_size_ == 0) { - RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length"); - visitor_->OnError(this); - return; - } - remaining_length_field_length_ = current_length_field_size_; - } - if (current_length_field_size_ == remaining_length_field_length_) { - length_buffer_.erase(length_buffer_.size()); - length_buffer_.reserve(current_length_field_size_); + if (current_length_field_length_ == remaining_length_field_length_) { + length_buffer_.fill(0); } QuicByteCount bytes_to_read = std::min<QuicByteCount>( remaining_length_field_length_, reader->BytesRemaining()); - if (!reader->ReadBytes(&(length_buffer_[0]) + current_length_field_size_ - + if (!reader->ReadBytes(length_buffer_.data() + current_length_field_length_ - remaining_length_field_length_, bytes_to_read)) { - RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length"); + RaiseError(QUIC_INTERNAL_ERROR, "Unable to buffer frame length bytes."); visitor_->OnError(this); return; } remaining_length_field_length_ -= bytes_to_read; } +void HttpDecoder::BufferFrameType(QuicDataReader* reader) { + if (current_type_field_length_ == remaining_type_field_length_) { + type_buffer_.fill(0); + } + QuicByteCount bytes_to_read = std::min<QuicByteCount>( + remaining_type_field_length_, reader->BytesRemaining()); + if (!reader->ReadBytes(type_buffer_.data() + current_type_field_length_ - + remaining_type_field_length_, + bytes_to_read)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to buffer frame type bytes."); + visitor_->OnError(this); + return; + } + remaining_type_field_length_ -= bytes_to_read; +} + void HttpDecoder::RaiseError(QuicErrorCode error, std::string error_detail) { state_ = STATE_ERROR; error_ = error; @@ -428,8 +491,8 @@ bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader, bool HttpDecoder::ParseSettingsFrame(QuicDataReader* reader, SettingsFrame* frame) { while (!reader->IsDoneReading()) { - uint16_t id; - if (!reader->ReadUInt16(&id)) { + uint64_t id; + if (!reader->ReadVarInt62(&id)) { RaiseError(QUIC_INTERNAL_ERROR, "Unable to read settings frame identifier"); return false; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h index 55de8adf3ac..a392962149e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder.h @@ -117,6 +117,7 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { QuicErrorCode error() const { return error_; } const std::string& error_detail() const { return error_detail_; } + uint64_t current_frame_type() const { return current_frame_type_; } private: // Represents the current state of the parsing state machine. @@ -128,15 +129,15 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { STATE_ERROR }; - // Reads the length of a frame from |reader|. Sets error_ and error_detail_ - // if there are any errors. - void ReadFrameLength(QuicDataReader* reader); - // Reads the type of a frame from |reader|. Sets error_ and error_detail_ // if there are any errors. Also calls OnDataFrameStart() or // OnHeadersFrameStart() for appropriate frame types. void ReadFrameType(QuicDataReader* reader); + // Reads the length of a frame from |reader|. Sets error_ and error_detail_ + // if there are any errors. + void ReadFrameLength(QuicDataReader* reader); + // Reads the payload of the current frame from |reader| and processes it, // possibly buffering the data or invoking the visitor. void ReadFramePayload(QuicDataReader* reader); @@ -152,9 +153,12 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { void BufferFramePayload(QuicDataReader* reader); // Buffers any remaining frame length field from |reader| into - // |length_buffer_| + // |length_buffer_|. void BufferFrameLength(QuicDataReader* reader); + // Buffers any remaining frame type field from |reader| into |type_buffer_|. + void BufferFrameType(QuicDataReader* reader); + // Sets |error_| and |error_detail_| accordingly. void RaiseError(QuicErrorCode error, std::string error_detail); @@ -172,15 +176,19 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { // Current state of the parsing. HttpDecoderState state_; // Type of the frame currently being parsed. - uint8_t current_frame_type_; + uint64_t current_frame_type_; // Size of the frame's length field. - QuicByteCount current_length_field_size_; + QuicByteCount current_length_field_length_; // Remaining length that's needed for the frame's length field. QuicByteCount remaining_length_field_length_; // Length of the payload of the frame currently being parsed. QuicByteCount current_frame_length_; // Remaining payload bytes to be parsed. QuicByteCount remaining_frame_length_; + // Length of the frame's type field. + QuicByteCount current_type_field_length_; + // Remaining length that's needed for the frame's type field. + QuicByteCount remaining_type_field_length_; // Last error. QuicErrorCode error_; // The issue which caused |error_| @@ -188,7 +196,9 @@ class QUIC_EXPORT_PRIVATE HttpDecoder { // Remaining unparsed data. std::string buffer_; // Remaining unparsed length field data. - std::string length_buffer_; + std::array<char, sizeof(uint64_t)> length_buffer_; + // Remaining unparsed type field data. + std::array<char, sizeof(uint64_t)> type_buffer_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc index 7f0dcd44048..a4903b5db18 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_decoder_test.cc @@ -7,6 +7,7 @@ #include "net/third_party/quiche/src/quic/core/http/http_encoder.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" using testing::InSequence; @@ -54,58 +55,106 @@ TEST_F(HttpDecoderTest, InitialState) { } TEST_F(HttpDecoderTest, ReservedFramesNoPayload) { + std::unique_ptr<char[]> input; for (int n = 0; n < 8; ++n) { const uint8_t type = 0xB + 0x1F * n; - char input[] = {// length - 0x00, - // type - type}; - - EXPECT_EQ(2u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))) << n; + QuicByteCount total_length = QuicDataWriter::GetVarInt62Len(0x00) + + QuicDataWriter::GetVarInt62Len(type); + input = QuicMakeUnique<char[]>(total_length); + QuicDataWriter writer(total_length, input.get()); + writer.WriteVarInt62(type); + writer.WriteVarInt62(0x00); + + EXPECT_EQ(total_length, decoder_.ProcessInput(input.get(), total_length)) + << n; EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); ASSERT_EQ("", decoder_.error_detail()); + EXPECT_EQ(type, decoder_.current_frame_type()); } + // Test on a arbitrary reserved frame with 2-byte type field by hard coding + // variable length integer. + char in[] = {// type 0xB + 0x1F*3 + 0x40, 0x68, + // length + 0x00}; + EXPECT_EQ(3u, decoder_.ProcessInput(in, QUIC_ARRAYSIZE(in))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + ASSERT_EQ("", decoder_.error_detail()); + EXPECT_EQ(0xB + 0x1F * 3u, decoder_.current_frame_type()); } TEST_F(HttpDecoderTest, ReservedFramesSmallPayload) { + std::unique_ptr<char[]> input; + const uint8_t payload_size = 50; + std::string data(payload_size, 'a'); for (int n = 0; n < 8; ++n) { const uint8_t type = 0xB + 0x1F * n; - const uint8_t payload_size = 50; - char input[payload_size + 2] = {// length - payload_size, - // type - type}; - - EXPECT_EQ(QUIC_ARRAYSIZE(input), - decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))) + QuicByteCount total_length = QuicDataWriter::GetVarInt62Len(payload_size) + + QuicDataWriter::GetVarInt62Len(type) + + payload_size; + input = QuicMakeUnique<char[]>(total_length); + QuicDataWriter writer(total_length, input.get()); + writer.WriteVarInt62(type); + writer.WriteVarInt62(payload_size); + writer.WriteStringPiece(data); + EXPECT_EQ(total_length, decoder_.ProcessInput(input.get(), total_length)) << n; EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); ASSERT_EQ("", decoder_.error_detail()); + EXPECT_EQ(type, decoder_.current_frame_type()); } + + // Test on a arbitrary reserved frame with 2-byte type field by hard coding + // variable length integer. + char in[payload_size + 3] = {// type 0xB + 0x1F*3 + 0x40, 0x68, + // length + payload_size}; + EXPECT_EQ(QUIC_ARRAYSIZE(in), decoder_.ProcessInput(in, QUIC_ARRAYSIZE(in))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + ASSERT_EQ("", decoder_.error_detail()); + EXPECT_EQ(0xB + 0x1F * 3u, decoder_.current_frame_type()); } TEST_F(HttpDecoderTest, ReservedFramesLargePayload) { + std::unique_ptr<char[]> input; + const QuicByteCount payload_size = 256; + std::string data(payload_size, 'a'); for (int n = 0; n < 8; ++n) { const uint8_t type = 0xB + 0x1F * n; - const QuicByteCount payload_size = 256; - char input[payload_size + 3] = {// length - 0x40 + 0x01, 0x00, - // type - type}; - - EXPECT_EQ(QUIC_ARRAYSIZE(input), - decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))) + QuicByteCount total_length = QuicDataWriter::GetVarInt62Len(payload_size) + + QuicDataWriter::GetVarInt62Len(type) + + payload_size; + input = QuicMakeUnique<char[]>(total_length); + QuicDataWriter writer(total_length, input.get()); + writer.WriteVarInt62(type); + writer.WriteVarInt62(payload_size); + writer.WriteStringPiece(data); + + EXPECT_EQ(total_length, decoder_.ProcessInput(input.get(), total_length)) << n; EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); ASSERT_EQ("", decoder_.error_detail()); + EXPECT_EQ(type, decoder_.current_frame_type()); } + + // Test on a arbitrary reserved frame with 2-byte type field by hard coding + // variable length integer. + char in[payload_size + 4] = {// type 0xB + 0x1F*3 + 0x40, 0x68, + // length + 0x40 + 0x01, 0x00}; + EXPECT_EQ(QUIC_ARRAYSIZE(in), decoder_.ProcessInput(in, QUIC_ARRAYSIZE(in))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + ASSERT_EQ("", decoder_.error_detail()); + EXPECT_EQ(0xB + 0x1F * 3u, decoder_.current_frame_type()); } TEST_F(HttpDecoderTest, CancelPush) { - char input[] = {// length - 0x1, - // type (CANCEL_PUSH) + char input[] = {// type (CANCEL_PUSH) 0x03, + // length + 0x1, // Push Id 0x01}; @@ -126,10 +175,10 @@ TEST_F(HttpDecoderTest, CancelPush) { } TEST_F(HttpDecoderTest, PushPromiseFrame) { - char input[] = {// length - 0x8, - // type (PUSH_PROMISE) + char input[] = {// type (PUSH_PROMISE) 0x05, + // length + 0x8, // Push Id 0x01, // Header Block @@ -163,10 +212,10 @@ TEST_F(HttpDecoderTest, PushPromiseFrame) { } TEST_F(HttpDecoderTest, MaxPushId) { - char input[] = {// length - 0x1, - // type (MAX_PUSH_ID) + char input[] = {// type (MAX_PUSH_ID) 0x0D, + // length + 0x1, // Push Id 0x01}; @@ -187,10 +236,10 @@ TEST_F(HttpDecoderTest, MaxPushId) { } TEST_F(HttpDecoderTest, DuplicatePush) { - char input[] = {// length - 0x1, - // type (DUPLICATE_PUSH) + char input[] = {// type (DUPLICATE_PUSH) 0x0E, + // length + 0x1, // Push Id 0x01}; // Process the full frame. @@ -210,10 +259,10 @@ TEST_F(HttpDecoderTest, DuplicatePush) { } TEST_F(HttpDecoderTest, PriorityFrame) { - char input[] = {// length - 0x4, - // type (PRIORITY) + char input[] = {// type (PRIORITY) 0x2, + // length + 0x4, // request stream, request stream, exclusive 0x01, // prioritized_element_id @@ -252,29 +301,32 @@ TEST_F(HttpDecoderTest, PriorityFrame) { TEST_F(HttpDecoderTest, SettingsFrame) { // clang-format off char input[] = { - // length - 0x06, // type (SETTINGS) 0x04, + // length + 0x07, // identifier (SETTINGS_NUM_PLACEHOLDERS) - 0x00, 0x03, // content 0x02, // identifier (SETTINGS_MAX_HEADER_LIST_SIZE) - 0x00, 0x06, // content 0x05, - }; + // identifier (256 in variable length integer) + 0x40 + 0x01, + 0x00, + // content + 0x04}; // clang-format on SettingsFrame frame; frame.values[3] = 2; frame.values[6] = 5; + frame.values[256] = 4; // Process the full frame. - EXPECT_CALL(visitor_, OnSettingsFrameStart(Http3FrameLengths(2, 6))); + EXPECT_CALL(visitor_, OnSettingsFrameStart(Http3FrameLengths(2, 7))); EXPECT_CALL(visitor_, OnSettingsFrame(frame)); EXPECT_EQ(QUIC_ARRAYSIZE(input), decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); @@ -282,7 +334,7 @@ TEST_F(HttpDecoderTest, SettingsFrame) { EXPECT_EQ("", decoder_.error_detail()); // Process the frame incremently. - EXPECT_CALL(visitor_, OnSettingsFrameStart(Http3FrameLengths(2, 6))); + EXPECT_CALL(visitor_, OnSettingsFrameStart(Http3FrameLengths(2, 7))); EXPECT_CALL(visitor_, OnSettingsFrame(frame)); for (char c : input) { EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); @@ -292,10 +344,10 @@ TEST_F(HttpDecoderTest, SettingsFrame) { } TEST_F(HttpDecoderTest, DataFrame) { - char input[] = {// length - 0x05, - // type (DATA) + char input[] = {// type (DATA) 0x00, + // length + 0x05, // data 'D', 'a', 't', 'a', '!'}; @@ -352,11 +404,32 @@ TEST_F(HttpDecoderTest, FrameHeaderPartialDelivery) { EXPECT_EQ("", decoder_.error_detail()); } +TEST_F(HttpDecoderTest, PartialDeliveryOfLargeFrameType) { + // Use a reserved type that's more than 1 byte in VarInt62. + const uint8_t type = 0xB + 0x1F * 3; + std::unique_ptr<char[]> input; + QuicByteCount total_length = QuicDataWriter::GetVarInt62Len(0x00) + + QuicDataWriter::GetVarInt62Len(type); + input.reset(new char[total_length]); + QuicDataWriter writer(total_length, input.get()); + writer.WriteVarInt62(type); + writer.WriteVarInt62(0x00); + + auto raw_input = input.get(); + for (uint64_t i = 0; i < total_length; ++i) { + char c = raw_input[i]; + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + EXPECT_EQ(type, decoder_.current_frame_type()); +} + TEST_F(HttpDecoderTest, GoAway) { - char input[] = {// length - 0x1, - // type (GOAWAY) + char input[] = {// type (GOAWAY) 0x07, + // length + 0x1, // StreamId 0x01}; @@ -377,10 +450,10 @@ TEST_F(HttpDecoderTest, GoAway) { } TEST_F(HttpDecoderTest, HeadersFrame) { - char input[] = {// length - 0x07, - // type (HEADERS) + char input[] = {// type (HEADERS) 0x01, + // length + 0x07, // headers 'H', 'e', 'a', 'd', 'e', 'r', 's'}; @@ -412,8 +485,8 @@ TEST_F(HttpDecoderTest, HeadersFrame) { } TEST_F(HttpDecoderTest, EmptyDataFrame) { - char input[] = {0x00, // length - 0x00}; // type (DATA) + char input[] = {0x00, // type (DATA) + 0x00}; // length // Process the full frame. InSequence s; @@ -435,8 +508,8 @@ TEST_F(HttpDecoderTest, EmptyDataFrame) { } TEST_F(HttpDecoderTest, EmptyHeadersFrame) { - char input[] = {0x00, // length - 0x01}; // type (HEADERS) + char input[] = {0x01, // type (HEADERS) + 0x00}; // length // Process the full frame. InSequence s; @@ -458,8 +531,8 @@ TEST_F(HttpDecoderTest, EmptyHeadersFrame) { } TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) { - char input[] = {0x01, // length - 0x05, // type (PUSH_PROMISE) + char input[] = {0x05, // type (PUSH_PROMISE) + 0x01, // length 0x01}; // Push Id // Process the full frame. @@ -482,8 +555,8 @@ TEST_F(HttpDecoderTest, PushPromiseFrameNoHeaders) { } TEST_F(HttpDecoderTest, MalformedFrameWithOverlyLargePayload) { - char input[] = {0x10, // length - 0x03, // type (CANCEL_PUSH) + char input[] = {0x03, // type (CANCEL_PUSH) + 0x10, // length 0x15}; // malformed payload // Process the full frame. EXPECT_CALL(visitor_, OnError(&decoder_)); @@ -495,10 +568,10 @@ TEST_F(HttpDecoderTest, MalformedFrameWithOverlyLargePayload) { TEST_F(HttpDecoderTest, MalformedSettingsFrame) { char input[30]; QuicDataWriter writer(30, input); - // Write length. - writer.WriteVarInt62(2048 * 1024); // Write type SETTINGS. writer.WriteUInt8(0x04); + // Write length. + writer.WriteVarInt62(2048 * 1024); writer.WriteStringPiece("Malformed payload"); EXPECT_CALL(visitor_, OnError(&decoder_)); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc index beeef9b6abb..01f9c10bea0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc @@ -44,14 +44,10 @@ uint8_t SetPriorityFields(uint8_t num, } } -// Length of the type field of a frame. -static const size_t kFrameTypeLength = 1; // Length of the weight field of a priority frame. static const size_t kPriorityWeightLength = 1; // Length of a priority frame's first byte. static const size_t kPriorityFirstByteLength = 1; -// Length of a key in the map of a settings frame. -static const size_t kSettingsMapKeyLength = 2; } // namespace @@ -63,8 +59,9 @@ QuicByteCount HttpEncoder::SerializeDataFrameHeader( QuicByteCount payload_length, std::unique_ptr<char[]>* output) { DCHECK_NE(0u, payload_length); - QuicByteCount header_length = - QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength; + QuicByteCount header_length = QuicDataWriter::GetVarInt62Len(payload_length) + + QuicDataWriter::GetVarInt62Len( + static_cast<uint64_t>(HttpFrameType::DATA)); output->reset(new char[header_length]); QuicDataWriter writer(header_length, output->get()); @@ -72,6 +69,8 @@ QuicByteCount HttpEncoder::SerializeDataFrameHeader( if (WriteFrameHeader(payload_length, HttpFrameType::DATA, &writer)) { return header_length; } + QUIC_DLOG(ERROR) + << "Http encoder failed when attempting to serialize data frame header."; return 0; } @@ -80,7 +79,9 @@ QuicByteCount HttpEncoder::SerializeHeadersFrameHeader( std::unique_ptr<char[]>* output) { DCHECK_NE(0u, payload_length); QuicByteCount header_length = - QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength; + QuicDataWriter::GetVarInt62Len(payload_length) + + QuicDataWriter::GetVarInt62Len( + static_cast<uint64_t>(HttpFrameType::HEADERS)); output->reset(new char[header_length]); QuicDataWriter writer(header_length, output->get()); @@ -88,6 +89,9 @@ QuicByteCount HttpEncoder::SerializeHeadersFrameHeader( if (WriteFrameHeader(payload_length, HttpFrameType::HEADERS, &writer)) { return header_length; } + QUIC_DLOG(ERROR) + << "Http encoder failed when attempting to serialize headers " + "frame header."; return 0; } @@ -99,12 +103,15 @@ QuicByteCount HttpEncoder::SerializePriorityFrame( QuicDataWriter::GetVarInt62Len(priority.prioritized_element_id) + QuicDataWriter::GetVarInt62Len(priority.element_dependency_id) + kPriorityWeightLength; - QuicByteCount total_length = GetTotalLength(payload_length); + QuicByteCount total_length = + GetTotalLength(payload_length, HttpFrameType::PRIORITY); output->reset(new char[total_length]); QuicDataWriter writer(total_length, output->get()); if (!WriteFrameHeader(payload_length, HttpFrameType::PRIORITY, &writer)) { + QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " + "priority frame header."; return 0; } @@ -122,6 +129,8 @@ QuicByteCount HttpEncoder::SerializePriorityFrame( writer.WriteUInt8(priority.weight)) { return total_length; } + QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " + "priority frame payload."; return 0; } @@ -130,7 +139,8 @@ QuicByteCount HttpEncoder::SerializeCancelPushFrame( std::unique_ptr<char[]>* output) { QuicByteCount payload_length = QuicDataWriter::GetVarInt62Len(cancel_push.push_id); - QuicByteCount total_length = GetTotalLength(payload_length); + QuicByteCount total_length = + GetTotalLength(payload_length, HttpFrameType::CANCEL_PUSH); output->reset(new char[total_length]); QuicDataWriter writer(total_length, output->get()); @@ -139,30 +149,37 @@ QuicByteCount HttpEncoder::SerializeCancelPushFrame( writer.WriteVarInt62(cancel_push.push_id)) { return total_length; } + QUIC_DLOG(ERROR) + << "Http encoder failed when attempting to serialize cancel push frame."; return 0; } QuicByteCount HttpEncoder::SerializeSettingsFrame( const SettingsFrame& settings, std::unique_ptr<char[]>* output) { - // Calculate the key sizes. - QuicByteCount payload_length = settings.values.size() * kSettingsMapKeyLength; - // Calculate the value sizes. + QuicByteCount payload_length = 0; + // Calculate the payload length. for (auto it = settings.values.begin(); it != settings.values.end(); ++it) { + payload_length += QuicDataWriter::GetVarInt62Len(it->first); payload_length += QuicDataWriter::GetVarInt62Len(it->second); } - QuicByteCount total_length = GetTotalLength(payload_length); + QuicByteCount total_length = + GetTotalLength(payload_length, HttpFrameType::SETTINGS); output->reset(new char[total_length]); QuicDataWriter writer(total_length, output->get()); if (!WriteFrameHeader(payload_length, HttpFrameType::SETTINGS, &writer)) { + QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " + "settings frame header."; return 0; } for (auto it = settings.values.begin(); it != settings.values.end(); ++it) { - if (!writer.WriteUInt16(it->first) || !writer.WriteVarInt62(it->second)) { + if (!writer.WriteVarInt62(it->first) || !writer.WriteVarInt62(it->second)) { + QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " + "settings frame payload."; return 0; } } @@ -178,7 +195,9 @@ QuicByteCount HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( push_promise.headers.length(); // GetTotalLength() is not used because headers will not be serialized. QuicByteCount total_length = - QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength + + QuicDataWriter::GetVarInt62Len(payload_length) + + QuicDataWriter::GetVarInt62Len( + static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE)) + QuicDataWriter::GetVarInt62Len(push_promise.push_id); output->reset(new char[total_length]); @@ -188,6 +207,8 @@ QuicByteCount HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( writer.WriteVarInt62(push_promise.push_id)) { return total_length; } + QUIC_DLOG(ERROR) + << "Http encoder failed when attempting to serialize push promise frame."; return 0; } @@ -196,7 +217,8 @@ QuicByteCount HttpEncoder::SerializeGoAwayFrame( std::unique_ptr<char[]>* output) { QuicByteCount payload_length = QuicDataWriter::GetVarInt62Len(goaway.stream_id); - QuicByteCount total_length = GetTotalLength(payload_length); + QuicByteCount total_length = + GetTotalLength(payload_length, HttpFrameType::GOAWAY); output->reset(new char[total_length]); QuicDataWriter writer(total_length, output->get()); @@ -205,6 +227,8 @@ QuicByteCount HttpEncoder::SerializeGoAwayFrame( writer.WriteVarInt62(goaway.stream_id)) { return total_length; } + QUIC_DLOG(ERROR) + << "Http encoder failed when attempting to serialize goaway frame."; return 0; } @@ -213,7 +237,8 @@ QuicByteCount HttpEncoder::SerializeMaxPushIdFrame( std::unique_ptr<char[]>* output) { QuicByteCount payload_length = QuicDataWriter::GetVarInt62Len(max_push_id.push_id); - QuicByteCount total_length = GetTotalLength(payload_length); + QuicByteCount total_length = + GetTotalLength(payload_length, HttpFrameType::MAX_PUSH_ID); output->reset(new char[total_length]); QuicDataWriter writer(total_length, output->get()); @@ -222,6 +247,8 @@ QuicByteCount HttpEncoder::SerializeMaxPushIdFrame( writer.WriteVarInt62(max_push_id.push_id)) { return total_length; } + QUIC_DLOG(ERROR) + << "Http encoder failed when attempting to serialize max push id frame."; return 0; } @@ -230,7 +257,8 @@ QuicByteCount HttpEncoder::SerializeDuplicatePushFrame( std::unique_ptr<char[]>* output) { QuicByteCount payload_length = QuicDataWriter::GetVarInt62Len(duplicate_push.push_id); - QuicByteCount total_length = GetTotalLength(payload_length); + QuicByteCount total_length = + GetTotalLength(payload_length, HttpFrameType::DUPLICATE_PUSH); output->reset(new char[total_length]); QuicDataWriter writer(total_length, output->get()); @@ -240,18 +268,22 @@ QuicByteCount HttpEncoder::SerializeDuplicatePushFrame( writer.WriteVarInt62(duplicate_push.push_id)) { return total_length; } + QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " + "duplicate push frame."; return 0; } bool HttpEncoder::WriteFrameHeader(QuicByteCount length, HttpFrameType type, QuicDataWriter* writer) { - return writer->WriteVarInt62(length) && - writer->WriteUInt8(static_cast<uint8_t>(type)); + return writer->WriteVarInt62(static_cast<uint64_t>(type)) && + writer->WriteVarInt62(length); } -QuicByteCount HttpEncoder::GetTotalLength(QuicByteCount payload_length) { - return QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength + +QuicByteCount HttpEncoder::GetTotalLength(QuicByteCount payload_length, + HttpFrameType type) { + return QuicDataWriter::GetVarInt62Len(payload_length) + + QuicDataWriter::GetVarInt62Len(static_cast<uint64_t>(type)) + payload_length; } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.h b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.h index f04e6e40700..6691e315700 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.h @@ -77,7 +77,8 @@ class QUIC_EXPORT_PRIVATE HttpEncoder { HttpFrameType type, QuicDataWriter* writer); - QuicByteCount GetTotalLength(QuicByteCount payload_length); + QuicByteCount GetTotalLength(QuicByteCount payload_length, + HttpFrameType type); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder_test.cc index 154d7688e8d..1ff5d8984c0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder_test.cc @@ -22,10 +22,10 @@ TEST_F(HttpEncoderTest, SerializeDataFrameHeader) { std::unique_ptr<char[]> buffer; uint64_t length = encoder_.SerializeDataFrameHeader(/* payload_length = */ 5, &buffer); - char output[] = {// length - 0x05, - // type (DATA) - 0x00}; + char output[] = {// type (DATA) + 0x00, + // length + 0x05}; EXPECT_EQ(QUIC_ARRAYSIZE(output), length); CompareCharArraysWithHexError("DATA", buffer.get(), length, output, QUIC_ARRAYSIZE(output)); @@ -35,10 +35,10 @@ TEST_F(HttpEncoderTest, SerializeHeadersFrameHeader) { std::unique_ptr<char[]> buffer; uint64_t length = encoder_.SerializeHeadersFrameHeader(/* payload_length = */ 7, &buffer); - char output[] = {// length - 0x07, - // type (HEADERS) - 0x01}; + char output[] = {// type (HEADERS) + 0x01, + // length + 0x07}; EXPECT_EQ(QUIC_ARRAYSIZE(output), length); CompareCharArraysWithHexError("HEADERS", buffer.get(), length, output, QUIC_ARRAYSIZE(output)); @@ -52,10 +52,10 @@ TEST_F(HttpEncoderTest, SerializePriorityFrame) { priority.prioritized_element_id = 0x03; priority.element_dependency_id = 0x04; priority.weight = 0xFF; - char output[] = {// length - 0x4, - // type (PRIORITY) + char output[] = {// type (PRIORITY) 0x2, + // length + 0x4, // request stream, request stream, exclusive 0x01, // prioritized_element_id @@ -75,10 +75,10 @@ TEST_F(HttpEncoderTest, SerializePriorityFrame) { TEST_F(HttpEncoderTest, SerializeCancelPushFrame) { CancelPushFrame cancel_push; cancel_push.push_id = 0x01; - char output[] = {// length - 0x1, - // type (CANCEL_PUSH) + char output[] = {// type (CANCEL_PUSH) 0x03, + // length + 0x1, // Push Id 0x01}; std::unique_ptr<char[]> buffer; @@ -92,22 +92,23 @@ TEST_F(HttpEncoderTest, SerializeSettingsFrame) { SettingsFrame settings; settings.values[3] = 2; settings.values[6] = 5; - char output[] = { - // length - 0x06, - // type (SETTINGS) - 0x04, - // identifier (SETTINGS_NUM_PLACEHOLDERS) - 0x00, - 0x03, - // content - 0x02, - // identifier (SETTINGS_MAX_HEADER_LIST_SIZE) - 0x00, - 0x06, - // content - 0x05, - }; + settings.values[256] = 4; + char output[] = {// type (SETTINGS) + 0x04, + // length + 0x07, + // identifier (SETTINGS_NUM_PLACEHOLDERS) + 0x03, + // content + 0x02, + // identifier (SETTINGS_MAX_HEADER_LIST_SIZE) + 0x06, + // content + 0x05, + // identifier (256 in variable length integer) + 0x40 + 0x01, 0x00, + // content + 0x04}; std::unique_ptr<char[]> buffer; uint64_t length = encoder_.SerializeSettingsFrame(settings, &buffer); EXPECT_EQ(QUIC_ARRAYSIZE(output), length); @@ -119,10 +120,10 @@ TEST_F(HttpEncoderTest, SerializePushPromiseFrameWithOnlyPushId) { PushPromiseFrame push_promise; push_promise.push_id = 0x01; push_promise.headers = "Headers"; - char output[] = {// length - 0x8, - // type (PUSH_PROMISE) + char output[] = {// type (PUSH_PROMISE) 0x05, + // length + 0x8, // Push Id 0x01}; std::unique_ptr<char[]> buffer; @@ -136,10 +137,10 @@ TEST_F(HttpEncoderTest, SerializePushPromiseFrameWithOnlyPushId) { TEST_F(HttpEncoderTest, SerializeGoAwayFrame) { GoAwayFrame goaway; goaway.stream_id = 0x1; - char output[] = {// length - 0x1, - // type (GOAWAY) + char output[] = {// type (GOAWAY) 0x07, + // length + 0x1, // StreamId 0x01}; std::unique_ptr<char[]> buffer; @@ -152,10 +153,10 @@ TEST_F(HttpEncoderTest, SerializeGoAwayFrame) { TEST_F(HttpEncoderTest, SerializeMaxPushIdFrame) { MaxPushIdFrame max_push_id; max_push_id.push_id = 0x1; - char output[] = {// length - 0x1, - // type (MAX_PUSH_ID) + char output[] = {// type (MAX_PUSH_ID) 0x0D, + // length + 0x1, // Push Id 0x01}; std::unique_ptr<char[]> buffer; @@ -168,10 +169,10 @@ TEST_F(HttpEncoderTest, SerializeMaxPushIdFrame) { TEST_F(HttpEncoderTest, SerializeDuplicatePushFrame) { DuplicatePushFrame duplicate_push; duplicate_push.push_id = 0x1; - char output[] = {// length - 0x1, - // type (DUPLICATE_PUSH) + char output[] = {// type (DUPLICATE_PUSH) 0x0E, + // length + 0x1, // Push Id 0x01}; std::unique_ptr<char[]> buffer; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h b/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h index ea115571fc2..f1aa7ff81f2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_frames.h @@ -90,8 +90,7 @@ struct CancelPushFrame { // affect how endpoints communicate, such as preferences and constraints // on peer behavior -using SettingsId = uint16_t; -using SettingsMap = std::map<SettingsId, uint64_t>; +using SettingsMap = std::map<uint64_t, uint64_t>; struct SettingsFrame { SettingsMap values; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc index 2f669df22c3..a41235fbc31 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc @@ -370,6 +370,10 @@ TEST_P(QuicHeadersStreamTest, StreamId) { } TEST_P(QuicHeadersStreamTest, WriteHeaders) { + if (VersionUsesQpack(transport_version())) { + return; + } + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; stream_id += next_stream_id_) { for (bool fin : {false, true}) { @@ -421,6 +425,10 @@ TEST_P(QuicHeadersStreamTest, WritePushPromises) { } TEST_P(QuicHeadersStreamTest, ProcessRawData) { + if (VersionUsesQpack(transport_version())) { + return; + } + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; stream_id += next_stream_id_) { for (bool fin : {false, true}) { @@ -536,6 +544,10 @@ TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) { } TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) { + if (VersionUsesQpack(transport_version())) { + return; + } + QuicSpdySessionPeer::SetMaxUncompressedHeaderBytes(&session_, 256 * 1024); // We want to create a frame that is more than the SPDY Framer's max control // frame size, which is 16K, but less than the HPACK decoders max decode @@ -710,6 +722,10 @@ TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) { } TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) { + if (VersionUsesQpack(transport_version())) { + return; + } + auto hpack_decoder_visitor = QuicMakeUnique<StrictMock<MockQuicHpackDebugVisitor>>(); { @@ -762,6 +778,10 @@ TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) { } TEST_P(QuicHeadersStreamTest, HpackEncoderDebugVisitor) { + if (VersionUsesQpack(transport_version())) { + return; + } + auto hpack_encoder_visitor = QuicMakeUnique<StrictMock<MockQuicHpackDebugVisitor>>(); if (perspective() == Perspective::IS_SERVER) { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc index 4c625c0df04..b53d4e9e1a2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc @@ -111,6 +111,14 @@ QuicReceiveControlStream::QuicReceiveControlStream(QuicStreamId id, sequencer()->set_level_triggered(true); } +QuicReceiveControlStream::QuicReceiveControlStream(PendingStream pending) + : QuicStream(std::move(pending), READ_UNIDIRECTIONAL, /*is_static=*/true), + received_settings_length_(0), + http_decoder_visitor_(new HttpDecoderVisitor(this)) { + decoder_.set_visitor(http_decoder_visitor_.get()); + sequencer()->set_level_triggered(true); +} + QuicReceiveControlStream::~QuicReceiveControlStream() {} void QuicReceiveControlStream::OnStreamReset(const QuicRstStreamFrame& frame) { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h index 1805d6ccc08..61e4299e118 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.h @@ -20,6 +20,9 @@ class QUIC_EXPORT_PRIVATE QuicReceiveControlStream : public QuicStream { // |session| can't be nullptr, and the ownership is not passed. The stream can // only be accessed through the session. explicit QuicReceiveControlStream(QuicStreamId id, QuicSpdySession* session); + // Construct control stream from pending stream, the |pending| object will no + // longer exist after the construction. + explicit QuicReceiveControlStream(PendingStream pending); QuicReceiveControlStream(const QuicReceiveControlStream&) = delete; QuicReceiveControlStream& operator=(const QuicReceiveControlStream&) = delete; ~QuicReceiveControlStream() override; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc index 1861d17495c..73e8fedabd2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc @@ -50,7 +50,7 @@ std::vector<TestParams> GetTestParams() { std::vector<TestParams> params; ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); for (const auto& version : AllSupportedVersions()) { - if (!VersionHasControlStreams(version.transport_version)) { + if (!VersionHasStreamType(version.transport_version)) { continue; } for (Perspective p : {Perspective::IS_SERVER, Perspective::IS_CLIENT}) { @@ -100,6 +100,7 @@ INSTANTIATE_TEST_SUITE_P(Tests, ::testing::ValuesIn(GetTestParams())); TEST_P(QuicReceiveControlStreamTest, ResetControlStream) { + EXPECT_TRUE(receive_control_stream_->is_static()); QuicRstStreamFrame rst_frame(kInvalidControlFrameId, receive_control_stream_->id(), QUIC_STREAM_CANCELLED, 1234); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc index 980cdf54133..a015c5fae30 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream_test.cc @@ -50,7 +50,7 @@ std::vector<TestParams> GetTestParams() { std::vector<TestParams> params; ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); for (const auto& version : AllSupportedVersions()) { - if (!VersionHasControlStreams(version.transport_version)) { + if (!VersionHasStreamType(version.transport_version)) { continue; } for (Perspective p : {Perspective::IS_SERVER, Perspective::IS_CLIENT}) { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc index 5cdb2c46451..683793dc838 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc @@ -227,8 +227,8 @@ bool QuicServerSessionBase::ShouldCreateOutgoingBidirectionalStream() { connection()->transport_version() != QUIC_VERSION_99) { if (GetNumOpenOutgoingStreams() >= stream_id_manager().max_open_outgoing_streams()) { - VLOG(1) << "No more streams should be created. " - << "Already " << GetNumOpenOutgoingStreams() << " open."; + QUIC_VLOG(1) << "No more streams should be created. " + << "Already " << GetNumOpenOutgoingStreams() << " open."; return false; } } @@ -251,8 +251,8 @@ bool QuicServerSessionBase::ShouldCreateOutgoingUnidirectionalStream() { connection()->transport_version() != QUIC_VERSION_99) { if (GetNumOpenOutgoingStreams() >= stream_id_manager().max_open_outgoing_streams()) { - VLOG(1) << "No more streams should be created. " - << "Already " << GetNumOpenOutgoingStreams() << " open."; + QUIC_VLOG(1) << "No more streams should be created. " + << "Already " << GetNumOpenOutgoingStreams() << " open."; return false; } } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc index e5945e1c9d6..94ebb67a0bf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc @@ -105,10 +105,8 @@ class TestServerSession : public QuicServerSessionBase { QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, QuicCompressedCertsCache* compressed_certs_cache) override { - return new QuicCryptoServerStream( - crypto_config, compressed_certs_cache, - GetQuicReloadableFlag(enable_quic_stateless_reject_support), this, - stream_helper()); + return new QuicCryptoServerStream(crypto_config, compressed_certs_cache, + this, stream_helper()); } private: @@ -131,9 +129,12 @@ class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> { TlsServerHandshaker::CreateSslCtx()), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { - config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest); - QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_, - kMaxStreamsForTest); + config_.SetMaxIncomingBidirectionalStreamsToSend(kMaxStreamsForTest); + config_.SetMaxIncomingUnidirectionalStreamsToSend(kMaxStreamsForTest); + QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams( + &config_, kMaxStreamsForTest); + QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams( + &config_, kMaxStreamsForTest); config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config_.SetInitialSessionFlowControlWindowToSend( @@ -460,12 +461,10 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { QuicCompressedCertsCache* compressed_certs_cache, QuicServerSessionBase* session, QuicCryptoServerStream::Helper* helper) - : QuicCryptoServerStream( - crypto_config, - compressed_certs_cache, - GetQuicReloadableFlag(enable_quic_stateless_reject_support), - session, - helper) {} + : QuicCryptoServerStream(crypto_config, + compressed_certs_cache, + session, + helper) {} MockQuicCryptoServerStream(const MockQuicCryptoServerStream&) = delete; MockQuicCryptoServerStream& operator=(const MockQuicCryptoServerStream&) = delete; @@ -693,13 +692,11 @@ TEST_P(StreamMemberLifetimeTest, Basic) { // TODO(nharper): Fix this test so it doesn't rely on QUIC crypto. return; } - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); const QuicClock* clock = helper_.GetClock(); CryptoHandshakeMessage chlo = crypto_test_utils::GenerateDefaultInchoateCHLO( clock, GetParam().transport_version, &crypto_config_); - chlo.SetVector(kCOPT, QuicTagVector{kSREJ}); + chlo.SetVector(kCOPT, QuicTagVector{kREJ}); std::vector<ParsedQuicVersion> packet_version_list = {GetParam()}; std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( TestConnectionId(1), EmptyQuicConnectionId(), true, false, 1, @@ -708,8 +705,6 @@ TEST_P(StreamMemberLifetimeTest, Basic) { EXPECT_CALL(stream_helper_, CanAcceptClientHello(_, _, _, _, _)) .WillOnce(testing::Return(true)); - EXPECT_CALL(stream_helper_, GenerateConnectionIdForReject(_, _)) - .WillOnce(testing::Return(TestConnectionId(12345))); // Set the current packet QuicConnectionPeer::SetCurrentPacket(session_->connection(), diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc index d388d2e1931..93f68808d42 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc @@ -64,7 +64,7 @@ void QuicSpdyClientSessionBase::OnPromiseHeaderList( QuicStreamId promised_stream_id, size_t frame_len, const QuicHeaderList& header_list) { - if (QuicContainsKey(static_streams(), stream_id)) { + if (IsStaticStream(stream_id)) { connection()->CloseConnection( QUIC_INVALID_HEADERS_STREAM_DATA, "stream is static", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc index 9a99ca7bfc8..ea9e0585967 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc @@ -8,7 +8,8 @@ #include <string> #include <vector> -#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" @@ -114,13 +115,13 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { connection_->transport_version(), 0); } - // The function ensures that A) the max stream id frames get properly deleted + // The function ensures that A) the MAX_STREAMS frames get properly deleted // (since the test uses a 'did we leak memory' check ... if we just lose the // frame, the test fails) and B) returns true (instead of the default, false) // which ensures that the rest of the system thinks that the frame actually // was transmitted. - bool ClearMaxStreamIdControlFrame(const QuicFrame& frame) { - if (frame.type == MAX_STREAM_ID_FRAME) { + bool ClearMaxStreamsControlFrame(const QuicFrame& frame) { + if (frame.type == MAX_STREAMS_FRAME) { DeleteFrame(&const_cast<QuicFrame&>(frame)); return true; } @@ -128,8 +129,8 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { } public: - bool ClearStreamIdBlockedControlFrame(const QuicFrame& frame) { - if (frame.type == STREAM_ID_BLOCKED_FRAME) { + bool ClearStreamsBlockedControlFrame(const QuicFrame& frame) { + if (frame.type == STREAMS_BLOCKED_FRAME) { DeleteFrame(&const_cast<QuicFrame&>(frame)); return true; } @@ -146,16 +147,23 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { EXPECT_CALL(*connection_, SendControlFrame(_)) .Times(testing::AnyNumber()) .WillRepeatedly(Invoke( - this, &QuicSpdyClientSessionTest::ClearMaxStreamIdControlFrame)); + this, &QuicSpdyClientSessionTest::ClearMaxStreamsControlFrame)); } session_->CryptoConnect(); QuicCryptoClientStream* stream = static_cast<QuicCryptoClientStream*>( session_->GetMutableCryptoStream()); - crypto_test_utils::FakeServerOptions options; QuicConfig config = DefaultQuicConfig(); - config.SetMaxIncomingDynamicStreamsToSend(server_max_incoming_streams); + if (connection_->transport_version() == QUIC_VERSION_99) { + config.SetMaxIncomingUnidirectionalStreamsToSend( + server_max_incoming_streams); + config.SetMaxIncomingBidirectionalStreamsToSend( + server_max_incoming_streams); + } else { + config.SetMaxIncomingBidirectionalStreamsToSend( + server_max_incoming_streams); + } crypto_test_utils::HandshakeWithFakeServer( - &config, &helper_, &alarm_factory_, connection_, stream, options); + &config, &helper_, &alarm_factory_, connection_, stream); } QuicCryptoClientConfig crypto_config_; @@ -199,16 +207,14 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) { EXPECT_TRUE(session_->IsEncryptionEstablished()); QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream(); ASSERT_TRUE(stream != nullptr); - if (!QuicVersionUsesCryptoFrames(GetParam().transport_version)) { - EXPECT_NE(QuicUtils::GetCryptoStreamId(connection_->transport_version()), - stream->id()); - } + EXPECT_FALSE(QuicUtils::IsCryptoStreamId(connection_->transport_version(), + stream->id())); // Process an "inchoate" REJ from the server which will cause // an inchoate CHLO to be sent and will leave the encryption level // at NONE. CryptoHandshakeMessage rej; - crypto_test_utils::FillInDummyReject(&rej, /* stateless */ false); + crypto_test_utils::FillInDummyReject(&rej); EXPECT_TRUE(session_->IsEncryptionEstablished()); crypto_test_utils::SendHandshakeMessageToStream( session_->GetMutableCryptoStream(), rej, Perspective::IS_CLIENT); @@ -244,12 +250,24 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) { EXPECT_FALSE(session_->CreateOutgoingBidirectionalStream()); // Close the stream, but without having received a FIN or a RST_STREAM - // or MAX_STREAM_ID (V99) and check that a new one can not be created. + // or MAX_STREAMS (V99) and check that a new one can not be created. session_->CloseStream(stream->id()); EXPECT_EQ(1u, session_->GetNumOpenOutgoingStreams()); stream = session_->CreateOutgoingBidirectionalStream(); EXPECT_FALSE(stream); + + if (GetParam().transport_version == QUIC_VERSION_99) { + // Ensure that we have/have had 3 open streams, crypto, header, and the + // 1 test stream. Primary purpose of this is to fail when crypto + // no longer uses a normal stream. Some above constants will then need + // to be changed. + EXPECT_EQ(QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) + ->outgoing_static_stream_count() + + 1, + QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) + ->outgoing_stream_count()); + } } TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) { @@ -276,17 +294,29 @@ TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) { // Check that a new one can be created. EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); if (GetParam().transport_version == QUIC_VERSION_99) { - // In V99 the stream limit increases only if we get a MAX_STREAM_ID + // In V99 the stream limit increases only if we get a MAX_STREAMS // frame; pretend we got one. - // Note that this is to be the second stream created, but GetNth... starts - // numbering at 0 (the first stream is 0, second is 1...) - QuicMaxStreamIdFrame frame(0, GetNthClientInitiatedBidirectionalStreamId( - connection_->transport_version(), 1)); - session_->OnMaxStreamIdFrame(frame); + // Note that this is to be the second stream created, hence + // the stream count is 3 (the two streams created as a part of + // the test plus the header stream, internally created). + QuicMaxStreamsFrame frame( + 0, + QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) + ->outgoing_static_stream_count() + + 2, + /*unidirectional=*/false); + session_->OnMaxStreamsFrame(frame); } stream = session_->CreateOutgoingBidirectionalStream(); EXPECT_NE(nullptr, stream); + if (GetParam().transport_version == QUIC_VERSION_99) { + // Ensure that we have/have had three open streams: two test streams and the + // header stream. + EXPECT_EQ(3u, + QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) + ->outgoing_stream_count()); + } } TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) { @@ -308,7 +338,7 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) { if (GetParam().transport_version == QUIC_VERSION_99) { // For v99, trying to open a stream and failing due to lack - // of stream ids will result in a STREAM_ID_BLOCKED. Make + // of stream ids will result in a STREAMS_BLOCKED. Make // sure we get one. Also clear out the frame because if it's // left sitting, the later SendRstStream will not actually // transmit the RST_STREAM because the connection will be in write-blocked @@ -316,8 +346,7 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) { // RST_STREAM, below, will not be satisfied. EXPECT_CALL(*connection_, SendControlFrame(_)) .WillOnce(Invoke( - this, - &QuicSpdyClientSessionTest::ClearStreamIdBlockedControlFrame)); + this, &QuicSpdyClientSessionTest::ClearStreamsBlockedControlFrame)); } EXPECT_EQ(nullptr, session_->CreateOutgoingBidirectionalStream()); @@ -347,14 +376,27 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) { // be able to create a new outgoing stream. EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); if (GetParam().transport_version == QUIC_VERSION_99) { - // Note that this is to be the second stream created, but GetNth... starts - // numbering at 0 (the first stream is 0, second is 1...) - QuicMaxStreamIdFrame frame(0, GetNthClientInitiatedBidirectionalStreamId( - connection_->transport_version(), 1)); - session_->OnMaxStreamIdFrame(frame); + // Note that this is to be the second stream created, hence + // the stream count is 3 (the two streams created as a part of + // the test plus the header stream, internally created). + QuicMaxStreamsFrame frame( + 0, + QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) + ->outgoing_static_stream_count() + + 2, + /*unidirectional=*/false); + + session_->OnMaxStreamsFrame(frame); } stream = session_->CreateOutgoingBidirectionalStream(); EXPECT_NE(nullptr, stream); + if (GetParam().transport_version == QUIC_VERSION_99) { + // Ensure that we have/have had three open streams: two test streams and the + // header stream. + EXPECT_EQ(3u, + QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) + ->outgoing_stream_count()); + } } TEST_P(QuicSpdyClientSessionTest, ReceivedMalformedTrailersAfterSendingRst) { @@ -394,7 +436,7 @@ TEST_P(QuicSpdyClientSessionTest, OnStreamHeaderListWithStaticStream) { EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1); session_->OnStreamHeaderList( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), + QuicUtils::GetHeadersStreamId(connection_->transport_version()), /*fin=*/false, 0, trailers); } @@ -410,7 +452,7 @@ TEST_P(QuicSpdyClientSessionTest, OnPromiseHeaderListWithStaticStream) { EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1); session_->OnPromiseHeaderList( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), + QuicUtils::GetHeadersStreamId(connection_->transport_version()), promised_stream_id_, 0, trailers); } @@ -462,13 +504,19 @@ TEST_P(QuicSpdyClientSessionTest, InvalidPacketReceived) { session_->ProcessUdpPacket(client_address, server_address, valid_packet); // Verify that a non-decryptable packet doesn't close the connection. - QuicFramerPeer::SetLastSerializedConnectionId( + QuicFramerPeer::SetLastSerializedServerConnectionId( QuicConnectionPeer::GetFramer(connection_), connection_id); ParsedQuicVersionVector versions = SupportedVersions(GetParam()); + QuicConnectionId destination_connection_id = EmptyQuicConnectionId(); + QuicConnectionId source_connection_id = connection_id; + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + destination_connection_id = connection_id; + source_connection_id = EmptyQuicConnectionId(); + } std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( - connection_id, EmptyQuicConnectionId(), false, false, 100, "data", - CONNECTION_ID_ABSENT, CONNECTION_ID_ABSENT, PACKET_4BYTE_PACKET_NUMBER, - &versions, Perspective::IS_SERVER)); + destination_connection_id, source_connection_id, false, false, 100, + "data", CONNECTION_ID_ABSENT, CONNECTION_ID_ABSENT, + PACKET_4BYTE_PACKET_NUMBER, &versions, Perspective::IS_SERVER)); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*packet, QuicTime::Zero())); // Change the last byte of the encrypted data. @@ -482,6 +530,15 @@ TEST_P(QuicSpdyClientSessionTest, InvalidPacketReceived) { TEST_P(QuicSpdyClientSessionTest, InvalidFramedPacketReceived) { QuicSocketAddress server_address(TestPeerIPAddress(), kTestPort); QuicSocketAddress client_address(TestPeerIPAddress(), kTestPort); + if (GetParam().KnowsWhichDecrypterToUse()) { + connection_->InstallDecrypter( + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); + } else { + connection_->SetDecrypter( + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); + } EXPECT_CALL(*connection_, ProcessUdpPacket(server_address, client_address, _)) .WillRepeatedly(Invoke(static_cast<MockQuicConnection*>(connection_), @@ -492,7 +549,7 @@ TEST_P(QuicSpdyClientSessionTest, InvalidFramedPacketReceived) { QuicConnectionId destination_connection_id = session_->connection()->connection_id(); QuicConnectionId source_connection_id = EmptyQuicConnectionId(); - QuicFramerPeer::SetLastSerializedConnectionId( + QuicFramerPeer::SetLastSerializedServerConnectionId( QuicConnectionPeer::GetFramer(connection_), destination_connection_id); ParsedQuicVersionVector versions = {GetParam()}; bool version_flag = false; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc index 007bba08e48..5f5d5c13466 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc @@ -193,9 +193,14 @@ TEST_P(QuicSpdyClientStreamTest, EXPECT_NE(QUIC_STREAM_NO_ERROR, stream_->stream_error()); } +// Test that receiving trailing headers (on the headers stream), containing a +// final offset, results in the stream being closed at that byte offset. TEST_P(QuicSpdyClientStreamTest, ReceivingTrailers) { - // Test that receiving trailing headers, containing a final offset, results in - // the stream being closed at that byte offset. + // There is no kFinalOffsetHeaderKey if trailers are sent on the + // request/response stream. + if (VersionUsesQpack(connection_->transport_version())) { + return; + } // Send headers as usual. auto headers = AsHeaderList(headers_); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc index bda2e172d01..35b2d5ef305 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc @@ -51,6 +51,9 @@ namespace quic { namespace { +// TODO(renjietang): remove this once HTTP/3 error codes are adopted. +const uint16_t kHttpUnknownStreamType = 0x0D; + class HeaderTableDebugVisitor : public HpackHeaderTable::DebugVisitorInterface { public: HeaderTableDebugVisitor(const QuicClock* clock, @@ -204,6 +207,12 @@ class QuicSpdySession::SpdyFramerVisitor return; } + if (VersionUsesQpack(session_->connection()->transport_version())) { + CloseConnection("HEADERS frame not allowed on headers stream.", + QUIC_INVALID_HEADERS_STREAM_DATA); + return; + } + // TODO(mpw): avoid down-conversion and plumb SpdyStreamPrecedence through // QuicHeadersStream. SpdyPriority priority = @@ -331,6 +340,9 @@ QuicSpdySession::~QuicSpdySession() { static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession(); } for (auto const& kv : dynamic_streams()) { + if (eliminate_static_stream_map() && kv.second->is_static()) { + continue; + } static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession(); } } @@ -355,9 +367,15 @@ void QuicSpdySession::Initialize() { headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this)); DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()), headers_stream_->id()); - RegisterStaticStream( - QuicUtils::GetHeadersStreamId(connection()->transport_version()), - headers_stream_.get()); + if (!eliminate_static_stream_map()) { + RegisterStaticStream( + QuicUtils::GetHeadersStreamId(connection()->transport_version()), + headers_stream_.get()); + } else { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 7, 17); + unowned_headers_stream_ = headers_stream_.get(); + RegisterStaticStreamNew(std::move(headers_stream_)); + } set_max_uncompressed_header_bytes(max_inbound_header_list_size_); @@ -390,7 +408,6 @@ void QuicSpdySession::WriteDecoderStreamData(QuicStringPiece data) { DCHECK(VersionUsesQpack(connection()->transport_version())); // TODO(112770235): Send decoder stream data on decoder stream. - QUIC_NOTREACHED(); } void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id, @@ -407,7 +424,7 @@ void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id, bool fin, size_t frame_len, const QuicHeaderList& header_list) { - if (QuicContainsKey(static_streams(), stream_id)) { + if (IsStaticStream(stream_id)) { connection()->CloseConnection( QUIC_INVALID_HEADERS_STREAM_DATA, "stream is static", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -429,8 +446,8 @@ void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; } - DVLOG(1) << "Received final byte offset in trailers for stream " - << stream_id << ", which no longer exists."; + QUIC_DVLOG(1) << "Received final byte offset in trailers for stream " + << stream_id << ", which no longer exists."; OnFinalByteOffsetReceived(stream_id, final_byte_offset); } } @@ -463,6 +480,8 @@ size_t QuicSpdySession::WriteHeadersOnHeadersStream( bool fin, SpdyPriority priority, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + DCHECK(!VersionUsesQpack(connection()->transport_version())); + return WriteHeadersOnHeadersStreamImpl( id, std::move(headers), fin, /* parent_stream_id = */ 0, Spdy3PriorityToHttp2Weight(priority), @@ -478,7 +497,7 @@ size_t QuicSpdySession::WritePriority(QuicStreamId id, } SpdyPriorityIR priority_frame(id, parent_stream_id, weight, exclusive); SpdySerializedFrame frame(spdy_framer_.SerializeFrame(priority_frame)); - headers_stream_->WriteOrBufferData( + headers_stream()->WriteOrBufferData( QuicStringPiece(frame.data(), frame.size()), false, nullptr); return frame.size(); } @@ -498,19 +517,18 @@ size_t QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id, push_promise.set_fin(false); SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise)); - headers_stream_->WriteOrBufferData( + headers_stream()->WriteOrBufferData( QuicStringPiece(frame.data(), frame.size()), false, nullptr); return frame.size(); } -size_t QuicSpdySession::SendMaxHeaderListSize(size_t value) { +void QuicSpdySession::SendMaxHeaderListSize(size_t value) { SpdySettingsIR settings_frame; settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, value); SpdySerializedFrame frame(spdy_framer_.SerializeFrame(settings_frame)); - headers_stream_->WriteOrBufferData( + headers_stream()->WriteOrBufferData( QuicStringPiece(frame.data(), frame.size()), false, nullptr); - return frame.size(); } QpackEncoder* QuicSpdySession::qpack_encoder() { @@ -527,7 +545,9 @@ QpackDecoder* QuicSpdySession::qpack_decoder() { QuicSpdyStream* QuicSpdySession::GetSpdyDataStream( const QuicStreamId stream_id) { - return static_cast<QuicSpdyStream*>(GetOrCreateDynamicStream(stream_id)); + QuicStream* stream = GetOrCreateDynamicStream(stream_id); + DCHECK(!stream || !stream->is_static()); + return static_cast<QuicSpdyStream*>(stream); } void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { @@ -545,9 +565,9 @@ bool QuicSpdySession::ShouldKeepConnectionAlive() const { return GetNumOpenDynamicStreams() > 0; } -bool QuicSpdySession::ShouldBufferIncomingStream(QuicStreamId id) const { - DCHECK_EQ(QUIC_VERSION_99, connection()->transport_version()); - return !QuicUtils::IsBidirectionalStreamId(id); +bool QuicSpdySession::UsesPendingStreams() const { + DCHECK(VersionHasStreamType(connection()->transport_version())); + return true; } size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl( @@ -558,6 +578,8 @@ size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl( int weight, bool exclusive, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + DCHECK(!VersionUsesQpack(connection()->transport_version())); + SpdyHeadersIR headers_frame(id, std::move(headers)); headers_frame.set_fin(fin); if (perspective() == Perspective::IS_CLIENT) { @@ -567,7 +589,7 @@ size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl( headers_frame.set_exclusive(exclusive); } SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame)); - headers_stream_->WriteOrBufferData( + headers_stream()->WriteOrBufferData( QuicStringPiece(frame.data(), frame.size()), false, std::move(ack_listener)); return frame.size(); @@ -695,8 +717,57 @@ void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error, } bool QuicSpdySession::HasActiveRequestStreams() const { - // TODO(renjietang): Exclude static streams. - return !dynamic_streams().empty(); + if (!eliminate_static_stream_map()) { + return !dynamic_streams().empty(); + } + // In the case where session is destructed by calling + // dynamic_streams().clear(), we will have incorrect accounting here. + // TODO(renjietang): Modify destructors and make this a DCHECK. + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 9, 17); + if (static_cast<size_t>(dynamic_streams().size()) > + num_incoming_static_streams() + num_outgoing_static_streams()) { + return dynamic_streams().size() - num_incoming_static_streams() - + num_outgoing_static_streams() > + 0; + } + return false; +} + +bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) { + DCHECK(VersionHasStreamType(connection()->transport_version())); + struct iovec iov; + if (!pending->sequencer()->GetReadableRegion(&iov)) { + // The first byte hasn't been received yet. + return false; + } + + QuicDataReader reader(static_cast<char*>(iov.iov_base), iov.iov_len); + uint8_t stream_type_length = reader.PeekVarInt62Length(); + uint64_t stream_type = 0; + if (!reader.ReadVarInt62(&stream_type)) { + return false; + } + pending->MarkConsumed(stream_type_length); + + switch (stream_type) { + case kControlStream: // HTTP/3 control stream. + // TODO(renjietang): Create incoming control stream. + break; + case kServerPushStream: { // Push Stream. + QuicSpdyStream* stream = CreateIncomingStream(std::move(*pending)); + stream->SetUnblocked(); + return true; + } + case kQpackEncoderStream: // QPACK encoder stream. + // TODO(bnc): Create QPACK encoder stream. + break; + case kQpackDecoderStream: // QPACK decoder stream. + // TODO(bnc): Create QPACK decoder stream. + break; + default: + SendStopSending(kHttpUnknownStreamType, pending->id()); + } + return false; } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h index 0ff1150293e..d0978c1e0ce 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h @@ -28,6 +28,12 @@ namespace test { class QuicSpdySessionPeer; } // namespace test +// Unidirectional stream types define by IETF HTTP/3 draft in section 3.2. +const uint64_t kControlStream = 0; +const uint64_t kServerPushStream = 1; +const uint64_t kQpackEncoderStream = 2; +const uint64_t kQpackDecoderStream = 3; + // QuicHpackDebugVisitor gathers data used for understanding HPACK HoL // dynamics. Specifically, it is to help predict the compression // penalty of avoiding HoL by chagning how the dynamic table is used. @@ -135,11 +141,19 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession spdy::SpdyHeaderBlock headers); // Sends SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame. - size_t SendMaxHeaderListSize(size_t value); + void SendMaxHeaderListSize(size_t value); QpackEncoder* qpack_encoder(); QpackDecoder* qpack_decoder(); - QuicHeadersStream* headers_stream() { return headers_stream_.get(); } + QuicHeadersStream* headers_stream() { + return eliminate_static_stream_map() ? unowned_headers_stream_ + : headers_stream_.get(); + } + + const QuicHeadersStream* headers_stream() const { + return eliminate_static_stream_map() ? unowned_headers_stream_ + : headers_stream_.get(); + } bool server_push_enabled() const { return server_push_enabled_; } @@ -187,8 +201,13 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // Returns true if there are open HTTP requests. bool ShouldKeepConnectionAlive() const override; - // Overridden to buffer incoming streams for version 99. - bool ShouldBufferIncomingStream(QuicStreamId id) const override; + // Overridden to buffer incoming unidirectional streams for version 99. + bool UsesPendingStreams() const override; + + // Overridden to Process HTTP/3 stream types. H/3 streams will be created from + // pending streams accordingly if the stream type can be read. Returns true if + // unidirectional streams are created. + bool ProcessPendingStream(PendingStream* pending) override; size_t WriteHeadersOnHeadersStreamImpl( QuicStreamId id, @@ -262,6 +281,13 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // TODO(123528590): Remove this member. std::unique_ptr<QuicHeadersStream> headers_stream_; + // Unowned headers stream pointer that points to the stream + // in dynamic_stream_map. + // TODO(renjietang): Merge this with headers_stream_ and clean up other + // static_stream_map logic when flag eliminate_static_stream_map + // is deprecated. + QuicHeadersStream* unowned_headers_stream_; + // The maximum size of a header block that will be accepted from the peer, // defined per spec as key + value + overhead per field (uncompressed). size_t max_inbound_header_list_size_; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc index 04605e1faf7..942688a62e7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc @@ -69,7 +69,7 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { kInitialStreamFlowControlWindowForTest); session()->config()->SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); - session()->config()->ToHandshakeMessage(&msg); + session()->config()->ToHandshakeMessage(&msg, transport_version()); const QuicErrorCode error = session()->config()->ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); @@ -94,7 +94,7 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { MOCK_METHOD0(OnCanWrite, void()); - bool HasPendingCryptoRetransmission() override { return false; } + bool HasPendingCryptoRetransmission() const override { return false; } MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); @@ -241,9 +241,8 @@ class TestSession : public QuicSpdySession { QuicConsumedData SendStreamData(QuicStream* stream) { struct iovec iov; - if ((QuicVersionUsesCryptoFrames(connection()->transport_version()) || - stream->id() != - QuicUtils::GetCryptoStreamId(connection()->transport_version())) && + if (!QuicUtils::IsCryptoStreamId(connection()->transport_version(), + stream->id()) && connection()->encryption_level() != ENCRYPTION_FORWARD_SECURE) { this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); } @@ -267,7 +266,8 @@ class TestSession : public QuicSpdySession { using QuicSession::closed_streams; using QuicSession::zombie_streams; - using QuicSpdySession::ShouldBufferIncomingStream; + using QuicSpdySession::ProcessPendingStream; + using QuicSpdySession::UsesPendingStreams; private: StrictMock<TestCryptoStream> crypto_stream_; @@ -277,8 +277,8 @@ class TestSession : public QuicSpdySession { class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { public: - bool ClearMaxStreamIdControlFrame(const QuicFrame& frame) { - if (frame.type == MAX_STREAM_ID_FRAME) { + bool ClearMaxStreamsControlFrame(const QuicFrame& frame) { + if (frame.type == MAX_STREAMS_FRAME) { DeleteFrame(&const_cast<QuicFrame&>(frame)); return true; } @@ -380,6 +380,24 @@ class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { return QuicUtils::StreamIdDelta(connection_->transport_version()); } + QuicStreamId StreamCountToId(QuicStreamCount stream_count, + Perspective perspective, + bool bidirectional) { + // Calculate and build up stream ID rather than use + // GetFirst... because the test that relies on this method + // needs to do the stream count where #1 is 0/1/2/3, and not + // take into account that stream 0 is special. + QuicStreamId id = + ((stream_count - 1) * QuicUtils::StreamIdDelta(QUIC_VERSION_99)); + if (!bidirectional) { + id |= 0x2; + } + if (perspective == Perspective::IS_SERVER) { + id |= 0x1; + } + return id; + } + MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; StrictMock<MockQuicConnection>* connection_; @@ -398,22 +416,11 @@ INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdySessionTestServer, ::testing::ValuesIn(AllSupportedVersions())); -TEST_P(QuicSpdySessionTestServer, ShouldBufferIncomingStreamUnidirectional) { - if (!IsVersion99()) { +TEST_P(QuicSpdySessionTestServer, UsesPendingStreams) { + if (!VersionHasStreamType(transport_version())) { return; } - EXPECT_TRUE(session_.ShouldBufferIncomingStream( - QuicUtils::GetFirstUnidirectionalStreamId( - connection_->transport_version(), Perspective::IS_CLIENT))); -} - -TEST_P(QuicSpdySessionTestServer, ShouldBufferIncomingStreamBidirectional) { - if (!IsVersion99()) { - return; - } - EXPECT_FALSE(session_.ShouldBufferIncomingStream( - QuicUtils::GetFirstBidirectionalStreamId(connection_->transport_version(), - Perspective::IS_CLIENT))); + EXPECT_TRUE(session_.UsesPendingStreams()); } TEST_P(QuicSpdySessionTestServer, PeerAddress) { @@ -426,6 +433,7 @@ TEST_P(QuicSpdySessionTestServer, SelfAddress) { } TEST_P(QuicSpdySessionTestServer, IsCryptoHandshakeConfirmed) { + EXPECT_CALL(*connection_, CloseConnection(_, _, _)); EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed()); CryptoHandshakeMessage message; session_.GetMutableCryptoStream()->OnHandshakeMessage(message); @@ -496,28 +504,35 @@ TEST_P(QuicSpdySessionTestServer, MaximumAvailableOpenedStreams) { // stream ID, the next ID should fail. Since the actual limit // is not the number of open streams, we allocate the max and the max+2. // Get the max allowed stream ID, this should succeed. - EXPECT_NE(nullptr, - session_.GetOrCreateDynamicStream( - QuicSessionPeer::v99_streamid_manager(&session_) - ->actual_max_allowed_incoming_bidirectional_stream_id())); - EXPECT_NE( - nullptr, - session_.GetOrCreateDynamicStream( - QuicSessionPeer::v99_streamid_manager(&session_) - ->actual_max_allowed_incoming_unidirectional_stream_id())); - EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1); - // Get the (max allowed stream ID)++, this should fail. - EXPECT_EQ(nullptr, - session_.GetOrCreateDynamicStream( - QuicSessionPeer::v99_streamid_manager(&session_) - ->actual_max_allowed_incoming_bidirectional_stream_id() + - IdDelta())); - EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1); - EXPECT_EQ(nullptr, - session_.GetOrCreateDynamicStream( - QuicSessionPeer::v99_streamid_manager(&session_) - ->actual_max_allowed_incoming_unidirectional_stream_id() + - IdDelta())); + QuicStreamId stream_id = StreamCountToId( + QuicSessionPeer::v99_streamid_manager(&session_) + ->actual_max_allowed_incoming_bidirectional_streams(), + Perspective::IS_CLIENT, // Client initates stream, allocs stream id. + /*bidirectional=*/true); + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); + stream_id = StreamCountToId( + QuicSessionPeer::v99_streamid_manager(&session_) + ->actual_max_allowed_incoming_unidirectional_streams(), + Perspective::IS_CLIENT, + /*bidirectional=*/false); + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(2); + // Get the (max allowed stream ID)++. These should all fail. + stream_id = StreamCountToId( + QuicSessionPeer::v99_streamid_manager(&session_) + ->actual_max_allowed_incoming_bidirectional_streams() + + 1, + Perspective::IS_CLIENT, + /*bidirectional=*/true); + EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id)); + + stream_id = StreamCountToId( + QuicSessionPeer::v99_streamid_manager(&session_) + ->actual_max_allowed_incoming_unidirectional_streams() + + 1, + Perspective::IS_CLIENT, + /*bidirectional=*/false); + EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id)); } else { QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); session_.GetOrCreateDynamicStream(stream_id); @@ -550,15 +565,20 @@ TEST_P(QuicSpdySessionTestServer, TooManyAvailableStreams) { TEST_P(QuicSpdySessionTestServer, ManyAvailableStreams) { // When max_open_streams_ is 200, should be able to create 200 streams // out-of-order, that is, creating the one with the largest stream ID first. - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + if (IsVersion99()) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, 200); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + } QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); // Create one stream. session_.GetOrCreateDynamicStream(stream_id); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); // Stream count is 200, GetNth... starts counting at 0, so the 200'th stream - // is 199. + // is 199. BUT actually we need to do 198 because the crypto stream (Stream + // ID 0) has not been registered, but GetNth... assumes that it has. EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream( - GetNthClientInitiatedBidirectionalId(199))); + GetNthClientInitiatedBidirectionalId(198))); } TEST_P(QuicSpdySessionTestServer, @@ -679,7 +699,7 @@ TEST_P(QuicSpdySessionTestServer, OnCanWriteBundlesStreams) { if (IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillRepeatedly(Invoke( - this, &QuicSpdySessionTestServer::ClearMaxStreamIdControlFrame)); + this, &QuicSpdySessionTestServer::ClearMaxStreamsControlFrame)); } // Encryption needs to be established before data can be sent. CryptoHandshakeMessage msg; @@ -796,6 +816,12 @@ TEST_P(QuicSpdySessionTestServer, OnCanWriteWriterBlocks) { } TEST_P(QuicSpdySessionTestServer, BufferedHandshake) { + // This tests prioritization of the crypto stream when flow control limits are + // reached. When CRYPTO frames are in use, there is no flow control for the + // crypto handshake, so this test is irrelevant. + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + return; + } session_.set_writev_consumes_all_data(true); EXPECT_FALSE(session_.HasPendingHandshake()); // Default value. @@ -883,8 +909,10 @@ TEST_P(QuicSpdySessionTestServer, // Mark the crypto and headers streams as write blocked, we expect them to be // allowed to write later. - session_.MarkConnectionLevelWriteBlocked( - QuicUtils::GetCryptoStreamId(connection_->transport_version())); + if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + session_.MarkConnectionLevelWriteBlocked( + QuicUtils::GetCryptoStreamId(connection_->transport_version())); + } // Create a data stream, and although it is write blocked we never expect it // to be allowed to write as we are connection level flow control blocked. @@ -894,11 +922,21 @@ TEST_P(QuicSpdySessionTestServer, // The crypto and headers streams should be called even though we are // connection flow control blocked. - TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); - EXPECT_CALL(*crypto_stream, OnCanWrite()); - QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr); - TestHeadersStream* headers_stream = new TestHeadersStream(&session_); - QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream); + if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); + EXPECT_CALL(*crypto_stream, OnCanWrite()); + } + TestHeadersStream* headers_stream; + if (!GetQuicReloadableFlag(quic_eliminate_static_stream_map_3) && + !QuicVersionUsesCryptoFrames(connection_->transport_version())) { + QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr); + headers_stream = new TestHeadersStream(&session_); + QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream); + } else { + QuicSpdySessionPeer::SetUnownedHeadersStream(&session_, nullptr); + headers_stream = new TestHeadersStream(&session_); + QuicSpdySessionPeer::SetUnownedHeadersStream(&session_, headers_stream); + } session_.MarkConnectionLevelWriteBlocked( QuicUtils::GetHeadersStreamId(connection_->transport_version())); EXPECT_CALL(*headers_stream, OnCanWrite()); @@ -983,6 +1021,7 @@ TEST_P(QuicSpdySessionTestServer, ServerReplyToConnecitivityProbe) { } TEST_P(QuicSpdySessionTestServer, IncreasedTimeoutAfterCryptoHandshake) { + EXPECT_CALL(*connection_, CloseConnection(_, _, _)); EXPECT_EQ(kInitialIdleTimeoutSecs + 3, QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); CryptoHandshakeMessage msg; @@ -1034,7 +1073,7 @@ TEST_P(QuicSpdySessionTestServer, RstStreamBeforeHeadersDecompressed) { TEST_P(QuicSpdySessionTestServer, OnStreamFrameFinStaticStreamId) { // Send two bytes of payload. QuicStreamFrame data1( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), true, 0, + QuicUtils::GetHeadersStreamId(connection_->transport_version()), true, 0, QuicStringPiece("HT")); EXPECT_CALL(*connection_, CloseConnection( @@ -1047,7 +1086,7 @@ TEST_P(QuicSpdySessionTestServer, OnRstStreamStaticStreamId) { // Send two bytes of payload. QuicRstStreamFrame rst1( kInvalidControlFrameId, - QuicUtils::GetCryptoStreamId(connection_->transport_version()), + QuicUtils::GetHeadersStreamId(connection_->transport_version()), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(*connection_, CloseConnection( @@ -1145,7 +1184,7 @@ TEST_P(QuicSpdySessionTestServer, QuicStreamOffset offset = crypto_stream->stream_bytes_written(); QuicConfig config; CryptoHandshakeMessage crypto_message; - config.ToHandshakeMessage(&crypto_message); + config.ToHandshakeMessage(&crypto_message, transport_version()); crypto_stream->SendHandshakeMessage(crypto_message); char buf[1000]; QuicDataWriter writer(1000, buf, NETWORK_BYTE_ORDER); @@ -1179,6 +1218,18 @@ TEST_P(QuicSpdySessionTestServer, // various names that are dependent on the parameters passed. TEST_P(QuicSpdySessionTestServer, HandshakeUnblocksFlowControlBlockedHeadersStream) { + // This test depends on stream-level flow control for the crypto stream, which + // doesn't exist when CRYPTO frames are used. + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + return; + } + + // This test depends on the headers stream, which does not exist when QPACK is + // used. + if (VersionUsesQpack(transport_version())) { + return; + } + // Test that if the header stream is flow control blocked, then if the SHLO // contains a larger send window offset, the stream becomes unblocked. session_.set_writev_consumes_all_data(true); @@ -1461,7 +1512,22 @@ TEST_P(QuicSpdySessionTestServer, // with a FIN or RST then we send an RST to refuse streams for versions other // than version 99. In version 99 the connection gets closed. const QuicStreamId kMaxStreams = 5; - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + if (IsVersion99()) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, + kMaxStreams); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + } + // GetNth assumes that both the crypto and header streams have been + // open, but the stream id manager, using GetFirstBidirectional... only + // assumes that the crypto stream is open. This means that GetNth...(0) + // Will return stream ID == 8 (with id ==0 for crypto and id==4 for headers). + // It also means that GetNth(kMax..=5) returns 28 (streams 0/1/2/3/4 are ids + // 8, 12, 16, 20, 24, respectively, so stream#5 is stream id 28). + // However, the stream ID manager does not assume stream 4 is for headers. + // The ID manager would assume that stream#5 is streamid 24. + // In order to make this all work out properly, kFinalStreamId will + // be set to GetNth...(kMaxStreams-1)... but only for V99 const QuicStreamId kFirstStreamId = GetNthClientInitiatedBidirectionalId(0); const QuicStreamId kFinalStreamId = GetNthClientInitiatedBidirectionalId(kMaxStreams); @@ -1498,8 +1564,10 @@ TEST_P(QuicSpdySessionTestServer, .Times(1); } else { // On version 99 opening such a stream results in a connection close. - EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, - "Stream id 28 above 24", _)); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_STREAM_ID, + "Stream id 24 would exceed stream count limit 6", _)); } // Create one more data streams to exceed limit of open stream. QuicStreamFrame data1(kFinalStreamId, false, 0, QuicStringPiece("HT")); @@ -1511,10 +1579,10 @@ TEST_P(QuicSpdySessionTestServer, DrainingStreamsDoNotCountAsOpened) { // it) does not count against the open quota (because it is closed from the // protocol point of view). if (IsVersion99()) { - // Version 99 will result in a MAX_STREAM_ID frame as streams are consumed + // Version 99 will result in a MAX_STREAMS frame as streams are consumed // (via the OnStreamFrame call) and then released (via // StreamDraining). Eventually this node will believe that the peer is - // running low on available stream ids and then send a MAX_STREAM_ID frame, + // running low on available stream ids and then send a MAX_STREAMS frame, // caught by this EXPECT_CALL. EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); } else { @@ -1522,7 +1590,12 @@ TEST_P(QuicSpdySessionTestServer, DrainingStreamsDoNotCountAsOpened) { } EXPECT_CALL(*connection_, OnStreamReset(_, QUIC_REFUSED_STREAM)).Times(0); const QuicStreamId kMaxStreams = 5; - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + if (IsVersion99()) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, + kMaxStreams); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + } // Create kMaxStreams + 1 data streams, and mark them draining. const QuicStreamId kFirstStreamId = GetNthClientInitiatedBidirectionalId(0); @@ -1547,6 +1620,13 @@ INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdySessionTestClient, ::testing::ValuesIn(AllSupportedVersions())); +TEST_P(QuicSpdySessionTestClient, UsesPendingStreams) { + if (!VersionHasStreamType(transport_version())) { + return; + } + EXPECT_TRUE(session_.UsesPendingStreams()); +} + TEST_P(QuicSpdySessionTestClient, AvailableStreamsClient) { ASSERT_TRUE(session_.GetOrCreateDynamicStream( GetNthServerInitiatedBidirectionalId(2)) != nullptr); @@ -1597,9 +1677,17 @@ TEST_P(QuicSpdySessionTestClient, RecordFinAfterReadSideClosed) { } TEST_P(QuicSpdySessionTestClient, WritePriority) { - QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr); - TestHeadersStream* headers_stream = new TestHeadersStream(&session_); - QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream); + TestHeadersStream* headers_stream; + if (!GetQuicReloadableFlag(quic_eliminate_static_stream_map_3) && + !QuicVersionUsesCryptoFrames(connection_->transport_version())) { + QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr); + headers_stream = new TestHeadersStream(&session_); + QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream); + } else { + QuicSpdySessionPeer::SetUnownedHeadersStream(&session_, nullptr); + headers_stream = new TestHeadersStream(&session_); + QuicSpdySessionPeer::SetUnownedHeadersStream(&session_, headers_stream); + } // Make packet writer blocked so |headers_stream| will buffer its write data. MockPacketWriter* writer = static_cast<MockPacketWriter*>( @@ -1632,6 +1720,55 @@ TEST_P(QuicSpdySessionTestClient, WritePriority) { } } +TEST_P(QuicSpdySessionTestClient, Http3ServerPush) { + if (!VersionHasStreamType(transport_version())) { + return; + } + + char type[] = {0x01}; + std::string data = std::string(type, 1) + "header"; + EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + QuicStreamId stream_id1 = + GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0); + QuicStreamFrame data1(stream_id1, false, 0, QuicStringPiece(data)); + session_.OnStreamFrame(data1); + EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); + QuicStream* stream = session_.GetOrCreateDynamicStream(stream_id1); + EXPECT_EQ(1u, stream->flow_controller()->bytes_consumed()); + EXPECT_EQ(1u, session_.flow_controller()->bytes_consumed()); + + char unoptimized_type[] = {0x80, 0x00, 0x00, 0x01}; + data = std::string(unoptimized_type, 4) + "header"; + QuicStreamId stream_id2 = + GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 1); + QuicStreamFrame data2(stream_id2, false, 0, QuicStringPiece(data)); + session_.OnStreamFrame(data2); + EXPECT_EQ(2u, session_.GetNumOpenIncomingStreams()); + stream = session_.GetOrCreateDynamicStream(stream_id2); + EXPECT_EQ(4u, stream->flow_controller()->bytes_consumed()); + EXPECT_EQ(5u, session_.flow_controller()->bytes_consumed()); +} + +TEST_P(QuicSpdySessionTestClient, Http3ServerPushOutofOrderFrame) { + if (!VersionHasStreamType(transport_version())) { + return; + } + + char type[] = {0x01}; + EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + QuicStreamFrame data1( + GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0), + false, 1, QuicStringPiece("header")); + session_.OnStreamFrame(data1); + EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + + QuicStreamFrame data2( + GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0), + false, 0, QuicStringPiece(type, 1)); + session_.OnStreamFrame(data2); + EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); +} + TEST_P(QuicSpdySessionTestServer, ZombieStreams) { TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); QuicStreamPeer::SetStreamBytesWritten(3, stream2); @@ -1803,6 +1940,75 @@ TEST_P(QuicSpdySessionTestServer, OnPriorityFrame) { EXPECT_EQ(kV3HighestPriority, stream->priority()); } +TEST_P(QuicSpdySessionTestServer, SimplePendingStreamType) { + if (!VersionHasStreamType(transport_version())) { + return; + } + PendingStream pending(QuicUtils::GetFirstUnidirectionalStreamId( + transport_version(), Perspective::IS_CLIENT), + &session_); + char input[] = {// type + 0x04, + // data + 'a', 'b', 'c'}; + QuicStreamFrame data(pending.id(), true, 0, QuicStringPiece(input, 4)); + pending.OnStreamFrame(data); + + // A stop sending frame will be sent to indicate unknown type. + EXPECT_CALL(*connection_, SendControlFrame(_)); + session_.ProcessPendingStream(&pending); +} + +TEST_P(QuicSpdySessionTestServer, SimplePendingStreamTypeOutOfOrderDelivery) { + if (!VersionHasStreamType(transport_version())) { + return; + } + PendingStream pending(QuicUtils::GetFirstUnidirectionalStreamId( + transport_version(), Perspective::IS_CLIENT), + &session_); + char input[] = {// type + 0x04, + // data + 'a', 'b', 'c'}; + QuicStreamFrame data1(pending.id(), true, 1, QuicStringPiece(&input[1], 3)); + pending.OnStreamFrame(data1); + session_.ProcessPendingStream(&pending); + + QuicStreamFrame data2(pending.id(), false, 0, QuicStringPiece(input, 1)); + pending.OnStreamFrame(data2); + + EXPECT_CALL(*connection_, SendControlFrame(_)); + session_.ProcessPendingStream(&pending); +} + +TEST_P(QuicSpdySessionTestServer, + MultipleBytesPendingStreamTypeOutOfOrderDelivery) { + if (!VersionHasStreamType(transport_version())) { + return; + } + PendingStream pending(QuicUtils::GetFirstUnidirectionalStreamId( + transport_version(), Perspective::IS_CLIENT), + &session_); + char input[] = {// type (256) + 0x40 + 0x01, 0x00, + // data + 'a', 'b', 'c'}; + + QuicStreamFrame data1(pending.id(), true, 2, QuicStringPiece(&input[2], 3)); + pending.OnStreamFrame(data1); + session_.ProcessPendingStream(&pending); + + QuicStreamFrame data2(pending.id(), false, 0, QuicStringPiece(input, 1)); + pending.OnStreamFrame(data2); + session_.ProcessPendingStream(&pending); + + QuicStreamFrame data3(pending.id(), false, 1, QuicStringPiece(&input[1], 1)); + pending.OnStreamFrame(data3); + + EXPECT_CALL(*connection_, SendControlFrame(_)); + session_.ProcessPendingStream(&pending); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc index 674b0760d23..d424cc04bc7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc @@ -4,13 +4,19 @@ #include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h" +#include <limits> #include <string> #include <utility> #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" @@ -139,19 +145,23 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id, StreamType type) : QuicStream(id, spdy_session, /*is_static=*/false, type), spdy_session_(spdy_session), + on_body_available_called_because_sequencer_is_closed_(false), visitor_(nullptr), headers_decompressed_(false), + headers_length_(0, 0), + trailers_length_(0, 0), trailers_decompressed_(false), trailers_consumed_(false), http_decoder_visitor_(new HttpDecoderVisitor(this)), body_buffer_(sequencer()), ack_listener_(nullptr) { - DCHECK_NE(QuicUtils::GetCryptoStreamId( - spdy_session->connection()->transport_version()), - id); - // Don't receive any callbacks from the sequencer until headers - // are complete. - sequencer()->SetBlockedUntilFlush(); + DCHECK(!QuicUtils::IsCryptoStreamId( + spdy_session->connection()->transport_version(), id)); + // If headers are sent on the headers stream, then do not receive any + // callbacks from the sequencer until headers are complete. + if (!VersionUsesQpack(spdy_session_->connection()->transport_version())) { + sequencer()->SetBlockedUntilFlush(); + } if (VersionHasDataFrameHeader( spdy_session_->connection()->transport_version())) { @@ -163,21 +173,25 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id, QuicSpdyStream::QuicSpdyStream(PendingStream pending, QuicSpdySession* spdy_session, StreamType type) - : QuicStream(std::move(pending), type), + : QuicStream(std::move(pending), type, /*is_static=*/false), spdy_session_(spdy_session), + on_body_available_called_because_sequencer_is_closed_(false), visitor_(nullptr), headers_decompressed_(false), + headers_length_(0, 0), + trailers_length_(0, 0), trailers_decompressed_(false), trailers_consumed_(false), http_decoder_visitor_(new HttpDecoderVisitor(this)), body_buffer_(sequencer()), ack_listener_(nullptr) { - DCHECK_NE(QuicUtils::GetCryptoStreamId( - spdy_session->connection()->transport_version()), - id()); - // Don't receive any callbacks from the sequencer until headers - // are complete. - sequencer()->SetBlockedUntilFlush(); + DCHECK(!QuicUtils::IsCryptoStreamId( + spdy_session->connection()->transport_version(), id())); + // If headers are sent on the headers stream, then do not receive any + // callbacks from the sequencer until headers are complete. + if (!VersionUsesQpack(spdy_session_->connection()->transport_version())) { + sequencer()->SetBlockedUntilFlush(); + } if (VersionHasDataFrameHeader( spdy_session_->connection()->transport_version())) { @@ -192,9 +206,30 @@ size_t QuicSpdyStream::WriteHeaders( SpdyHeaderBlock header_block, bool fin, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + QuicConnection::ScopedPacketFlusher flusher( + spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING); + // Send stream type for server push stream + if (VersionHasStreamType(session()->connection()->transport_version()) && + type() == WRITE_UNIDIRECTIONAL && send_buffer().stream_offset() == 0) { + char data[sizeof(kServerPushStream)]; + QuicDataWriter writer(QUIC_ARRAYSIZE(data), data); + writer.WriteVarInt62(kServerPushStream); + + // Similar to frame headers, stream type byte shouldn't be exposed to upper + // layer applications. + unacked_frame_headers_offsets_.Add(0, writer.length()); + + QUIC_LOG(INFO) << "Stream " << id() << " is writing type as server push"; + WriteOrBufferData(QuicStringPiece(writer.data(), writer.length()), false, + nullptr); + } size_t bytes_written = WriteHeadersImpl(std::move(header_block), fin, std::move(ack_listener)); - if (fin) { + if (!VersionUsesQpack(spdy_session_->connection()->transport_version()) && + fin) { + // If HEADERS are sent on the headers stream, then |fin_sent_| needs to be + // set and write side needs to be closed without actually sending a FIN on + // this stream. // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent. set_fin_sent(true); CloseWriteSide(); @@ -219,13 +254,15 @@ void QuicSpdyStream::WriteOrBufferBody(QuicStringPiece data, bool fin) { unacked_frame_headers_offsets_.Add( send_buffer().stream_offset(), send_buffer().stream_offset() + header_length); - QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length " + QUIC_DLOG(INFO) << "Stream " << id() + << " is writing DATA frame header of length " << header_length; WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false, nullptr); // Write body. - QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length " + QUIC_DLOG(INFO) << "Stream " << id() + << " is writing DATA frame payload of length " << data.length(); WriteOrBufferData(data, fin, nullptr); } @@ -238,26 +275,33 @@ size_t QuicSpdyStream::WriteTrailers( return 0; } - // The header block must contain the final offset for this stream, as the - // trailers may be processed out of order at the peer. - QUIC_DLOG(INFO) << "Inserting trailer: (" << kFinalOffsetHeaderKey << ", " - << stream_bytes_written() + BufferedDataBytes() << ")"; - trailer_block.insert( - std::make_pair(kFinalOffsetHeaderKey, - QuicTextUtils::Uint64ToString(stream_bytes_written() + - BufferedDataBytes()))); + if (!VersionUsesQpack(spdy_session_->connection()->transport_version())) { + // The header block must contain the final offset for this stream, as the + // trailers may be processed out of order at the peer. + const QuicStreamOffset final_offset = + stream_bytes_written() + BufferedDataBytes(); + QUIC_DLOG(INFO) << "Inserting trailer: (" << kFinalOffsetHeaderKey << ", " + << final_offset << ")"; + trailer_block.insert(std::make_pair( + kFinalOffsetHeaderKey, QuicTextUtils::Uint64ToString(final_offset))); + } // Write the trailing headers with a FIN, and close stream for writing: // trailers are the last thing to be sent on a stream. const bool kFin = true; size_t bytes_written = WriteHeadersImpl(std::move(trailer_block), kFin, std::move(ack_listener)); - set_fin_sent(kFin); - // Trailers are the last thing to be sent on a stream, but if there is still - // queued data then CloseWriteSide() will cause it never to be sent. - if (BufferedDataBytes() == 0) { - CloseWriteSide(); + // If trailers are sent on the headers stream, then |fin_sent_| needs to be + // set without actually sending a FIN on this stream. + if (!VersionUsesQpack(spdy_session_->connection()->transport_version())) { + set_fin_sent(kFin); + + // Also, write side of this stream needs to be closed. However, only do + // this if there is no more buffered data, otherwise it will never be sent. + if (BufferedDataBytes() == 0) { + CloseWriteSide(); + } } return bytes_written; @@ -300,12 +344,14 @@ QuicConsumedData QuicSpdyStream::WriteBodySlices(QuicMemSliceSpan slices, unacked_frame_headers_offsets_.Add( send_buffer().stream_offset(), send_buffer().stream_offset() + header_length); - QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length " + QUIC_DLOG(INFO) << "Stream " << id() + << " is writing DATA frame header of length " << header_length; WriteMemSlices(storage.ToSpan(), false); // Write body. - QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length " + QUIC_DLOG(INFO) << "Stream " << id() + << " is writing DATA frame payload of length " << slices.total_length(); return WriteMemSlices(slices, fin); } @@ -354,6 +400,15 @@ bool QuicSpdyStream::HasBytesToRead() const { } void QuicSpdyStream::MarkTrailersConsumed() { + if (VersionUsesQpack(spdy_session_->connection()->transport_version()) && + !reading_stopped()) { + const QuicByteCount trailers_total_length = + trailers_length_.header_length + trailers_length_.payload_length; + if (trailers_total_length > 0) { + sequencer()->MarkConsumed(trailers_total_length); + } + } + trailers_consumed_ = true; } @@ -367,8 +422,35 @@ uint64_t QuicSpdyStream::total_body_bytes_read() const { void QuicSpdyStream::ConsumeHeaderList() { header_list_.Clear(); - if (FinishedReadingHeaders()) { - sequencer()->SetUnblocked(); + + if (!VersionUsesQpack(spdy_session_->connection()->transport_version())) { + if (FinishedReadingHeaders()) { + sequencer()->SetUnblocked(); + } + return; + } + + if (!reading_stopped()) { + const QuicByteCount headers_total_length = + headers_length_.header_length + headers_length_.payload_length; + if (headers_total_length > 0) { + sequencer()->MarkConsumed(headers_total_length); + } + } + + if (!FinishedReadingHeaders()) { + return; + } + + if (body_buffer_.HasBytesToRead()) { + OnBodyAvailable(); + return; + } + + if (sequencer()->IsClosed() && + !on_body_available_called_because_sequencer_is_closed_) { + on_body_available_called_because_sequencer_is_closed_ = true; + OnBodyAvailable(); } } @@ -400,7 +482,15 @@ void QuicSpdyStream::OnStreamHeaderList(bool fin, } void QuicSpdyStream::OnHeadersTooLarge() { - Reset(QUIC_HEADERS_TOO_LARGE); + if (VersionUsesQpack(spdy_session_->connection()->transport_version())) { + // TODO(124216424): Use HTTP_EXCESSIVE_LOAD error code. + std::string error_message = + QuicStrCat("Too large headers received on stream ", id()); + CloseConnectionWithDetails(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, + error_message); + } else { + Reset(QUIC_HEADERS_TOO_LARGE); + } } void QuicSpdyStream::OnInitialHeadersComplete( @@ -409,8 +499,20 @@ void QuicSpdyStream::OnInitialHeadersComplete( const QuicHeaderList& header_list) { headers_decompressed_ = true; header_list_ = header_list; + + if (VersionUsesQpack(spdy_session_->connection()->transport_version())) { + if (fin) { + OnStreamFrame( + QuicStreamFrame(id(), /* fin = */ true, + flow_controller()->highest_received_byte_offset(), + QuicStringPiece())); + } + return; + } + if (fin) { - OnStreamFrame(QuicStreamFrame(id(), fin, 0, QuicStringPiece())); + OnStreamFrame( + QuicStreamFrame(id(), fin, /* offset = */ 0, QuicStringPiece())); } if (FinishedReadingHeaders()) { sequencer()->SetUnblocked(); @@ -433,15 +535,20 @@ void QuicSpdyStream::OnTrailingHeadersComplete( size_t /*frame_len*/, const QuicHeaderList& header_list) { DCHECK(!trailers_decompressed_); - if (fin_received()) { - QUIC_DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id(); + if ((VersionUsesQpack(spdy_session_->connection()->transport_version()) && + sequencer()->IsClosed()) || + (!VersionUsesQpack(spdy_session_->connection()->transport_version()) && + fin_received())) { + QUIC_DLOG(INFO) << "Received Trailers after FIN, on stream: " << id(); session()->connection()->CloseConnection( QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; } - if (!fin) { - QUIC_DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id(); + + if (!VersionUsesQpack(spdy_session_->connection()->transport_version()) && + !fin) { + QUIC_DLOG(INFO) << "Trailers must have FIN set, on stream: " << id(); session()->connection()->CloseConnection( QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -449,8 +556,9 @@ void QuicSpdyStream::OnTrailingHeadersComplete( } size_t final_byte_offset = 0; - if (!SpdyUtils::CopyAndValidateTrailers(header_list, - /* expect_final_byte_offset = */ true, + const bool expect_final_byte_offset = + !VersionUsesQpack(spdy_session_->connection()->transport_version()); + if (!SpdyUtils::CopyAndValidateTrailers(header_list, expect_final_byte_offset, &final_byte_offset, &received_trailers_)) { QUIC_DLOG(ERROR) << "Trailers for stream " << id() << " are malformed."; @@ -460,16 +568,12 @@ void QuicSpdyStream::OnTrailingHeadersComplete( return; } trailers_decompressed_ = true; + const QuicStreamOffset offset = + VersionUsesQpack(spdy_session_->connection()->transport_version()) + ? flow_controller()->highest_received_byte_offset() + : final_byte_offset; OnStreamFrame( - QuicStreamFrame(id(), fin, final_byte_offset, QuicStringPiece())); -} - -size_t QuicSpdyStream::WriteHeadersImpl( - spdy::SpdyHeaderBlock header_block, - bool fin, - QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { - return spdy_session_->WriteHeadersOnHeadersStream( - id(), std::move(header_block), fin, priority(), std::move(ack_listener)); + QuicStreamFrame(id(), /* fin = */ true, offset, QuicStringPiece())); } void QuicSpdyStream::OnPriorityFrame(SpdyPriority priority) { @@ -490,7 +594,10 @@ void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) { } void QuicSpdyStream::OnDataAvailable() { - DCHECK(FinishedReadingHeaders()); + if (!VersionUsesQpack(spdy_session_->connection()->transport_version())) { + // Sequencer must be blocked until headers are consumed. + DCHECK(FinishedReadingHeaders()); + } if (!VersionHasDataFrameHeader( session()->connection()->transport_version())) { @@ -504,14 +611,20 @@ void QuicSpdyStream::OnDataAvailable() { iov.iov_len); } + // Do not call OnBodyAvailable() until headers are consumed. + if (!FinishedReadingHeaders()) { + return; + } + if (body_buffer_.HasBytesToRead()) { OnBodyAvailable(); return; } - if (sequencer()->IsClosed()) { + if (sequencer()->IsClosed() && + !on_body_available_called_because_sequencer_is_closed_) { + on_body_available_called_because_sequencer_is_closed_ = true; OnBodyAvailable(); - return; } } @@ -594,8 +707,8 @@ void QuicSpdyStream::OnDataFramePayload(QuicStringPiece payload) { void QuicSpdyStream::OnDataFrameEnd() { DCHECK( VersionHasDataFrameHeader(session()->connection()->transport_version())); - DVLOG(1) << "Reaches the end of a data frame. Total bytes received are " - << body_buffer_.total_body_bytes_received(); + QUIC_DVLOG(1) << "Reaches the end of a data frame. Total bytes received are " + << body_buffer_.total_body_bytes_received(); } bool QuicSpdyStream::OnStreamFrameAcked(QuicStreamOffset offset, @@ -647,14 +760,96 @@ QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval( void QuicSpdyStream::OnHeadersFrameStart(Http3FrameLengths frame_length) { DCHECK(VersionUsesQpack(spdy_session_->connection()->transport_version())); + DCHECK(!qpack_decoded_headers_accumulator_); + + if (headers_decompressed_) { + trailers_length_ = frame_length; + } else { + headers_length_ = frame_length; + } + + qpack_decoded_headers_accumulator_ = + QuicMakeUnique<QpackDecodedHeadersAccumulator>( + id(), spdy_session_->qpack_decoder(), + spdy_session_->max_inbound_header_list_size()); } void QuicSpdyStream::OnHeadersFramePayload(QuicStringPiece payload) { DCHECK(VersionUsesQpack(spdy_session_->connection()->transport_version())); + + if (!qpack_decoded_headers_accumulator_->Decode(payload)) { + // TODO(124216424): Use HTTP_QPACK_DECOMPRESSION_FAILED error code. + std::string error_message = + QuicStrCat("Error decompressing header block on stream ", id(), ": ", + qpack_decoded_headers_accumulator_->error_message()); + CloseConnectionWithDetails(QUIC_DECOMPRESSION_FAILURE, error_message); + return; + } } void QuicSpdyStream::OnHeadersFrameEnd() { DCHECK(VersionUsesQpack(spdy_session_->connection()->transport_version())); + + if (!qpack_decoded_headers_accumulator_->EndHeaderBlock()) { + // TODO(124216424): Use HTTP_QPACK_DECOMPRESSION_FAILED error code. + std::string error_message = + QuicStrCat("Error decompressing header block on stream ", id(), ": ", + qpack_decoded_headers_accumulator_->error_message()); + CloseConnectionWithDetails(QUIC_DECOMPRESSION_FAILURE, error_message); + return; + } + + const QuicByteCount frame_length = headers_decompressed_ + ? trailers_length_.payload_length + : headers_length_.payload_length; + OnStreamHeaderList(/* fin = */ false, frame_length, + qpack_decoded_headers_accumulator_->quic_header_list()); + + qpack_decoded_headers_accumulator_.reset(); +} + +size_t QuicSpdyStream::WriteHeadersImpl( + spdy::SpdyHeaderBlock header_block, + bool fin, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + if (!VersionUsesQpack(spdy_session_->connection()->transport_version())) { + return spdy_session_->WriteHeadersOnHeadersStream( + id(), std::move(header_block), fin, priority(), + std::move(ack_listener)); + } + + // Encode header list. + auto progressive_encoder = spdy_session_->qpack_encoder()->EncodeHeaderList( + /* stream_id = */ id(), &header_block); + std::string encoded_headers; + while (progressive_encoder->HasNext()) { + progressive_encoder->Next( + /* max_encoded_bytes = */ std::numeric_limits<size_t>::max(), + &encoded_headers); + } + + // Write HEADERS frame. + std::unique_ptr<char[]> headers_frame_header; + const size_t headers_frame_header_length = + encoder_.SerializeHeadersFrameHeader(encoded_headers.size(), + &headers_frame_header); + unacked_frame_headers_offsets_.Add( + send_buffer().stream_offset(), + send_buffer().stream_offset() + headers_frame_header_length); + + QUIC_DLOG(INFO) << "Stream " << id() + << " is writing HEADERS frame header of length " + << headers_frame_header_length; + WriteOrBufferData( + QuicStringPiece(headers_frame_header.get(), headers_frame_header_length), + /* fin = */ false, /* ack_listener = */ nullptr); + + QUIC_DLOG(INFO) << "Stream " << id() + << " is writing HEADERS frame payload of length " + << encoded_headers.length(); + WriteOrBufferData(encoded_headers, fin, nullptr); + + return encoded_headers.size(); } #undef ENDPOINT // undef for jumbo builds diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h index f81a421a44b..dc0d6f5a318 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h @@ -34,6 +34,7 @@ class QuicSpdyStreamPeer; class QuicStreamPeer; } // namespace test +class QpackDecodedHeadersAccumulator; class QuicSpdySession; // A QUIC stream that can send and receive HTTP2 (SPDY) headers. @@ -105,8 +106,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream : public QuicStream { // Called in OnDataAvailable() after it finishes the decoding job. virtual void OnBodyAvailable() = 0; - // Writes the headers contained in |header_block| to the dedicated - // headers stream. + // Writes the headers contained in |header_block| on the dedicated headers + // stream or on this stream, depending on VersionUsesQpack(). virtual size_t WriteHeaders( spdy::SpdyHeaderBlock header_block, bool fin, @@ -115,8 +116,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream : public QuicStream { // Sends |data| to the peer, or buffers if it can't be sent immediately. void WriteOrBufferBody(QuicStringPiece data, bool fin); - // Writes the trailers contained in |trailer_block| to the dedicated - // headers stream. Trailers will always have the FIN set. + // Writes the trailers contained in |trailer_block| on the dedicated headers + // stream or on this stream, depending on VersionUsesQpack(). Trailers will + // always have the FIN flag set. virtual size_t WriteTrailers( spdy::SpdyHeaderBlock trailer_block, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); @@ -151,6 +153,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream : public QuicStream { // Clears |header_list_|. void ConsumeHeaderList(); + void SetUnblocked() { sequencer()->SetUnblocked(); } + // This block of functions wraps the sequencer's functions of the same // name. These methods return uncompressed data until that has // been fully processed. Then they simply delegate to the sequencer. @@ -247,12 +251,18 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream : public QuicStream { QuicSpdySession* spdy_session_; + bool on_body_available_called_because_sequencer_is_closed_; + Visitor* visitor_; // True if the headers have been completely decompressed. bool headers_decompressed_; // Contains a copy of the decompressed header (name, value) pairs until they // are consumed via Readv. QuicHeaderList header_list_; + // Length of HEADERS frame, including frame header and payload. + Http3FrameLengths headers_length_; + // Length of TRAILERS frame, including frame header and payload. + Http3FrameLengths trailers_length_; // True if the trailers have been completely decompressed. bool trailers_decompressed_; @@ -265,6 +275,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream : public QuicStream { HttpEncoder encoder_; // Http decoder for processing raw incoming stream frames. HttpDecoder decoder_; + // Headers accumulator for decoding HEADERS frame payload. + std::unique_ptr<QpackDecodedHeadersAccumulator> + qpack_decoded_headers_accumulator_; // Visitor of the HttpDecoder. std::unique_ptr<HttpDecoderVisitor> http_decoder_visitor_; // Buffer that contains decoded data of the stream. diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer_test.cc index ba2dbca22e3..6e8e20d23dd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_buffer_test.cc @@ -6,7 +6,6 @@ #include <string> -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc index 1451533e8e0..eb9a0b3dbb2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc @@ -78,6 +78,11 @@ class TestStream : public QuicSpdyStream { ack_listener) override { saved_headers_ = std::move(header_block); WriteHeadersMock(fin); + if (VersionUsesQpack(transport_version())) { + // In this case, call QuicSpdyStream::WriteHeadersImpl() that does the + // actual work of closing the stream. + QuicSpdyStream::WriteHeadersImpl(saved_headers_.Clone(), fin, nullptr); + } return 0; } @@ -212,10 +217,23 @@ TEST_P(QuicSpdyStreamTest, ProcessTooLargeHeaderList) { QuicHeaderList headers; stream_->OnStreamHeadersPriority(kV3HighestPriority); - EXPECT_CALL(*session_, - SendRstStream(stream_->id(), QUIC_HEADERS_TOO_LARGE, 0)); + const bool version_uses_qpack = + VersionUsesQpack(connection_->transport_version()); + + if (version_uses_qpack) { + EXPECT_CALL(*connection_, + CloseConnection(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, + "Too large headers received on stream 4", _)); + } else { + EXPECT_CALL(*session_, + SendRstStream(stream_->id(), QUIC_HEADERS_TOO_LARGE, 0)); + } + stream_->OnStreamHeaderList(false, 1 << 20, headers); - EXPECT_EQ(QUIC_HEADERS_TOO_LARGE, stream_->stream_error()); + + if (!version_uses_qpack) { + EXPECT_EQ(QUIC_HEADERS_TOO_LARGE, stream_->stream_error()); + } } TEST_P(QuicSpdyStreamTest, ProcessHeaderListWithFin) { @@ -331,7 +349,7 @@ TEST_P(QuicSpdyStreamTest, ProcessWrongFramesOnSpdyStream) { connection_->ReallyCloseConnection(error, error_details, connection_close_behavior); }))); - EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _, _)); + EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _)); EXPECT_CALL(*session_, OnConnectionClosed(_, _, _)) .WillOnce( Invoke([this](QuicErrorCode error, const std::string& error_details, @@ -919,7 +937,11 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersViaHeaderList) { trailers_block["key2"] = "value2"; trailers_block["key3"] = "value3"; SpdyHeaderBlock trailers_block_with_final_offset = trailers_block.Clone(); - trailers_block_with_final_offset[kFinalOffsetHeaderKey] = "0"; + if (!VersionUsesQpack(GetParam().transport_version)) { + // :final-offset pseudo-header is only added if trailers are sent + // on the headers stream. + trailers_block_with_final_offset[kFinalOffsetHeaderKey] = "0"; + } total_bytes = 0; QuicHeaderList trailers; for (const auto& p : trailers_block_with_final_offset) { @@ -943,6 +965,12 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithOffset) { // body, stream is closed at the right offset. Initialize(kShouldProcessData); + // kFinalOffsetHeaderKey is not used when HEADERS are sent on the + // request/response stream. + if (VersionUsesQpack(GetParam().transport_version)) { + return; + } + // Receive initial headers. QuicHeaderList headers = ProcessHeaders(false, headers_); stream_->ConsumeHeaderList(); @@ -988,6 +1016,12 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) { // Test that receiving trailers without a final offset field is an error. Initialize(kShouldProcessData); + // kFinalOffsetHeaderKey is not used when HEADERS are sent on the + // request/response stream. + if (VersionUsesQpack(GetParam().transport_version)) { + return; + } + // Receive initial headers. ProcessHeaders(false, headers_); stream_->ConsumeHeaderList(); @@ -1010,10 +1044,60 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) { trailers.uncompressed_header_bytes(), trailers); } +TEST_P(QuicSpdyStreamTest, ReceivingTrailersOnRequestStream) { + Initialize(kShouldProcessData); + + if (!VersionUsesQpack(GetParam().transport_version)) { + return; + } + + // Receive initial headers. + QuicHeaderList headers = ProcessHeaders(false, headers_); + stream_->ConsumeHeaderList(); + + const std::string body = "this is the body"; + std::unique_ptr<char[]> buf; + QuicByteCount header_length = + encoder_.SerializeDataFrameHeader(body.length(), &buf); + std::string header = std::string(buf.get(), header_length); + std::string data = HasFrameHeader() ? header + body : body; + + // Receive trailing headers. + SpdyHeaderBlock trailers_block; + trailers_block["key1"] = "value1"; + trailers_block["key2"] = "value2"; + trailers_block["key3"] = "value3"; + + QuicHeaderList trailers = ProcessHeaders(true, trailers_block); + + // The trailers should be decompressed, and readable from the stream. + EXPECT_TRUE(stream_->trailers_decompressed()); + + EXPECT_EQ(trailers_block, stream_->received_trailers()); + + // Consuming the trailers erases them from the stream. + stream_->MarkTrailersConsumed(); + EXPECT_TRUE(stream_->FinishedReadingTrailers()); + EXPECT_TRUE(stream_->IsDoneReading()); + + // Receive and consume body. + QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), /*fin=*/false, + 0, data); + stream_->OnStreamFrame(frame); + EXPECT_EQ(body, stream_->data()); + EXPECT_TRUE(stream_->IsDoneReading()); +} + TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutFin) { // Test that received Trailers must always have the FIN set. Initialize(kShouldProcessData); + // In IETF QUIC, there is no such thing as FIN flag on HTTP/3 frames like the + // HEADERS frame. + if (VersionUsesQpack(GetParam().transport_version)) { + return; + } + // Receive initial headers. auto headers = AsHeaderList(headers_); stream_->OnStreamHeaderList(/*fin=*/false, @@ -1053,6 +1137,13 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterBodyWithFin) { // If body data are received with a FIN, no trailers should then arrive. Initialize(kShouldProcessData); + // If HEADERS frames are sent on the request/response stream, + // then the sequencer will block them from reaching QuicSpdyStream + // after the stream is closed. + if (VersionUsesQpack(GetParam().transport_version)) { + return; + } + // Receive initial headers without FIN set. ProcessHeaders(false, headers_); stream_->ConsumeHeaderList(); @@ -1101,6 +1192,12 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersSendsAFin) { // to be sent on a stream. Initialize(kShouldProcessData); + if (VersionUsesQpack(GetParam().transport_version)) { + // In this case, TestStream::WriteHeadersImpl() does not prevent writes. + EXPECT_CALL(*session_, WritevData(stream_, stream_->id(), _, _, _)) + .Times(AtLeast(1)); + } + // Write the initial headers, without a FIN. EXPECT_CALL(*stream_, WriteHeadersMock(false)); stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr); @@ -1118,6 +1215,12 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) { // peer contain the final offset field indicating last byte of data. Initialize(kShouldProcessData); + if (VersionUsesQpack(GetParam().transport_version)) { + // In this case, TestStream::WriteHeadersImpl() does not prevent writes. + EXPECT_CALL(*session_, WritevData(stream_, stream_->id(), _, _, _)) + .Times(AtLeast(1)); + } + // Write the initial headers. EXPECT_CALL(*stream_, WriteHeadersMock(false)); stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr); @@ -1137,12 +1240,18 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) { // number of body bytes written (including queued bytes). SpdyHeaderBlock trailers; trailers["trailer key"] = "trailer value"; - SpdyHeaderBlock trailers_with_offset(trailers.Clone()); - trailers_with_offset[kFinalOffsetHeaderKey] = - QuicTextUtils::Uint64ToString(body.length() + header_length); + + SpdyHeaderBlock expected_trailers(trailers.Clone()); + // :final-offset pseudo-header is only added if trailers are sent + // on the headers stream. + if (!VersionUsesQpack(GetParam().transport_version)) { + expected_trailers[kFinalOffsetHeaderKey] = + QuicTextUtils::Uint64ToString(body.length() + header_length); + } + EXPECT_CALL(*stream_, WriteHeadersMock(true)); stream_->WriteTrailers(std::move(trailers), nullptr); - EXPECT_EQ(trailers_with_offset, stream_->saved_headers()); + EXPECT_EQ(expected_trailers, stream_->saved_headers()); } TEST_P(QuicSpdyStreamTest, WritingTrailersClosesWriteSide) { @@ -1150,12 +1259,16 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersClosesWriteSide) { // (headers and body), that this closes the stream for writing. Initialize(kShouldProcessData); + // Expect data being written on the stream. In addition to that, headers are + // also written on the stream in case of IETF QUIC. + EXPECT_CALL(*session_, WritevData(stream_, stream_->id(), _, _, _)) + .Times(AtLeast(1)); + // Write the initial headers. EXPECT_CALL(*stream_, WriteHeadersMock(false)); stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr); // Write non-zero body data. - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); const int kBodySize = 1 * 1024; // 1 kB stream_->WriteOrBufferBody(std::string(kBodySize, 'x'), false); EXPECT_EQ(0u, stream_->BufferedDataBytes()); @@ -1168,6 +1281,13 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersClosesWriteSide) { } TEST_P(QuicSpdyStreamTest, WritingTrailersWithQueuedBytes) { + // This test exercises sending trailers on the headers stream while data is + // still queued on the response/request stream. In IETF QUIC, data and + // trailers are sent on the same stream, so this test does not apply. + if (VersionUsesQpack(GetParam().transport_version)) { + return; + } + // Test that the stream is not closed for writing when trailers are sent // while there are still body bytes queued. testing::InSequence seq; @@ -1202,7 +1322,10 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersWithQueuedBytes) { TEST_P(QuicSpdyStreamTest, WritingTrailersAfterFIN) { // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. - if (GetParam() != AllSupportedVersions()[0]) { + // In IETF QUIC, there is no such thing as FIN flag on HTTP/3 frames like the + // HEADERS frame. That is version 99, which is element 0 of the array, so + // pick another element. + if (GetParam() != AllSupportedVersions()[1]) { return; } @@ -1554,6 +1677,65 @@ TEST_P(QuicSpdyStreamTest, HeaderBytesNotReportedOnRetransmission) { QuicSpdyStreamPeer::unacked_frame_headers_offsets(stream_).Empty()); } +TEST_P(QuicSpdyStreamTest, HeadersFrameOnRequestStream) { + if (!VersionUsesQpack(GetParam().transport_version)) { + return; + } + + Initialize(kShouldProcessData); + + // QPACK encoded header block with single header field "foo: bar". + std::string headers_frame_payload = + QuicTextUtils::HexDecode("00002a94e703626172"); + std::unique_ptr<char[]> headers_buffer; + QuicByteCount headers_frame_header_length = + encoder_.SerializeHeadersFrameHeader(headers_frame_payload.length(), + &headers_buffer); + QuicStringPiece headers_frame_header(headers_buffer.get(), + headers_frame_header_length); + + std::string data_frame_payload = "some data"; + std::unique_ptr<char[]> data_buffer; + QuicByteCount data_frame_header_length = encoder_.SerializeDataFrameHeader( + data_frame_payload.length(), &data_buffer); + QuicStringPiece data_frame_header(data_buffer.get(), + data_frame_header_length); + + // QPACK encoded header block with single header field + // "custom-key: custom-value". + std::string trailers_frame_payload = + QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"); + std::unique_ptr<char[]> trailers_buffer; + QuicByteCount trailers_frame_header_length = + encoder_.SerializeHeadersFrameHeader(trailers_frame_payload.length(), + &trailers_buffer); + QuicStringPiece trailers_frame_header(trailers_buffer.get(), + trailers_frame_header_length); + + std::string stream_frame_payload = QuicStrCat( + headers_frame_header, headers_frame_payload, data_frame_header, + data_frame_payload, trailers_frame_header, trailers_frame_payload); + QuicStreamFrame frame(stream_->id(), false, 0, stream_frame_payload); + stream_->OnStreamFrame(frame); + + auto it = stream_->header_list().begin(); + ASSERT_TRUE(it != stream_->header_list().end()); + EXPECT_EQ("foo", it->first); + EXPECT_EQ("bar", it->second); + ++it; + EXPECT_TRUE(it == stream_->header_list().end()); + + // QuicSpdyStream only calls OnBodyAvailable() + // after the header list has been consumed. + EXPECT_EQ("", stream_->data()); + stream_->ConsumeHeaderList(); + EXPECT_EQ("some data", stream_->data()); + + const spdy::SpdyHeaderBlock& trailers = stream_->received_trailers(); + EXPECT_THAT(trailers, testing::ElementsAre( + testing::Pair("custom-key", "custom-value"))); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc index 6fb662a2008..447f16d84bd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc @@ -19,14 +19,18 @@ LegacyQuicStreamIdManager::LegacyQuicStreamIdManager( : session_(session), max_open_outgoing_streams_(max_open_outgoing_streams), max_open_incoming_streams_(max_open_incoming_streams), - next_outgoing_stream_id_( - QuicUtils::GetCryptoStreamId( - session->connection()->transport_version()) + - (session->perspective() == Perspective::IS_SERVER ? 1 : 2)), + next_outgoing_stream_id_(QuicUtils::GetFirstBidirectionalStreamId( + session->connection()->transport_version(), + session->perspective())), largest_peer_created_stream_id_( session->perspective() == Perspective::IS_SERVER - ? QuicUtils::GetCryptoStreamId( - session->connection()->transport_version()) + ? (QuicVersionUsesCryptoFrames( + session->connection()->transport_version()) + ? QuicUtils::GetFirstBidirectionalStreamId( + session->connection()->transport_version(), + Perspective::IS_CLIENT) + : QuicUtils::GetCryptoStreamId( + session->connection()->transport_version())) : QuicUtils::GetInvalidStreamId( session->connection()->transport_version())) {} diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md new file mode 100644 index 00000000000..4f6697c66b5 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md @@ -0,0 +1,28 @@ +# QPACK Offline Interop Testing tools + +See +[QPACK Offline Interop](https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop) +for description of test data format. + +Example usage: + +```shell +$ # Download test data +$ cd $TEST_DATA +$ git clone https://github.com/qpackers/qifs.git +$ TEST_ENCODED_DATA=`pwd`/qifs/encoded/qpack-03 +$ TEST_QIF_DATA=`pwd`/qifs/qifs +$ +$ # Decode encoded test data in four files and verify that they match +$ # the original headers in corresponding files +$ $BIN/qpack_offline_decoder \ +> $TEST_ENCODED_DATA/f5/fb-req.qifencoded.4096.100.0 \ +> $TEST_QIF_DATA/fb-req.qif +> $TEST_ENCODED_DATA/h2o/fb-req-hq.out.512.0.1 \ +> $TEST_QIF_DATA/fb-req-hq.qif +> $TEST_ENCODED_DATA/ls-qpack/fb-resp-hq.out.0.0.0 \ +> $TEST_QIF_DATA/fb-resp-hq.qif +> $TEST_ENCODED_DATA/proxygen/netbsd.qif.proxygen.out.4096.0.0 \ +> $TEST_QIF_DATA/netbsd.qif +$ +``` diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc index fc7225f8139..29a00d15a79 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver_test.cc @@ -4,8 +4,6 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc index cc957591083..c7c132e0a27 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc @@ -4,8 +4,7 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" @@ -16,19 +15,12 @@ namespace quic { namespace test { namespace { -class MockSenderDelegate : public QpackDecoderStreamSender::Delegate { - public: - ~MockSenderDelegate() override = default; - - MOCK_METHOD1(WriteDecoderStreamData, void(QuicStringPiece data)); -}; - class QpackDecoderStreamSenderTest : public QuicTest { protected: QpackDecoderStreamSenderTest() : stream_(&delegate_) {} ~QpackDecoderStreamSenderTest() override = default; - StrictMock<MockSenderDelegate> delegate_; + StrictMock<MockDecoderStreamSenderDelegate> delegate_; QpackDecoderStreamSender stream_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc index e8bbd178e62..9fc29deb779 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc @@ -8,7 +8,7 @@ #include <cstddef> #include <utility> -#include "testing/gmock/include/gmock/gmock.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h index ca5b60818fa..55761b6c388 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h @@ -5,11 +5,11 @@ #ifndef QUICHE_QUIC_CORE_QPACK_QPACK_DECODER_TEST_UTILS_H_ #define QUICHE_QUIC_CORE_QPACK_QPACK_DECODER_TEST_UTILS_H_ -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc index 108ffd57ee4..09c42869544 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc @@ -9,7 +9,6 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_progressive_encoder.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h index 4e655329b5f..2c450b17c9d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h @@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h" namespace spdy { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc index dcb2039ccfd..f0123902979 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver_test.cc @@ -4,8 +4,6 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc index a2e73763dea..ee8f399690d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc @@ -4,8 +4,6 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc index fb07d49e1ad..8200e14f8a3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc @@ -6,7 +6,6 @@ #include <string> -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -163,6 +162,19 @@ TEST_P(QpackEncoderTest, DecoderStreamError) { QuicTextUtils::HexDecode("ffffffffffffffffffffff")); } +TEST_P(QpackEncoderTest, SplitAlongNullCharacter) { + spdy::SpdyHeaderBlock header_list; + header_list["foo"] = QuicStringPiece("bar\0bar\0baz", 11); + std::string output = Encode(&header_list); + + EXPECT_EQ(QuicTextUtils::HexDecode("0000" // prefix + "2a94e703626172" // foo: bar + "2a94e703626172" // foo: bar + "2a94e70362617a" // foo: baz + ), + output); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc index f3ac5b5d3ef..6f9009d8aa4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table_test.cc @@ -4,7 +4,6 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_static_table.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc index f0d1d1d0564..175d39dc6bf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc @@ -6,8 +6,6 @@ #include <algorithm> -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc index 8f6aeaab97a..738a1b7bc9c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc @@ -4,8 +4,6 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_encoder.cc index 05a025b28be..731ec102866 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_encoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_encoder.cc @@ -22,7 +22,7 @@ QpackProgressiveEncoder::QpackProgressiveEncoder( header_table_(header_table), encoder_stream_sender_(encoder_stream_sender), header_list_(header_list), - header_list_iterator_(header_list_->begin()), + header_list_iterator_(header_list_.begin()), prefix_encoded_(false) { // TODO(bnc): Use |stream_id_| for dynamic table entry management, and // remove this dummy DCHECK. @@ -30,11 +30,10 @@ QpackProgressiveEncoder::QpackProgressiveEncoder( DCHECK(header_table_); DCHECK(encoder_stream_sender_); - DCHECK(header_list_); } bool QpackProgressiveEncoder::HasNext() const { - return header_list_iterator_ != header_list_->end() || !prefix_encoded_; + return header_list_iterator_ != header_list_.end() || !prefix_encoded_; } void QpackProgressiveEncoder::Next(size_t max_encoded_bytes, @@ -61,7 +60,7 @@ void QpackProgressiveEncoder::Next(size_t max_encoded_bytes, } do { - // Call QpackInstructionEncoder::Encode for |*header_list_iterator_| if it + // Call QpackInstructionEncoder::Encode() for |*header_list_iterator_| if it // has not been called yet. if (!instruction_encoder_.HasNext()) { DCHECK(prefix_encoded_); diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_encoder.h index 8e204e23b38..98a3cfeacea 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_encoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_encoder.h @@ -9,6 +9,7 @@ #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h" +#include "net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h" @@ -24,6 +25,8 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveEncoder : public spdy::HpackEncoder::ProgressiveEncoder { public: QpackProgressiveEncoder() = delete; + // |header_table|, |encoder_stream_sender|, and |header_list| must all outlive + // this object. QpackProgressiveEncoder(QuicStreamId stream_id, QpackHeaderTable* header_table, QpackEncoderStreamSender* encoder_stream_sender, @@ -43,10 +46,10 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveEncoder QpackInstructionEncoder instruction_encoder_; const QpackHeaderTable* const header_table_; QpackEncoderStreamSender* const encoder_stream_sender_; - const spdy::SpdyHeaderBlock* const header_list_; + const ValueSplittingHeaderList header_list_; // Header field currently being encoded. - spdy::SpdyHeaderBlock::const_iterator header_list_iterator_; + ValueSplittingHeaderList::const_iterator header_list_iterator_; // False until prefix is fully encoded. bool prefix_encoded_; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc index 9b2df550b88..45ad667f0d0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc @@ -5,7 +5,6 @@ #include <string> #include <tuple> -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h" #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h" @@ -132,6 +131,14 @@ TEST_P(QpackRoundTripTest, StaticTable) { } } +TEST_P(QpackRoundTripTest, ValueHasNullCharacter) { + spdy::SpdyHeaderBlock header_list; + header_list["foo"] = QuicStringPiece("bar\0bar\0baz", 11); + + spdy::SpdyHeaderBlock output = EncodeThenDecode(header_list); + EXPECT_EQ(header_list, output); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_static_table_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_static_table_test.cc index 50289f2e298..1742502e35b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_static_table_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_static_table_test.cc @@ -6,9 +6,9 @@ #include <set> -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.cc new file mode 100644 index 00000000000..d8a0ee81766 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2019 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/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h" + +namespace quic { + +ValueSplittingHeaderList::const_iterator::const_iterator( + const spdy::SpdyHeaderBlock* header_list, + spdy::SpdyHeaderBlock::const_iterator header_list_iterator) + : header_list_(header_list), + header_list_iterator_(header_list_iterator), + value_start_(0) { + UpdateHeaderField(); +} + +bool ValueSplittingHeaderList::const_iterator::operator==( + const const_iterator& other) const { + return header_list_iterator_ == other.header_list_iterator_ && + value_start_ == other.value_start_; +} + +bool ValueSplittingHeaderList::const_iterator::operator!=( + const const_iterator& other) const { + return !(*this == other); +} + +const ValueSplittingHeaderList::const_iterator& +ValueSplittingHeaderList::const_iterator::operator++() { + if (value_end_ == QuicStringPiece::npos) { + // This was the last frament within |*header_list_iterator_|, + // move on to the next header element of |header_list_|. + ++header_list_iterator_; + value_start_ = 0; + } else { + // Find the next fragment within |*header_list_iterator_|. + value_start_ = value_end_ + 1; + } + UpdateHeaderField(); + + return *this; +} + +const ValueSplittingHeaderList::value_type& + ValueSplittingHeaderList::const_iterator::operator*() const { + return header_field_; +} +const ValueSplittingHeaderList::value_type* + ValueSplittingHeaderList::const_iterator::operator->() const { + return &header_field_; +} + +void ValueSplittingHeaderList::const_iterator::UpdateHeaderField() { + DCHECK(value_start_ != QuicStringPiece::npos); + + if (header_list_iterator_ == header_list_->end()) { + return; + } + + const QuicStringPiece name = header_list_iterator_->first; + + value_end_ = header_list_iterator_->second.find('\0', value_start_); + const QuicStringPiece::size_type value_length = + value_end_ == QuicStringPiece::npos ? QuicStringPiece::npos + : value_end_ - value_start_; + const QuicStringPiece value = + header_list_iterator_->second.substr(value_start_, value_length); + + header_field_ = std::make_pair(name, value); +} + +ValueSplittingHeaderList::ValueSplittingHeaderList( + const spdy::SpdyHeaderBlock* header_list) + : header_list_(header_list) { + DCHECK(header_list_); +} + +ValueSplittingHeaderList::const_iterator ValueSplittingHeaderList::begin() + const { + return const_iterator(header_list_, header_list_->begin()); +} + +ValueSplittingHeaderList::const_iterator ValueSplittingHeaderList::end() const { + return const_iterator(header_list_, header_list_->end()); +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h new file mode 100644 index 00000000000..8d994aeff6d --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h @@ -0,0 +1,61 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_QPACK_VALUE_SPLITTING_HEADER_LIST_H_ +#define QUICHE_QUIC_CORE_QPACK_VALUE_SPLITTING_HEADER_LIST_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" + +namespace quic { + +// A wrapper class around SpdyHeaderBlock that splits header values along '\0' +// characters. +class QUIC_EXPORT_PRIVATE ValueSplittingHeaderList { + public: + using value_type = spdy::SpdyHeaderBlock::value_type; + + class QUIC_EXPORT_PRIVATE const_iterator { + public: + // |header_list| must outlive this object. + const_iterator(const spdy::SpdyHeaderBlock* header_list, + spdy::SpdyHeaderBlock::const_iterator header_list_iterator); + const_iterator(const const_iterator&) = default; + const_iterator& operator=(const const_iterator&) = delete; + + bool operator==(const const_iterator& other) const; + bool operator!=(const const_iterator& other) const; + + const const_iterator& operator++(); + + const value_type& operator*() const; + const value_type* operator->() const; + + private: + // Find next '\0' character; update |value_end_| and |header_field_|. + void UpdateHeaderField(); + + const spdy::SpdyHeaderBlock* const header_list_; + spdy::SpdyHeaderBlock::const_iterator header_list_iterator_; + QuicStringPiece::size_type value_start_; + QuicStringPiece::size_type value_end_; + value_type header_field_; + }; + + // |header_list| must outlive this object. + explicit ValueSplittingHeaderList(const spdy::SpdyHeaderBlock* header_list); + ValueSplittingHeaderList(const ValueSplittingHeaderList&) = delete; + ValueSplittingHeaderList& operator=(const ValueSplittingHeaderList&) = delete; + + const_iterator begin() const; + const_iterator end() const; + + private: + const spdy::SpdyHeaderBlock* const header_list_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QPACK_VALUE_SPLITTING_HEADER_LIST_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc new file mode 100644 index 00000000000..9ece65d9673 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2019 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/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { +namespace { + +using ::testing::ElementsAre; +using ::testing::Pair; + +TEST(ValueSplittingHeaderListTest, Comparison) { + spdy::SpdyHeaderBlock block; + block["foo"] = QuicStringPiece("bar\0baz", 7); + block["baz"] = "qux"; + + ValueSplittingHeaderList headers(&block); + ValueSplittingHeaderList::const_iterator it1 = headers.begin(); + const int kEnd = 4; + for (int i = 0; i < kEnd; ++i) { + // Compare to begin(). + if (i == 0) { + EXPECT_TRUE(it1 == headers.begin()); + EXPECT_TRUE(headers.begin() == it1); + EXPECT_FALSE(it1 != headers.begin()); + EXPECT_FALSE(headers.begin() != it1); + } else { + EXPECT_FALSE(it1 == headers.begin()); + EXPECT_FALSE(headers.begin() == it1); + EXPECT_TRUE(it1 != headers.begin()); + EXPECT_TRUE(headers.begin() != it1); + } + + // Compare to end(). + if (i == kEnd - 1) { + EXPECT_TRUE(it1 == headers.end()); + EXPECT_TRUE(headers.end() == it1); + EXPECT_FALSE(it1 != headers.end()); + EXPECT_FALSE(headers.end() != it1); + } else { + EXPECT_FALSE(it1 == headers.end()); + EXPECT_FALSE(headers.end() == it1); + EXPECT_TRUE(it1 != headers.end()); + EXPECT_TRUE(headers.end() != it1); + } + + // Compare to another iterator walking through the container. + ValueSplittingHeaderList::const_iterator it2 = headers.begin(); + for (int j = 0; j < kEnd; ++j) { + if (i == j) { + EXPECT_TRUE(it1 == it2); + EXPECT_FALSE(it1 != it2); + } else { + EXPECT_FALSE(it1 == it2); + EXPECT_TRUE(it1 != it2); + } + ++it2; + } + + ++it1; + } +} + +TEST(ValueSplittingHeaderListTest, Empty) { + spdy::SpdyHeaderBlock block; + + ValueSplittingHeaderList headers(&block); + EXPECT_THAT(headers, ElementsAre()); + EXPECT_EQ(headers.begin(), headers.end()); +} + +TEST(ValueSplittingHeaderListTest, Simple) { + spdy::SpdyHeaderBlock block; + block["foo"] = "bar"; + block["baz"] = "qux"; + + ValueSplittingHeaderList headers(&block); + EXPECT_THAT(headers, ElementsAre(Pair("foo", "bar"), Pair("baz", "qux"))); + EXPECT_NE(headers.begin(), headers.end()); +} + +TEST(ValueSplittingHeaderListTest, EmptyValue) { + spdy::SpdyHeaderBlock block; + block["foo"] = ""; + + ValueSplittingHeaderList headers(&block); + EXPECT_THAT(headers, ElementsAre(Pair("foo", ""))); +} + +TEST(ValueSplittingHeaderListTest, SimpleSplit) { + spdy::SpdyHeaderBlock block; + block["foo"] = QuicStringPiece("bar\0baz", 7); + block["baz"] = QuicStringPiece("foo\0foo", 7); + + ValueSplittingHeaderList headers(&block); + EXPECT_THAT(headers, ElementsAre(Pair("foo", "bar"), Pair("foo", "baz"), + Pair("baz", "foo"), Pair("baz", "foo"))); +} + +TEST(ValueSplittingHeaderListTest, EmptyFragments) { + spdy::SpdyHeaderBlock block; + block["foo"] = QuicStringPiece("\0", 1); + block["bar"] = QuicStringPiece("foo\0", 4); + block["baz"] = QuicStringPiece("\0bar", 4); + block["qux"] = QuicStringPiece("\0foobar\0", 8); + + ValueSplittingHeaderList headers(&block); + EXPECT_THAT( + headers, + ElementsAre(Pair("foo", ""), Pair("foo", ""), Pair("bar", "foo"), + Pair("bar", ""), Pair("baz", ""), Pair("baz", "bar"), + Pair("qux", ""), Pair("qux", "foobar"), Pair("qux", ""))); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth.cc b/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth.cc index a1dbf67c99c..9fcc3b986ae 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth.cc @@ -11,7 +11,7 @@ namespace quic { -std::string QuicBandwidth::ToDebugValue() const { +std::string QuicBandwidth::ToDebuggingValue() const { if (bits_per_second_ < 80000) { return QuicStringPrintf("%" PRId64 " bits/s (%" PRId64 " bytes/s)", bits_per_second_, bits_per_second_ / 8); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth.h b/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth.h index 5b747446d18..a5bb30697bc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth.h @@ -77,6 +77,9 @@ class QUIC_EXPORT_PRIVATE QuicBandwidth { } inline bool IsZero() const { return bits_per_second_ == 0; } + inline bool IsInfinite() const { + return bits_per_second_ == Infinite().ToBitsPerSecond(); + } inline QuicTime::Delta TransferTime(QuicByteCount bytes) const { if (bits_per_second_ == 0) { @@ -86,7 +89,7 @@ class QUIC_EXPORT_PRIVATE QuicBandwidth { bits_per_second_); } - std::string ToDebugValue() const; + std::string ToDebuggingValue() const; private: explicit constexpr QuicBandwidth(int64_t bits_per_second) @@ -143,7 +146,7 @@ inline QuicByteCount operator*(QuicTime::Delta lhs, QuicBandwidth rhs) { // Override stream output operator for gtest. inline std::ostream& operator<<(std::ostream& output, const QuicBandwidth bandwidth) { - output << bandwidth.ToDebugValue(); + output << bandwidth.ToDebuggingValue(); return output; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth_test.cc index ed23dac1675..22a510752bb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_bandwidth_test.cc @@ -3,6 +3,9 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" + +#include <limits> + #include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -102,20 +105,32 @@ TEST_F(QuicBandwidthTest, RelOps) { EXPECT_GE(b2, b1); } -TEST_F(QuicBandwidthTest, DebugValue) { +TEST_F(QuicBandwidthTest, DebuggingValue) { EXPECT_EQ("128 bits/s (16 bytes/s)", - QuicBandwidth::FromBytesPerSecond(16).ToDebugValue()); + QuicBandwidth::FromBytesPerSecond(16).ToDebuggingValue()); EXPECT_EQ("4096 bits/s (512 bytes/s)", - QuicBandwidth::FromBytesPerSecond(512).ToDebugValue()); + QuicBandwidth::FromBytesPerSecond(512).ToDebuggingValue()); QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(1000 * 50); - EXPECT_EQ("400.00 kbits/s (50.00 kbytes/s)", bandwidth.ToDebugValue()); + EXPECT_EQ("400.00 kbits/s (50.00 kbytes/s)", bandwidth.ToDebuggingValue()); bandwidth = bandwidth * 1000; - EXPECT_EQ("400.00 Mbits/s (50.00 Mbytes/s)", bandwidth.ToDebugValue()); + EXPECT_EQ("400.00 Mbits/s (50.00 Mbytes/s)", bandwidth.ToDebuggingValue()); bandwidth = bandwidth * 1000; - EXPECT_EQ("400.00 Gbits/s (50.00 Gbytes/s)", bandwidth.ToDebugValue()); + EXPECT_EQ("400.00 Gbits/s (50.00 Gbytes/s)", bandwidth.ToDebuggingValue()); +} + +TEST_F(QuicBandwidthTest, SpecialValues) { + EXPECT_EQ(0, QuicBandwidth::Zero().ToBitsPerSecond()); + EXPECT_EQ(std::numeric_limits<int64_t>::max(), + QuicBandwidth::Infinite().ToBitsPerSecond()); + + EXPECT_TRUE(QuicBandwidth::Zero().IsZero()); + EXPECT_FALSE(QuicBandwidth::Zero().IsInfinite()); + + EXPECT_TRUE(QuicBandwidth::Infinite().IsInfinite()); + EXPECT_FALSE(QuicBandwidth::Infinite().IsZero()); } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc index 25b549cdafe..09148092165 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc @@ -5,10 +5,12 @@ #include "net/third_party/quiche/src/quic/core/quic_config.h" #include <algorithm> +#include <cstring> #include <string> #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" @@ -17,7 +19,9 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" namespace quic { @@ -400,7 +404,7 @@ QuicConfig::QuicConfig() client_connection_options_(kCLOP, PRESENCE_OPTIONAL), idle_network_timeout_seconds_(kICSL, PRESENCE_REQUIRED), silent_close_(kSCLS, PRESENCE_OPTIONAL), - max_incoming_dynamic_streams_(kMIDS, PRESENCE_REQUIRED), + max_incoming_bidirectional_streams_(kMIBS, PRESENCE_REQUIRED), bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL), initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL), initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL), @@ -408,7 +412,8 @@ QuicConfig::QuicConfig() connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL), alternate_server_address_(kASAD, PRESENCE_OPTIONAL), support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL), - stateless_reset_token_(kSRST, PRESENCE_OPTIONAL) { + stateless_reset_token_(kSRST, PRESENCE_OPTIONAL), + max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL) { SetDefaults(); } @@ -501,21 +506,38 @@ bool QuicConfig::SilentClose() const { return silent_close_.GetUint32() > 0; } -void QuicConfig::SetMaxIncomingDynamicStreamsToSend( - uint32_t max_incoming_dynamic_streams) { - max_incoming_dynamic_streams_.SetSendValue(max_incoming_dynamic_streams); +void QuicConfig::SetMaxIncomingBidirectionalStreamsToSend( + uint32_t max_streams) { + max_incoming_bidirectional_streams_.SetSendValue(max_streams); } -uint32_t QuicConfig::GetMaxIncomingDynamicStreamsToSend() { - return max_incoming_dynamic_streams_.GetSendValue(); +uint32_t QuicConfig::GetMaxIncomingBidirectionalStreamsToSend() { + return max_incoming_bidirectional_streams_.GetSendValue(); } -bool QuicConfig::HasReceivedMaxIncomingDynamicStreams() { - return max_incoming_dynamic_streams_.HasReceivedValue(); +bool QuicConfig::HasReceivedMaxIncomingBidirectionalStreams() { + return max_incoming_bidirectional_streams_.HasReceivedValue(); } -uint32_t QuicConfig::ReceivedMaxIncomingDynamicStreams() { - return max_incoming_dynamic_streams_.GetReceivedValue(); +uint32_t QuicConfig::ReceivedMaxIncomingBidirectionalStreams() { + return max_incoming_bidirectional_streams_.GetReceivedValue(); +} + +void QuicConfig::SetMaxIncomingUnidirectionalStreamsToSend( + uint32_t max_streams) { + max_incoming_unidirectional_streams_.SetSendValue(max_streams); +} + +uint32_t QuicConfig::GetMaxIncomingUnidirectionalStreamsToSend() { + return max_incoming_unidirectional_streams_.GetSendValue(); +} + +bool QuicConfig::HasReceivedMaxIncomingUnidirectionalStreams() { + return max_incoming_unidirectional_streams_.HasReceivedValue(); +} + +uint32_t QuicConfig::ReceivedMaxIncomingUnidirectionalStreams() { + return max_incoming_unidirectional_streams_.GetReceivedValue(); } bool QuicConfig::HasSetBytesForConnectionIdToSend() const { @@ -558,7 +580,7 @@ void QuicConfig::SetInitialStreamFlowControlWindowToSend( uint32_t window_bytes) { if (window_bytes < kMinimumFlowControlSendWindow) { QUIC_BUG << "Initial stream flow control receive window (" << window_bytes - << ") cannot be set lower than default (" + << ") cannot be set lower than minimum (" << kMinimumFlowControlSendWindow << ")."; window_bytes = kMinimumFlowControlSendWindow; } @@ -660,7 +682,8 @@ void QuicConfig::SetDefaults() { idle_network_timeout_seconds_.set(kMaximumIdleTimeoutSecs, kDefaultIdleTimeoutSecs); silent_close_.set(1, 0); - SetMaxIncomingDynamicStreamsToSend(kDefaultMaxStreamsPerConnection); + SetMaxIncomingBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); + SetMaxIncomingUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); max_time_before_crypto_handshake_ = QuicTime::Delta::FromSeconds(kMaxTimeForCryptoHandshakeSecs); max_idle_time_before_crypto_handshake_ = @@ -672,10 +695,18 @@ void QuicConfig::SetDefaults() { SetSupportMaxHeaderListSize(); } -void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const { +void QuicConfig::ToHandshakeMessage( + CryptoHandshakeMessage* out, + QuicTransportVersion transport_version) const { idle_network_timeout_seconds_.ToHandshakeMessage(out); silent_close_.ToHandshakeMessage(out); - max_incoming_dynamic_streams_.ToHandshakeMessage(out); + // Do not need a version check here, max...bi... will encode + // as "MIDS" -- the max initial dynamic streams tag -- if + // doing some version other than IETF QUIC/V99. + max_incoming_bidirectional_streams_.ToHandshakeMessage(out); + if (transport_version == QUIC_VERSION_99) { + max_incoming_unidirectional_streams_.ToHandshakeMessage(out); + } bytes_for_connection_id_.ToHandshakeMessage(out); initial_round_trip_time_us_.ToHandshakeMessage(out); initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out); @@ -703,7 +734,11 @@ QuicErrorCode QuicConfig::ProcessPeerHello( silent_close_.ProcessPeerHello(peer_hello, hello_type, error_details); } if (error == QUIC_NO_ERROR) { - error = max_incoming_dynamic_streams_.ProcessPeerHello( + error = max_incoming_bidirectional_streams_.ProcessPeerHello( + peer_hello, hello_type, error_details); + } + if (error == QUIC_NO_ERROR) { + error = max_incoming_unidirectional_streams_.ProcessPeerHello( peer_hello, hello_type, error_details); } if (error == QUIC_NO_ERROR) { @@ -746,25 +781,47 @@ QuicErrorCode QuicConfig::ProcessPeerHello( } bool QuicConfig::FillTransportParameters(TransportParameters* params) const { - params->initial_max_stream_data = - initial_stream_flow_control_window_bytes_.GetSendValue(); - params->initial_max_data = - initial_session_flow_control_window_bytes_.GetSendValue(); - - uint32_t idle_timeout = idle_network_timeout_seconds_.GetUint32(); - if (idle_timeout > std::numeric_limits<uint16_t>::max()) { - QUIC_BUG << "idle network timeout set too large"; - return false; - } - params->idle_timeout = idle_timeout; - - uint32_t initial_max_streams = max_incoming_dynamic_streams_.GetSendValue(); - if (initial_max_streams > std::numeric_limits<uint16_t>::max()) { - QUIC_BUG << "max incoming streams set too large"; - return false; + params->idle_timeout_milliseconds.set_value( + idle_network_timeout_seconds_.GetUint32() * kNumMillisPerSecond); + + if (stateless_reset_token_.HasSendValue()) { + QuicUint128 stateless_reset_token = stateless_reset_token_.GetSendValue(); + params->stateless_reset_token.assign( + reinterpret_cast<const char*>(&stateless_reset_token), + reinterpret_cast<const char*>(&stateless_reset_token) + + sizeof(stateless_reset_token)); + } + + params->max_packet_size.set_value(kMaxIncomingPacketSize); + params->initial_max_data.set_value( + initial_session_flow_control_window_bytes_.GetSendValue()); + params->initial_max_stream_data_bidi_local.set_value( + initial_stream_flow_control_window_bytes_.GetSendValue()); + params->initial_max_stream_data_bidi_remote.set_value( + initial_stream_flow_control_window_bytes_.GetSendValue()); + params->initial_max_stream_data_uni.set_value( + initial_stream_flow_control_window_bytes_.GetSendValue()); + params->initial_max_streams_bidi.set_value( + max_incoming_bidirectional_streams_.GetSendValue()); + params->initial_max_streams_uni.set_value( + max_incoming_unidirectional_streams_.GetSendValue()); + params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs); + params->disable_migration = + connection_migration_disabled_.HasSendValue() && + connection_migration_disabled_.GetSendValue() != 0; + + if (alternate_server_address_.HasSendValue()) { + TransportParameters::PreferredAddress preferred_address; + QuicSocketAddress socket_address = alternate_server_address_.GetSendValue(); + if (socket_address.host().IsIPv6()) { + preferred_address.ipv6_socket_address = socket_address; + } else { + preferred_address.ipv4_socket_address = socket_address; + } + params->preferred_address = + QuicMakeUnique<TransportParameters::PreferredAddress>( + preferred_address); } - params->initial_max_bidi_streams.present = true; - params->initial_max_bidi_streams.value = initial_max_streams; if (!params->google_quic_params) { params->google_quic_params = QuicMakeUnique<CryptoHandshakeMessage>(); @@ -773,6 +830,7 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const { initial_round_trip_time_us_.ToHandshakeMessage( params->google_quic_params.get()); connection_options_.ToHandshakeMessage(params->google_quic_params.get()); + return true; } @@ -780,12 +838,69 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( const TransportParameters& params, HelloType hello_type, std::string* error_details) { + // Intentionally round down to probe too often rather than not often enough. + uint64_t idle_timeout_seconds = + params.idle_timeout_milliseconds.value() / kNumMillisPerSecond; + // An idle timeout of zero indicates it is disabled (in other words, it is + // set to infinity). When the idle timeout is very high, we set it to our + // preferred maximum and still probe that often. + if (idle_timeout_seconds > kMaximumIdleTimeoutSecs || + idle_timeout_seconds == 0) { + idle_timeout_seconds = kMaximumIdleTimeoutSecs; + } QuicErrorCode error = idle_network_timeout_seconds_.ReceiveValue( - params.idle_timeout, hello_type, error_details); + idle_timeout_seconds, hello_type, error_details); if (error != QUIC_NO_ERROR) { DCHECK(!error_details->empty()); return error; } + + if (!params.stateless_reset_token.empty()) { + QuicUint128 stateless_reset_token; + if (params.stateless_reset_token.size() != sizeof(stateless_reset_token)) { + QUIC_BUG << "Bad stateless reset token length " + << params.stateless_reset_token.size(); + *error_details = "Bad stateless reset token length"; + return QUIC_INTERNAL_ERROR; + } + memcpy(&stateless_reset_token, params.stateless_reset_token.data(), + params.stateless_reset_token.size()); + stateless_reset_token_.SetReceivedValue(stateless_reset_token); + } + + if (params.max_packet_size.value() < kMaxOutgoingPacketSize) { + // TODO(dschinazi) act on this. + QUIC_DLOG(ERROR) << "Ignoring peer's requested max packet size of " + << params.max_packet_size.value(); + } + + initial_session_flow_control_window_bytes_.SetReceivedValue( + std::min<uint64_t>(params.initial_max_data.value(), + std::numeric_limits<uint32_t>::max())); + max_incoming_bidirectional_streams_.SetReceivedValue( + std::min<uint64_t>(params.initial_max_streams_bidi.value(), + std::numeric_limits<uint32_t>::max())); + max_incoming_unidirectional_streams_.SetReceivedValue( + std::min<uint64_t>(params.initial_max_streams_uni.value(), + std::numeric_limits<uint32_t>::max())); + + initial_stream_flow_control_window_bytes_.SetReceivedValue( + std::min<uint64_t>(params.initial_max_stream_data_bidi_local.value(), + std::numeric_limits<uint32_t>::max())); + + connection_migration_disabled_.SetReceivedValue( + params.disable_migration ? 1u : 0u); + + if (params.preferred_address != nullptr) { + if (params.preferred_address->ipv6_socket_address.port() != 0) { + alternate_server_address_.SetReceivedValue( + params.preferred_address->ipv6_socket_address); + } else if (params.preferred_address->ipv4_socket_address.port() != 0) { + alternate_server_address_.SetReceivedValue( + params.preferred_address->ipv4_socket_address); + } + } + const CryptoHandshakeMessage* peer_params = params.google_quic_params.get(); if (peer_params != nullptr) { error = @@ -808,18 +923,6 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( } } - initial_stream_flow_control_window_bytes_.SetReceivedValue( - params.initial_max_stream_data); - initial_session_flow_control_window_bytes_.SetReceivedValue( - params.initial_max_data); - if (params.initial_max_bidi_streams.present) { - max_incoming_dynamic_streams_.SetReceivedValue( - params.initial_max_bidi_streams.value); - } else { - // An absent value for initial_max_bidi_streams is treated as a value of 0. - max_incoming_dynamic_streams_.SetReceivedValue(0); - } - return QUIC_NO_ERROR; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.h b/chromium/net/third_party/quiche/src/quic/core/quic_config.h index 8ad161db9ec..ae15b6aae38 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.h @@ -305,14 +305,24 @@ class QUIC_EXPORT_PRIVATE QuicConfig { bool SilentClose() const; - void SetMaxIncomingDynamicStreamsToSend( - uint32_t max_incoming_dynamic_streams); - - uint32_t GetMaxIncomingDynamicStreamsToSend(); - - bool HasReceivedMaxIncomingDynamicStreams(); - - uint32_t ReceivedMaxIncomingDynamicStreams(); + // Configuration for the Google QUIC and IETF QUIC stream ID managers. Note + // that the naming is a bit weird; it is from the perspective of the node + // generating (sending) the configuration and, thus, The "incoming" counts are + // the number of streams that the node sending the configuration is willing to + // accept and therefore the number that the node receiving the confguration + // can create .. the number of outbound streams that may be intiated.. + // There are two sets, one for unidirectional streams and one for + // bidirectional. The bidirectional set also covers Google-QUICs + // dynamic stream count (which are bidirectional streams). + void SetMaxIncomingBidirectionalStreamsToSend(uint32_t max_streams); + uint32_t GetMaxIncomingBidirectionalStreamsToSend(); + bool HasReceivedMaxIncomingBidirectionalStreams(); + uint32_t ReceivedMaxIncomingBidirectionalStreams(); + + void SetMaxIncomingUnidirectionalStreamsToSend(uint32_t max_streams); + uint32_t GetMaxIncomingUnidirectionalStreamsToSend(); + bool HasReceivedMaxIncomingUnidirectionalStreams(); + uint32_t ReceivedMaxIncomingUnidirectionalStreams(); void set_max_time_before_crypto_handshake( QuicTime::Delta max_time_before_crypto_handshake) { @@ -412,7 +422,8 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // ToHandshakeMessage serialises the settings in this object as a series of // tags /value pairs and adds them to |out|. - void ToHandshakeMessage(CryptoHandshakeMessage* out) const; + void ToHandshakeMessage(CryptoHandshakeMessage* out, + QuicTransportVersion transport_version) const; // Calls ProcessPeerHello on each negotiable parameter. On failure returns // the corresponding QuicErrorCode and sets detailed error in |error_details|. @@ -456,8 +467,10 @@ class QUIC_EXPORT_PRIVATE QuicConfig { QuicNegotiableUint32 idle_network_timeout_seconds_; // Whether to use silent close. Defaults to 0 (false) and is otherwise true. QuicNegotiableUint32 silent_close_; - // Maximum number of incoming dynamic streams that the connection can support. - QuicFixedUint32 max_incoming_dynamic_streams_; + // Maximum number of incoming dynamic streams that a Google QUIC connection + // can support or the maximum number of incoming bidirectional streams that + // an IETF QUIC connection can support. + QuicFixedUint32 max_incoming_bidirectional_streams_; // The number of bytes required for the connection ID. QuicFixedUint32 bytes_for_connection_id_; // Initial round trip time estimate in microseconds. @@ -484,6 +497,10 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // be created. This allows for CHLOs that are larger than a single // packet to be processed. QuicTagVector create_session_tag_indicators_; + + // Maximum number of incoming unidirectional streams that the connection can + // support. + QuicFixedUint32 max_incoming_unidirectional_streams_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc index c18c5200708..84e89c17d2d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc @@ -21,12 +21,17 @@ namespace quic { namespace test { namespace { -class QuicConfigTest : public QuicTest { +class QuicConfigTest : public QuicTestWithParam<QuicTransportVersion> { protected: QuicConfig config_; }; -TEST_F(QuicConfigTest, ToHandshakeMessage) { +// Run all tests with all versions of QUIC. +INSTANTIATE_TEST_SUITE_P(QuicConfigTests, + QuicConfigTest, + ::testing::ValuesIn(AllSupportedTransportVersions())); + +TEST_P(QuicConfigTest, ToHandshakeMessage) { config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config_.SetInitialSessionFlowControlWindowToSend( @@ -34,7 +39,7 @@ TEST_F(QuicConfigTest, ToHandshakeMessage) { config_.SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(5), QuicTime::Delta::FromSeconds(2)); CryptoHandshakeMessage msg; - config_.ToHandshakeMessage(&msg); + config_.ToHandshakeMessage(&msg, GetParam()); uint32_t value; QuicErrorCode error = msg.GetUint32(kICSL, &value); @@ -50,7 +55,7 @@ TEST_F(QuicConfigTest, ToHandshakeMessage) { EXPECT_EQ(kInitialSessionFlowControlWindowForTest, value); } -TEST_F(QuicConfigTest, ProcessClientHello) { +TEST_P(QuicConfigTest, ProcessClientHello) { QuicConfig client_config; QuicTagVector cgst; cgst.push_back(kQBIC); @@ -66,7 +71,7 @@ TEST_F(QuicConfigTest, ProcessClientHello) { copt.push_back(kTBBR); client_config.SetConnectionOptionsToSend(copt); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; QuicTagVector initial_received_options; @@ -96,7 +101,7 @@ TEST_F(QuicConfigTest, ProcessClientHello) { 2 * kInitialSessionFlowControlWindowForTest); } -TEST_F(QuicConfigTest, ProcessServerHello) { +TEST_P(QuicConfigTest, ProcessServerHello) { QuicIpAddress host; host.FromString("127.0.3.1"); const QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234); @@ -115,7 +120,7 @@ TEST_F(QuicConfigTest, ProcessServerHello) { server_config.SetAlternateServerAddressToSend(kTestServerAddress); server_config.SetStatelessResetTokenToSend(kTestResetToken); CryptoHandshakeMessage msg; - server_config.ToHandshakeMessage(&msg); + server_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); @@ -134,13 +139,13 @@ TEST_F(QuicConfigTest, ProcessServerHello) { EXPECT_EQ(kTestResetToken, config_.ReceivedStatelessResetToken()); } -TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) { +TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) { CryptoHandshakeMessage msg; msg.SetValue(kICSL, 1); // Set all REQUIRED tags. msg.SetValue(kICSL, 1); - msg.SetValue(kMIDS, 1); + msg.SetValue(kMIBS, 1); // No error, as rest are optional. std::string error_details; @@ -150,12 +155,12 @@ TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) { EXPECT_TRUE(config_.negotiated()); } -TEST_F(QuicConfigTest, MissingOptionalValuesInSHLO) { +TEST_P(QuicConfigTest, MissingOptionalValuesInSHLO) { CryptoHandshakeMessage msg; // Set all REQUIRED tags. msg.SetValue(kICSL, 1); - msg.SetValue(kMIDS, 1); + msg.SetValue(kMIBS, 1); // No error, as rest are optional. std::string error_details; @@ -165,7 +170,7 @@ TEST_F(QuicConfigTest, MissingOptionalValuesInSHLO) { EXPECT_TRUE(config_.negotiated()); } -TEST_F(QuicConfigTest, MissingValueInCHLO) { +TEST_P(QuicConfigTest, MissingValueInCHLO) { // Server receives CHLO with missing kICSL. CryptoHandshakeMessage msg; std::string error_details; @@ -174,7 +179,7 @@ TEST_F(QuicConfigTest, MissingValueInCHLO) { EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error); } -TEST_F(QuicConfigTest, MissingValueInSHLO) { +TEST_P(QuicConfigTest, MissingValueInSHLO) { // Client receives SHLO with missing kICSL. CryptoHandshakeMessage msg; std::string error_details; @@ -183,21 +188,21 @@ TEST_F(QuicConfigTest, MissingValueInSHLO) { EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error); } -TEST_F(QuicConfigTest, OutOfBoundSHLO) { +TEST_P(QuicConfigTest, OutOfBoundSHLO) { QuicConfig server_config; server_config.SetIdleNetworkTimeout( QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs), QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs)); CryptoHandshakeMessage msg; - server_config.ToHandshakeMessage(&msg); + server_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); EXPECT_EQ(QUIC_INVALID_NEGOTIATED_VALUE, error); } -TEST_F(QuicConfigTest, InvalidFlowControlWindow) { +TEST_P(QuicConfigTest, InvalidFlowControlWindow) { // QuicConfig should not accept an invalid flow control window to send to the // peer: the receive window must be at least the default of 16 Kb. QuicConfig config; @@ -210,7 +215,7 @@ TEST_F(QuicConfigTest, InvalidFlowControlWindow) { config.GetInitialStreamFlowControlWindowToSend()); } -TEST_F(QuicConfigTest, HasClientSentConnectionOption) { +TEST_P(QuicConfigTest, HasClientSentConnectionOption) { QuicConfig client_config; QuicTagVector copt; copt.push_back(kTBBR); @@ -219,7 +224,7 @@ TEST_F(QuicConfigTest, HasClientSentConnectionOption) { kTBBR, Perspective::IS_CLIENT)); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error = @@ -233,14 +238,14 @@ TEST_F(QuicConfigTest, HasClientSentConnectionOption) { config_.HasClientSentConnectionOption(kTBBR, Perspective::IS_SERVER)); } -TEST_F(QuicConfigTest, DontSendClientConnectionOptions) { +TEST_P(QuicConfigTest, DontSendClientConnectionOptions) { QuicConfig client_config; QuicTagVector copt; copt.push_back(kTBBR); client_config.SetClientConnectionOptions(copt); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error = @@ -251,7 +256,7 @@ TEST_F(QuicConfigTest, DontSendClientConnectionOptions) { EXPECT_FALSE(config_.HasReceivedConnectionOptions()); } -TEST_F(QuicConfigTest, HasClientRequestedIndependentOption) { +TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) { QuicConfig client_config; QuicTagVector client_opt; client_opt.push_back(kRENO); @@ -267,7 +272,7 @@ TEST_F(QuicConfigTest, HasClientRequestedIndependentOption) { kTBBR, Perspective::IS_CLIENT)); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error = diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc index cb901bafaf3..226a4ccf0eb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc @@ -16,12 +16,14 @@ #include <utility> #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.pb.h" #include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_packet_generator.h" #include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" @@ -181,21 +183,6 @@ class MtuDiscoveryAlarmDelegate : public QuicAlarm::Delegate { QuicConnection* connection_; }; -class RetransmittableOnWireAlarmDelegate : public QuicAlarm::Delegate { - public: - explicit RetransmittableOnWireAlarmDelegate(QuicConnection* connection) - : connection_(connection) {} - RetransmittableOnWireAlarmDelegate( - const RetransmittableOnWireAlarmDelegate&) = delete; - RetransmittableOnWireAlarmDelegate& operator=( - const RetransmittableOnWireAlarmDelegate&) = delete; - - void OnAlarm() override { connection_->OnPingTimeout(); } - - private: - QuicConnection* connection_; -}; - class ProcessUndecryptablePacketsAlarmDelegate : public QuicAlarm::Delegate { public: explicit ProcessUndecryptablePacketsAlarmDelegate(QuicConnection* connection) @@ -232,7 +219,7 @@ bool PacketCanReplaceConnectionId(const QuicPacketHeader& header, (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") QuicConnection::QuicConnection( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, QuicSocketAddress initial_peer_address, QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, @@ -243,7 +230,7 @@ QuicConnection::QuicConnection( : framer_(supported_versions, helper->GetClock()->ApproximateNow(), perspective, - connection_id.length()), + server_connection_id.length()), current_packet_content_(NO_FRAMES_RECEIVED), is_current_packet_connectivity_probing_(false), current_effective_peer_migration_type_(NO_CHANGE), @@ -255,7 +242,7 @@ QuicConnection::QuicConnection( encryption_level_(ENCRYPTION_INITIAL), clock_(helper->GetClock()), random_generator_(helper->GetRandomGenerator()), - connection_id_(connection_id), + server_connection_id_(server_connection_id), peer_address_(initial_peer_address), direct_peer_address_(initial_peer_address), active_effective_peer_migration_type_(NO_CHANGE), @@ -315,7 +302,10 @@ QuicConnection::QuicConnection( &arena_)), visitor_(nullptr), debug_visitor_(nullptr), - packet_generator_(connection_id_, &framer_, random_generator_, this), + packet_generator_(server_connection_id_, + &framer_, + random_generator_, + this), idle_network_timeout_(QuicTime::Delta::Infinite()), handshake_timeout_(QuicTime::Delta::Infinite()), time_of_first_packet_sent_after_receiving_( @@ -328,6 +318,7 @@ QuicConnection::QuicConnection( sent_packet_manager_( perspective, clock_, + random_generator_, &stats_, GetQuicReloadableFlag(quic_default_to_bbr) ? kBBR : kCubicBytes, kNack), @@ -358,9 +349,8 @@ QuicConnection::QuicConnection( supports_release_time_(false), release_time_into_future_(QuicTime::Delta::Zero()), no_version_negotiation_(supported_versions.size() == 1), - fix_termination_packets_( - GetQuicReloadableFlag(quic_fix_termination_packets)), send_ack_when_on_can_write_(false), + retry_has_been_parsed_(false), validate_packet_number_post_decryption_( GetQuicReloadableFlag(quic_validate_packet_number_post_decryption)), use_uber_received_packet_manager_( @@ -386,14 +376,14 @@ QuicConnection::QuicConnection( if (use_uber_received_packet_manager_) { QUIC_RELOADABLE_FLAG_COUNT(quic_use_uber_received_packet_manager); } - QUIC_DLOG(INFO) << ENDPOINT - << "Created connection with connection_id: " << connection_id + QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID " + << server_connection_id << " and version: " << ParsedQuicVersionToString(version()); - QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(connection_id, + QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(server_connection_id, transport_version())) - << "QuicConnection: attempted to use connection ID " << connection_id - << " which is invalid with version " + << "QuicConnection: attempted to use server connection ID " + << server_connection_id << " which is invalid with version " << QuicVersionToString(transport_version()); framer_.set_visitor(this); @@ -421,6 +411,19 @@ QuicConnection::QuicConnection( DCHECK(!GetQuicRestartFlag(quic_no_server_conn_ver_negotiation2) || perspective_ == Perspective::IS_CLIENT || supported_versions.size() == 1); + InstallInitialCrypters(); +} + +void QuicConnection::InstallInitialCrypters() { + if (version().handshake_protocol != PROTOCOL_TLS1_3) { + // Initial crypters are currently only supported with TLS. + return; + } + CrypterPair crypters; + CryptoUtils::CreateTlsInitialCrypters(perspective_, transport_version(), + server_connection_id_, &crypters); + SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter)); + InstallDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter)); } QuicConnection::~QuicConnection() { @@ -457,7 +460,7 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { sent_packet_manager_.SetFromConfig(config); if (config.HasReceivedBytesForConnectionId() && can_truncate_connection_ids_) { - packet_generator_.SetConnectionIdLength( + packet_generator_.SetServerConnectionIdLength( config.ReceivedBytesForConnectionId()); } max_undecryptable_packets_ = config.max_undecryptable_packets(); @@ -559,8 +562,10 @@ void QuicConnection::SetMaxPacingRate(QuicBandwidth max_pacing_rate) { } void QuicConnection::AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) { - sent_packet_manager_.AdjustNetworkParameters(bandwidth, rtt); + QuicTime::Delta rtt, + bool allow_cwnd_to_decrease) { + sent_packet_manager_.AdjustNetworkParameters(bandwidth, rtt, + allow_cwnd_to_decrease); } QuicBandwidth QuicConnection::MaxPacingRate() const { @@ -603,7 +608,7 @@ void QuicConnection::OnPublicResetPacket(const QuicPublicResetPacket& packet) { // Check that any public reset packet with a different connection ID that was // routed to this QuicConnection has been redirected before control reaches // here. (Check for a bug regression.) - DCHECK_EQ(connection_id_, packet.connection_id); + DCHECK_EQ(server_connection_id_, packet.connection_id); DCHECK_EQ(perspective_, Perspective::IS_CLIENT); if (debug_visitor_ != nullptr) { debug_visitor_->OnPublicResetPacket(packet); @@ -626,8 +631,8 @@ bool QuicConnection::OnProtocolVersionMismatch( if (perspective_ == Perspective::IS_CLIENT) { const std::string error_details = "Protocol version mismatch."; QUIC_BUG << ENDPOINT << error_details; - TearDownLocalConnectionState(QUIC_INTERNAL_ERROR, error_details, - ConnectionCloseSource::FROM_SELF); + CloseConnection(QUIC_INTERNAL_ERROR, error_details, + ConnectionCloseBehavior::SILENT_CLOSE); return false; } if (no_version_negotiation_) { @@ -694,14 +699,14 @@ void QuicConnection::OnVersionNegotiationPacket( // Check that any public reset packet with a different connection ID that was // routed to this QuicConnection has been redirected before control reaches // here. (Check for a bug regression.) - DCHECK_EQ(connection_id_, packet.connection_id); + DCHECK_EQ(server_connection_id_, packet.connection_id); if (perspective_ == Perspective::IS_SERVER) { const std::string error_details = - "Server receieved version negotiation packet."; + "Server received version negotiation packet."; QUIC_BUG << error_details; QUIC_CODE_COUNT(quic_tear_down_local_connection_on_version_negotiation); - TearDownLocalConnectionState(QUIC_INTERNAL_ERROR, error_details, - ConnectionCloseSource::FROM_SELF); + CloseConnection(QUIC_INTERNAL_ERROR, error_details, + ConnectionCloseBehavior::SILENT_CLOSE); return; } if (debug_visitor_ != nullptr) { @@ -718,9 +723,8 @@ void QuicConnection::OnVersionNegotiationPacket( "Server already supports client's version and should have accepted the " "connection."; QUIC_DLOG(WARNING) << error_details; - TearDownLocalConnectionState(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, - error_details, - ConnectionCloseSource::FROM_SELF); + CloseConnection(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, error_details, + ConnectionCloseBehavior::SILENT_CLOSE); return; } @@ -740,6 +744,7 @@ void QuicConnection::OnVersionNegotiationPacket( return; } + ParsedQuicVersion original_version = version(); if (!SelectMutualVersion(packet.versions)) { CloseConnection( QUIC_INVALID_VERSION, @@ -752,13 +757,56 @@ void QuicConnection::OnVersionNegotiationPacket( return; } + if (original_version.handshake_protocol != version().handshake_protocol) { + const std::string error_details = + "In-connection version negotiation between mismatched handshake " + " protocols " + + ParsedQuicVersionToString(original_version) + " and " + + ParsedQuicVersionToString(version()) + " is currently unsupported."; + QUIC_DLOG(WARNING) << error_details; + CloseConnection(QUIC_INVALID_VERSION, error_details, + ConnectionCloseBehavior::SILENT_CLOSE); + return; + } + QUIC_DLOG(INFO) << ENDPOINT << "Negotiated version: " - << QuicVersionToString(transport_version()); + << ParsedQuicVersionToString(version()); no_stop_waiting_frames_ = transport_version() > QUIC_VERSION_43; version_negotiation_state_ = NEGOTIATION_IN_PROGRESS; + RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); } +// Handles retry for client connection. +void QuicConnection::OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) { + DCHECK_EQ(Perspective::IS_CLIENT, perspective_); + if (original_connection_id != server_connection_id_) { + QUIC_DLOG(ERROR) << "Ignoring RETRY with original connection ID " + << original_connection_id << " not matching expected " + << server_connection_id_ << " token " + << QuicTextUtils::HexEncode(retry_token); + return; + } + if (retry_has_been_parsed_) { + QUIC_DLOG(ERROR) << "Ignoring non-first RETRY with token " + << QuicTextUtils::HexEncode(retry_token); + return; + } + retry_has_been_parsed_ = true; + QUIC_DLOG(INFO) << "Received RETRY, replacing connection ID " + << server_connection_id_ << " with " << new_connection_id + << ", received token " + << QuicTextUtils::HexEncode(retry_token); + server_connection_id_ = new_connection_id; + packet_generator_.SetServerConnectionId(server_connection_id_); + packet_generator_.SetRetryToken(retry_token); + + // Reinstall initial crypters because the connection ID changed. + InstallInitialCrypters(); +} + bool QuicConnection::HasIncomingConnectionId(QuicConnectionId connection_id) { for (QuicConnectionId const& incoming_connection_id : incoming_connection_ids_) { @@ -778,25 +826,28 @@ void QuicConnection::AddIncomingConnectionId(QuicConnectionId connection_id) { bool QuicConnection::OnUnauthenticatedPublicHeader( const QuicPacketHeader& header) { - if (header.destination_connection_id == connection_id_ || - HasIncomingConnectionId(header.destination_connection_id)) { + QuicConnectionId server_connection_id = + GetServerConnectionIdAsRecipient(header, perspective_); + + if (server_connection_id == server_connection_id_ || + HasIncomingConnectionId(server_connection_id)) { return true; } if (PacketCanReplaceConnectionId(header, perspective_)) { QUIC_DLOG(INFO) << ENDPOINT << "Accepting packet with new connection ID " - << header.destination_connection_id << " instead of " - << connection_id_; + << server_connection_id << " instead of " + << server_connection_id_; return true; } ++stats_.packets_dropped; QUIC_DLOG(INFO) << ENDPOINT << "Ignoring packet from unexpected ConnectionId: " - << header.destination_connection_id << " instead of " - << connection_id_; + << server_connection_id << " instead of " + << server_connection_id_; if (debug_visitor_ != nullptr) { - debug_visitor_->OnIncorrectConnectionId(header.destination_connection_id); + debug_visitor_->OnIncorrectConnectionId(server_connection_id); } // If this is a server, the dispatcher routes each packet to the // QuicConnection responsible for the packet's connection ID. So if control @@ -813,8 +864,10 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) { // Check that any public reset packet with a different connection ID that was // routed to this QuicConnection has been redirected before control reaches // here. - DCHECK(header.destination_connection_id == connection_id_ || - HasIncomingConnectionId(header.destination_connection_id) || + DCHECK(GetServerConnectionIdAsRecipient(header, perspective_) == + server_connection_id_ || + HasIncomingConnectionId( + GetServerConnectionIdAsRecipient(header, perspective_)) || PacketCanReplaceConnectionId(header, perspective_)); if (!packet_generator_.IsPendingPacketEmpty()) { @@ -988,7 +1041,7 @@ bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnStreamFrame(frame); } - if (frame.stream_id != QuicUtils::GetCryptoStreamId(transport_version()) && + if (!QuicUtils::IsCryptoStreamId(transport_version(), frame.stream_id) && last_decrypted_packet_level_ == ENCRYPTION_INITIAL) { if (MaybeConsiderAsMemoryCorruption(frame)) { CloseConnection(QUIC_MAYBE_CORRUPTED_MEMORY, @@ -1001,7 +1054,7 @@ bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) { << "Received an unencrypted data frame: closing connection" << " packet_number:" << last_header_.packet_number << " stream_id:" << frame.stream_id - << " received_packets:" << GetUpdatedAckFrame(); + << " received_packets:" << ack_frame(); CloseConnection(QUIC_UNENCRYPTED_STREAM_DATA, "Unencrypted stream data seen.", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -1070,7 +1123,7 @@ bool QuicConnection::OnAckFrameStart(QuicPacketNumber largest_acked, << " packet_number:" << last_header_.packet_number << " largest seen with ack:" << GetLargestReceivedPacketWithAck() - << " connection_id: " << connection_id_; + << " server_connection_id: " << server_connection_id_; // A new ack has a diminished largest_observed value. // If this was an old packet, we wouldn't even have checked. CloseConnection(QUIC_INVALID_ACK_DATA, "Largest observed too low.", @@ -1150,7 +1203,13 @@ bool QuicConnection::OnAckFrameEnd(QuicPacketNumber start) { // If the incoming ack's packets set expresses received packets: peer is still // acking packets which we never care about. // Send an ack to raise the high water mark. - PostProcessAfterAckFrame(GetLeastUnacked() > start, + bool send_stop_waiting = GetLeastUnacked() > start; + if (GetQuicReloadableFlag(quic_simplify_stop_waiting) && + no_stop_waiting_frames_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_simplify_stop_waiting); + send_stop_waiting = false; + } + PostProcessAfterAckFrame(send_stop_waiting, ack_result == PACKETS_NEWLY_ACKED); processing_ack_frame_ = false; @@ -1335,13 +1394,13 @@ bool QuicConnection::OnConnectionCloseFrame( return connected_; } -bool QuicConnection::OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) { - return visitor_->OnMaxStreamIdFrame(frame); +bool QuicConnection::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) { + return visitor_->OnMaxStreamsFrame(frame); } -bool QuicConnection::OnStreamIdBlockedFrame( - const QuicStreamIdBlockedFrame& frame) { - return visitor_->OnStreamIdBlockedFrame(frame); +bool QuicConnection::OnStreamsBlockedFrame( + const QuicStreamsBlockedFrame& frame) { + return visitor_->OnStreamsBlockedFrame(frame); } bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) { @@ -1442,7 +1501,8 @@ void QuicConnection::OnPacketComplete() { } QUIC_DVLOG(1) << ENDPOINT << "Got packet " << last_header_.packet_number - << " for " << last_header_.destination_connection_id; + << " for " + << GetServerConnectionIdAsRecipient(last_header_, perspective_); QUIC_DLOG_IF(INFO, current_packet_content_ == SECOND_FRAME_IS_PADDING) << ENDPOINT << "Received a padded PING packet. is_probing: " @@ -1451,7 +1511,8 @@ void QuicConnection::OnPacketComplete() { if (perspective_ == Perspective::IS_CLIENT) { QUIC_DVLOG(1) << ENDPOINT << "Received a speculative connectivity probing packet for " - << last_header_.destination_connection_id + << GetServerConnectionIdAsRecipient(last_header_, + perspective_) << " from ip:port: " << last_packet_source_address_.ToString() << " to ip:port: " << last_packet_destination_address_.ToString(); @@ -1462,7 +1523,8 @@ void QuicConnection::OnPacketComplete() { // This node is not a client (is a server) AND the received packet was // connectivity-probing, send an appropriate response. QUIC_DVLOG(1) << ENDPOINT << "Received a connectivity probing packet for " - << last_header_.destination_connection_id + << GetServerConnectionIdAsRecipient(last_header_, + perspective_) << " from ip:port: " << last_packet_source_address_.ToString() << " to ip:port: " << last_packet_destination_address_.ToString(); @@ -1502,11 +1564,31 @@ void QuicConnection::OnPacketComplete() { if (received_packet_manager_.decide_when_to_send_acks()) { if (use_uber_received_packet_manager_) { - uber_received_packet_manager_.MaybeUpdateAckTimeout( - should_last_packet_instigate_acks_, last_decrypted_packet_level_, - last_header_.packet_number, time_of_last_received_packet_, - clock_->ApproximateNow(), sent_packet_manager_.GetRttStats(), - sent_packet_manager_.delayed_ack_time()); + // Some encryption levels share a packet number space, it is therefore + // possible for us to want to ack some packets even though we do not yet + // have the appropriate keys to encrypt the acks. In this scenario we + // do not update the ACK timeout. This can happen for example with + // IETF QUIC on the server when we receive 0-RTT packets and do not yet + // have 1-RTT keys (0-RTT packets are acked at the 1-RTT level). + // Note that this could cause slight performance degradations in the edge + // case where one packet is received, then the encrypter is installed, + // then a second packet is received; as that could cause the ACK for the + // second packet to be delayed instead of immediate. This is currently + // considered to be small enough of an edge case to not be optimized for. + if (!SupportsMultiplePacketNumberSpaces() || + framer_.HasEncrypterOfEncryptionLevel(QuicUtils::GetEncryptionLevel( + QuicUtils::GetPacketNumberSpace(last_decrypted_packet_level_)))) { + uber_received_packet_manager_.MaybeUpdateAckTimeout( + should_last_packet_instigate_acks_, last_decrypted_packet_level_, + last_header_.packet_number, time_of_last_received_packet_, + clock_->ApproximateNow(), sent_packet_manager_.GetRttStats(), + sent_packet_manager_.delayed_ack_time()); + } else { + QUIC_DLOG(INFO) << ENDPOINT << "Not updating ACK timeout for " + << QuicUtils::EncryptionLevelToString( + last_decrypted_packet_level_) + << " as we do not have the corresponding encrypter"; + } } else { received_packet_manager_.MaybeUpdateAckTimeout( should_last_packet_instigate_acks_, last_header_.packet_number, @@ -1725,10 +1807,15 @@ void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic) { QUIC_DLOG(INFO) << ENDPOINT << "Sending version negotiation packet: {" << ParsedQuicVersionVectorToString( framer_.supported_versions()) - << "}, ietf_quic: " << ietf_quic; + << "}, " << (ietf_quic ? "" : "!") << "ietf_quic"; std::unique_ptr<QuicEncryptedPacket> version_packet( packet_generator_.SerializeVersionNegotiationPacket( ietf_quic, framer_.supported_versions())); + QUIC_DVLOG(2) << ENDPOINT << "Sending version negotiation packet: {" + << ParsedQuicVersionVectorToString(framer_.supported_versions()) + << "}, " << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl + << QuicTextUtils::HexDump(QuicStringPiece( + version_packet->data(), version_packet->length())); WriteResult result = writer_->WritePacket( version_packet->data(), version_packet->length(), self_address().host(), peer_address(), per_packet_options_); @@ -1779,13 +1866,19 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, } bool QuicConnection::SendControlFrame(const QuicFrame& frame) { - if (!CanWrite(HAS_RETRANSMITTABLE_DATA) && frame.type != PING_FRAME) { + if (!packet_generator_.deprecate_queued_control_frames() && + !CanWrite(HAS_RETRANSMITTABLE_DATA) && frame.type != PING_FRAME) { QUIC_DVLOG(1) << ENDPOINT << "Failed to send control frame: " << frame; // Do not check congestion window for ping. return false; } ScopedPacketFlusher flusher(this, SEND_ACK_IF_PENDING); - packet_generator_.AddControlFrame(frame); + const bool consumed = + packet_generator_.ConsumeRetransmittableControlFrame(frame); + if (packet_generator_.deprecate_queued_control_frames() && !consumed) { + QUIC_DVLOG(1) << ENDPOINT << "Failed to send control frame: " << frame; + return false; + } if (frame.type == PING_FRAME) { // Flush PING frame immediately. packet_generator_.FlushAllQueuedFrames(); @@ -1922,6 +2015,7 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address, // If we are unable to decrypt this packet, it might be // because the CHLO or SHLO packet was lost. if (framer_.error() == QUIC_DECRYPTION_FAILURE) { + ++stats_.undecryptable_packets_received; if (encryption_level_ != ENCRYPTION_FORWARD_SECURE && undecryptable_packets_.size() < max_undecryptable_packets_) { QueueUndecryptablePacket(packet); @@ -2064,11 +2158,12 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { } if (PacketCanReplaceConnectionId(header, perspective_) && - connection_id_ != header.source_connection_id) { - QUIC_DLOG(INFO) << ENDPOINT << "Replacing connection ID " << connection_id_ - << " with " << header.source_connection_id; - connection_id_ = header.source_connection_id; - packet_generator_.SetConnectionId(connection_id_); + server_connection_id_ != header.source_connection_id) { + QUIC_DLOG(INFO) << ENDPOINT << "Replacing connection ID " + << server_connection_id_ << " with " + << header.source_connection_id; + server_connection_id_ = header.source_connection_id; + packet_generator_.SetServerConnectionId(server_connection_id_); } if (!ValidateReceivedPacketNumber(header.packet_number)) { @@ -2260,10 +2355,7 @@ void QuicConnection::WritePendingRetransmissions() { void QuicConnection::SendProbingRetransmissions() { while (sent_packet_manager_.GetSendAlgorithm()->ShouldSendProbingPacket() && CanWrite(HAS_RETRANSMITTABLE_DATA)) { - const bool can_retransmit = - sent_packet_manager_.MaybeRetransmitOldestPacket( - PROBING_RETRANSMISSION); - if (!can_retransmit) { + if (!visitor_->SendProbingData()) { QUIC_DVLOG(1) << "Cannot send probing retransmissions: nothing to retransmit."; break; @@ -2324,7 +2416,14 @@ const QuicFrames QuicConnection::MaybeBundleAckOpportunistically() { ResetAckStates(); QUIC_DVLOG(1) << ENDPOINT << "Bundle an ACK opportunistically"; - frames.push_back(GetUpdatedAckFrame()); + QuicFrame updated_ack_frame = GetUpdatedAckFrame(); + QUIC_BUG_IF(updated_ack_frame.ack_frame->packets.Empty()) + << ENDPOINT << "Attempted to opportunistically bundle an empty " + << QuicUtils::EncryptionLevelToString(encryption_level_) << " ACK, " + << (has_pending_ack ? "" : "!") << "has_pending_ack, stop_waiting_count_ " + << stop_waiting_count_; + frames.push_back(updated_ack_frame); + if (!no_stop_waiting_frames_) { QuicStopWaitingFrame stop_waiting; PopulateStopWaitingFrame(&stop_waiting); @@ -2623,9 +2722,8 @@ void QuicConnection::OnWriteError(int error_code) { QUIC_LOG_FIRST_N(ERROR, 2) << ENDPOINT << error_details; switch (error_code) { case QUIC_EMSGSIZE: - CloseConnection( - QUIC_PACKET_WRITE_ERROR, error_details, - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK); + CloseConnection(QUIC_PACKET_WRITE_ERROR, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); break; default: // We can't send an error as the socket is presumably borked. @@ -2635,8 +2733,8 @@ void QuicConnection::OnWriteError(int error_code) { QUIC_CODE_COUNT( quic_tear_down_local_connection_on_write_error_non_ietf); } - TearDownLocalConnectionState(QUIC_PACKET_WRITE_ERROR, error_details, - ConnectionCloseSource::FROM_SELF); + CloseConnection(QUIC_PACKET_WRITE_ERROR, error_details, + ConnectionCloseBehavior::SILENT_CLOSE); } } @@ -2647,7 +2745,7 @@ char* QuicConnection::GetPacketBuffer() { void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) { if (serialized_packet->encrypted_buffer == nullptr) { // We failed to serialize the packet, so close the connection. - // TearDownLocalConnectionState does not send close packet, so no infinite + // Specify that the close is silent, that no packet be sent, so no infinite // loop here. // TODO(ianswett): This is actually an internal error, not an // encryption failure. @@ -2658,10 +2756,9 @@ void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) { QUIC_CODE_COUNT( quic_tear_down_local_connection_on_serialized_packet_non_ietf); } - TearDownLocalConnectionState( - QUIC_ENCRYPTION_FAILURE, - "Serialized packet does not have an encrypted buffer.", - ConnectionCloseSource::FROM_SELF); + CloseConnection(QUIC_ENCRYPTION_FAILURE, + "Serialized packet does not have an encrypted buffer.", + ConnectionCloseBehavior::SILENT_CLOSE); return; } @@ -2677,8 +2774,7 @@ void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) { } void QuicConnection::OnUnrecoverableError(QuicErrorCode error, - const std::string& error_details, - ConnectionCloseSource source) { + const std::string& error_details) { // The packet creator or generator encountered an unrecoverable error: tear // down local connection state immediately. if (transport_version() > QUIC_VERSION_43) { @@ -2688,7 +2784,7 @@ void QuicConnection::OnUnrecoverableError(QuicErrorCode error, QUIC_CODE_COUNT( quic_tear_down_local_connection_on_unrecoverable_error_non_ietf); } - TearDownLocalConnectionState(error, error_details, source); + CloseConnection(error, error_details, ConnectionCloseBehavior::SILENT_CLOSE); } void QuicConnection::OnCongestionChange() { @@ -2749,11 +2845,13 @@ void QuicConnection::OnPingTimeout() { sent_packet_manager_.enable_half_rtt_tail_loss_probe(); if (enable_half_rtt_tail_loss_probe && GetQuicReloadableFlag(quic_ignore_tlpr_if_sending_ping)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_sending_ping, 1, 2); sent_packet_manager_.set_enable_half_rtt_tail_loss_probe(false); } visitor_->SendPing(); if (enable_half_rtt_tail_loss_probe && GetQuicReloadableFlag(quic_ignore_tlpr_if_sending_ping)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_ignore_tlpr_if_sending_ping, 2, 2); sent_packet_manager_.set_enable_half_rtt_tail_loss_probe(true); } } @@ -2977,6 +3075,7 @@ void QuicConnection::MaybeProcessCoalescedPackets() { // If we are unable to decrypt this packet, it might be // because the CHLO or SHLO packet was lost. if (framer_.error() == QUIC_DECRYPTION_FAILURE) { + ++stats_.undecryptable_packets_received; if (encryption_level_ != ENCRYPTION_FORWARD_SECURE && undecryptable_packets_.size() < max_undecryptable_packets_) { QueueUndecryptablePacket(*packet); @@ -3007,13 +3106,8 @@ void QuicConnection::CloseConnection( << ", with error: " << QuicErrorCodeToString(error) << " (" << error << "), and details: " << error_details; - if (connection_close_behavior == - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET) { - SendConnectionClosePacket(error, error_details, SEND_ACK); - } else if (connection_close_behavior == - ConnectionCloseBehavior:: - SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK) { - SendConnectionClosePacket(error, error_details, NO_ACK); + if (connection_close_behavior != ConnectionCloseBehavior::SILENT_CLOSE) { + SendConnectionClosePacket(error, error_details); } ConnectionCloseSource source = ConnectionCloseSource::FROM_SELF; @@ -3022,18 +3116,17 @@ void QuicConnection::CloseConnection( // Regard stateless rejected connection as closed by server. source = ConnectionCloseSource::FROM_PEER; } + TearDownLocalConnectionState(error, error_details, source); } void QuicConnection::SendConnectionClosePacket(QuicErrorCode error, - const std::string& details, - AckBundling ack_mode) { + const std::string& details) { QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet."; - if (fix_termination_packets_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_termination_packets); - SetDefaultEncryptionLevel(GetConnectionCloseEncryptionLevel()); - } + SetDefaultEncryptionLevel(GetConnectionCloseEncryptionLevel()); ClearQueuedPackets(); + // If there was a packet write error, write the smallest close possible. + AckBundling ack_mode = (error == QUIC_PACKET_WRITE_ERROR) ? NO_ACK : SEND_ACK; ScopedPacketFlusher flusher(this, ack_mode); // When multiple packet number spaces is supported, an ACK frame will be // bundled when connection is not write blocked. @@ -3049,7 +3142,7 @@ void QuicConnection::SendConnectionClosePacket(QuicErrorCode error, if (transport_version() == QUIC_VERSION_99) { frame->close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE; } - packet_generator_.AddControlFrame(QuicFrame(frame)); + packet_generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame)); packet_generator_.FlushAllQueuedFrames(); } @@ -3085,6 +3178,7 @@ void QuicConnection::CancelAllAlarms() { timeout_alarm_->Cancel(); mtu_discovery_alarm_->Cancel(); path_degrading_alarm_->Cancel(); + process_undecryptable_packets_alarm_->Cancel(); } QuicByteCount QuicConnection::max_packet_length() const { @@ -3204,12 +3298,13 @@ void QuicConnection::SetTimeoutAlarm() { void QuicConnection::SetPingAlarm() { if (perspective_ == Perspective::IS_SERVER) { - // Only clients send pings. + // Only clients send pings to avoid NATs from timing out. return; } if (!visitor_->ShouldKeepConnectionAlive()) { ping_alarm_->Cancel(); - // Don't send a ping unless there are open streams. + // Don't send a ping unless the application (ie: HTTP/3) says to, usually + // because it is expecting a response from the server. return; } if (retransmittable_on_wire_timeout_.IsInfinite() || @@ -3517,7 +3612,7 @@ bool QuicConnection::SendGenericPathProbePacket( QUIC_DLOG(INFO) << ENDPOINT << "Sending path probe packet for connection_id = " - << connection_id_; + << server_connection_id_; OwningSerializedPacketPointer probing_packet; if (transport_version() != QUIC_VERSION_99) { @@ -3559,6 +3654,12 @@ bool QuicConnection::SendGenericPathProbePacket( DCHECK_EQ(IsRetransmittable(*probing_packet), NO_RETRANSMITTABLE_DATA); const QuicTime packet_send_time = clock_->Now(); + QUIC_DVLOG(2) << ENDPOINT + << "Sending path probe packet for server connection ID " + << server_connection_id_ << std::endl + << QuicTextUtils::HexDump( + QuicStringPiece(probing_packet->encrypted_buffer, + probing_packet->encrypted_length)); WriteResult result = probing_writer->WritePacket( probing_packet->encrypted_buffer, probing_packet->encrypted_length, self_address().host(), peer_address, per_packet_options_); @@ -3683,7 +3784,7 @@ QuicStringPiece QuicConnection::GetCurrentPacket() { bool QuicConnection::MaybeConsiderAsMemoryCorruption( const QuicStreamFrame& frame) { - if (frame.stream_id == QuicUtils::GetCryptoStreamId(transport_version()) || + if (QuicUtils::IsCryptoStreamId(transport_version(), frame.stream_id) || last_decrypted_packet_level_ != ENCRYPTION_INITIAL) { return false; } @@ -3830,8 +3931,6 @@ void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting, SetRetransmissionAlarm(); MaybeSetPathDegradingAlarm(acked_new_packet); - // TODO(ianswett): Only increment stop_waiting_count_ if StopWaiting frames - // are sent. if (send_stop_waiting) { ++stop_waiting_count_; } else { @@ -3948,13 +4047,14 @@ bool QuicConnection::ShouldSetAckAlarm() const { } EncryptionLevel QuicConnection::GetConnectionCloseEncryptionLevel() const { - DCHECK(fix_termination_packets_); if (perspective_ == Perspective::IS_CLIENT) { return encryption_level_; } if (sent_packet_manager_.handshake_confirmed()) { // A forward secure packet has been received. - QUIC_BUG_IF(encryption_level_ != ENCRYPTION_FORWARD_SECURE); + QUIC_BUG_IF(encryption_level_ != ENCRYPTION_FORWARD_SECURE) + << ENDPOINT << "Unexpected connection close encryption level " + << QuicUtils::EncryptionLevelToString(encryption_level_); return ENCRYPTION_FORWARD_SECURE; } if (framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_ZERO_RTT)) { @@ -3982,6 +4082,13 @@ void QuicConnection::SendAllPendingAcks() { ack_timeout > clock_->ApproximateNow()) { continue; } + if (!framer_.HasEncrypterOfEncryptionLevel( + QuicUtils::GetEncryptionLevel(static_cast<PacketNumberSpace>(i)))) { + QUIC_BUG << ENDPOINT << "Cannot send ACKs for packet number space " + << static_cast<uint32_t>(i) + << " without corresponding encrypter"; + continue; + } QUIC_DVLOG(1) << ENDPOINT << "Sending ACK of packet number space: " << static_cast<uint32_t>(i); // Switch to the appropriate encryption level. @@ -4137,5 +4244,16 @@ void QuicConnection::set_ack_frequency_before_ack_decimation(size_t new_value) { } } +const QuicAckFrame& QuicConnection::ack_frame() const { + if (SupportsMultiplePacketNumberSpaces()) { + return uber_received_packet_manager_.GetAckFrame( + QuicUtils::GetPacketNumberSpace(last_decrypted_packet_level_)); + } + if (use_uber_received_packet_manager_) { + return uber_received_packet_manager_.ack_frame(); + } + return received_packet_manager_.ack_frame(); +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h index c921d1b202a..9392f26e949 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h @@ -116,12 +116,11 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called when |message| has been received. virtual void OnMessageReceived(QuicStringPiece message) = 0; - // Called when a MAX_STREAM_ID frame has been received from the peer. - virtual bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) = 0; + // Called when a MAX_STREAMS frame has been received from the peer. + virtual bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) = 0; - // Called when a STREAM_ID_BLOCKED frame has been received from the peer. - virtual bool OnStreamIdBlockedFrame( - const QuicStreamIdBlockedFrame& frame) = 0; + // Called when a STREAMS_BLOCKED frame has been received from the peer. + virtual bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) = 0; // Called when the connection is closed either locally by the framer, or // remotely by the peer. @@ -144,6 +143,10 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called when a blocked socket becomes writable. virtual void OnCanWrite() = 0; + // Called when the connection needs more data to probe for additional + // bandwidth. Returns true if data was sent, false otherwise. + virtual bool SendProbingData() = 0; + // Called when the connection experiences a change in congestion window. virtual void OnCongestionWindowChange(QuicTime now) = 0; @@ -338,7 +341,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // |initial_peer_address| using |writer| to write packets. |owns_writer| // specifies whether the connection takes ownership of |writer|. |helper| must // outlive this connection. - QuicConnection(QuicConnectionId connection_id, + QuicConnection(QuicConnectionId server_connection_id, QuicSocketAddress initial_peer_address, QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, @@ -371,7 +374,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Allows the client to adjust network parameters based on external // information. - void AdjustNetworkParameters(QuicBandwidth bandwidth, QuicTime::Delta rtt); + void AdjustNetworkParameters(QuicBandwidth bandwidth, + QuicTime::Delta rtt, + bool allow_cwnd_to_decrease); // Returns the max pacing rate for the connection. virtual QuicBandwidth MaxPacingRate() const; @@ -478,6 +483,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection void OnPublicResetPacket(const QuicPublicResetPacket& packet) override; void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override; + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override; bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override; bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override; @@ -500,8 +508,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override; bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override; bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override; - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override; - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override; + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override; + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override; bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; bool OnBlockedFrame(const QuicBlockedFrame& frame) override; bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override; @@ -514,21 +522,20 @@ class QUIC_EXPORT_PRIVATE QuicConnection void OnAuthenticatedIetfStatelessResetPacket( const QuicIetfStatelessResetPacket& packet) override; - // QuicConnectionCloseDelegateInterface - void OnUnrecoverableError(QuicErrorCode error, - const std::string& error_details, - ConnectionCloseSource source) override; - // QuicPacketGenerator::DelegateInterface bool ShouldGeneratePacket(HasRetransmittableData retransmittable, IsHandshake handshake) override; const QuicFrames MaybeBundleAckOpportunistically() override; + // Please note, this is not a const function. For logging purpose, please use + // ack_frame(). const QuicFrame GetUpdatedAckFrame() override; void PopulateStopWaitingFrame(QuicStopWaitingFrame* stop_waiting) override; // QuicPacketCreator::DelegateInterface char* GetPacketBuffer() override; void OnSerializedPacket(SerializedPacket* packet) override; + void OnUnrecoverableError(QuicErrorCode error, + const std::string& error_details) override; // QuicSentPacketManager::NetworkChangeVisitor void OnCongestionChange() override; @@ -574,7 +581,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection const QuicSocketAddress& effective_peer_address() const { return effective_peer_address_; } - QuicConnectionId connection_id() const { return connection_id_; } + QuicConnectionId connection_id() const { return server_connection_id_; } const QuicClock* clock() const { return clock_; } QuicRandom* random_generator() const { return random_generator_; } QuicByteCount max_packet_length() const; @@ -833,8 +840,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection bool session_decides_what_to_write() const; - void SetRetransmittableOnWireAlarm(); - // Sets the current per-packet options for the connection. The QuicConnection // does not take ownership of |options|; |options| must live for as long as // the QuicConnection is in use. @@ -883,6 +888,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Returns true if this connection supports multiple packet number spaces. bool SupportsMultiplePacketNumberSpaces() const; + // For logging purpose. + const QuicAckFrame& ack_frame() const; + protected: // Calls cancel() on all the alarms owned by this connection. void CancelAllAlarms(); @@ -930,13 +938,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection return active_effective_peer_migration_type_; } - // Sends the connection close packet to the peer. |ack_mode| determines - // whether ack frame will be bundled with the connection close packet. - // TODO(fayang): change |ack_mode| to bool |force_sending_ack| when - // deprecating quic_deprecate_ack_bundling_mode. + // Sends a connection close packet to the peer and includes an ACK if the ACK + // is not empty, the |error| is not PACKET_WRITE_ERROR, and it fits. virtual void SendConnectionClosePacket(QuicErrorCode error, - const std::string& details, - AckBundling ack_mode); + const std::string& details); // Returns true if the packet should be discarded and not sent. virtual bool ShouldDiscardPacket(const SerializedPacket& packet); @@ -968,7 +973,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection typedef std::list<SerializedPacket> QueuedPacketList; // Notifies the visitor of the close and marks the connection as disconnected. - // Does not send a connection close frame to the peer. + // Does not send a connection close frame to the peer. It should only be + // called by CloseConnection or OnConnectionCloseFrame, OnPublicResetPacket, + // and OnAuthenticatedIetfStatelessResetPacket. void TearDownLocalConnectionState(QuicErrorCode error, const std::string& details, ConnectionCloseSource source); @@ -1137,6 +1144,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Whether incoming_connection_ids_ contains connection_id. bool HasIncomingConnectionId(QuicConnectionId connection_id); + // Install encrypter and decrypter for ENCRYPTION_INITIAL. + void InstallInitialCrypters(); + QuicFramer framer_; // Contents received in the current packet, especially used to identify @@ -1162,7 +1172,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection const QuicClock* clock_; QuicRandom* random_generator_; - QuicConnectionId connection_id_; + QuicConnectionId server_connection_id_; // Address on the last successfully processed packet received from the // direct peer. QuicSocketAddress self_address_; @@ -1278,6 +1288,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicPacketCount num_packets_received_since_last_ack_sent_; // Indicates how many consecutive times an ack has arrived which indicates // the peer needs to stop waiting for some packets. + // TODO(fayang): remove this when deprecating quic_simplify_stop_waiting. int stop_waiting_count_; // TODO(fayang): Remove ack_mode_, ack_decimation_delay_, // unlimited_ack_decimation_, fast_ack_after_quiescence_ when deprecating @@ -1502,9 +1513,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection // vector to improve performance since it is expected to be very small. std::vector<QuicConnectionId> incoming_connection_ids_; - // Latched value of quic_fix_termination_packets. - const bool fix_termination_packets_; - // Indicates whether an ACK needs to be sent in OnCanWrite(). Only used when // deprecate_ack_bundling_mode is true. // TODO(fayang): Remove this when ACK sending logic is moved to received @@ -1512,6 +1520,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // needs to be sent. bool send_ack_when_on_can_write_; + // Indicates whether a RETRY packet has been parsed. + bool retry_has_been_parsed_; + // Latched value of quic_validate_packet_number_post_decryption. const bool validate_packet_number_post_decryption_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_close_delegate_interface.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_close_delegate_interface.h deleted file mode 100644 index b245f4c16a9..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_close_delegate_interface.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_QUIC_CONNECTION_CLOSE_DELEGATE_INTERFACE_H_ -#define QUICHE_QUIC_CORE_QUIC_CONNECTION_CLOSE_DELEGATE_INTERFACE_H_ - -#include <string> - -#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" - -namespace quic { - -// Pure virtual class to close connection on unrecoverable errors. -class QUIC_EXPORT_PRIVATE QuicConnectionCloseDelegateInterface { - public: - virtual ~QuicConnectionCloseDelegateInterface() {} - - // Called when an unrecoverable error is encountered. - virtual void OnUnrecoverableError(QuicErrorCode error, - const std::string& error_details, - ConnectionCloseSource source) = 0; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_CORE_QUIC_CONNECTION_CLOSE_DELEGATE_INTERFACE_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_test.cc index c855192c8c8..bbe04f95c2c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_id_test.cc @@ -8,7 +8,6 @@ #include <cstring> #include <string> -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc index 4d5c578c3a6..246b9f1200c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc @@ -29,6 +29,7 @@ QuicConnectionStats::QuicConnectionStats() slowstart_duration(QuicTime::Delta::Zero()), slowstart_start_time(QuicTime::Zero()), packets_dropped(0), + undecryptable_packets_received(0), crypto_retransmit_count(0), loss_timeout_count(0), tlp_count(0), @@ -71,6 +72,7 @@ std::ostream& operator<<(std::ostream& os, const QuicConnectionStats& s) { os << " slowstart_packets_lost: " << s.slowstart_packets_lost; os << " slowstart_bytes_lost: " << s.slowstart_bytes_lost; os << " packets_dropped: " << s.packets_dropped; + os << " undecryptable_packets_received: " << s.undecryptable_packets_received; os << " crypto_retransmit_count: " << s.crypto_retransmit_count; os << " loss_timeout_count: " << s.loss_timeout_count; os << " tlp_count: " << s.tlp_count; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h index df2f7f8ba7d..5317c7a6180 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h @@ -66,6 +66,10 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats { QuicTime slowstart_start_time; QuicPacketCount packets_dropped; // Duplicate or less than least unacked. + + // Packets that failed to decrypt when they were first received. + QuicPacketCount undecryptable_packets_received; + size_t crypto_retransmit_count; // Count of times the loss detection alarm fired. At least one packet should // be lost when the alarm fires. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc index 56b0453b51a..554f71a59c9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc @@ -65,8 +65,8 @@ namespace quic { namespace test { namespace { -const char data1[] = "foo"; -const char data2[] = "bar"; +const char data1[] = "foo data"; +const char data2[] = "bar data"; const bool kHasStopWaiting = true; @@ -660,7 +660,7 @@ class TestConnection : public QuicConnection { QuicStreamOffset offset, StreamSendingState state) { ScopedPacketFlusher flusher(this, NO_ACK); - if (id != QuicUtils::GetCryptoStreamId(transport_version()) && + if (!QuicUtils::IsCryptoStreamId(transport_version(), id) && this->encryption_level() == ENCRYPTION_INITIAL) { this->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); } @@ -709,6 +709,11 @@ class TestConnection : public QuicConnection { QuicConsumedData SendCryptoStreamData() { QuicStreamOffset offset = 0; QuicStringPiece data("chlo"); + return SendCryptoDataWithString(data, offset); + } + + QuicConsumedData SendCryptoDataWithString(QuicStringPiece data, + QuicStreamOffset offset) { if (!QuicVersionUsesCryptoFrames(transport_version())) { return SendStreamDataWithString( QuicUtils::GetCryptoStreamId(transport_version()), data, offset, @@ -806,8 +811,7 @@ class TestConnection : public QuicConnection { } QuicByteCount GetBytesInFlight() { - return QuicSentPacketManagerPeer::GetBytesInFlight( - QuicConnectionPeer::GetSentPacketManager(this)); + return QuicConnectionPeer::GetSentPacketManager(this)->GetBytesInFlight(); } void set_notifier(SimpleSessionNotifier* notifier) { notifier_ = notifier; } @@ -816,6 +820,8 @@ class TestConnection : public QuicConnection { next_effective_peer_addr_ = QuicMakeUnique<QuicSocketAddress>(addr); } + SimpleDataProducer* producer() { return &producer_; } + using QuicConnection::active_effective_peer_migration_type; using QuicConnection::IsCurrentPacketConnectivityProbing; using QuicConnection::SelectMutualVersion; @@ -869,7 +875,7 @@ struct TestParams { // Constructs various test permutations. std::vector<TestParams> GetTestParams() { QuicFlagSaver flags; - SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); std::vector<TestParams> params; ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); for (size_t i = 0; i < all_supported_versions.size(); ++i) { @@ -877,11 +883,11 @@ std::vector<TestParams> GetTestParams() { {AckResponse::kDefer, AckResponse::kImmediate}) { for (bool no_stop_waiting : {true, false}) { // After version 43, never use STOP_WAITING. - if (all_supported_versions[i].transport_version <= QUIC_VERSION_43 || - no_stop_waiting) { - params.push_back(TestParams(all_supported_versions[i], ack_response, - no_stop_waiting)); - } + params.push_back(TestParams( + all_supported_versions[i], ack_response, + all_supported_versions[i].transport_version <= QUIC_VERSION_43 + ? no_stop_waiting + : true)); } } } @@ -918,21 +924,29 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { creator_(QuicConnectionPeer::GetPacketCreator(&connection_)), generator_(QuicConnectionPeer::GetPacketGenerator(&connection_)), manager_(QuicConnectionPeer::GetSentPacketManager(&connection_)), - frame1_(QuicUtils::GetCryptoStreamId(version().transport_version), - false, - 0, - QuicStringPiece(data1)), - frame2_(QuicUtils::GetCryptoStreamId(version().transport_version), - false, - 3, - QuicStringPiece(data2)), + frame1_(0, false, 0, QuicStringPiece(data1)), + frame2_(0, false, 3, QuicStringPiece(data2)), + crypto_frame_(ENCRYPTION_INITIAL, 0, QuicStringPiece(data1)), packet_number_length_(PACKET_4BYTE_PACKET_NUMBER), connection_id_included_(CONNECTION_ID_PRESENT), notifier_(&connection_) { - SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); connection_.set_defer_send_in_response_to_packets(GetParam().ack_response == AckResponse::kDefer); - QuicFramerPeer::SetLastSerializedConnectionId( + for (EncryptionLevel level : + {ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) { + peer_creator_.SetEncrypter( + level, QuicMakeUnique<NullEncrypter>(peer_framer_.perspective())); + } + if (version().handshake_protocol == PROTOCOL_TLS1_3) { + connection_.SetEncrypter( + ENCRYPTION_INITIAL, + QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT)); + connection_.InstallDecrypter( + ENCRYPTION_INITIAL, + QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); + } + QuicFramerPeer::SetLastSerializedServerConnectionId( QuicConnectionPeer::GetFramer(&connection_), connection_id_); if (version().transport_version > QUIC_VERSION_43) { EXPECT_TRUE(QuicConnectionPeer::GetNoStopWaitingFrames(&connection_)); @@ -940,6 +954,15 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { QuicConnectionPeer::SetNoStopWaitingFrames(&connection_, GetParam().no_stop_waiting); } + QuicStreamId stream_id; + if (QuicVersionUsesCryptoFrames(version().transport_version)) { + stream_id = QuicUtils::GetFirstBidirectionalStreamId( + version().transport_version, Perspective::IS_CLIENT); + } else { + stream_id = QuicUtils::GetCryptoStreamId(version().transport_version); + } + frame1_.stream_id = stream_id; + frame2_.stream_id = stream_id; connection_.set_visitor(&visitor_); if (connection_.session_decides_what_to_write()) { connection_.SetSessionNotifier(¬ifier_); @@ -1052,13 +1075,6 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { frames.push_back(QuicFrame(frame)); QuicPacketCreatorPeer::SetSendVersionInPacket( &peer_creator_, connection_.perspective() == Perspective::IS_SERVER); - if (QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_) > - ENCRYPTION_INITIAL) { - // Set peer_framer_'s corresponding encrypter. - peer_creator_.SetEncrypter( - QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_), - QuicMakeUnique<NullEncrypter>(peer_framer_.perspective())); - } char buffer[kMaxOutgoingPacketSize]; SerializedPacket serialized_packet = @@ -1110,7 +1126,8 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { header.destination_connection_id = connection_id_; header.packet_number_length = packet_number_length_; header.destination_connection_id_included = connection_id_included_; - if (peer_framer_.transport_version() > QUIC_VERSION_43 && + if ((peer_framer_.transport_version() > QUIC_VERSION_43 || + GetQuicRestartFlag(quic_do_not_override_connection_id)) && peer_framer_.perspective() == Perspective::IS_SERVER) { header.destination_connection_id_included = CONNECTION_ID_ABSENT; } @@ -1119,10 +1136,14 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { header.version_flag = true; header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; - if (peer_framer_.perspective() == Perspective::IS_SERVER) { - header.source_connection_id = connection_id_; - header.source_connection_id_included = CONNECTION_ID_PRESENT; - } + } + if ((GetQuicRestartFlag(quic_do_not_override_connection_id) || + (level == ENCRYPTION_INITIAL && + peer_framer_.version().KnowsWhichDecrypterToUse())) && + header.version_flag && + peer_framer_.perspective() == Perspective::IS_SERVER) { + header.source_connection_id = connection_id_; + header.source_connection_id_included = CONNECTION_ID_PRESENT; } header.packet_number = QuicPacketNumber(number); QuicFrames frames; @@ -1163,11 +1184,12 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { } size_t ProcessDataPacket(uint64_t number) { - return ProcessDataPacketAtLevel(number, false, ENCRYPTION_INITIAL); + return ProcessDataPacketAtLevel(number, false, ENCRYPTION_FORWARD_SECURE); } size_t ProcessDataPacket(QuicPacketNumber packet_number) { - return ProcessDataPacketAtLevel(packet_number, false, ENCRYPTION_INITIAL); + return ProcessDataPacketAtLevel(packet_number, false, + ENCRYPTION_FORWARD_SECURE); } size_t ProcessDataPacketAtLevel(QuicPacketNumber packet_number, @@ -1177,6 +1199,29 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { level); } + size_t ProcessCryptoPacketAtLevel(uint64_t number, EncryptionLevel level) { + QuicPacketHeader header = ConstructPacketHeader(1000, ENCRYPTION_INITIAL); + QuicFrames frames; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frames.push_back(QuicFrame(&crypto_frame_)); + } else { + frames.push_back(QuicFrame(frame1_)); + } + std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames); + char buffer[kMaxOutgoingPacketSize]; + peer_creator_.set_encryption_level(ENCRYPTION_INITIAL); + size_t encrypted_length = + peer_framer_.EncryptPayload(ENCRYPTION_INITIAL, QuicPacketNumber(1000), + *packet, buffer, kMaxOutgoingPacketSize); + connection_.ProcessUdpPacket( + kSelfAddress, kPeerAddress, + QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false)); + if (connection_.GetSendAlarm()->IsSet()) { + connection_.GetSendAlarm()->Fire(); + } + return encrypted_length; + } + size_t ProcessDataPacketAtLevel(uint64_t number, bool has_stop_waiting, EncryptionLevel level) { @@ -1299,9 +1344,8 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { return packet; } - std::unique_ptr<QuicPacket> ConstructDataPacket(uint64_t number, - bool has_stop_waiting, - EncryptionLevel level) { + QuicPacketHeader ConstructPacketHeader(uint64_t number, + EncryptionLevel level) { QuicPacketHeader header; if (peer_framer_.transport_version() > QUIC_VERSION_43 && level < ENCRYPTION_FORWARD_SECURE) { @@ -1318,9 +1362,15 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { } // Set connection_id to peer's in memory representation as this data packet // is created by peer_framer. - header.destination_connection_id = connection_id_; - header.packet_number_length = packet_number_length_; - header.destination_connection_id_included = connection_id_included_; + if (GetQuicRestartFlag(quic_do_not_override_connection_id) && + peer_framer_.perspective() == Perspective::IS_SERVER) { + header.source_connection_id = connection_id_; + header.source_connection_id_included = connection_id_included_; + header.destination_connection_id_included = CONNECTION_ID_ABSENT; + } else { + header.destination_connection_id = connection_id_; + header.destination_connection_id_included = connection_id_included_; + } if (peer_framer_.transport_version() > QUIC_VERSION_43 && peer_framer_.perspective() == Perspective::IS_SERVER) { header.destination_connection_id_included = CONNECTION_ID_ABSENT; @@ -1333,8 +1383,15 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { } } } + header.packet_number_length = packet_number_length_; header.packet_number = QuicPacketNumber(number); + return header; + } + std::unique_ptr<QuicPacket> ConstructDataPacket(uint64_t number, + bool has_stop_waiting, + EncryptionLevel level) { + QuicPacketHeader header = ConstructPacketHeader(number, level); QuicFrames frames; frames.push_back(QuicFrame(frame1_)); if (has_stop_waiting) { @@ -1359,13 +1416,22 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { QuicPacketHeader header; // Set connection_id to peer's in memory representation as this connection // close packet is created by peer_framer. - header.destination_connection_id = connection_id_; - header.packet_number = QuicPacketNumber(number); - if (peer_framer_.transport_version() > QUIC_VERSION_43 && + if (GetQuicRestartFlag(quic_do_not_override_connection_id) && peer_framer_.perspective() == Perspective::IS_SERVER) { + header.source_connection_id = connection_id_; header.destination_connection_id_included = CONNECTION_ID_ABSENT; + if (peer_framer_.transport_version() <= QUIC_VERSION_43) { + header.source_connection_id_included = CONNECTION_ID_PRESENT; + } + } else { + header.destination_connection_id = connection_id_; + if (peer_framer_.transport_version() > QUIC_VERSION_43) { + header.destination_connection_id_included = CONNECTION_ID_ABSENT; + } } + header.packet_number = QuicPacketNumber(number); + QuicConnectionCloseFrame qccf(QUIC_PEER_GOING_AWAY); if (peer_framer_.transport_version() == QUIC_VERSION_99) { // Default close-type is Google QUIC. If doing IETF/V99 then @@ -1495,6 +1561,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { QuicStreamFrame frame1_; QuicStreamFrame frame2_; + QuicCryptoFrame crypto_frame_; QuicAckFrame ack_; QuicStopWaitingFrame stop_waiting_; QuicPacketNumberLength packet_number_length_; @@ -1509,34 +1576,36 @@ INSTANTIATE_TEST_SUITE_P(SupportedVersion, ::testing::ValuesIn(GetTestParams())); TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); EXPECT_TRUE(connection_.connected()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); // Cause change in self_address. QuicIpAddress host; host.FromString("1.1.1.1"); QuicSocketAddress self_address(host, 123); - EXPECT_CALL(visitor_, OnStreamFrame(_)); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address, - kPeerAddress); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)); + } + ProcessFramePacketWithAddresses(frame, self_address, kPeerAddress); EXPECT_TRUE(connection_.connected()); } TEST_P(QuicConnectionTest, SelfAddressChangeAtServer) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); @@ -1545,27 +1614,28 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtServer) { EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); EXPECT_TRUE(connection_.connected()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); // Cause change in self_address. QuicIpAddress host; host.FromString("1.1.1.1"); QuicSocketAddress self_address(host, 123); EXPECT_CALL(visitor_, AllowSelfAddressChange()).WillOnce(Return(false)); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_ERROR_MIGRATING_ADDRESS, _, _)); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, self_address, kPeerAddress); EXPECT_FALSE(connection_.connected()); } TEST_P(QuicConnectionTest, AllowSelfAddressChangeToMappedIpv4AddressAtServer) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); @@ -1574,33 +1644,33 @@ TEST_P(QuicConnectionTest, AllowSelfAddressChangeToMappedIpv4AddressAtServer) { EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); EXPECT_TRUE(connection_.connected()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(3); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3); + } QuicIpAddress host; host.FromString("1.1.1.1"); QuicSocketAddress self_address1(host, 443); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address1, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, self_address1, kPeerAddress); // Cause self_address change to mapped Ipv4 address. QuicIpAddress host2; host2.FromString( QuicStrCat("::ffff:", connection_.self_address().host().ToString())); QuicSocketAddress self_address2(host2, connection_.self_address().port()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address2, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, self_address2, kPeerAddress); EXPECT_TRUE(connection_.connected()); // self_address change back to Ipv4 address. - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address1, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, self_address1, kPeerAddress); EXPECT_TRUE(connection_.connected()); } TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1612,16 +1682,21 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { QuicConnectionPeer::SetEffectivePeerAddress(&connection_, QuicSocketAddress()); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kNewPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); @@ -1629,16 +1704,12 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 4); // This is an old packet, do not migrate. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1652,12 +1723,17 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -1666,16 +1742,12 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kNewPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1691,12 +1763,17 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/43210); connection_.ReturnEffectivePeerAddressForNextPacket(kEffectivePeerAddress); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kEffectivePeerAddress, connection_.effective_peer_address()); @@ -1706,8 +1783,7 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/54321); connection_.ReturnEffectivePeerAddressForNextPacket(kNewEffectivePeerAddress); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewEffectivePeerAddress, connection_.effective_peer_address()); @@ -1736,8 +1812,7 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { connection_.ReturnEffectivePeerAddressForNextPacket( kNewerEffectivePeerAddress); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kFinalPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kFinalPeerAddress); EXPECT_EQ(kFinalPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewerEffectivePeerAddress, connection_.effective_peer_address()); EXPECT_EQ(PORT_CHANGE, connection_.active_effective_peer_migration_type()); @@ -1751,8 +1826,7 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { kNewestEffectivePeerAddress); EXPECT_CALL(visitor_, OnConnectionMigration(IPV6_TO_IPV4_CHANGE)).Times(1); EXPECT_CALL(*send_algorithm_, OnConnectionMigration()).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kFinalPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kFinalPeerAddress); EXPECT_EQ(kFinalPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewestEffectivePeerAddress, connection_.effective_peer_address()); EXPECT_EQ(IPV6_TO_IPV4_CHANGE, @@ -1760,9 +1834,6 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { } TEST_P(QuicConnectionTest, ReceivePaddedPingAtServer) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1776,12 +1847,17 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -1845,9 +1921,6 @@ TEST_P(QuicConnectionTest, WriteOutOfOrderQueuedPackets) { } TEST_P(QuicConnectionTest, DiscardQueuedPacketsAfterConnectionClose) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Regression test for b/74073386. { InSequence seq; @@ -1873,9 +1946,6 @@ TEST_P(QuicConnectionTest, DiscardQueuedPacketsAfterConnectionClose) { } TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1889,12 +1959,17 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -1924,16 +1999,12 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { // Process another packet with the old peer address on server side will not // start peer migration. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); } TEST_P(QuicConnectionTest, ReceiveReorderedConnectivityProbingAtServer) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -1947,13 +2018,18 @@ TEST_P(QuicConnectionTest, ReceiveReorderedConnectivityProbingAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -1986,9 +2062,6 @@ TEST_P(QuicConnectionTest, ReceiveReorderedConnectivityProbingAtServer) { } TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -2002,12 +2075,17 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2032,16 +2110,12 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { // side will start peer migration. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kNewPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_CLIENT); EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); @@ -2054,12 +2128,17 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2084,9 +2163,6 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { } TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtClient) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_CLIENT); EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); @@ -2099,12 +2175,17 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtClient) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2132,9 +2213,6 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtClient) { } TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_CLIENT); EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); @@ -2147,12 +2225,17 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2161,24 +2244,17 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) { const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kNewPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } TEST_P(QuicConnectionTest, MaxPacketSize) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); EXPECT_EQ(1350u, connection_.max_packet_length()); } TEST_P(QuicConnectionTest, SmallerServerMaxPacketSize) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } TestConnection connection(TestConnectionId(), kPeerAddress, helper_.get(), alarm_factory_.get(), writer_.get(), Perspective::IS_SERVER, version()); @@ -2187,9 +2263,6 @@ TEST_P(QuicConnectionTest, SmallerServerMaxPacketSize) { } TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); @@ -2209,7 +2282,11 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) { QuicFrames frames; QuicPaddingFrame padding; - frames.push_back(QuicFrame(frame1_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frames.push_back(QuicFrame(&crypto_frame_)); + } else { + frames.push_back(QuicFrame(frame1_)); + } frames.push_back(QuicFrame(padding)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxOutgoingPacketSize]; @@ -2219,7 +2296,11 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) { EXPECT_EQ(kMaxOutgoingPacketSize, encrypted_length); framer_.set_version(version()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + } connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); @@ -2228,9 +2309,6 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) { } TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSizeWhileWriterLimited) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); const QuicByteCount lower_max_packet_size = 1240; @@ -2253,7 +2331,11 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSizeWhileWriterLimited) { QuicFrames frames; QuicPaddingFrame padding; - frames.push_back(QuicFrame(frame1_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frames.push_back(QuicFrame(&crypto_frame_)); + } else { + frames.push_back(QuicFrame(frame1_)); + } frames.push_back(QuicFrame(padding)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxOutgoingPacketSize]; @@ -2263,7 +2345,11 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSizeWhileWriterLimited) { EXPECT_EQ(kMaxOutgoingPacketSize, encrypted_length); framer_.set_version(version()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + } connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); @@ -2274,9 +2360,6 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSizeWhileWriterLimited) { } TEST_P(QuicConnectionTest, LimitMaxPacketSizeByWriter) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } const QuicByteCount lower_max_packet_size = 1240; writer_->set_max_packet_size(lower_max_packet_size); @@ -2288,9 +2371,6 @@ TEST_P(QuicConnectionTest, LimitMaxPacketSizeByWriter) { } TEST_P(QuicConnectionTest, LimitMaxPacketSizeByWriterForNewConnection) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } const QuicConnectionId connection_id = TestConnectionId(17); const QuicByteCount lower_max_packet_size = 1240; writer_->set_max_packet_size(lower_max_packet_size); @@ -2413,9 +2493,6 @@ TEST_P(QuicConnectionTest, RejectPacketTooFarOut) { } TEST_P(QuicConnectionTest, RejectUnencryptedStreamData) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. if (!IsDefaultTestConfiguration()) { return; @@ -2426,20 +2503,18 @@ TEST_P(QuicConnectionTest, RejectUnencryptedStreamData) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_UNENCRYPTED_STREAM_DATA, _, ConnectionCloseSource::FROM_SELF)); - EXPECT_QUIC_PEER_BUG(ProcessDataPacket(1), ""); + EXPECT_QUIC_PEER_BUG(ProcessDataPacketAtLevel(1, false, ENCRYPTION_INITIAL), + ""); EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) == nullptr); const std::vector<QuicConnectionCloseFrame>& connection_close_frames = writer_->connection_close_frames(); - EXPECT_EQ(1u, connection_close_frames.size()); + ASSERT_EQ(1u, connection_close_frames.size()); EXPECT_EQ(QUIC_UNENCRYPTED_STREAM_DATA, connection_close_frames[0].quic_error_code); } TEST_P(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(3); @@ -2478,9 +2553,6 @@ TEST_P(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) { } TEST_P(QuicConnectionTest, OutOfOrderAckReceiptCausesNoAck) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr); @@ -2500,9 +2572,6 @@ TEST_P(QuicConnectionTest, OutOfOrderAckReceiptCausesNoAck) { } TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacketNumber original, second; @@ -2543,7 +2612,8 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)); connection_.SendStreamDataWithString(3, "foo", 6, NO_FIN); // No ack sent. - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->stream_frames().size()); // No more packet loss for the rest of the test. @@ -2552,15 +2622,25 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { ProcessAckPacket(&frame2); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)); - connection_.SendStreamDataWithString(3, "foo", 9, NO_FIN); + connection_.SendStreamDataWithString(3, "foofoofoo", 9, NO_FIN); // Ack bundled. if (GetParam().no_stop_waiting) { - EXPECT_EQ(2u, writer_->frame_count()); + if (GetQuicReloadableFlag(quic_simplify_stop_waiting)) { + // Do not ACK acks. + EXPECT_EQ(1u, writer_->frame_count()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + } } else { EXPECT_EQ(3u, writer_->frame_count()); } EXPECT_EQ(1u, writer_->stream_frames().size()); - EXPECT_FALSE(writer_->ack_frames().empty()); + if (GetParam().no_stop_waiting && + GetQuicReloadableFlag(quic_simplify_stop_waiting)) { + EXPECT_TRUE(writer_->ack_frames().empty()); + } else { + EXPECT_FALSE(writer_->ack_frames().empty()); + } // But an ack with no missing packets will not send an ack. AckPacket(original, &frame2); @@ -2569,9 +2649,6 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { } TEST_P(QuicConnectionTest, AckSentEveryNthPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.set_ack_frequency_before_ack_decimation(3); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -2586,9 +2663,6 @@ TEST_P(QuicConnectionTest, AckSentEveryNthPacket) { } TEST_P(QuicConnectionTest, AckDecimationReducesAcks) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } const size_t kMinRttMs = 40; RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), @@ -2616,9 +2690,7 @@ TEST_P(QuicConnectionTest, AckDecimationReducesAcks) { } TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(99); @@ -2646,7 +2718,8 @@ TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) { } // Send a packet containing stream frame. SendStreamDataToPeer( - QuicUtils::GetCryptoStreamId(connection_.version().transport_version), + QuicUtils::GetFirstBidirectionalStreamId( + connection_.version().transport_version, Perspective::IS_CLIENT), "bar", 0, NO_FIN, nullptr); // Session will not be informed until receiving another 20 packets. @@ -2705,9 +2778,6 @@ TEST_P(QuicConnectionTest, LeastUnackedLower) { } TEST_P(QuicConnectionTest, TooManySentPackets) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacketCount max_tracked_packets = 50; @@ -2731,9 +2801,6 @@ TEST_P(QuicConnectionTest, TooManySentPackets) { } TEST_P(QuicConnectionTest, LargestObservedLower) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr); @@ -2758,9 +2825,6 @@ TEST_P(QuicConnectionTest, LargestObservedLower) { } TEST_P(QuicConnectionTest, AckUnsentData) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Ack a packet which has not been sent. EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, _, ConnectionCloseSource::FROM_SELF)); @@ -2866,9 +2930,6 @@ TEST_P(QuicConnectionTest, BasicSending) { // QuicConnection should record the packet sent-time prior to sending the // packet. TEST_P(QuicConnectionTest, RecordSentTimeBeforePacketSent) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // We're using a MockClock for the tests, so we have complete control over the // time. // Our recorded timestamp for the last packet sent time will be passed in to @@ -2900,9 +2961,6 @@ TEST_P(QuicConnectionTest, RecordSentTimeBeforePacketSent) { } TEST_P(QuicConnectionTest, FramePacking) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Send two stream frames in 1 packet by queueing them. connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); { @@ -2935,9 +2993,6 @@ TEST_P(QuicConnectionTest, FramePacking) { } TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Send two stream frames (one non-crypto, then one crypto) in 2 packets by // queueing them. connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); @@ -2964,9 +3019,6 @@ TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) { } TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Send two stream frames (one crypto, then one non-crypto) in 2 packets by // queueing them. { @@ -2981,7 +3033,8 @@ TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) { EXPECT_FALSE(connection_.HasQueuedData()); // Parse the last packet and ensure it's the stream frame from stream 3. - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); ASSERT_EQ(1u, writer_->stream_frames().size()); EXPECT_EQ(GetNthClientInitiatedStreamId(1, connection_.transport_version()), writer_->stream_frames()[0]->stream_id); @@ -2996,9 +3049,13 @@ TEST_P(QuicConnectionTest, FramePackingAckResponse) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacket(1); QuicPacketNumber last_packet; - SendStreamDataToPeer( - QuicUtils::GetCryptoStreamId(connection_.version().transport_version), - "foo", 0, NO_FIN, &last_packet); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + connection_.SendCryptoDataWithString("foo", 0); + } else { + SendStreamDataToPeer( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, + NO_FIN, &last_packet); + } // Verify ack is bundled with outging packet. EXPECT_FALSE(writer_->ack_frames().empty()); @@ -3016,7 +3073,7 @@ TEST_P(QuicConnectionTest, FramePackingAckResponse) { QuicMakeUnique<TaggingEncrypter>(0x01)); SetDecrypter(ENCRYPTION_FORWARD_SECURE, QuicMakeUnique<StrictTaggingDecrypter>(0x01)); - ProcessDataPacketAtLevel(2, false, ENCRYPTION_FORWARD_SECURE); + ProcessDataPacket(2); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); @@ -3039,9 +3096,7 @@ TEST_P(QuicConnectionTest, FramePackingAckResponse) { } TEST_P(QuicConnectionTest, FramePackingSendv) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Send data in 1 packet by writing multiple blocks in a single iovector // using writev. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); @@ -3052,28 +3107,25 @@ TEST_P(QuicConnectionTest, FramePackingSendv) { iov[0].iov_len = 4; iov[1].iov_base = data + 4; iov[1].iov_len = 2; - connection_.SaveAndSendStreamData( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), iov, 2, 6, - 0, NO_FIN); + QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( + connection_.transport_version(), Perspective::IS_CLIENT); + connection_.SaveAndSendStreamData(stream_id, iov, 2, 6, 0, NO_FIN); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); // Parse the last packet and ensure multiple iovector blocks have // been packed into a single stream frame from one stream. - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->stream_frames().size()); - EXPECT_EQ(1u, writer_->padding_frames().size()); + EXPECT_EQ(0u, writer_->padding_frames().size()); QuicStreamFrame* frame = writer_->stream_frames()[0].get(); - EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()), - frame->stream_id); + EXPECT_EQ(stream_id, frame->stream_id); EXPECT_EQ("ABCDEF", QuicStringPiece(frame->data_buffer, frame->data_length)); } TEST_P(QuicConnectionTest, FramePackingSendvQueued) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Try to send two stream frames in 1 packet by using writev. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); @@ -3084,9 +3136,9 @@ TEST_P(QuicConnectionTest, FramePackingSendvQueued) { iov[0].iov_len = 4; iov[1].iov_base = data + 4; iov[1].iov_len = 2; - connection_.SaveAndSendStreamData( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), iov, 2, 6, - 0, NO_FIN); + QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( + connection_.transport_version(), Perspective::IS_CLIENT); + connection_.SaveAndSendStreamData(stream_id, iov, 2, 6, 0, NO_FIN); EXPECT_EQ(1u, connection_.NumQueuedPackets()); EXPECT_TRUE(connection_.HasQueuedData()); @@ -3097,39 +3149,38 @@ TEST_P(QuicConnectionTest, FramePackingSendvQueued) { EXPECT_EQ(0u, connection_.NumQueuedPackets()); // Parse the last packet and ensure it's one stream frame from one stream. - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->stream_frames().size()); - EXPECT_EQ(1u, writer_->padding_frames().size()); - EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()), - writer_->stream_frames()[0]->stream_id); + EXPECT_EQ(0u, writer_->padding_frames().size()); + EXPECT_EQ(stream_id, writer_->stream_frames()[0]->stream_id); } TEST_P(QuicConnectionTest, SendingZeroBytes) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Send a zero byte write with a fin using writev. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); - connection_.SaveAndSendStreamData( - QuicUtils::GetHeadersStreamId(connection_.transport_version()), nullptr, - 0, 0, 0, FIN); + QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( + connection_.transport_version(), Perspective::IS_CLIENT); + connection_.SaveAndSendStreamData(stream_id, nullptr, 0, 0, 0, FIN); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); + // Padding frames are added by v99 to ensure a minimum packet size. + size_t extra_padding_frames = 0; + if (GetParam().version.HasHeaderProtection()) { + extra_padding_frames = 1; + } + // Parse the last packet and ensure it's one stream frame from one stream. - EXPECT_EQ(1u, writer_->frame_count()); - EXPECT_EQ(1u, writer_->stream_frames().size()); - EXPECT_EQ(QuicUtils::GetHeadersStreamId(connection_.transport_version()), - writer_->stream_frames()[0]->stream_id); + EXPECT_EQ(1u + extra_padding_frames, writer_->frame_count()); + EXPECT_EQ(extra_padding_frames, writer_->padding_frames().size()); + ASSERT_EQ(1u, writer_->stream_frames().size()); + EXPECT_EQ(stream_id, writer_->stream_frames()[0]->stream_id); EXPECT_TRUE(writer_->stream_frames()[0]->fin); } TEST_P(QuicConnectionTest, LargeSendWithPendingAck) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Set the ack alarm by processing a ping frame. EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -3158,7 +3209,7 @@ TEST_P(QuicConnectionTest, LargeSendWithPendingAck) { // Parse the last packet and ensure it's one stream frame with a fin. EXPECT_EQ(1u, writer_->frame_count()); - EXPECT_EQ(1u, writer_->stream_frames().size()); + ASSERT_EQ(1u, writer_->stream_frames().size()); EXPECT_EQ(QuicUtils::GetHeadersStreamId(connection_.transport_version()), writer_->stream_frames()[0]->stream_id); EXPECT_TRUE(writer_->stream_frames()[0]->fin); @@ -3167,9 +3218,6 @@ TEST_P(QuicConnectionTest, LargeSendWithPendingAck) { } TEST_P(QuicConnectionTest, OnCanWrite) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Visitor's OnCanWrite will send data, but will have more pending writes. EXPECT_CALL(visitor_, OnCanWrite()) .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs( @@ -3199,9 +3247,6 @@ TEST_P(QuicConnectionTest, OnCanWrite) { } TEST_P(QuicConnectionTest, RetransmitOnNack) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicPacketNumber last_packet; QuicByteCount second_packet_size; SendStreamDataToPeer(3, "foo", 0, NO_FIN, &last_packet); // Packet 1 @@ -3230,9 +3275,6 @@ TEST_P(QuicConnectionTest, RetransmitOnNack) { } TEST_P(QuicConnectionTest, DoNotSendQueuedPacketForResetStream) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Block the connection to queue the packet. BlockOnNextWrite(); @@ -3251,14 +3293,12 @@ TEST_P(QuicConnectionTest, DoNotSendQueuedPacketForResetStream) { connection_.SendControlFrame(QuicFrame(new QuicRstStreamFrame( 1, stream_id, QUIC_ERROR_PROCESSING_STREAM, 14))); } - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->rst_stream_frames().size()); } TEST_P(QuicConnectionTest, SendQueuedPacketForQuicRstStreamNoError) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Block the connection to queue the packet. BlockOnNextWrite(); @@ -3278,14 +3318,12 @@ TEST_P(QuicConnectionTest, SendQueuedPacketForQuicRstStreamNoError) { connection_.SendControlFrame(QuicFrame( new QuicRstStreamFrame(1, stream_id, QUIC_STREAM_NO_ERROR, 14))); } - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->rst_stream_frames().size()); } TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnNack) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicStreamId stream_id = 2; QuicPacketNumber last_packet; SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_packet); @@ -3305,9 +3343,6 @@ TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnNack) { } TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnNack) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicStreamId stream_id = 2; QuicPacketNumber last_packet; SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_packet); @@ -3330,9 +3365,6 @@ TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnNack) { } TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnRTO) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicStreamId stream_id = 2; QuicPacketNumber last_packet; SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_packet); @@ -3344,7 +3376,8 @@ TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnRTO) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); clock_.AdvanceTime(DefaultRetransmissionTime()); connection_.GetRetransmissionAlarm()->Fire(); - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->rst_stream_frames().size()); EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id); } @@ -3352,9 +3385,6 @@ TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnRTO) { // Ensure that if the only data in flight is non-retransmittable, the // retransmission alarm is not set. TEST_P(QuicConnectionTest, CancelRetransmissionAlarmAfterResetStream) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicStreamId stream_id = 2; QuicPacketNumber last_data_packet; SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_data_packet); @@ -3375,20 +3405,17 @@ TEST_P(QuicConnectionTest, CancelRetransmissionAlarmAfterResetStream) { // Ensure that the data is still in flight, but the retransmission alarm is no // longer set. - EXPECT_GT(QuicSentPacketManagerPeer::GetBytesInFlight(manager_), 0u); + EXPECT_GT(manager_->GetBytesInFlight(), 0u); if (GetQuicReloadableFlag(quic_optimize_inflight_check)) { EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); // Firing the alarm should remove all bytes_in_flight. connection_.GetRetransmissionAlarm()->Fire(); - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); + EXPECT_EQ(0u, manager_->GetBytesInFlight()); } EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); } TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnRTO) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetMaxTailLossProbes(0); QuicStreamId stream_id = 2; @@ -3403,15 +3430,13 @@ TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnRTO) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(2)); clock_.AdvanceTime(DefaultRetransmissionTime()); connection_.GetRetransmissionAlarm()->Fire(); - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); ASSERT_EQ(1u, writer_->rst_stream_frames().size()); EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id); } TEST_P(QuicConnectionTest, DoNotSendPendingRetransmissionForResetStream) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicStreamId stream_id = 2; QuicPacketNumber last_packet; SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_packet); @@ -3439,15 +3464,13 @@ TEST_P(QuicConnectionTest, DoNotSendPendingRetransmissionForResetStream) { connection_.SendControlFrame(QuicFrame(new QuicRstStreamFrame( 1, stream_id, QUIC_ERROR_PROCESSING_STREAM, 14))); } - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); ASSERT_EQ(1u, writer_->rst_stream_frames().size()); EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id); } TEST_P(QuicConnectionTest, SendPendingRetransmissionForQuicRstStreamNoError) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicStreamId stream_id = 2; QuicPacketNumber last_packet; SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_packet); @@ -3477,14 +3500,12 @@ TEST_P(QuicConnectionTest, SendPendingRetransmissionForQuicRstStreamNoError) { // retransmission. connection_.SendControlFrame(QuicFrame( new QuicRstStreamFrame(1, stream_id, QUIC_STREAM_NO_ERROR, 14))); - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->rst_stream_frames().size()); } TEST_P(QuicConnectionTest, RetransmitAckedPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicPacketNumber last_packet; SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet); // Packet 1 SendStreamDataToPeer(1, "foos", 3, NO_FIN, &last_packet); // Packet 2 @@ -3527,9 +3548,6 @@ TEST_P(QuicConnectionTest, RetransmitAckedPacket) { } TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacketNumber original, second; @@ -3557,9 +3575,6 @@ TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) { } TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetMaxTailLossProbes(0); for (int i = 0; i < 10; ++i) { @@ -3591,9 +3606,6 @@ TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) { } TEST_P(QuicConnectionTest, WriteBlockedBufferedThenSent) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } BlockOnNextWrite(); writer_->set_is_write_blocked_data_buffered(true); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); @@ -3606,9 +3618,6 @@ TEST_P(QuicConnectionTest, WriteBlockedBufferedThenSent) { } TEST_P(QuicConnectionTest, WriteBlockedThenSent) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); BlockOnNextWrite(); connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN); @@ -3628,9 +3637,6 @@ TEST_P(QuicConnectionTest, WriteBlockedThenSent) { } TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); connection_.SendStreamDataWithString(3, "foo", 0, NO_FIN); EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); @@ -3654,16 +3660,13 @@ TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) { EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); // Firing the alarm should remove all bytes_in_flight. connection_.GetRetransmissionAlarm()->Fire(); - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); + EXPECT_EQ(0u, manager_->GetBytesInFlight()); } EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_, 2)); } TEST_P(QuicConnectionTest, AlarmsWhenWriteBlocked) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Block the connection. BlockOnNextWrite(); connection_.SendStreamDataWithString(3, "foo", 0, NO_FIN); @@ -3678,9 +3681,6 @@ TEST_P(QuicConnectionTest, AlarmsWhenWriteBlocked) { } TEST_P(QuicConnectionTest, NoSendAlarmAfterProcessPacketWhenWriteBlocked) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Block the connection. @@ -3698,7 +3698,7 @@ TEST_P(QuicConnectionTest, NoSendAlarmAfterProcessPacketWhenWriteBlocked) { const bool has_stop_waiting = false; const EncryptionLevel level = ENCRYPTION_INITIAL; std::unique_ptr<QuicPacket> packet(ConstructDataPacket( - received_packet_num, has_stop_waiting, ENCRYPTION_INITIAL)); + received_packet_num, has_stop_waiting, ENCRYPTION_FORWARD_SECURE)); char buffer[kMaxOutgoingPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload(level, QuicPacketNumber(received_packet_num), @@ -3712,9 +3712,6 @@ TEST_P(QuicConnectionTest, NoSendAlarmAfterProcessPacketWhenWriteBlocked) { } TEST_P(QuicConnectionTest, AddToWriteBlockedListIfWriterBlockedWhenProcessing) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr); @@ -3729,9 +3726,6 @@ TEST_P(QuicConnectionTest, AddToWriteBlockedListIfWriterBlockedWhenProcessing) { } TEST_P(QuicConnectionTest, DoNotAddToWriteBlockedListAfterDisconnect) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } writer_->SetBatchMode(true); EXPECT_TRUE(connection_.connected()); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _, @@ -3751,9 +3745,6 @@ TEST_P(QuicConnectionTest, DoNotAddToWriteBlockedListAfterDisconnect) { } TEST_P(QuicConnectionTest, AddToWriteBlockedListIfBlockedOnFlushPackets) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } writer_->SetBatchMode(true); writer_->BlockOnNextFlush(); @@ -3767,9 +3758,6 @@ TEST_P(QuicConnectionTest, AddToWriteBlockedListIfBlockedOnFlushPackets) { } TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); int offset = 0; // Send packets 1 to 15. @@ -3902,9 +3890,6 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) { } TEST_P(QuicConnectionTest, TLP) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetMaxTailLossProbes(1); SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr); @@ -3925,9 +3910,6 @@ TEST_P(QuicConnectionTest, TLP) { } TEST_P(QuicConnectionTest, TailLossProbeDelayForStreamDataInTLPR) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Set TLPR from QuicConfig. EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; @@ -3959,9 +3941,6 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForStreamDataInTLPR) { } TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Set TLPR from QuicConfig. EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; @@ -4083,9 +4062,6 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) { } TEST_P(QuicConnectionTest, RTO) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetMaxTailLossProbes(0); QuicTime default_retransmission_time = @@ -4106,18 +4082,17 @@ TEST_P(QuicConnectionTest, RTO) { } TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } use_tagging_decrypter(); // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at // the end of the packet. We can test this to check which encrypter was used. connection_.SetEncrypter(ENCRYPTION_INITIAL, QuicMakeUnique<TaggingEncrypter>(0x01)); - SendStreamDataToPeer( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN, nullptr); + QuicByteCount packet_size; + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .WillOnce(SaveArg<3>(&packet_size)); + connection_.SendCryptoDataWithString("foo", 0); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, @@ -4145,9 +4120,6 @@ TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) { } TEST_P(QuicConnectionTest, SendHandshakeMessages) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } use_tagging_decrypter(); // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at // the end of the packet. We can test this to check which encrypter was used. @@ -4157,9 +4129,7 @@ TEST_P(QuicConnectionTest, SendHandshakeMessages) { // Attempt to send a handshake message and have the socket block. EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true)); BlockOnNextWrite(); - connection_.SendStreamDataWithString( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN); + connection_.SendCryptoDataWithString("foo", 0); // The packet should be serialized, but not queued. EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -4180,9 +4150,6 @@ TEST_P(QuicConnectionTest, SendHandshakeMessages) { TEST_P(QuicConnectionTest, DropRetransmitsForNullEncryptedPacketAfterForwardSecure) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } use_tagging_decrypter(); connection_.SetEncrypter(ENCRYPTION_INITIAL, QuicMakeUnique<TaggingEncrypter>(0x01)); @@ -4209,17 +4176,12 @@ TEST_P(QuicConnectionTest, } TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } use_tagging_decrypter(); connection_.SetEncrypter(ENCRYPTION_INITIAL, QuicMakeUnique<TaggingEncrypter>(0x01)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - SendStreamDataToPeer( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN, nullptr); + connection_.SendCryptoDataWithString("foo", 0); connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(0x02)); @@ -4267,9 +4229,6 @@ TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) { } TEST_P(QuicConnectionTest, TestRetransmitOrder) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetMaxTailLossProbes(0); QuicByteCount first_packet_size; @@ -4343,9 +4302,6 @@ TEST_P(QuicConnectionTest, Buffer100NonDecryptablePacketsThenKeyChange) { } TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } BlockOnNextWrite(); connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN); // Make sure that RTO is not started when the packet is queued. @@ -4358,9 +4314,6 @@ TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) { } TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetMaxTailLossProbes(0); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -4404,9 +4357,6 @@ TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) { } TEST_P(QuicConnectionTest, TestQueued) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetMaxTailLossProbes(0); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -4421,9 +4371,6 @@ TEST_P(QuicConnectionTest, TestQueued) { } TEST_P(QuicConnectionTest, InitialTimeout) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); @@ -4452,12 +4399,10 @@ TEST_P(QuicConnectionTest, InitialTimeout) { EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet()); + EXPECT_FALSE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet()); } TEST_P(QuicConnectionTest, IdleTimeoutAfterFirstSentPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); @@ -4509,9 +4454,6 @@ TEST_P(QuicConnectionTest, IdleTimeoutAfterFirstSentPacket) { } TEST_P(QuicConnectionTest, IdleTimeoutAfterSendTwoPackets) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); @@ -4572,9 +4514,6 @@ TEST_P(QuicConnectionTest, IdleTimeoutAfterSendTwoPackets) { } TEST_P(QuicConnectionTest, HandshakeTimeout) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Use a shorter handshake timeout than idle timeout for this test. const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5); connection_.SetNetworkTimeouts(timeout, timeout); @@ -4655,7 +4594,8 @@ TEST_P(QuicConnectionTest, PingAfterSend) { clock_.AdvanceTime(QuicTime::Delta::FromSeconds(15)); EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); })); connection_.GetPingAlarm()->Fire(); - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); ASSERT_EQ(1u, writer_->ping_frames().size()); writer_->Reset(); @@ -4710,7 +4650,8 @@ TEST_P(QuicConnectionTest, ReducedPingTimeout) { connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); })); connection_.GetPingAlarm()->Fire(); - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); ASSERT_EQ(1u, writer_->ping_frames().size()); writer_->Reset(); @@ -4767,9 +4708,6 @@ TEST_P(QuicConnectionTest, SendMtuDiscoveryPacket) { // Tests whether MTU discovery does not happen when it is not explicitly enabled // by the connection options. TEST_P(QuicConnectionTest, MtuDiscoveryDisabled) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); const QuicPacketCount packets_between_probes_base = 10; @@ -4786,9 +4724,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryDisabled) { // Tests whether MTU discovery works when the probe gets acknowledged on the // first try. TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); connection_.EnablePathMtuDiscovery(send_algorithm_); @@ -4837,9 +4772,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) { // Tests whether MTU discovery works correctly when the probes never get // acknowledged. TEST_P(QuicConnectionTest, MtuDiscoveryFailed) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); connection_.EnablePathMtuDiscovery(send_algorithm_); @@ -4922,9 +4854,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryFailed) { // Tests whether MTU discovery works when the writer has a limit on how large a // packet can be. TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); const QuicByteCount mtu_limit = kMtuDiscoveryTargetPacketSizeHigh - 1; @@ -4975,9 +4904,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) { // Tests whether MTU discovery works when the writer returns an error despite // advertising higher packet length. TEST_P(QuicConnectionTest, MtuDiscoveryWriterFailed) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); const QuicByteCount mtu_limit = kMtuDiscoveryTargetPacketSizeHigh - 1; @@ -5030,9 +4956,6 @@ TEST_P(QuicConnectionTest, MtuDiscoveryWriterFailed) { } TEST_P(QuicConnectionTest, NoMtuDiscoveryAfterConnectionClosed) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); connection_.EnablePathMtuDiscovery(send_algorithm_); @@ -5057,9 +4980,6 @@ TEST_P(QuicConnectionTest, NoMtuDiscoveryAfterConnectionClosed) { } TEST_P(QuicConnectionTest, TimeoutAfterSend) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; @@ -5109,9 +5029,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) { } TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); @@ -5187,9 +5104,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) { } TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Same test as above, but complete a handshake which enables silent close, // causing no connection close packet to be sent. EXPECT_TRUE(connection_.connected()); @@ -5207,7 +5121,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { client_config.SetIdleNetworkTimeout( QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); @@ -5257,9 +5171,6 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { } TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Same test as above, but complete a handshake which enables silent close, // but sending TLPs causes the connection close to be sent. EXPECT_TRUE(connection_.connected()); @@ -5277,7 +5188,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { client_config.SetIdleNetworkTimeout( QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); @@ -5316,9 +5227,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { } TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Same test as above, but complete a handshake which enables silent close, // but having open streams causes the connection close to be sent. EXPECT_TRUE(connection_.connected()); @@ -5336,7 +5244,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { client_config.SetIdleNetworkTimeout( QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); @@ -5373,9 +5281,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { } TEST_P(QuicConnectionTest, TimeoutAfterReceive) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); @@ -5426,9 +5331,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceive) { } TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); @@ -5491,9 +5393,6 @@ TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) { } TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetMaxTailLossProbes(2); EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); @@ -5528,9 +5427,6 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) { } TEST_P(QuicConnectionTest, SendScheduler) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Test that if we send a packet without delay, it is not queued. QuicFramerPeer::SetPerspective(&peer_framer_, Perspective::IS_CLIENT); std::unique_ptr<QuicPacket> packet = @@ -5543,9 +5439,6 @@ TEST_P(QuicConnectionTest, SendScheduler) { } TEST_P(QuicConnectionTest, FailToSendFirstPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Test that the connection does not crash when it fails to send the first // packet at which point self_address_ might be uninitialized. QuicFramerPeer::SetPerspective(&peer_framer_, Perspective::IS_CLIENT); @@ -5559,9 +5452,6 @@ TEST_P(QuicConnectionTest, FailToSendFirstPacket) { } TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicFramerPeer::SetPerspective(&peer_framer_, Perspective::IS_CLIENT); std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting, ENCRYPTION_INITIAL); @@ -5575,10 +5465,6 @@ TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) { } TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } - // Queue the first packet. size_t payload_length = connection_.max_packet_length(); EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(testing::Return(false)); @@ -5593,10 +5479,6 @@ TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) { } TEST_P(QuicConnectionTest, SendingThreePackets) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } - // Make the payload twice the size of the packet, so 3 packets are written. size_t total_payload_length = 2 * connection_.max_packet_length(); const std::string payload(total_payload_length, 'a'); @@ -5610,9 +5492,6 @@ TEST_P(QuicConnectionTest, SendingThreePackets) { } TEST_P(QuicConnectionTest, LoopThroughSendingPacketsWithTruncation) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } set_perspective(Perspective::IS_SERVER); if (GetParam().version.transport_version <= QUIC_VERSION_43) { // For IETF QUIC, encryption level will be switched to FORWARD_SECURE in @@ -5653,9 +5532,6 @@ TEST_P(QuicConnectionTest, LoopThroughSendingPacketsWithTruncation) { } TEST_P(QuicConnectionTest, SendDelayedAck) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime(); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); @@ -5679,11 +5555,12 @@ TEST_P(QuicConnectionTest, SendDelayedAck) { clock_.AdvanceTime(DefaultDelayedAckTime()); connection_.GetAckAlarm()->Fire(); // Check that ack is sent and that delayed ack alarm is reset. + size_t padding_frame_count = writer_->padding_frames().size(); if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); @@ -5691,9 +5568,6 @@ TEST_P(QuicConnectionTest, SendDelayedAck) { } TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicConnectionPeer::SetFastAckAfterQuiescence(&connection_, true); // The beginning of the connection counts as quiescence. @@ -5721,11 +5595,12 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { clock_.AdvanceTime(DefaultDelayedAckTime()); connection_.GetAckAlarm()->Fire(); // Check that ack is sent and that delayed ack alarm is reset. + size_t padding_frame_count = writer_->padding_frames().size(); if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); @@ -5744,11 +5619,12 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { clock_.AdvanceTime(DefaultDelayedAckTime()); connection_.GetAckAlarm()->Fire(); // Check that ack is sent and that delayed ack alarm is reset. + padding_frame_count = writer_->padding_frames().size(); if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); @@ -5766,9 +5642,6 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { } TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION); @@ -5827,9 +5700,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { } TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION); QuicConnectionPeer::SetFastAckAfterQuiescence(&connection_, true); @@ -5864,11 +5734,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { clock_.AdvanceTime(DefaultDelayedAckTime()); connection_.GetAckAlarm()->Fire(); // Check that ack is sent and that delayed ack alarm is reset. + size_t padding_frame_count = writer_->padding_frames().size(); if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); @@ -5887,11 +5758,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { clock_.AdvanceTime(DefaultDelayedAckTime()); connection_.GetAckAlarm()->Fire(); // Check that ack is sent and that delayed ack alarm is reset. + padding_frame_count = writer_->padding_frames().size(); if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); @@ -5959,9 +5831,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { } TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; @@ -6021,9 +5890,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) { } TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); @@ -6083,9 +5949,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { } TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); @@ -6150,9 +6013,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { } TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); @@ -6236,9 +6096,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { } TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); @@ -6307,9 +6164,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReorderingEighthRtt) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); @@ -6394,9 +6248,6 @@ TEST_P(QuicConnectionTest, } TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); // Check that ack is sent and that delayed ack alarm is set. @@ -6418,18 +6269,16 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) { } TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); ProcessPacket(2); // Check that ack is sent and that delayed ack alarm is reset. + size_t padding_frame_count = writer_->padding_frames().size(); if (GetParam().no_stop_waiting) { - EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); @@ -6437,9 +6286,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) { } TEST_P(QuicConnectionTest, NoAckOnOldNacks) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Drop one packet, triggering a sequence of acks. if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { @@ -6450,14 +6296,16 @@ TEST_P(QuicConnectionTest, NoAckOnOldNacks) { ProcessPacket(2); size_t frames_per_ack = GetParam().no_stop_waiting ? 1 : 2; if (!GetQuicRestartFlag(quic_enable_accept_random_ipn)) { - EXPECT_EQ(frames_per_ack, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); } EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); ProcessPacket(3); - EXPECT_EQ(frames_per_ack, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); @@ -6470,35 +6318,34 @@ TEST_P(QuicConnectionTest, NoAckOnOldNacks) { if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { EXPECT_EQ(0u, writer_->frame_count()); } else { - EXPECT_EQ(frames_per_ack, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); } EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); ProcessPacket(5); - EXPECT_EQ(frames_per_ack, writer_->frame_count()); + padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); // Now only set the timer on the 6th packet, instead of sending another ack. ProcessPacket(6); - EXPECT_EQ(0u, writer_->frame_count()); + padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count, writer_->frame_count()); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); } TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnStreamFrame(_)); peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, QuicMakeUnique<TaggingEncrypter>(0x01)); SetDecrypter(ENCRYPTION_FORWARD_SECURE, QuicMakeUnique<StrictTaggingDecrypter>(0x01)); - ProcessDataPacketAtLevel(1, false, ENCRYPTION_FORWARD_SECURE); + ProcessDataPacket(1); connection_.SendStreamDataWithString( GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", 0, NO_FIN); @@ -6521,9 +6368,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) { } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); - connection_.SendStreamDataWithString( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN); + connection_.SendCryptoDataWithString("foo", 0); // Check that ack is bundled with outgoing crypto data. if (GetParam().no_stop_waiting) { EXPECT_EQ(3u, writer_->frame_count()); @@ -6536,21 +6381,14 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) { } TEST_P(QuicConnectionTest, BlockAndBufferOnFirstCHLOPacketOfTwo) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); BlockOnNextWrite(); writer_->set_is_write_blocked_data_buffered(true); - connection_.SendStreamDataWithString( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN); + connection_.SendCryptoDataWithString("foo", 0); EXPECT_TRUE(writer_->IsWriteBlocked()); EXPECT_FALSE(connection_.HasQueuedData()); - connection_.SendStreamDataWithString( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "bar", 3, - NO_FIN); + connection_.SendCryptoDataWithString("bar", 3); EXPECT_TRUE(writer_->IsWriteBlocked()); EXPECT_TRUE(connection_.HasQueuedData()); } @@ -6624,9 +6462,6 @@ TEST_P(QuicConnectionTest, BundleAckForSecondCHLOTwoPacketReject) { } TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); connection_.SendStreamDataWithString( GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", @@ -6643,7 +6478,8 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) { .WillOnce(SetArgPointee<5>(lost_packets)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); ProcessAckPacket(&ack); - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->stream_frames().size()); writer_->Reset(); @@ -6670,22 +6506,30 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) { // Check that ack is bundled with outgoing data and the delayed ack // alarm is reset. if (GetParam().no_stop_waiting) { - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + if (GetQuicReloadableFlag(quic_simplify_stop_waiting)) { + // Do not ACK acks. + EXPECT_EQ(1u, writer_->frame_count()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } } else { EXPECT_EQ(3u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(writer_->ack_frames().front())); + if (GetParam().no_stop_waiting && + GetQuicReloadableFlag(quic_simplify_stop_waiting)) { + EXPECT_TRUE(writer_->ack_frames().empty()); + } else { + EXPECT_FALSE(writer_->ack_frames().empty()); + EXPECT_EQ(QuicPacketNumber(3u), + LargestAcked(writer_->ack_frames().front())); + } EXPECT_EQ(1u, writer_->stream_frames().size()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } TEST_P(QuicConnectionTest, NoAckSentForClose) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _, @@ -6695,9 +6539,6 @@ TEST_P(QuicConnectionTest, NoAckSentForClose) { } TEST_P(QuicConnectionTest, SendWhenDisconnected) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _, ConnectionCloseSource::FROM_SELF)); @@ -6738,9 +6579,6 @@ TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) { } TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); TestPacketWriter probing_writer(version(), &clock_); // Block next write so that sending connectivity probe will encounter a @@ -6757,9 +6595,6 @@ TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) { } TEST_P(QuicConnectionTest, WriterBlockedAfterServerSendsConnectivityProbe) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -6777,9 +6612,6 @@ TEST_P(QuicConnectionTest, WriterBlockedAfterServerSendsConnectivityProbe) { } TEST_P(QuicConnectionTest, WriterErrorWhenClientSendsConnectivityProbe) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); TestPacketWriter probing_writer(version(), &clock_); probing_writer.SetShouldWriteFail(); @@ -6795,9 +6627,6 @@ TEST_P(QuicConnectionTest, WriterErrorWhenClientSendsConnectivityProbe) { } TEST_P(QuicConnectionTest, WriterErrorWhenServerSendsConnectivityProbe) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); @@ -6868,9 +6697,6 @@ TEST_P(QuicConnectionTest, GoAway) { } TEST_P(QuicConnectionTest, WindowUpdate) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicWindowUpdateFrame window_update; @@ -6881,9 +6707,6 @@ TEST_P(QuicConnectionTest, WindowUpdate) { } TEST_P(QuicConnectionTest, Blocked) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicBlockedFrame blocked; @@ -6895,9 +6718,6 @@ TEST_P(QuicConnectionTest, Blocked) { } TEST_P(QuicConnectionTest, ZeroBytePacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Don't close the connection for zero byte packets. EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(0); QuicReceivedPacket encrypted(nullptr, 0, QuicTime::Zero()); @@ -6905,8 +6725,7 @@ TEST_P(QuicConnectionTest, ZeroBytePacket) { } TEST_P(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) { - if (GetParam().version.transport_version > QUIC_VERSION_43 || - connection_.SupportsMultiplePacketNumberSpaces()) { + if (GetParam().version.transport_version > QUIC_VERSION_43) { return; } // Set the packet number of the ack packet to be least unacked (4). @@ -6917,9 +6736,6 @@ TEST_P(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) { } TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Turn off QUIC_VERSION_99. SetQuicReloadableFlag(quic_enable_version_99, false); connection_.SetSupportedVersions(CurrentSupportedVersions()); @@ -6973,9 +6789,6 @@ TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacket) { } TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Turn off QUIC_VERSION_99. SetQuicReloadableFlag(quic_enable_version_99, false); connection_.SetSupportedVersions(CurrentSupportedVersions()); @@ -7036,9 +6849,6 @@ TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) { TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlockedDataBuffered) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Turn off QUIC_VERSION_99. SetQuicReloadableFlag(quic_enable_version_99, false); connection_.SetSupportedVersions(CurrentSupportedVersions()); @@ -7085,30 +6895,28 @@ TEST_P(QuicConnectionTest, } TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } - // Start out with some unsupported version. + const bool expect_failure = + GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation) || + connection_.version().handshake_protocol != + QuicVersionReservedForNegotiation().handshake_protocol; + // Start out with an unsupported version. QuicConnectionPeer::GetFramer(&connection_) - ->set_version_for_tests(ParsedQuicVersion( - PROTOCOL_UNSUPPORTED, - GetParam().version.transport_version == QUIC_VERSION_99 - ? QUIC_VERSION_99 - : QUIC_VERSION_UNSUPPORTED)); + ->set_version_for_tests(QuicVersionReservedForNegotiation()); // Send a version negotiation packet. std::unique_ptr<QuicEncryptedPacket> encrypted( - peer_framer_.BuildVersionNegotiationPacket( - connection_id_, connection_.transport_version() > QUIC_VERSION_43, + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), + connection_.transport_version() > QUIC_VERSION_43, AllSupportedVersions())); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero())); - if (GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation)) { + if (expect_failure) { EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_VERSION, _, ConnectionCloseSource::FROM_SELF)); } connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); - if (GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation)) { + if (expect_failure) { EXPECT_FALSE(connection_.connected()); return; } @@ -7116,8 +6924,12 @@ TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { // Now force another packet. The connection should transition into // NEGOTIATED_VERSION state and tell the packet creator to StopSendingVersion. QuicPacketHeader header; - header.destination_connection_id = connection_id_; header.destination_connection_id_included = CONNECTION_ID_ABSENT; + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + header.destination_connection_id = connection_id_; + } else { + header.source_connection_id = connection_id_; + } header.packet_number = QuicPacketNumber(12); header.version_flag = false; QuicFrames frames; @@ -7143,17 +6955,15 @@ TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { } TEST_P(QuicConnectionTest, BadVersionNegotiation) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // 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, _, ConnectionCloseSource::FROM_SELF)); std::unique_ptr<QuicEncryptedPacket> encrypted( - framer_.BuildVersionNegotiationPacket( - connection_id_, connection_.transport_version() > QUIC_VERSION_43, + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), + connection_.transport_version() > QUIC_VERSION_43, AllSupportedVersions())); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero())); @@ -7161,9 +6971,6 @@ TEST_P(QuicConnectionTest, BadVersionNegotiation) { } TEST_P(QuicConnectionTest, CheckSendStats) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetMaxTailLossProbes(0); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); @@ -7221,14 +7028,20 @@ TEST_P(QuicConnectionTest, CheckSendStats) { } TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Construct a packet with stream frame and connection close frame. QuicPacketHeader header; - header.destination_connection_id = connection_id_; - if (peer_framer_.transport_version() > QUIC_VERSION_43) { + if (GetQuicRestartFlag(quic_do_not_override_connection_id) && + peer_framer_.perspective() == Perspective::IS_SERVER) { + header.source_connection_id = connection_id_; header.destination_connection_id_included = CONNECTION_ID_ABSENT; + if (peer_framer_.transport_version() <= QUIC_VERSION_43) { + header.source_connection_id_included = CONNECTION_ID_PRESENT; + } + } else { + header.destination_connection_id = connection_id_; + if (peer_framer_.transport_version() > QUIC_VERSION_43) { + header.destination_connection_id_included = CONNECTION_ID_ABSENT; + } } header.packet_number = QuicPacketNumber(1); header.version_flag = false; @@ -7261,9 +7074,6 @@ TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) { } TEST_P(QuicConnectionTest, SelectMutualVersion) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } connection_.SetSupportedVersions(AllSupportedVersions()); // Set the connection to speak the lowest quic version. connection_.set_version(QuicVersionMin()); @@ -7290,9 +7100,6 @@ TEST_P(QuicConnectionTest, SelectMutualVersion) { } TEST_P(QuicConnectionTest, ConnectionCloseWhenWritable) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_FALSE(writer_->IsWriteBlocked()); // Send a packet. @@ -7305,9 +7112,6 @@ TEST_P(QuicConnectionTest, ConnectionCloseWhenWritable) { } TEST_P(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } BlockOnNextWrite(); TriggerConnectionClose(); EXPECT_EQ(1u, writer_->packets_write_attempts()); @@ -7315,9 +7119,6 @@ TEST_P(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) { } TEST_P(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } BlockOnNextWrite(); connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -7328,9 +7129,6 @@ TEST_P(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) { } TEST_P(QuicConnectionTest, OnPacketSentDebugVisitor) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); @@ -7343,9 +7141,6 @@ TEST_P(QuicConnectionTest, OnPacketSentDebugVisitor) { } TEST_P(QuicConnectionTest, OnPacketHeaderDebugVisitor) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicPacketHeader header; header.packet_number = QuicPacketNumber(1); if (GetParam().version.transport_version > QUIC_VERSION_43) { @@ -7361,9 +7156,6 @@ TEST_P(QuicConnectionTest, OnPacketHeaderDebugVisitor) { } TEST_P(QuicConnectionTest, Pacing) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } TestConnection server(connection_id_, kSelfAddress, helper_.get(), alarm_factory_.get(), writer_.get(), Perspective::IS_SERVER, version()); @@ -7379,9 +7171,6 @@ TEST_P(QuicConnectionTest, Pacing) { } TEST_P(QuicConnectionTest, WindowUpdateInstigateAcks) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Send a WINDOW_UPDATE frame. @@ -7397,9 +7186,6 @@ TEST_P(QuicConnectionTest, WindowUpdateInstigateAcks) { } TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Send a BLOCKED frame. @@ -7414,9 +7200,6 @@ TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) { } TEST_P(QuicConnectionTest, ReevaluateTimeUntilSendOnAck) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Enable pacing. EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; @@ -7455,7 +7238,8 @@ TEST_P(QuicConnectionTest, ReevaluateTimeUntilSendOnAck) { EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true)); ProcessAckPacket(&ack); - EXPECT_EQ(1u, writer_->frame_count()); + size_t padding_frame_count = writer_->padding_frames().size(); + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->stream_frames().size()); EXPECT_TRUE(connection_.GetSendAlarm()->IsSet()); EXPECT_EQ(scheduled_pacing_time, connection_.GetSendAlarm()->deadline()); @@ -7474,9 +7258,6 @@ TEST_P(QuicConnectionTest, SendAcksImmediately) { } TEST_P(QuicConnectionTest, SendPingImmediately) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); @@ -7489,9 +7270,6 @@ TEST_P(QuicConnectionTest, SendPingImmediately) { } TEST_P(QuicConnectionTest, SendBlockedImmediately) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); @@ -7504,9 +7282,6 @@ TEST_P(QuicConnectionTest, SendBlockedImmediately) { } TEST_P(QuicConnectionTest, SendingUnencryptedStreamDataFails) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. if (!IsDefaultTestConfiguration()) { return; @@ -7518,14 +7293,11 @@ TEST_P(QuicConnectionTest, SendingUnencryptedStreamDataFails) { struct iovec iov; MakeIOVector("", &iov); EXPECT_QUIC_BUG(connection_.SaveAndSendStreamData(3, &iov, 1, 0, 0, FIN), - "Cannot send stream data without encryption."); + "Cannot send stream data with level: ENCRYPTION_INITIAL"); EXPECT_FALSE(connection_.connected()); } TEST_P(QuicConnectionTest, SetRetransmissionAlarmForCryptoPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); @@ -7547,9 +7319,6 @@ TEST_P(QuicConnectionTest, SetRetransmissionAlarmForCryptoPacket) { } TEST_P(QuicConnectionTest, PathDegradingAlarmForCryptoPacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); EXPECT_FALSE(connection_.IsPathDegrading()); @@ -7575,9 +7344,6 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForCryptoPacket) { // Includes regression test for b/69979024. TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); EXPECT_FALSE(connection_.IsPathDegrading()); @@ -7652,9 +7418,6 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { } TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } const QuicTime::Delta retransmittable_on_wire_timeout = QuicTime::Delta::FromMilliseconds(50); connection_.set_retransmittable_on_wire_timeout( @@ -7726,9 +7489,6 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) { // spin timer to detect path degrading when a new packet is sent on the // degraded path. TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); EXPECT_FALSE(connection_.IsPathDegrading()); @@ -7795,9 +7555,6 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { // the timer to detect future path degrading when forward progress is made // after path has been marked degrading. TEST_P(QuicConnectionTest, UnmarkPathDegradingOnForwardProgress) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_TRUE(connection_.connected()); EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); EXPECT_FALSE(connection_.IsPathDegrading()); @@ -7910,9 +7667,6 @@ TEST_P(QuicConnectionTest, NoPathDegradingAfterSendingAck) { } TEST_P(QuicConnectionTest, MultipleCallsToCloseConnection) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Verifies that multiple calls to CloseConnection do not // result in multiple attempts to close the connection - it will be marked as // disconnected after the first call. @@ -7924,9 +7678,6 @@ TEST_P(QuicConnectionTest, MultipleCallsToCloseConnection) { } TEST_P(QuicConnectionTest, ServerReceivesChloOnNonCryptoStream) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); @@ -7946,9 +7697,6 @@ TEST_P(QuicConnectionTest, ServerReceivesChloOnNonCryptoStream) { } TEST_P(QuicConnectionTest, ClientReceivesRejOnNonCryptoStream) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); CryptoHandshakeMessage message; @@ -7965,9 +7713,6 @@ TEST_P(QuicConnectionTest, ClientReceivesRejOnNonCryptoStream) { } TEST_P(QuicConnectionTest, CloseConnectionOnPacketTooLarge) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } SimulateNextPacketTooLarge(); // A connection close packet is sent EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PACKET_WRITE_ERROR, _, @@ -7977,9 +7722,6 @@ TEST_P(QuicConnectionTest, CloseConnectionOnPacketTooLarge) { } TEST_P(QuicConnectionTest, AlwaysGetPacketTooLarge) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // Test even we always get packet too large, we do not infinitely try to send // close packet. AlwaysGetPacketTooLarge(); @@ -7992,9 +7734,6 @@ TEST_P(QuicConnectionTest, AlwaysGetPacketTooLarge) { // Verify that if connection has no outstanding data, it notifies the send // algorithm after the write. TEST_P(QuicConnectionTest, SendDataAndBecomeApplicationLimited) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(1); { InSequence seq; @@ -8010,9 +7749,6 @@ TEST_P(QuicConnectionTest, SendDataAndBecomeApplicationLimited) { // Verify that the connection does not become app-limited if there is // outstanding data to send after the write. TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedIfMoreDataAvailable) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(0); { InSequence seq; @@ -8026,9 +7762,6 @@ TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedIfMoreDataAvailable) { // Verify that the connection does not become app-limited after blocked write // even if there is outstanding data to send after the write. TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedDueToWriteBlock) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(0); EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true)); BlockOnNextWrite(); @@ -8051,9 +7784,6 @@ TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedDueToWriteBlock) { // Test the mode in which the link is filled up with probing retransmissions if // the connection becomes application-limited. TEST_P(QuicConnectionTest, SendDataWhenApplicationLimited) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, ShouldSendProbingPacket()) .WillRepeatedly(Return(true)); @@ -8064,6 +7794,10 @@ TEST_P(QuicConnectionTest, SendDataWhenApplicationLimited) { EXPECT_CALL(visitor_, WillingAndAbleToWrite()) .WillRepeatedly(Return(false)); } + EXPECT_CALL(visitor_, SendProbingData()).WillRepeatedly([this] { + return connection_.sent_packet_manager().MaybeRetransmitOldestPacket( + PROBING_RETRANSMISSION); + }); // Fix congestion window to be 20,000 bytes. EXPECT_CALL(*send_algorithm_, CanSend(Ge(20000u))) .WillRepeatedly(Return(false)); @@ -8097,9 +7831,6 @@ TEST_P(QuicConnectionTest, SendDataWhenApplicationLimited) { } TEST_P(QuicConnectionTest, DonotForceSendingAckOnPacketTooLarge) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Send an ack by simulating delayed ack alarm firing. ProcessPacket(1); @@ -8117,9 +7848,6 @@ TEST_P(QuicConnectionTest, DonotForceSendingAckOnPacketTooLarge) { } TEST_P(QuicConnectionTest, CloseConnectionForStatelessReject) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } std::string error_details("stateless reject"); EXPECT_CALL(visitor_, OnConnectionClosed( QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, @@ -8132,9 +7860,6 @@ TEST_P(QuicConnectionTest, CloseConnectionForStatelessReject) { // Regression test for b/63620844. TEST_P(QuicConnectionTest, FailedToWriteHandshakePacket) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } SimulateNextPacketTooLarge(); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PACKET_WRITE_ERROR, _, ConnectionCloseSource::FROM_SELF)) @@ -8143,18 +7868,12 @@ TEST_P(QuicConnectionTest, FailedToWriteHandshakePacket) { } TEST_P(QuicConnectionTest, MaxPacingRate) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_EQ(0, connection_.MaxPacingRate().ToBytesPerSecond()); connection_.SetMaxPacingRate(QuicBandwidth::FromBytesPerSecond(100)); EXPECT_EQ(100, connection_.MaxPacingRate().ToBytesPerSecond()); } TEST_P(QuicConnectionTest, ClientAlwaysSendConnectionId) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.SendStreamDataWithString(3, "foo", 0, NO_FIN); @@ -8174,9 +7893,6 @@ TEST_P(QuicConnectionTest, ClientAlwaysSendConnectionId) { } TEST_P(QuicConnectionTest, SendProbingRetransmissions) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); @@ -8210,6 +7926,10 @@ TEST_P(QuicConnectionTest, SendProbingRetransmissions) { })); EXPECT_CALL(*send_algorithm_, ShouldSendProbingPacket()) .WillRepeatedly(Return(true)); + EXPECT_CALL(visitor_, SendProbingData()).WillRepeatedly([this] { + return connection_.sent_packet_manager().MaybeRetransmitOldestPacket( + PROBING_RETRANSMISSION); + }); connection_.SendProbingRetransmissions(); @@ -8223,9 +7943,6 @@ TEST_P(QuicConnectionTest, SendProbingRetransmissions) { // there are no outstanding packets. TEST_P(QuicConnectionTest, SendProbingRetransmissionsFailsWhenNothingToRetransmit) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } ASSERT_TRUE(connection_.sent_packet_manager().unacked_packets().empty()); MockQuicConnectionDebugVisitor debug_visitor; @@ -8233,14 +7950,15 @@ TEST_P(QuicConnectionTest, EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(0); EXPECT_CALL(*send_algorithm_, ShouldSendProbingPacket()) .WillRepeatedly(Return(true)); + EXPECT_CALL(visitor_, SendProbingData()).WillRepeatedly([this] { + return connection_.sent_packet_manager().MaybeRetransmitOldestPacket( + PROBING_RETRANSMISSION); + }); connection_.SendProbingRetransmissions(); } TEST_P(QuicConnectionTest, PingAfterLastRetransmittablePacketAcked) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } const QuicTime::Delta retransmittable_on_wire_timeout = QuicTime::Delta::FromMilliseconds(50); connection_.set_retransmittable_on_wire_timeout( @@ -8324,18 +8042,16 @@ TEST_P(QuicConnectionTest, PingAfterLastRetransmittablePacketAcked) { connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); })); connection_.GetPingAlarm()->Fire(); + size_t padding_frame_count = writer_->padding_frames().size(); if (GetParam().no_stop_waiting) { - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); } else { - EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 3u, writer_->frame_count()); } ASSERT_EQ(1u, writer_->ping_frames().size()); } TEST_P(QuicConnectionTest, NoPingIfRetransmittablePacketSent) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } const QuicTime::Delta retransmittable_on_wire_timeout = QuicTime::Delta::FromMilliseconds(50); connection_.set_retransmittable_on_wire_timeout( @@ -8399,18 +8115,21 @@ TEST_P(QuicConnectionTest, NoPingIfRetransmittablePacketSent) { connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); })); connection_.GetPingAlarm()->Fire(); + size_t padding_frame_count = writer_->padding_frames().size(); if (GetParam().no_stop_waiting) { - EXPECT_EQ(2u, writer_->frame_count()); + if (GetQuicReloadableFlag(quic_simplify_stop_waiting)) { + // Do not ACK acks. + EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); + } else { + EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); + } } else { - EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_EQ(padding_frame_count + 3u, writer_->frame_count()); } ASSERT_EQ(1u, writer_->ping_frames().size()); } TEST_P(QuicConnectionTest, OnForwardProgressConfirmed) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(Exactly(0)); EXPECT_TRUE(connection_.connected()); @@ -8450,9 +8169,6 @@ TEST_P(QuicConnectionTest, OnForwardProgressConfirmed) { } TEST_P(QuicConnectionTest, ValidStatelessResetToken) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } const QuicUint128 kTestToken = 1010101; const QuicUint128 kWrongTestToken = 1010100; QuicConfig config; @@ -8471,9 +8187,6 @@ TEST_P(QuicConnectionTest, ValidStatelessResetToken) { } TEST_P(QuicConnectionTest, WriteBlockedWithInvalidAck) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, _, _)); @@ -8551,6 +8264,7 @@ TEST_P(QuicConnectionTest, PathChallengeResponse) { connection_.peer_address()); // Save the random contents of the challenge for later comparison to the // response. + ASSERT_GE(writer_->path_challenge_frames().size(), 1u); QuicPathFrameBuffer challenge_data = writer_->path_challenge_frames().front().data_buffer; @@ -8578,9 +8292,6 @@ TEST_P(QuicConnectionTest, PathChallengeResponse) { // Regression test for b/110259444 TEST_P(QuicConnectionTest, DoNotScheduleSpuriousAckAlarm) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } SetQuicReloadableFlag(quic_fix_spurious_ack_alarm, true); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1)); @@ -8602,9 +8313,6 @@ TEST_P(QuicConnectionTest, DoNotScheduleSpuriousAckAlarm) { } TEST_P(QuicConnectionTest, DisablePacingOffloadConnectionOptions) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } EXPECT_FALSE(QuicConnectionPeer::SupportsReleaseTime(&connection_)); writer_->set_supports_release_time(true); QuicConfig config; @@ -8624,9 +8332,6 @@ TEST_P(QuicConnectionTest, DisablePacingOffloadConnectionOptions) { // Regression test for b/110259444 // Get a path response without having issued a path challenge... TEST_P(QuicConnectionTest, OrphanPathResponse) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } QuicPathFrameBuffer data = {{0, 1, 2, 3, 4, 5, 6, 7}}; QuicPathResponseFrame frame(99, data); @@ -8642,9 +8347,6 @@ TEST_P(QuicConnectionTest, OrphanPathResponse) { // Regression test for b/120791670 TEST_P(QuicConnectionTest, StopProcessingGQuicPacketInIetfQuicConnection) { - if (connection_.SupportsMultiplePacketNumberSpaces()) { - return; - } // This test mimics a problematic scenario where an IETF QUIC connection // receives a Google QUIC packet and continue processing it using Google QUIC // wire format. @@ -8652,13 +8354,18 @@ TEST_P(QuicConnectionTest, StopProcessingGQuicPacketInIetfQuicConnection) { return; } set_perspective(Perspective::IS_SERVER); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); // Let connection process a Google QUIC packet. peer_framer_.set_version_for_tests( @@ -8777,10 +8484,13 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) { return; } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); use_tagging_decrypter(); // Receives packet 1000 in initial data. - ProcessDataPacketAtLevel(1000, false, ENCRYPTION_INITIAL); + ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(0x02)); @@ -8816,7 +8526,7 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) { QuicMakeUnique<StrictTaggingDecrypter>(0x02)); // Verify zero rtt and forward secure packets get acked in the same packet. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - ProcessDataPacketAtLevel(1003, false, ENCRYPTION_FORWARD_SECURE); + ProcessDataPacket(1003); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } @@ -8825,10 +8535,13 @@ TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) { return; } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); use_tagging_decrypter(); // Receives packet 1000 in initial data. - ProcessDataPacketAtLevel(1000, false, ENCRYPTION_INITIAL); + ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(0x02)); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_constants.h b/chromium/net/third_party/quiche/src/quic/core/quic_constants.h index 4181cb7449b..caac2c76295 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_constants.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_constants.h @@ -21,8 +21,9 @@ namespace quic { const uint64_t kNumSecondsPerMinute = 60; const uint64_t kNumSecondsPerHour = kNumSecondsPerMinute * 60; const uint64_t kNumSecondsPerWeek = kNumSecondsPerHour * 24 * 7; +const uint64_t kNumMillisPerSecond = 1000; const uint64_t kNumMicrosPerMilli = 1000; -const uint64_t kNumMicrosPerSecond = 1000 * 1000; +const uint64_t kNumMicrosPerSecond = kNumMicrosPerMilli * kNumMillisPerSecond; // Default number of connections for N-connection emulation. const uint32_t kDefaultNumConnections = 2; @@ -57,8 +58,17 @@ const QuicByteCount kMinPacketSizeForVersionNegotiation = 1200; // We match SPDY's use of 32 (since we'd compete with SPDY). const QuicPacketCount kInitialCongestionWindow = 32; +// Do not allow initial congestion window to be greater than 200 packets. +const QuicPacketCount kMaxInitialCongestionWindow = 200; + +// Do not allow initial congestion window to be smaller than 10 packets. +const QuicPacketCount kMinInitialCongestionWindow = 10; + // Minimum size of initial flow control window, for both stream and session. +// This is only enforced when version.AllowsLowFlowControlLimits() is false. const uint32_t kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB +// Default size of initial flow control window, for both stream and session. +const uint32_t kDefaultFlowControlSendWindow = 16 * 1024; // 16 KB // Maximum flow control receive window limits for connection and stream. const QuicByteCount kStreamReceiveWindowLimit = 16 * 1024 * 1024; // 16 MB @@ -211,6 +221,9 @@ const uint64_t kMaxIetfVarInt = UINT64_C(0x3fffffffffffffff); // TODO(fkastenholz): Should update this to 64 bits for IETF Quic. const QuicStreamId kMaxQuicStreamId = 0xffffffff; +// The maximum value that can be stored in a 32-bit QuicStreamCount. +const QuicStreamCount kMaxQuicStreamCount = 0xffffffff; + // Number of bytes reserved for packet header type. const size_t kPacketHeaderTypeSize = 1; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc index ed178f44594..511ef2be82b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc @@ -68,18 +68,20 @@ void QuicControlFrameManager::WriteOrBufferBlocked(QuicStreamId id) { QuicFrame(new QuicBlockedFrame(++last_control_frame_id_, id))); } -void QuicControlFrameManager::WriteOrBufferStreamIdBlocked(QuicStreamId id) { - QUIC_DVLOG(1) << "Writing STREAM_ID_BLOCKED Frame"; - QUIC_CODE_COUNT(stream_id_blocked_transmits); - WriteOrBufferQuicFrame( - QuicFrame(QuicStreamIdBlockedFrame(++last_control_frame_id_, id))); +void QuicControlFrameManager::WriteOrBufferStreamsBlocked(QuicStreamCount count, + bool unidirectional) { + QUIC_DVLOG(1) << "Writing STREAMS_BLOCKED Frame"; + QUIC_CODE_COUNT(quic_streams_blocked_transmits); + WriteOrBufferQuicFrame(QuicFrame(QuicStreamsBlockedFrame( + ++last_control_frame_id_, count, unidirectional))); } -void QuicControlFrameManager::WriteOrBufferMaxStreamId(QuicStreamId id) { - QUIC_DVLOG(1) << "Writing MAX_STREAM_ID Frame"; - QUIC_CODE_COUNT(max_stream_id_transmits); - WriteOrBufferQuicFrame( - QuicFrame(QuicMaxStreamIdFrame(++last_control_frame_id_, id))); +void QuicControlFrameManager::WriteOrBufferMaxStreams(QuicStreamCount count, + bool unidirectional) { + QUIC_DVLOG(1) << "Writing MAX_STREAMS Frame"; + QUIC_CODE_COUNT(quic_max_streams_transmits); + WriteOrBufferQuicFrame(QuicFrame( + QuicMaxStreamsFrame(++last_control_frame_id_, count, unidirectional))); } void QuicControlFrameManager::WriteOrBufferStopSending(uint16_t code, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h index a5213c42b41..a4c26780d40 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h @@ -54,13 +54,13 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager { // immediately. void WriteOrBufferBlocked(QuicStreamId id); - // Tries to send a STREAM_ID_BLOCKED Frame. Buffers the frame if it cannot be + // Tries to send a STREAMS_BLOCKED Frame. Buffers the frame if it cannot be // sent immediately. - void WriteOrBufferStreamIdBlocked(QuicStreamId id); + void WriteOrBufferStreamsBlocked(QuicStreamCount count, bool unidirectional); - // Tries to send a MAX_STREAM_ID Frame. Buffers the frame if it cannot be sent + // Tries to send a MAX_STREAMS Frame. Buffers the frame if it cannot be sent // immediately. - void WriteOrBufferMaxStreamId(QuicStreamId id); + void WriteOrBufferMaxStreams(QuicStreamCount count, bool unidirectional); // Tries to send an IETF-QUIC STOP_SENDING frame. The frame is buffered if it // can not be sent immediately. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc index d6c9af4bf04..bf432ff4967 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc @@ -17,32 +17,6 @@ namespace quic { -QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl:: - ChannelIDSourceCallbackImpl(QuicCryptoClientHandshaker* parent) - : parent_(parent) {} - -QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl:: - ~ChannelIDSourceCallbackImpl() {} - -void QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::Run( - std::unique_ptr<ChannelIDKey>* channel_id_key) { - if (parent_ == nullptr) { - return; - } - - parent_->channel_id_key_ = std::move(*channel_id_key); - parent_->channel_id_source_callback_run_ = true; - parent_->channel_id_source_callback_ = nullptr; - parent_->DoHandshakeLoop(nullptr); - - // The ChannelIDSource owns this object and will delete it when this method - // returns. -} - -void QuicCryptoClientHandshaker::ChannelIDSourceCallbackImpl::Cancel() { - parent_ = nullptr; -} - QuicCryptoClientHandshaker::ProofVerifierCallbackImpl:: ProofVerifierCallbackImpl(QuicCryptoClientHandshaker* parent) : parent_(parent) {} @@ -87,14 +61,10 @@ QuicCryptoClientHandshaker::QuicCryptoClientHandshaker( crypto_config_(crypto_config), server_id_(server_id), generation_counter_(0), - channel_id_sent_(false), - channel_id_source_callback_run_(false), - channel_id_source_callback_(nullptr), verify_context_(std::move(verify_context)), proof_verify_callback_(nullptr), proof_handler_(proof_handler), verify_ok_(false), - stateless_reject_received_(false), proof_verify_start_time_(QuicTime::Zero()), num_scup_messages_received_(0), encryption_established_(false), @@ -102,9 +72,6 @@ QuicCryptoClientHandshaker::QuicCryptoClientHandshaker( crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {} QuicCryptoClientHandshaker::~QuicCryptoClientHandshaker() { - if (channel_id_source_callback_) { - channel_id_source_callback_->Cancel(); - } if (proof_verify_callback_) { proof_verify_callback_->Cancel(); } @@ -153,14 +120,6 @@ int QuicCryptoClientHandshaker::num_scup_messages_received() const { return num_scup_messages_received_; } -bool QuicCryptoClientHandshaker::WasChannelIDSent() const { - return channel_id_sent_; -} - -bool QuicCryptoClientHandshaker::WasChannelIDSourceCallbackRun() const { - return channel_id_source_callback_run_; -} - std::string QuicCryptoClientHandshaker::chlo_hash() const { return chlo_hash_; } @@ -234,12 +193,6 @@ void QuicCryptoClientHandshaker::DoHandshakeLoop( case STATE_VERIFY_PROOF_COMPLETE: DoVerifyProofComplete(cached); break; - case STATE_GET_CHANNEL_ID: - rv = DoGetChannelID(cached); - break; - case STATE_GET_CHANNEL_ID_COMPLETE: - DoGetChannelIDComplete(); - break; case STATE_RECV_SHLO: DoReceiveSHLO(in, cached); break; @@ -272,26 +225,12 @@ void QuicCryptoClientHandshaker::DoInitialize( // If the cached state needs to be verified, do it now. next_state_ = STATE_VERIFY_PROOF; } else { - next_state_ = STATE_GET_CHANNEL_ID; + next_state_ = STATE_SEND_CHLO; } } void QuicCryptoClientHandshaker::DoSendCHLO( QuicCryptoClientConfig::CachedState* cached) { - if (stateless_reject_received_) { - // If we've gotten to this point, we've sent at least one hello - // and received a stateless reject in response. We cannot - // continue to send hellos because the server has abandoned state - // for this connection. Abandon further handshakes. - next_state_ = STATE_NONE; - if (session()->connection()->connected()) { - session()->connection()->CloseConnection( - QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject received", - ConnectionCloseBehavior::SILENT_CLOSE); - } - return; - } - // Send the client hello in plaintext. session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); encryption_established_ = false; @@ -309,7 +248,7 @@ void QuicCryptoClientHandshaker::DoSendCHLO( DCHECK(session()->config() != nullptr); // Send all the options, regardless of whether we're sending an // inchoate or subsequent hello. - session()->config()->ToHandshakeMessage(&out); + session()->config()->ToHandshakeMessage(&out, session()->transport_version()); if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { crypto_config_->FillInchoateClientHello( @@ -341,22 +280,13 @@ void QuicCryptoClientHandshaker::DoSendCHLO( return; } - // If the server nonce is empty, copy over the server nonce from a previous - // SREJ, if there is one. - if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) && - crypto_negotiated_params_->server_nonce.empty() && - cached->has_server_nonce()) { - crypto_negotiated_params_->server_nonce = cached->GetNextServerNonce(); - DCHECK(!crypto_negotiated_params_->server_nonce.empty()); - } - std::string error_details; QuicErrorCode error = crypto_config_->FillClientHello( server_id_, session()->connection()->connection_id(), session()->supported_versions().front(), cached, session()->connection()->clock()->WallNow(), - session()->connection()->random_generator(), channel_id_key_.get(), - crypto_negotiated_params_, &out, &error_details); + session()->connection()->random_generator(), crypto_negotiated_params_, + &out, &error_details); if (error != QUIC_NO_ERROR) { // Flush the cached config so that, if it's bad, the server has a // chance to send us another in the future. @@ -365,7 +295,6 @@ void QuicCryptoClientHandshaker::DoSendCHLO( return; } chlo_hash_ = CryptoUtils::HashHandshakeMessage(out, Perspective::IS_CLIENT); - channel_id_sent_ = (channel_id_key_ != nullptr); if (cached->proof_verify_details()) { proof_handler_->OnProofVerifyDetailsAvailable( *cached->proof_verify_details()); @@ -405,7 +334,7 @@ void QuicCryptoClientHandshaker::DoReceiveREJ( // perform a handshake, or we sent a full hello that the server // rejected. Here we hope to have a REJ that contains the information // that we need. - if ((in->tag() != kREJ) && (in->tag() != kSREJ)) { + if (in->tag() != kREJ) { next_state_ = STATE_NONE; stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "Expected REJ"); @@ -425,7 +354,7 @@ void QuicCryptoClientHandshaker::DoReceiveREJ( static_cast<HandshakeFailureReason>(reject_reasons[i]); packed_error |= 1 << (reason - 1); } - DVLOG(1) << "Reasons for rejection: " << packed_error; + QUIC_DVLOG(1) << "Reasons for rejection: " << packed_error; if (num_client_hellos_ == QuicCryptoClientStream::kMaxClientHellos) { QuicClientSparseHistogram("QuicClientHelloRejectReasons.TooMany", packed_error); @@ -438,7 +367,6 @@ void QuicCryptoClientHandshaker::DoReceiveREJ( // so we can cancel and retransmissions. session()->NeuterUnencryptedData(); - stateless_reject_received_ = in->tag() == kSREJ; std::string error_details; QuicErrorCode error = crypto_config_->ProcessRejection( *in, session()->connection()->clock()->WallNow(), @@ -461,7 +389,7 @@ void QuicCryptoClientHandshaker::DoReceiveREJ( return; } } - next_state_ = STATE_GET_CHANNEL_ID; + next_state_ = STATE_SEND_CHLO; } QuicAsyncStatus QuicCryptoClientHandshaker::DoVerifyProof( @@ -531,7 +459,7 @@ void QuicCryptoClientHandshaker::DoVerifyProofComplete( SetCachedProofValid(cached); cached->SetProofVerifyDetails(verify_details_.release()); if (!handshake_confirmed()) { - next_state_ = STATE_GET_CHANNEL_ID; + next_state_ = STATE_SEND_CHLO; } else { // TODO: Enable Expect-Staple. https://crbug.com/631101 next_state_ = STATE_NONE; @@ -539,48 +467,6 @@ void QuicCryptoClientHandshaker::DoVerifyProofComplete( } } -QuicAsyncStatus QuicCryptoClientHandshaker::DoGetChannelID( - QuicCryptoClientConfig::CachedState* cached) { - next_state_ = STATE_GET_CHANNEL_ID_COMPLETE; - channel_id_key_.reset(); - if (!RequiresChannelID(cached)) { - next_state_ = STATE_SEND_CHLO; - return QUIC_SUCCESS; - } - - ChannelIDSourceCallbackImpl* channel_id_source_callback = - new ChannelIDSourceCallbackImpl(this); - QuicAsyncStatus status = crypto_config_->channel_id_source()->GetChannelIDKey( - server_id_.host(), &channel_id_key_, channel_id_source_callback); - - switch (status) { - case QUIC_PENDING: - channel_id_source_callback_ = channel_id_source_callback; - QUIC_DVLOG(1) << "Looking up channel ID"; - break; - case QUIC_FAILURE: - next_state_ = STATE_NONE; - delete channel_id_source_callback; - stream_->CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE, - "Channel ID lookup failed"); - break; - case QUIC_SUCCESS: - delete channel_id_source_callback; - break; - } - return status; -} - -void QuicCryptoClientHandshaker::DoGetChannelIDComplete() { - if (!channel_id_key_.get()) { - next_state_ = STATE_NONE; - stream_->CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE, - "Channel ID lookup failed"); - return; - } - next_state_ = STATE_SEND_CHLO; -} - void QuicCryptoClientHandshaker::DoReceiveSHLO( const CryptoHandshakeMessage* in, QuicCryptoClientConfig::CachedState* cached) { @@ -589,7 +475,7 @@ void QuicCryptoClientHandshaker::DoReceiveSHLO( // hoping for a SHLO from the server to confirm that. First check // to see whether the response was a reject, and if so, move on to // the reject-processing state. - if ((in->tag() == kREJ) || (in->tag() == kSREJ)) { + if (in->tag() == kREJ) { // A reject message must be sent in ENCRYPTION_INITIAL. if (session()->connection()->last_decrypted_level() != ENCRYPTION_INITIAL) { // The rejection was sent encrypted! @@ -677,26 +563,4 @@ void QuicCryptoClientHandshaker::SetCachedProofValid( proof_handler_->OnProofValid(*cached); } -bool QuicCryptoClientHandshaker::RequiresChannelID( - QuicCryptoClientConfig::CachedState* cached) { - if (server_id_.privacy_mode_enabled() || - !crypto_config_->channel_id_source()) { - return false; - } - const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); - if (!scfg) { // scfg may be null then we send an inchoate CHLO. - return false; - } - QuicTagVector their_proof_demands; - if (scfg->GetTaglist(kPDMD, &their_proof_demands) != QUIC_NO_ERROR) { - return false; - } - for (const QuicTag tag : their_proof_demands) { - if (tag == kCHID) { - return true; - } - } - return false; -} - } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h index 4aa5d469dcb..5b7ce35e29b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h @@ -7,7 +7,6 @@ #include <string> -#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h" #include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h" @@ -39,8 +38,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker bool CryptoConnect() override; int num_sent_client_hellos() const override; int num_scup_messages_received() const override; - bool WasChannelIDSent() const override; - bool WasChannelIDSourceCallbackRun() const override; std::string chlo_hash() const override; bool encryption_established() const override; bool handshake_confirmed() const override; @@ -59,25 +56,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker void DoSendCHLO(QuicCryptoClientConfig::CachedState* cached); private: - // ChannelIDSourceCallbackImpl is passed as the callback method to - // GetChannelIDKey. The ChannelIDSource calls this class with the result of - // channel ID lookup when lookup is performed asynchronously. - class ChannelIDSourceCallbackImpl : public ChannelIDSourceCallback { - public: - explicit ChannelIDSourceCallbackImpl(QuicCryptoClientHandshaker* parent); - ~ChannelIDSourceCallbackImpl() override; - - // ChannelIDSourceCallback interface. - void Run(std::unique_ptr<ChannelIDKey>* channel_id_key) override; - - // Cancel causes any future callbacks to be ignored. It must be called on - // the same thread as the callback will be made on. - void Cancel(); - - private: - QuicCryptoClientHandshaker* parent_; - }; - // ProofVerifierCallbackImpl is passed as the callback method to VerifyProof. // The ProofVerifier calls this class with the result of proof verification // when verification is performed asynchronously. @@ -106,8 +84,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker STATE_RECV_REJ, STATE_VERIFY_PROOF, STATE_VERIFY_PROOF_COMPLETE, - STATE_GET_CHANNEL_ID, - STATE_GET_CHANNEL_ID_COMPLETE, STATE_RECV_SHLO, STATE_INITIALIZE_SCUP, STATE_NONE, @@ -137,15 +113,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker // server config). If not, it closes the connection. void DoVerifyProofComplete(QuicCryptoClientConfig::CachedState* cached); - // Start the look up of Channel ID process. Returns either QUIC_SUCCESS if - // RequiresChannelID returns false or QuicAsyncStatus returned by - // GetChannelIDKey. - QuicAsyncStatus DoGetChannelID(QuicCryptoClientConfig::CachedState* cached); - - // If there is no channel ID, then close the connection otherwise transtion to - // STATE_SEND_CHLO state. - void DoGetChannelIDComplete(); - // Process SHLO message from the server. void DoReceiveSHLO(const CryptoHandshakeMessage* in, QuicCryptoClientConfig::CachedState* cached); @@ -159,10 +126,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker // OnProofValid() method. void SetCachedProofValid(QuicCryptoClientConfig::CachedState* cached); - // Returns true if the server crypto config in |cached| requires a ChannelID - // and the client config settings also allow sending a ChannelID. - bool RequiresChannelID(QuicCryptoClientConfig::CachedState* cached); - QuicCryptoClientStream* stream_; QuicSession* session_; @@ -183,22 +146,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker // Generation counter from QuicCryptoClientConfig's CachedState. uint64_t generation_counter_; - // True if a channel ID was sent. - bool channel_id_sent_; - - // True if channel_id_source_callback_ was run. - bool channel_id_source_callback_run_; - - // channel_id_source_callback_ contains the callback object that we passed - // to an asynchronous channel ID lookup. The ChannelIDSource owns this - // object. - ChannelIDSourceCallbackImpl* channel_id_source_callback_; - - // These members are used to store the result of an asynchronous channel ID - // lookup. These members must not be used after - // STATE_GET_CHANNEL_ID_COMPLETE. - std::unique_ptr<ChannelIDKey> channel_id_key_; - // verify_context_ contains the context object that we pass to asynchronous // proof verifications. std::unique_ptr<ProofVerifyContext> verify_context_; @@ -217,11 +164,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker std::string verify_error_details_; std::unique_ptr<ProofVerifyDetails> verify_details_; - // True if the server responded to a previous CHLO with a stateless - // reject. Used for book-keeping between the STATE_RECV_REJ, - // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state. - bool stateless_reject_received_; - QuicTime proof_verify_start_time_; int num_scup_messages_received_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc index 992df8f0378..92cfab1f3e0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker_test.cc @@ -3,11 +3,11 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" + #include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.pb.h" #include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" #include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" namespace quic { @@ -49,6 +49,8 @@ class InsecureProofVerifier : public ProofVerifier { QuicAsyncStatus VerifyCertChain( const std::string& hostname, const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, const ProofVerifyContext* context, std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc index 7c2aa404989..93f2a61104a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc @@ -84,14 +84,6 @@ CryptoMessageParser* QuicCryptoClientStream::crypto_message_parser() { return handshaker_->crypto_message_parser(); } -bool QuicCryptoClientStream::WasChannelIDSent() const { - return handshaker_->WasChannelIDSent(); -} - -bool QuicCryptoClientStream::WasChannelIDSourceCallbackRun() const { - return handshaker_->WasChannelIDSourceCallbackRun(); -} - std::string QuicCryptoClientStream::chlo_hash() const { return handshaker_->chlo_hash(); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h index d0e4ee1e3b1..b8dff7e9d34 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h @@ -9,7 +9,6 @@ #include <memory> #include <string> -#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h" #include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" @@ -85,13 +84,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream // to handshake confirmation. virtual int num_scup_messages_received() const = 0; - // Returns true if a channel ID was sent on this connection. - virtual bool WasChannelIDSent() const = 0; - - // Returns true if our ChannelIDSourceCallback was run, which implies the - // ChannelIDSource operated asynchronously. Intended for testing. - virtual bool WasChannelIDSourceCallbackRun() const = 0; - virtual std::string chlo_hash() const = 0; // Returns true once any encrypter (initial/0RTT or final/1RTT) has been set @@ -151,13 +143,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream const override; CryptoMessageParser* crypto_message_parser() override; - // Returns true if a channel ID was sent on this connection. - bool WasChannelIDSent() const; - - // Returns true if our ChannelIDSourceCallback was run, which implies the - // ChannelIDSource operated asynchronously. Intended for testing. - bool WasChannelIDSourceCallbackRun() const; - std::string chlo_hash() const; protected: diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc index 5839477b8fc..e09546d93ca 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc @@ -64,9 +64,8 @@ class QuicCryptoClientStreamTest : public QuicTest { .Times(testing::AnyNumber()); stream()->CryptoConnect(); QuicConfig config; - crypto_test_utils::HandshakeWithFakeServer(&config, &server_helper_, - &alarm_factory_, connection_, - stream(), server_options_); + crypto_test_utils::HandshakeWithFakeServer( + &config, &server_helper_, &alarm_factory_, connection_, stream()); } QuicCryptoClientStream* stream() { @@ -82,7 +81,6 @@ class QuicCryptoClientStreamTest : public QuicTest { QuicServerId server_id_; CryptoHandshakeMessage message_; QuicCryptoClientConfig crypto_config_; - crypto_test_utils::FakeServerOptions server_options_; }; TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) { @@ -97,7 +95,7 @@ TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { } TEST_F(QuicCryptoClientStreamTest, ConnectedAfterTlsHandshake) { - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); supported_versions_.clear(); for (QuicTransportVersion transport_version : AllSupportedTransportVersions()) { @@ -262,9 +260,8 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) { QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), crypto_test_utils::ProofSourceForTesting(), KeyExchangeSource::Default(), TlsServerHandshaker::CreateSslCtx()); - crypto_test_utils::FakeServerOptions options; crypto_test_utils::SetupCryptoServerConfigForTest( - connection_->clock(), QuicRandom::GetInstance(), &crypto_config, options); + connection_->clock(), QuicRandom::GetInstance(), &crypto_config); SourceAddressTokens tokens; QuicCompressedCertsCache cache(1); CachedNetworkParameters network_params; @@ -321,14 +318,6 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) { stream(), server_config_update, Perspective::IS_SERVER); } -TEST_F(QuicCryptoClientStreamTest, NoChannelID) { - crypto_config_.SetChannelIDSource(nullptr); - - CompleteCryptoHandshake(); - EXPECT_FALSE(stream()->WasChannelIDSent()); - EXPECT_FALSE(stream()->WasChannelIDSourceCallbackRun()); -} - TEST_F(QuicCryptoClientStreamTest, PreferredVersion) { // This mimics the case where client receives version negotiation packet, such // that, the preferred version is different from the packets' version. @@ -360,115 +349,6 @@ TEST_F(QuicCryptoClientStreamTest, PreferredVersion) { client_version_label); } -class QuicCryptoClientStreamStatelessTest : public QuicTest { - public: - QuicCryptoClientStreamStatelessTest() - : client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(), - TlsClientHandshaker::CreateSslCtx()), - server_crypto_config_(QuicCryptoServerConfig::TESTING, - QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting(), - KeyExchangeSource::Default(), - TlsServerHandshaker::CreateSslCtx()), - server_compressed_certs_cache_( - QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), - server_id_(kServerHostname, kServerPort, false) { - TestQuicSpdyClientSession* client_session = nullptr; - CreateClientSessionForTest(server_id_, - /* supports_stateless_rejects= */ true, - QuicTime::Delta::FromSeconds(100000), - AllSupportedVersions(), &helper_, - &alarm_factory_, &client_crypto_config_, - &client_connection_, &client_session); - CHECK(client_session); - client_session_.reset(client_session); - } - - QuicCryptoServerStream* server_stream() { - return server_session_->GetMutableCryptoStream(); - } - - void AdvanceHandshakeWithFakeServer() { - client_session_->GetMutableCryptoStream()->CryptoConnect(); - EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _)) - .Times(testing::AnyNumber()); - EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_, _)) - .Times(testing::AnyNumber()); - crypto_test_utils::AdvanceHandshake( - client_connection_, client_session_->GetMutableCryptoStream(), 0, - server_connection_, server_stream(), 0); - } - - // Initializes the server_stream_ for stateless rejects. - void InitializeFakeStatelessRejectServer() { - TestQuicSpdyServerSession* server_session = nullptr; - CreateServerSessionForTest( - server_id_, QuicTime::Delta::FromSeconds(100000), - ParsedVersionOfIndex(AllSupportedVersions(), 0), &helper_, - &alarm_factory_, &server_crypto_config_, - &server_compressed_certs_cache_, &server_connection_, &server_session); - CHECK(server_session); - server_session_.reset(server_session); - server_session_->OnSuccessfulVersionNegotiation(AllSupportedVersions()[0]); - crypto_test_utils::FakeServerOptions options; - crypto_test_utils::SetupCryptoServerConfigForTest( - server_connection_->clock(), server_connection_->random_generator(), - &server_crypto_config_, options); - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - } - - MockQuicConnectionHelper helper_; - MockAlarmFactory alarm_factory_; - - // Client crypto stream state - PacketSavingConnection* client_connection_; - std::unique_ptr<TestQuicSpdyClientSession> client_session_; - QuicCryptoClientConfig client_crypto_config_; - - // Server crypto stream state - PacketSavingConnection* server_connection_; - std::unique_ptr<TestQuicSpdyServerSession> server_session_; - QuicCryptoServerConfig server_crypto_config_; - QuicCompressedCertsCache server_compressed_certs_cache_; - QuicServerId server_id_; -}; - -TEST_F(QuicCryptoClientStreamStatelessTest, StatelessReject) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - - QuicCryptoClientConfig::CachedState* client_state = - client_crypto_config_.LookupOrCreate(server_id_); - - EXPECT_FALSE(client_state->has_server_designated_connection_id()); - EXPECT_CALL(*client_session_, OnProofValid(testing::_)); - - InitializeFakeStatelessRejectServer(); - EXPECT_CALL(*client_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - EXPECT_CALL(*server_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - AdvanceHandshakeWithFakeServer(); - - EXPECT_EQ(1, server_stream()->NumHandshakeMessages()); - EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces()); - - EXPECT_FALSE(client_session_->IsEncryptionEstablished()); - EXPECT_FALSE(client_session_->IsCryptoHandshakeConfirmed()); - // Even though the handshake was not complete, the cached client_state is - // complete, and can be used for a subsequent successful handshake. - EXPECT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); - - ASSERT_TRUE(client_state->has_server_nonce()); - ASSERT_FALSE(client_state->GetNextServerNonce().empty()); - ASSERT_TRUE(client_state->has_server_designated_connection_id()); - QuicConnectionId server_designated_id = - client_state->GetNextServerDesignatedConnectionId(); - QuicConnectionId expected_id = QuicUtils::CreateRandomConnectionId( - server_session_->connection()->random_generator()); - EXPECT_EQ(expected_id, server_designated_id); - EXPECT_FALSE(client_state->has_server_designated_connection_id()); -} - } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc index c0e61efb21f..f345a147208 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_handshaker.cc @@ -138,18 +138,11 @@ void QuicCryptoServerHandshaker::FinishProcessingHandshakeMessage( QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result, std::unique_ptr<ProofSource::Details> details) { - const CryptoHandshakeMessage& message = result->client_hello; - // Clear the callback that got us here. DCHECK(validate_client_hello_cb_ != nullptr); DCHECK(process_client_hello_cb_ == nullptr); validate_client_hello_cb_ = nullptr; - if (stream_->UseStatelessRejectsIfPeerSupported()) { - stream_->SetPeerSupportsStatelessRejects( - QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects(message)); - } - std::unique_ptr<ProcessClientHelloCallback> cb( new ProcessClientHelloCallback(this, result)); process_client_hello_cb_ = cb.get(); @@ -176,29 +169,9 @@ void QuicCryptoServerHandshaker:: } if (reply->tag() != kSHLO) { - if (reply->tag() == kSREJ) { - DCHECK(stream_->UseStatelessRejectsIfPeerSupported()); - DCHECK(stream_->PeerSupportsStatelessRejects()); - // Before sending the SREJ, cause the connection to save crypto packets - // so that they can be added to the time wait list manager and - // retransmitted. - session()->connection()->EnableSavingCryptoPackets(); - } session()->connection()->set_fully_pad_crypto_hadshake_packets( crypto_config_->pad_rej()); SendHandshakeMessage(*reply); - - if (reply->tag() == kSREJ) { - DCHECK(stream_->UseStatelessRejectsIfPeerSupported()); - DCHECK(stream_->PeerSupportsStatelessRejects()); - DCHECK(!handshake_confirmed()); - QUIC_DLOG(INFO) << "Closing connection " - << session()->connection()->connection_id() - << " because of a stateless reject."; - session()->connection()->CloseConnection( - QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject", - ConnectionCloseBehavior::SILENT_CLOSE); - } return; } @@ -217,7 +190,7 @@ void QuicCryptoServerHandshaker:: session()->OnConfigNegotiated(); - config->ToHandshakeMessage(reply.get()); + config->ToHandshakeMessage(reply.get(), session()->transport_version()); // Receiving a full CHLO implies the client is prepared to decrypt with // the new server write key. We can start to encrypt with the new server @@ -431,16 +404,13 @@ void QuicCryptoServerHandshaker::ProcessClientHello( } previous_source_address_tokens_ = result->info.source_address_tokens; - const bool use_stateless_rejects_in_crypto_config = - stream_->UseStatelessRejectsIfPeerSupported() && - stream_->PeerSupportsStatelessRejects(); QuicConnection* connection = session()->connection(); const QuicConnectionId server_designated_connection_id = - GenerateConnectionIdForReject(use_stateless_rejects_in_crypto_config); + GenerateConnectionIdForReject(/*use_stateless_rejects=*/false); crypto_config_->ProcessClientHello( result, /*reject_only=*/false, connection->connection_id(), connection->self_address(), GetClientAddress(), connection->version(), - session()->supported_versions(), use_stateless_rejects_in_crypto_config, + session()->supported_versions(), /*use_stateless_rejects=*/false, server_designated_connection_id, connection->clock(), connection->random_generator(), compressed_certs_cache_, crypto_negotiated_params_, signed_config_, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc index 010ac361ea9..a6486d88014 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc @@ -28,34 +28,12 @@ namespace quic { QuicCryptoServerStreamBase::QuicCryptoServerStreamBase(QuicSession* session) : QuicCryptoStream(session) {} -// TODO(jokulik): Once stateless rejects support is inherent in the version -// number, this function will likely go away entirely. -// static -bool QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects( - const CryptoHandshakeMessage& message) { - QuicTagVector received_tags; - QuicErrorCode error = message.GetTaglist(kCOPT, &received_tags); - if (error != QUIC_NO_ERROR) { - return false; - } - for (const QuicTag tag : received_tags) { - if (tag == kSREJ) { - return true; - } - } - return false; -} - QuicCryptoServerStream::QuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, QuicCompressedCertsCache* compressed_certs_cache, - bool use_stateless_rejects_if_peer_supported, QuicSession* session, Helper* helper) : QuicCryptoServerStreamBase(session), - use_stateless_rejects_if_peer_supported_( - use_stateless_rejects_if_peer_supported), - peer_supports_stateless_rejects_(false), crypto_config_(crypto_config), compressed_certs_cache_(compressed_certs_cache), helper_(helper) { @@ -97,23 +75,10 @@ QuicCryptoServerStream::PreviousCachedNetworkParams() const { return handshaker()->PreviousCachedNetworkParams(); } -bool QuicCryptoServerStream::UseStatelessRejectsIfPeerSupported() const { - return use_stateless_rejects_if_peer_supported_; -} - -bool QuicCryptoServerStream::PeerSupportsStatelessRejects() const { - return peer_supports_stateless_rejects_; -} - bool QuicCryptoServerStream::ZeroRttAttempted() const { return handshaker()->ZeroRttAttempted(); } -void QuicCryptoServerStream::SetPeerSupportsStatelessRejects( - bool peer_supports_stateless_rejects) { - peer_supports_stateless_rejects_ = peer_supports_stateless_rejects; -} - void QuicCryptoServerStream::SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) { handshaker()->SetPreviousCachedNetworkParams(cached_network_params); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h index a00302779d9..71ce29700ff 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h @@ -51,19 +51,11 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream { // These are all accessors and setters to their respective counters. virtual uint8_t NumHandshakeMessages() const = 0; virtual uint8_t NumHandshakeMessagesWithServerNonces() const = 0; - virtual bool UseStatelessRejectsIfPeerSupported() const = 0; - virtual bool PeerSupportsStatelessRejects() const = 0; virtual bool ZeroRttAttempted() const = 0; - virtual void SetPeerSupportsStatelessRejects(bool set) = 0; virtual const CachedNetworkParameters* PreviousCachedNetworkParams() const = 0; virtual void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) = 0; - - // Checks the options on the handshake-message to see whether the - // peer supports stateless-rejects. - static bool DoesPeerSupportStatelessRejects( - const CryptoHandshakeMessage& message); }; class QUIC_EXPORT_PRIVATE QuicCryptoServerStream @@ -154,7 +146,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream // |helper| must outlive the stream. QuicCryptoServerStream(const QuicCryptoServerConfig* crypto_config, QuicCompressedCertsCache* compressed_certs_cache, - bool use_stateless_rejects_if_peer_supported, QuicSession* session, Helper* helper); QuicCryptoServerStream(const QuicCryptoServerStream&) = delete; @@ -171,11 +162,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream uint8_t NumHandshakeMessagesWithServerNonces() const override; int NumServerConfigUpdateMessagesSent() const override; const CachedNetworkParameters* PreviousCachedNetworkParams() const override; - bool UseStatelessRejectsIfPeerSupported() const override; - bool PeerSupportsStatelessRejects() const override; bool ZeroRttAttempted() const override; - void SetPeerSupportsStatelessRejects( - bool peer_supports_stateless_rejects) override; void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) override; @@ -201,17 +188,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream private: std::unique_ptr<HandshakerDelegate> handshaker_; - // If true, the server should use stateless rejects, so long as the - // client supports them, as indicated by - // peer_supports_stateless_rejects_. - bool use_stateless_rejects_if_peer_supported_; - - // Set to true, once the server has received information from the - // client that it supports stateless reject. - // TODO(jokulik): Remove once client stateless reject support - // becomes the default. - bool peer_supports_stateless_rejects_; - // Arguments from QuicCryptoServerStream constructor that might need to be // passed to the HandshakerDelegate constructor in its late construction. const QuicCryptoServerConfig* crypto_config_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc index 660c588377b..5105a27b53c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc @@ -45,14 +45,6 @@ using testing::NiceMock; namespace quic { namespace test { -class QuicCryptoServerStreamPeer { - public: - static bool DoesPeerSupportStatelessRejects( - const CryptoHandshakeMessage& message) { - return QuicCryptoServerStream::DoesPeerSupportStatelessRejects(message); - } -}; - namespace { const char kServerHostname[] = "test.example.com"; @@ -74,9 +66,7 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> { QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), server_id_(kServerHostname, kServerPort, false), client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(), - TlsClientHandshaker::CreateSslCtx()) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, false); - } + TlsClientHandshaker::CreateSslCtx()) {} void Initialize() { InitializeServer(); } @@ -106,11 +96,9 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> { .Times(testing::AnyNumber()); EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_, _)) .Times(testing::AnyNumber()); - crypto_test_utils::FakeServerOptions options; - options.token_binding_params = QuicTagVector{kTB10}; crypto_test_utils::SetupCryptoServerConfigForTest( server_connection_->clock(), server_connection_->random_generator(), - &server_crypto_config_, options); + &server_crypto_config_); server_session_->GetMutableCryptoStream()->OnSuccessfulVersionNegotiation( supported_versions_.front()); } @@ -125,13 +113,12 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> { // Initializes a fake client, and all its associated state, for // testing. May be called multiple times. - void InitializeFakeClient(bool supports_stateless_rejects) { + void InitializeFakeClient() { TestQuicSpdyClientSession* client_session = nullptr; helpers_.push_back(QuicMakeUnique<NiceMock<MockQuicConnectionHelper>>()); alarm_factories_.push_back(QuicMakeUnique<MockAlarmFactory>()); CreateClientSessionForTest( - server_id_, supports_stateless_rejects, - QuicTime::Delta::FromSeconds(100000), supported_versions_, + server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_, helpers_.back().get(), alarm_factories_.back().get(), &client_crypto_config_, &client_connection_, &client_session); CHECK(client_session); @@ -197,12 +184,6 @@ TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) { EXPECT_FALSE(server_stream()->handshake_confirmed()); } -TEST_P(QuicCryptoServerStreamTest, NotInitiallySendingStatelessRejects) { - Initialize(); - EXPECT_FALSE(server_stream()->UseStatelessRejectsIfPeerSupported()); - EXPECT_FALSE(server_stream()->PeerSupportsStatelessRejects()); -} - TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { // CompleteCryptoHandshake returns the number of client hellos sent. This // test should send: @@ -215,7 +196,7 @@ TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { } TEST_P(QuicCryptoServerStreamTest, ConnectedAfterTlsHandshake) { - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); client_options_.only_tls_versions = true; supported_versions_.clear(); for (QuicTransportVersion transport_version : @@ -232,7 +213,7 @@ TEST_P(QuicCryptoServerStreamTest, ConnectedAfterTlsHandshake) { TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) { Initialize(); - InitializeFakeClient(/* supports_stateless_rejects= */ false); + InitializeFakeClient(); // Do a first handshake in order to prime the client config with the server's // information. @@ -242,7 +223,7 @@ TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) { // Now do another handshake, with the blocking SHLO connection option. InitializeServer(); - InitializeFakeClient(/* supports_stateless_rejects= */ false); + InitializeFakeClient(); AdvanceHandshakeWithFakeClient(); EXPECT_TRUE(server_stream()->encryption_established()); @@ -251,112 +232,9 @@ TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) { server_session_->connection()->encryption_level()); } -TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - Initialize(); - - InitializeFakeClient(/* supports_stateless_rejects= */ true); - EXPECT_CALL(*server_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - EXPECT_CALL(*client_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - AdvanceHandshakeWithFakeClient(); - - // Check the server to make the sure the handshake did not succeed. - EXPECT_FALSE(server_stream()->encryption_established()); - EXPECT_FALSE(server_stream()->handshake_confirmed()); - - // Check the client state to make sure that it received a server-designated - // connection id. - QuicCryptoClientConfig::CachedState* client_state = - client_crypto_config_.LookupOrCreate(server_id_); - - ASSERT_TRUE(client_state->has_server_nonce()); - ASSERT_FALSE(client_state->GetNextServerNonce().empty()); - ASSERT_FALSE(client_state->has_server_nonce()); - - ASSERT_TRUE(client_state->has_server_designated_connection_id()); - const QuicConnectionId server_designated_connection_id = - client_state->GetNextServerDesignatedConnectionId(); - const QuicConnectionId expected_id = QuicUtils::CreateRandomConnectionId( - server_connection_->random_generator()); - EXPECT_EQ(expected_id, server_designated_connection_id); - EXPECT_FALSE(client_state->has_server_designated_connection_id()); - ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); -} - -TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - Initialize(); - - InitializeFakeClient(/* supports_stateless_rejects= */ true); - EXPECT_CALL(*server_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - EXPECT_CALL(*client_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - AdvanceHandshakeWithFakeClient(); - - // 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()->NumHandshakeMessages()); - EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces()); - - // Now check the client state. - QuicCryptoClientConfig::CachedState* client_state = - client_crypto_config_.LookupOrCreate(server_id_); - - ASSERT_TRUE(client_state->has_server_designated_connection_id()); - const QuicConnectionId server_designated_connection_id = - client_state->GetNextServerDesignatedConnectionId(); - const QuicConnectionId expected_id = QuicUtils::CreateRandomConnectionId( - server_connection_->random_generator()); - EXPECT_EQ(expected_id, server_designated_connection_id); - EXPECT_FALSE(client_state->has_server_designated_connection_id()); - ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); - - // Now create new client and server streams with the existing config - // and try the handshake again (0-RTT handshake). - InitializeServer(); - - InitializeFakeClient(/* supports_stateless_rejects= */ true); - // In the stateless case, the second handshake contains a server-nonce, so the - // AsyncStrikeRegisterVerification() case will still succeed (unlike a 0-RTT - // handshake). - AdvanceHandshakeWithFakeClient(); - - // On the second round, encryption will be established. - EXPECT_TRUE(server_stream()->encryption_established()); - EXPECT_TRUE(server_stream()->handshake_confirmed()); - EXPECT_EQ(1, server_stream()->NumHandshakeMessages()); - EXPECT_EQ(1, server_stream()->NumHandshakeMessagesWithServerNonces()); -} - -TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - Initialize(); - - // The server is configured to use stateless rejects, but the client does not - // support it. - InitializeFakeClient(/* supports_stateless_rejects= */ false); - AdvanceHandshakeWithFakeClient(); - - // Check the server to make the sure the handshake did not succeed. - EXPECT_FALSE(server_stream()->encryption_established()); - EXPECT_FALSE(server_stream()->handshake_confirmed()); - - // Check the client state to make sure that it did not receive a - // server-designated connection id. - QuicCryptoClientConfig::CachedState* client_state = - client_crypto_config_.LookupOrCreate(server_id_); - - ASSERT_FALSE(client_state->has_server_designated_connection_id()); - ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); -} - TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { Initialize(); - InitializeFakeClient(/* supports_stateless_rejects= */ false); + InitializeFakeClient(); // Do a first handshake in order to prime the client config with the server's // information. @@ -365,7 +243,7 @@ TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { // Now do another handshake, hopefully in 0-RTT. QUIC_LOG(INFO) << "Resetting for 0-RTT handshake attempt"; - InitializeFakeClient(/* supports_stateless_rejects= */ false); + InitializeFakeClient(); InitializeServer(); EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber()); @@ -387,7 +265,7 @@ TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { TEST_P(QuicCryptoServerStreamTest, FailByPolicy) { Initialize(); - InitializeFakeClient(/* supports_stateless_rejects= */ false); + InitializeFakeClient(); EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _)) .WillOnce(testing::Return(false)); @@ -418,30 +296,6 @@ TEST_P(QuicCryptoServerStreamTest, BadMessageType) { Perspective::IS_SERVER); } -TEST_P(QuicCryptoServerStreamTest, ChannelID) { - Initialize(); - - client_options_.channel_id_enabled = true; - client_options_.channel_id_source_async = false; - // CompleteCryptoHandshake verifies - // server_stream()->crypto_negotiated_params().channel_id is correct. - EXPECT_EQ(2, CompleteCryptoHandshake()); - EXPECT_TRUE(server_stream()->encryption_established()); - EXPECT_TRUE(server_stream()->handshake_confirmed()); -} - -TEST_P(QuicCryptoServerStreamTest, ChannelIDAsync) { - Initialize(); - - client_options_.channel_id_enabled = true; - client_options_.channel_id_source_async = true; - // CompleteCryptoHandshake verifies - // server_stream()->crypto_negotiated_params().channel_id is correct. - EXPECT_EQ(2, CompleteCryptoHandshake()); - EXPECT_TRUE(server_stream()->encryption_established()); - EXPECT_TRUE(server_stream()->handshake_confirmed()); -} - TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) { // An attempt to send a SCUP before completing handshake should fail. Initialize(); @@ -453,7 +307,7 @@ TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) { TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) { Initialize(); - InitializeFakeClient(/* supports_stateless_rejects= */ false); + InitializeFakeClient(); // Do a first handshake in order to prime the client config with the server's // information. @@ -461,7 +315,7 @@ TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) { // Now do another handshake, with the blocking SHLO connection option. InitializeServer(); - InitializeFakeClient(/* supports_stateless_rejects= */ false); + InitializeFakeClient(); AdvanceHandshakeWithFakeClient(); // Send a SCUP message and ensure that the client was able to verify it. @@ -474,21 +328,6 @@ TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) { EXPECT_EQ(1, client_stream()->num_scup_messages_received()); } -TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) { - Initialize(); - - QuicConfig stateless_reject_config = DefaultQuicConfigStatelessRejects(); - stateless_reject_config.ToHandshakeMessage(&message_); - EXPECT_TRUE( - QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_)); - - message_.Clear(); - QuicConfig stateful_reject_config = DefaultQuicConfig(); - stateful_reject_config.ToHandshakeMessage(&message_); - EXPECT_FALSE( - QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_)); -} - class QuicCryptoServerStreamTestWithFailingProofSource : public QuicCryptoServerStreamTest { public: @@ -503,7 +342,7 @@ INSTANTIATE_TEST_SUITE_P(MoreTests, TEST_P(QuicCryptoServerStreamTestWithFailingProofSource, Test) { Initialize(); - InitializeFakeClient(/* supports_stateless_rejects= */ false); + InitializeFakeClient(); EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _)) .WillOnce(testing::Return(true)); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc index 836fbac67ab..f394b3d5110 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc @@ -24,11 +24,18 @@ namespace quic { " ") QuicCryptoStream::QuicCryptoStream(QuicSession* session) - : QuicStream(QuicUtils::GetCryptoStreamId( - session->connection()->transport_version()), + : QuicStream(QuicVersionUsesCryptoFrames( + session->connection()->transport_version()) + ? QuicUtils::GetInvalidStreamId( + session->connection()->transport_version()) + : QuicUtils::GetCryptoStreamId( + session->connection()->transport_version()), session, /*is_static=*/true, - BIDIRECTIONAL), + QuicVersionUsesCryptoFrames( + session->connection()->transport_version()) + ? CRYPTO + : BIDIRECTIONAL), substreams_{{this, ENCRYPTION_INITIAL}, {this, ENCRYPTION_HANDSHAKE}, {this, ENCRYPTION_ZERO_RTT}, @@ -156,6 +163,9 @@ void QuicCryptoStream::WriteCryptoData(EncryptionLevel level, size_t bytes_consumed = session()->connection()->SendCryptoData(level, data.length(), offset); session()->connection()->SetDefaultEncryptionLevel(current_level); + // Since CRYPTO frames aren't flow controlled, SendCryptoData should have sent + // all data we asked it to send. + DCHECK_EQ(bytes_consumed, data.length()); send_buffer->OnStreamDataConsumed(bytes_consumed); } @@ -210,7 +220,7 @@ void QuicCryptoStream::OnStreamDataConsumed(size_t bytes_consumed) { QuicStream::OnStreamDataConsumed(bytes_consumed); } -bool QuicCryptoStream::HasPendingCryptoRetransmission() { +bool QuicCryptoStream::HasPendingCryptoRetransmission() const { if (!QuicVersionUsesCryptoFrames( session()->connection()->transport_version())) { return false; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h index 0c6d08aa607..1b641b19cec 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h @@ -92,7 +92,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { // Returns whether there are any bytes pending retransmission in CRYPTO // frames. - virtual bool HasPendingCryptoRetransmission(); + virtual bool HasPendingCryptoRetransmission() const; // Writes any pending CRYPTO frame retransmissions. void WritePendingCryptoRetransmission(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc index 0488fd39d00..ef094830a09 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.cc @@ -12,6 +12,9 @@ namespace quic { +QuicDataReader::QuicDataReader(QuicStringPiece data) + : QuicDataReader(data.data(), data.length(), NETWORK_BYTE_ORDER) {} + QuicDataReader::QuicDataReader(const char* data, const size_t len) : QuicDataReader(data, len, NETWORK_BYTE_ORDER) {} @@ -180,6 +183,15 @@ bool QuicDataReader::ReadBytes(void* result, size_t size) { return true; } +bool QuicDataReader::Seek(size_t size) { + if (!CanRead(size)) { + OnFailure(); + return false; + } + pos_ += size; + return true; +} + bool QuicDataReader::IsDoneReading() const { return len_ == pos_; } @@ -295,7 +307,7 @@ bool QuicDataReader::ReadVarInt62(uint64_t* result) { return false; } -bool QuicDataReader::ReadVarIntStreamId(QuicStreamId* result) { +bool QuicDataReader::ReadVarIntU32(uint32_t* result) { uint64_t temp_uint64; // TODO(fkastenholz): We should disambiguate read-errors from // value errors. @@ -305,7 +317,7 @@ bool QuicDataReader::ReadVarIntStreamId(QuicStreamId* result) { if (temp_uint64 > kMaxQuicStreamId) { return false; } - *result = static_cast<QuicStreamId>(temp_uint64); + *result = static_cast<uint32_t>(temp_uint64); return true; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h index 3426e48efc6..a03b92751a5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_reader.h @@ -33,6 +33,9 @@ class QUIC_EXPORT_PRIVATE QuicDataReader { public: // Constructs a reader using NETWORK_BYTE_ORDER endianness. // Caller must provide an underlying buffer to work on. + explicit QuicDataReader(QuicStringPiece data); + // Constructs a reader using NETWORK_BYTE_ORDER endianness. + // Caller must provide an underlying buffer to work on. QuicDataReader(const char* data, const size_t len); // Constructs a reader using the specified endianness. // Caller must provide an underlying buffer to work on. @@ -108,6 +111,11 @@ class QUIC_EXPORT_PRIVATE QuicDataReader { // Returns true on success, false otherwise. bool ReadBytes(void* result, size_t size); + // Skips over |size| bytes from the buffer and forwards the internal iterator. + // Returns true if there are at least |size| bytes remaining to read, false + // otherwise. + bool Seek(size_t size); + // Returns true if the entirety of the underlying buffer has been read via // Read*() calls. bool IsDoneReading() const; @@ -142,11 +150,11 @@ class QUIC_EXPORT_PRIVATE QuicDataReader { // and that the integers in the range 0 ... (2^62)-1. bool ReadVarInt62(uint64_t* result); - // Convenience method that reads a StreamId. - // Atempts to read a Stream ID into |result| using ReadVarInt62 and + // Convenience method that reads a uint32_t. + // Attempts to read a varint into a uint32_t. using ReadVarInt62 and // returns false if there is a read error or if the value is // greater than (2^32)-1. - bool ReadVarIntStreamId(QuicStreamId* result); + bool ReadVarIntU32(uint32_t* result); std::string DebugString() const; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.cc index 7116853e77d..42f1e4e2092 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.cc @@ -196,6 +196,14 @@ bool QuicDataWriter::WriteRandomBytes(QuicRandom* random, size_t length) { return true; } +bool QuicDataWriter::Seek(size_t length) { + if (!BeginWrite(length)) { + return false; + } + length_ += length; + return true; +} + // Converts a uint64_t into an IETF/Quic formatted Variable Length // Integer. IETF Variable Length Integers have 62 significant bits, so // the value to write must be in the range of 0..(2^62)-1. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.h b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.h index bd1ded6c6da..d2d2b6bf3df 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer.h @@ -117,6 +117,11 @@ class QUIC_EXPORT_PRIVATE QuicDataWriter { // Write |length| random bytes generated by |random|. bool WriteRandomBytes(QuicRandom* random, size_t length); + // Advance the writer's position for writing by |length| bytes without writing + // anything. This method only makes sense to be used on a buffer that has + // already been written to (and is having certain parts rewritten). + bool Seek(size_t length); + size_t capacity() const { return capacity_; } size_t remaining() const { return capacity_ - length_; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc index 031620df4e8..07f0313f9ef 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_data_writer_test.cc @@ -1026,7 +1026,7 @@ void EncodeDecodeStreamId(uint64_t value_in, bool expected_decode_result) { QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER); QuicStreamId received_stream_id; - bool read_result = reader.ReadVarIntStreamId(&received_stream_id); + bool read_result = reader.ReadVarIntU32(&received_stream_id); EXPECT_EQ(expected_decode_result, read_result); if (read_result) { EXPECT_EQ(value_in, received_stream_id); @@ -1114,6 +1114,74 @@ TEST_P(QuicDataWriterTest, InvalidConnectionIdLengthRead) { EXPECT_FALSE(ok); } +// Test that ReadVarIntU32 works properly. Tests a valid stream count +// (a 32 bit number) and an invalid one (a >32 bit number) +TEST_P(QuicDataWriterTest, ValidU32) { + char buffer[1024]; + memset(buffer, 0, sizeof(buffer)); + QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + Endianness::NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer, sizeof(buffer)); + const QuicStreamCount write_stream_count = 0xffeeddcc; + EXPECT_TRUE(writer.WriteVarInt62(write_stream_count)); + QuicStreamCount read_stream_count; + EXPECT_TRUE(reader.ReadVarIntU32(&read_stream_count)); + EXPECT_EQ(write_stream_count, read_stream_count); +} + +TEST_P(QuicDataWriterTest, InvalidU32) { + char buffer[1024]; + memset(buffer, 0, sizeof(buffer)); + QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + Endianness::NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer, sizeof(buffer)); + EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x1ffeeddcc))); + QuicStreamCount read_stream_count = 123456; + EXPECT_FALSE(reader.ReadVarIntU32(&read_stream_count)); + // If the value is bad, read_stream_count ought not change. + EXPECT_EQ(123456u, read_stream_count); +} + +TEST_P(QuicDataWriterTest, Seek) { + char buffer[3] = {}; + QuicDataWriter writer(QUIC_ARRAYSIZE(buffer), buffer, GetParam().endianness); + EXPECT_TRUE(writer.WriteUInt8(42)); + EXPECT_TRUE(writer.Seek(1)); + EXPECT_TRUE(writer.WriteUInt8(3)); + + char expected[] = {42, 0, 3}; + for (size_t i = 0; i < QUIC_ARRAYSIZE(expected); ++i) { + EXPECT_EQ(buffer[i], expected[i]); + } +} + +TEST_P(QuicDataWriterTest, SeekTooFarFails) { + char buffer[20]; + + // Check that one can seek to the end of the writer, but not past. + { + QuicDataWriter writer(QUIC_ARRAYSIZE(buffer), buffer, + GetParam().endianness); + EXPECT_TRUE(writer.Seek(20)); + EXPECT_FALSE(writer.Seek(1)); + } + + // Seeking several bytes past the end fails. + { + QuicDataWriter writer(QUIC_ARRAYSIZE(buffer), buffer, + GetParam().endianness); + EXPECT_FALSE(writer.Seek(100)); + } + + // Seeking so far that arithmetic overflow could occur also fails. + { + QuicDataWriter writer(QUIC_ARRAYSIZE(buffer), buffer, + GetParam().endianness); + EXPECT_TRUE(writer.Seek(10)); + EXPECT_FALSE(writer.Seek(std::numeric_limits<size_t>::max())); + } +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc index 75b3c30ffc6..5bf072d7e09 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc @@ -10,10 +10,10 @@ #include "net/third_party/quiche/src/quic/core/chlo_extractor.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/stateless_rejector.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" @@ -21,6 +21,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" namespace quic { @@ -71,8 +72,7 @@ class PacketCollector : public QuicPacketCreator::DelegateInterface, } void OnUnrecoverableError(QuicErrorCode error, - const std::string& error_details, - ConnectionCloseSource source) override {} + const std::string& error_details) override {} void SaveStatelessRejectFrameData(QuicStringPiece reject) { struct iovec iovec; @@ -114,21 +114,24 @@ class PacketCollector : public QuicPacketCreator::DelegateInterface, // list manager. class StatelessConnectionTerminator { public: - StatelessConnectionTerminator(QuicConnectionId connection_id, - QuicFramer* framer, + StatelessConnectionTerminator(QuicConnectionId server_connection_id, + const ParsedQuicVersion version, QuicConnectionHelperInterface* helper, QuicTimeWaitListManager* time_wait_list_manager) - : connection_id_(connection_id), - framer_(framer), + : server_connection_id_(server_connection_id), + framer_(ParsedQuicVersionVector{version}, + /*unused*/ QuicTime::Zero(), + Perspective::IS_SERVER, + /*unused*/ kQuicDefaultConnectionIdLength), collector_(helper->GetStreamSendBufferAllocator()), - creator_(connection_id, framer, &collector_), + creator_(server_connection_id, &framer_, &collector_), time_wait_list_manager_(time_wait_list_manager) { - framer_->set_data_producer(&collector_); + framer_.set_data_producer(&collector_); } ~StatelessConnectionTerminator() { // Clear framer's producer. - framer_->set_data_producer(nullptr); + framer_.set_data_producer(nullptr); } // Generates a packet containing a CONNECTION_CLOSE frame specifying @@ -138,8 +141,7 @@ class StatelessConnectionTerminator { bool ietf_quic) { QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame(error_code, error_details); - // TODO(fkastenholz): The framer version may be incorrect in some cases. - if (framer_->transport_version() == QUIC_VERSION_99) { + if (framer_.transport_version() == QUIC_VERSION_99) { frame->close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE; } @@ -151,7 +153,7 @@ class StatelessConnectionTerminator { creator_.Flush(); DCHECK_EQ(1u, collector_.packets()->size()); time_wait_list_manager_->AddConnectionIdToTimeWait( - connection_id_, ietf_quic, + server_connection_id_, ietf_quic, QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, quic::ENCRYPTION_INITIAL, collector_.packets()); } @@ -164,9 +166,9 @@ class StatelessConnectionTerminator { collector_.SaveStatelessRejectFrameData(reject); while (offset < reject.length()) { QuicFrame frame; - if (!QuicVersionUsesCryptoFrames(framer_->transport_version())) { + if (!QuicVersionUsesCryptoFrames(framer_.transport_version())) { if (!creator_.ConsumeData( - QuicUtils::GetCryptoStreamId(framer_->transport_version()), + QuicUtils::GetCryptoStreamId(framer_.transport_version()), reject.length() - offset, offset, /*fin=*/false, /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)) { @@ -175,31 +177,33 @@ class StatelessConnectionTerminator { } offset += frame.stream_frame.data_length; } else { - if (!creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, - reject.length() - offset, offset, - NOT_RETRANSMISSION, &frame)) { + if (!creator_.ConsumeCryptoData( + ENCRYPTION_INITIAL, reject.length() - offset, offset, + /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)) { QUIC_BUG << "Unable to consume crypto data into an empty packet."; return; } offset += frame.crypto_frame->data_length; } - if (offset < reject.length()) { + if (offset < reject.length() && + !QuicVersionUsesCryptoFrames(framer_.transport_version())) { DCHECK(!creator_.HasRoomForStreamFrame( - QuicUtils::GetCryptoStreamId(framer_->transport_version()), offset, + QuicUtils::GetCryptoStreamId(framer_.transport_version()), offset, frame.stream_frame.data_length)); } creator_.Flush(); } time_wait_list_manager_->AddConnectionIdToTimeWait( - connection_id_, ietf_quic, + server_connection_id_, ietf_quic, QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, ENCRYPTION_INITIAL, collector_.packets()); - DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id_)); + DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( + server_connection_id_)); } private: - QuicConnectionId connection_id_; - QuicFramer* framer_; // Unowned. + QuicConnectionId server_connection_id_; + QuicFramer framer_; // Set as the visitor of |creator_| to collect any generated packets. PacketCollector collector_; QuicPacketCreator creator_; @@ -210,7 +214,7 @@ class StatelessConnectionTerminator { class ChloAlpnExtractor : public ChloExtractor::Delegate { public: void OnChlo(QuicTransportVersion version, - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, const CryptoHandshakeMessage& chlo) override { QuicStringPiece alpn_value; if (chlo.GetStringPiece(kALPN, &alpn_value)) { @@ -224,54 +228,6 @@ class ChloAlpnExtractor : public ChloExtractor::Delegate { std::string alpn_; }; -// Class which sits between the ChloExtractor and the StatelessRejector -// to give the QuicDispatcher a chance to apply policy checks to the CHLO. -class ChloValidator : public ChloAlpnExtractor { - public: - ChloValidator(QuicCryptoServerStream::Helper* helper, - const QuicSocketAddress& client_address, - const QuicSocketAddress& peer_address, - const QuicSocketAddress& self_address, - StatelessRejector* rejector) - : helper_(helper), - client_address_(client_address), - peer_address_(peer_address), - self_address_(self_address), - rejector_(rejector), - can_accept_(false), - error_details_("CHLO not processed") {} - - // ChloExtractor::Delegate implementation. - void OnChlo(QuicTransportVersion version, - QuicConnectionId connection_id, - const CryptoHandshakeMessage& chlo) override { - // Extract the ALPN - ChloAlpnExtractor::OnChlo(version, connection_id, chlo); - if (helper_->CanAcceptClientHello(chlo, client_address_, peer_address_, - self_address_, &error_details_)) { - can_accept_ = true; - rejector_->OnChlo( - version, connection_id, - helper_->GenerateConnectionIdForReject(version, connection_id), chlo); - } - } - - bool can_accept() const { return can_accept_; } - - const std::string& error_details() const { return error_details_; } - - private: - QuicCryptoServerStream::Helper* helper_; // Unowned. - // client_address_ and peer_address_ could be different values for proxy - // connections. - QuicSocketAddress client_address_; - QuicSocketAddress peer_address_; - QuicSocketAddress self_address_; - StatelessRejector* rejector_; // Unowned. - bool can_accept_; - std::string error_details_; -}; - } // namespace QuicDispatcher::QuicDispatcher( @@ -281,7 +237,7 @@ QuicDispatcher::QuicDispatcher( std::unique_ptr<QuicConnectionHelperInterface> helper, std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, std::unique_ptr<QuicAlarmFactory> alarm_factory, - uint8_t expected_connection_id_length) + uint8_t expected_server_connection_id_length) : config_(config), crypto_config_(crypto_config), compressed_certs_cache_( @@ -297,12 +253,19 @@ QuicDispatcher::QuicDispatcher( framer_(GetSupportedVersions(), /*unused*/ QuicTime::Zero(), Perspective::IS_SERVER, - expected_connection_id_length), + expected_server_connection_id_length), last_error_(QUIC_NO_ERROR), new_sessions_allowed_per_event_loop_(0u), accept_new_connections_(true), - allow_short_initial_connection_ids_(false) { - framer_.set_visitor(this); + allow_short_initial_server_connection_ids_(false), + last_version_label_(0), + expected_server_connection_id_length_( + expected_server_connection_id_length), + should_update_expected_server_connection_id_length_(false), + no_framer_(GetQuicRestartFlag(quic_no_framer_object_in_dispatcher)) { + if (!no_framer_) { + framer_.set_visitor(this); + } } QuicDispatcher::~QuicDispatcher() { @@ -319,48 +282,93 @@ void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) { void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, const QuicReceivedPacket& packet) { + QUIC_DVLOG(2) << "Dispatcher received encrypted " << packet.length() + << " bytes:" << std::endl + << QuicTextUtils::HexDump( + QuicStringPiece(packet.data(), packet.length())); current_self_address_ = self_address; current_peer_address_ = peer_address; // GetClientAddress must be called after current_peer_address_ is set. current_client_address_ = GetClientAddress(); current_packet_ = &packet; - // ProcessPacket will cause the packet to be dispatched in - // OnUnauthenticatedPublicHeader, or sent to the time wait list manager - // in OnUnauthenticatedHeader. - framer_.ProcessPacket(packet); - // TODO(rjshade): Return a status describing if/why a packet was dropped, - // and log somehow. Maybe expose as a varz. - // TODO(wub): Consider invalidate the current_* variables so processing of the - // next packet does not use them incorrectly. -} - -QuicConnectionId QuicDispatcher::MaybeReplaceConnectionId( - QuicConnectionId connection_id, + if (!no_framer_) { + // ProcessPacket will cause the packet to be dispatched in + // OnUnauthenticatedPublicHeader, or sent to the time wait list manager + // in OnUnauthenticatedHeader. + framer_.ProcessPacket(packet); + // TODO(rjshade): Return a status describing if/why a packet was dropped, + // and log somehow. Maybe expose as a varz. + return; + } + QUIC_RESTART_FLAG_COUNT(quic_no_framer_object_in_dispatcher); + QuicPacketHeader header; + uint8_t destination_connection_id_length; + std::string detailed_error; + const QuicErrorCode error = QuicFramer::ProcessPacketDispatcher( + packet, expected_server_connection_id_length_, &header.form, + &header.version_flag, &last_version_label_, + &destination_connection_id_length, &header.destination_connection_id, + &detailed_error); + if (error != QUIC_NO_ERROR) { + // Packet has framing error. + SetLastError(error); + QUIC_DLOG(ERROR) << detailed_error; + return; + } + header.version = ParseQuicVersionLabel(last_version_label_); + if (destination_connection_id_length != + expected_server_connection_id_length_ && + !should_update_expected_server_connection_id_length_ && + !QuicUtils::VariableLengthConnectionIdAllowedForVersion( + header.version.transport_version)) { + SetLastError(QUIC_INVALID_PACKET_HEADER); + QUIC_DLOG(ERROR) << "Invalid Connection Id Length"; + return; + } + if (should_update_expected_server_connection_id_length_) { + expected_server_connection_id_length_ = destination_connection_id_length; + } + // TODO(fayang): Instead of passing in QuicPacketHeader, pass format, + // version_flag, version and destination_connection_id. Combine + // OnUnauthenticatedPublicHeader and OnUnauthenticatedHeader to a single + // function when deprecating quic_no_framer_object_in_dispatcher. + if (!OnUnauthenticatedPublicHeader(header)) { + return; + } + OnUnauthenticatedHeader(header); + // TODO(wub): Consider invalidate the current_* variables so processing of + // the next packet does not use them incorrectly. +} + +QuicConnectionId QuicDispatcher::MaybeReplaceServerConnectionId( + QuicConnectionId server_connection_id, ParsedQuicVersion version) { - const uint8_t expected_connection_id_length = - framer_.GetExpectedConnectionIdLength(); - if (connection_id.length() == expected_connection_id_length) { - return connection_id; + const uint8_t expected_server_connection_id_length = + no_framer_ ? expected_server_connection_id_length_ + : framer_.GetExpectedServerConnectionIdLength(); + if (server_connection_id.length() == expected_server_connection_id_length) { + return server_connection_id; } DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion( version.transport_version)); - auto it = connection_id_map_.find(connection_id); + auto it = connection_id_map_.find(server_connection_id); if (it != connection_id_map_.end()) { return it->second; } QuicConnectionId new_connection_id = session_helper_->GenerateConnectionIdForReject(version.transport_version, - connection_id); - DCHECK_EQ(expected_connection_id_length, new_connection_id.length()); - connection_id_map_.insert(std::make_pair(connection_id, new_connection_id)); - QUIC_DLOG(INFO) << "Replacing incoming connection ID " << connection_id + server_connection_id); + DCHECK_EQ(expected_server_connection_id_length, new_connection_id.length()); + connection_id_map_.insert( + std::make_pair(server_connection_id, new_connection_id)); + QUIC_DLOG(INFO) << "Replacing incoming connection ID " << server_connection_id << " with " << new_connection_id; return new_connection_id; } bool QuicDispatcher::OnUnauthenticatedPublicHeader( const QuicPacketHeader& header) { - current_connection_id_ = header.destination_connection_id; + current_server_connection_id_ = header.destination_connection_id; // Port zero is only allowed for unidirectional UDP, so is disallowed by QUIC. // Given that we can't even send a reply rejecting the packet, just drop the @@ -374,50 +382,53 @@ bool QuicDispatcher::OnUnauthenticatedPublicHeader( if (header.destination_connection_id_included != CONNECTION_ID_PRESENT) { return false; } - QuicConnectionId connection_id = header.destination_connection_id; + QuicConnectionId server_connection_id = header.destination_connection_id; // The IETF spec requires the client to generate an initial server // connection ID that is at least 64 bits long. After that initial // connection ID, the dispatcher picks a new one of its expected length. // Therefore we should never receive a connection ID that is smaller // than 64 bits and smaller than what we expect. - if (connection_id.length() < kQuicMinimumInitialConnectionIdLength && - connection_id.length() < framer_.GetExpectedConnectionIdLength() && - !allow_short_initial_connection_ids_) { + const uint8_t expected_server_connection_id_length = + no_framer_ ? expected_server_connection_id_length_ + : framer_.GetExpectedServerConnectionIdLength(); + if (server_connection_id.length() < kQuicMinimumInitialConnectionIdLength && + server_connection_id.length() < expected_server_connection_id_length && + !allow_short_initial_server_connection_ids_) { DCHECK(header.version_flag); DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion( header.version.transport_version)); QUIC_DLOG(INFO) << "Packet with short destination connection ID " - << connection_id << " expected " - << static_cast<int>( - framer_.GetExpectedConnectionIdLength()); - ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, header.form, + << server_connection_id << " expected " + << static_cast<int>(expected_server_connection_id_length); + ProcessUnauthenticatedHeaderFate(kFateTimeWait, server_connection_id, + header.form, header.version_flag, header.version); return false; } // Packets with connection IDs for active connections are processed // immediately. - auto it = session_map_.find(connection_id); + auto it = session_map_.find(server_connection_id); if (it != session_map_.end()) { - DCHECK(!buffered_packets_.HasBufferedPackets(connection_id)); + DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id)); it->second->ProcessUdpPacket(current_self_address_, current_peer_address_, *current_packet_); return false; } - if (buffered_packets_.HasChloForConnection(connection_id)) { - BufferEarlyPacket(connection_id, header.form != GOOGLE_QUIC_PACKET, + if (buffered_packets_.HasChloForConnection(server_connection_id)) { + BufferEarlyPacket(server_connection_id, header.form != GOOGLE_QUIC_PACKET, header.version); return false; } // Check if we are buffering packets for this connection ID - if (temporarily_buffered_connections_.find(connection_id) != + if (temporarily_buffered_connections_.find(server_connection_id) != temporarily_buffered_connections_.end()) { // This packet was received while the a CHLO for the same connection ID was // being processed. Buffer it. - BufferEarlyPacket(connection_id, header.form != GOOGLE_QUIC_PACKET, + BufferEarlyPacket(server_connection_id, header.form != GOOGLE_QUIC_PACKET, header.version); return false; } @@ -432,7 +443,7 @@ bool QuicDispatcher::OnUnauthenticatedPublicHeader( return false; } - if (time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) { + if (time_wait_list_manager_->IsConnectionIdInTimeWait(server_connection_id)) { // This connection ID is already in time-wait state. time_wait_list_manager_->ProcessPacket( current_self_address_, current_peer_address_, @@ -447,12 +458,14 @@ bool QuicDispatcher::OnUnauthenticatedPublicHeader( ParsedQuicVersion version = GetSupportedVersions().front(); if (header.version_flag) { ParsedQuicVersion packet_version = header.version; - if (framer_.supported_versions() != GetSupportedVersions()) { + if (!no_framer_ && framer_.supported_versions() != GetSupportedVersions()) { // Reset framer's version if version flags change in flight. framer_.SetSupportedVersions(GetSupportedVersions()); } - if (!framer_.IsSupportedVersion(packet_version)) { - if (ShouldCreateSessionForUnknownVersion(framer_.last_version_label())) { + if (!IsSupportedVersion(packet_version)) { + if (ShouldCreateSessionForUnknownVersion( + no_framer_ ? last_version_label_ + : framer_.last_version_label())) { return true; } if (!crypto_config()->validate_chlo_size() || @@ -460,41 +473,52 @@ bool QuicDispatcher::OnUnauthenticatedPublicHeader( // Since the version is not supported, send a version negotiation // packet and stop processing the current packet. time_wait_list_manager()->SendVersionNegotiationPacket( - connection_id, header.form != GOOGLE_QUIC_PACKET, - GetSupportedVersions(), current_self_address_, - current_peer_address_, GetPerPacketContext()); + server_connection_id, EmptyQuicConnectionId(), + header.form != GOOGLE_QUIC_PACKET, GetSupportedVersions(), + current_self_address_, current_peer_address_, + GetPerPacketContext()); } return false; } version = packet_version; } - // Set the framer's version and continue processing. - framer_.set_version(version); + if (!no_framer_) { + // Set the framer's version and continue processing. + framer_.set_version(version); + } + + if (version.HasHeaderProtection()) { + ProcessHeader(header); + return false; + } return true; } bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) { - QuicConnectionId connection_id = header.destination_connection_id; + ProcessHeader(header); + return false; +} + +void QuicDispatcher::ProcessHeader(const QuicPacketHeader& header) { + QuicConnectionId server_connection_id = header.destination_connection_id; // Packet's connection ID is unknown. Apply the validity checks. QuicPacketFate fate = ValidityChecks(header); if (fate == kFateProcess) { - // Execute stateless rejection logic to determine the packet fate, then - // invoke ProcessUnauthenticatedHeaderFate. - MaybeRejectStatelessly(connection_id, header.form, header.version); + ProcessOrBufferPacket(server_connection_id, header.form, + header.version_flag, header.version); } else { // If the fate is already known, process it without executing stateless // rejection logic. - ProcessUnauthenticatedHeaderFate(fate, connection_id, header.form, - header.version); + ProcessUnauthenticatedHeaderFate(fate, server_connection_id, header.form, + header.version_flag, header.version); } - - return false; } void QuicDispatcher::ProcessUnauthenticatedHeaderFate( QuicPacketFate fate, - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, PacketHeaderFormat form, + bool version_flag, ParsedQuicVersion version) { switch (fate) { case kFateProcess: { @@ -502,36 +526,34 @@ void QuicDispatcher::ProcessUnauthenticatedHeaderFate( break; } case kFateTimeWait: - // MaybeRejectStatelessly or OnExpiredPackets might have already added the - // connection to time wait, in which case it should not be added again. - if (!GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) || - !time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) { - // Add this connection_id to the time-wait state, to safely reject - // future packets. - QUIC_DLOG(INFO) << "Adding connection ID " << connection_id - << " to time-wait list."; - QUIC_CODE_COUNT(quic_reject_fate_time_wait); - StatelesslyTerminateConnection( - connection_id, form, version, QUIC_HANDSHAKE_FAILED, - "Reject connection", - quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); - } - DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); + // Add this connection_id to the time-wait state, to safely reject + // future packets. + QUIC_DLOG(INFO) << "Adding connection ID " << server_connection_id + << " to time-wait list."; + QUIC_CODE_COUNT(quic_reject_fate_time_wait); + StatelesslyTerminateConnection( + server_connection_id, form, version_flag, version, + QUIC_HANDSHAKE_FAILED, "Reject connection", + quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); + + DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( + server_connection_id)); time_wait_list_manager_->ProcessPacket( - current_self_address_, current_peer_address_, connection_id, form, - GetPerPacketContext()); + current_self_address_, current_peer_address_, server_connection_id, + form, GetPerPacketContext()); // Any packets which were buffered while the stateless rejector logic was // running should be discarded. Do not inform the time wait list manager, // which should already have a made a decision about sending a reject // based on the CHLO alone. - buffered_packets_.DiscardPackets(connection_id); + buffered_packets_.DiscardPackets(server_connection_id); break; case kFateBuffer: // This packet is a non-CHLO packet which has arrived before the // corresponding CHLO, *or* this packet was received while the // corresponding CHLO was being processed. Buffer it. - BufferEarlyPacket(connection_id, form != GOOGLE_QUIC_PACKET, version); + BufferEarlyPacket(server_connection_id, form != GOOGLE_QUIC_PACKET, + version); break; case kFateDrop: // Do nothing with the packet. @@ -561,31 +583,38 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( return kFateTimeWait; } - // initial packet number of 0 is always invalid. - if (!header.packet_number.IsInitialized()) { - return kFateTimeWait; + if (no_framer_) { + // Let the connection parse and validate packet number. + return kFateProcess; } - if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { - QUIC_RESTART_FLAG_COUNT_N(quic_enable_accept_random_ipn, 1, 2); - // Accepting Initial Packet Numbers in 1...((2^31)-1) range... check - // maximum accordingly. - if (header.packet_number > MaxRandomInitialPacketNumber()) { + + // initial packet number of 0 is always invalid. + if (!framer_.version().HasHeaderProtection()) { + if (!header.packet_number.IsInitialized()) { return kFateTimeWait; } - } else { - // Count those that would have been accepted if FLAGS..random_ipn - // were true -- to detect/diagnose potential issues prior to - // enabling the flag. - if ((header.packet_number > - QuicPacketNumber(kMaxReasonableInitialPacketNumber)) && - (header.packet_number <= MaxRandomInitialPacketNumber())) { - QUIC_CODE_COUNT_N(had_possibly_random_ipn, 1, 2); - } - // Check that the sequence number is within the range that the client is - // expected to send before receiving a response from the server. - if (header.packet_number > - QuicPacketNumber(kMaxReasonableInitialPacketNumber)) { - return kFateTimeWait; + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + QUIC_RESTART_FLAG_COUNT_N(quic_enable_accept_random_ipn, 1, 2); + // Accepting Initial Packet Numbers in 1...((2^31)-1) range... check + // maximum accordingly. + if (header.packet_number > MaxRandomInitialPacketNumber()) { + return kFateTimeWait; + } + } else { + // Count those that would have been accepted if FLAGS..random_ipn + // were true -- to detect/diagnose potential issues prior to + // enabling the flag. + if ((header.packet_number > + QuicPacketNumber(kMaxReasonableInitialPacketNumber)) && + (header.packet_number <= MaxRandomInitialPacketNumber())) { + QUIC_CODE_COUNT_N(had_possibly_random_ipn, 1, 2); + } + // Check that the sequence number is within the range that the client is + // expected to send before receiving a response from the server. + if (header.packet_number > + QuicPacketNumber(kMaxReasonableInitialPacketNumber)) { + return kFateTimeWait; + } } } return kFateProcess; @@ -605,15 +634,23 @@ void QuicDispatcher::CleanUpSession(SessionMap::iterator it, if (connection->termination_packets() != nullptr && !connection->termination_packets()->empty()) { action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS; - } else if (connection->transport_version() > QUIC_VERSION_43) { + } else if (connection->transport_version() > QUIC_VERSION_43 || + GetQuicReloadableFlag(quic_terminate_gquic_connection_as_ietf)) { if (!connection->IsHandshakeConfirmed()) { - QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_handshake_failed); + if (connection->transport_version() <= QUIC_VERSION_43) { + QUIC_CODE_COUNT(gquic_add_to_time_wait_list_with_handshake_failed); + } else { + QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_handshake_failed); + } action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS; // This serializes a connection close termination packet with error code // QUIC_HANDSHAKE_FAILED and adds the connection to the time wait list. StatelesslyTerminateConnection( - connection->connection_id(), IETF_QUIC_LONG_HEADER_PACKET, - connection->version(), QUIC_HANDSHAKE_FAILED, + connection->connection_id(), + connection->transport_version() > QUIC_VERSION_43 + ? IETF_QUIC_LONG_HEADER_PACKET + : GOOGLE_QUIC_PACKET, + /*version_flag=*/true, connection->version(), QUIC_HANDSHAKE_FAILED, "Connection is closed by server before handshake confirmed", // Although it is our intention to send termination packets, the // |action| argument is not used by this call to @@ -695,13 +732,13 @@ void QuicDispatcher::Shutdown() { DeleteSessions(); } -void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id, +void QuicDispatcher::OnConnectionClosed(QuicConnectionId server_connection_id, QuicErrorCode error, const std::string& error_details, ConnectionCloseSource source) { - auto it = session_map_.find(connection_id); + auto it = session_map_.find(server_connection_id); if (it == session_map_.end()) { - QUIC_BUG << "ConnectionId " << connection_id + QUIC_BUG << "ConnectionId " << server_connection_id << " does not exist in the session map. Error: " << QuicErrorCodeToString(error); QUIC_BUG << QuicStackTrace(); @@ -709,7 +746,7 @@ void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id, } QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR) - << "Closing connection (" << connection_id + << "Closing connection (" << server_connection_id << ") due to error: " << QuicErrorCodeToString(error) << ", with details: " << error_details; @@ -748,53 +785,55 @@ void QuicDispatcher::OnRstStreamReceived(const QuicRstStreamFrame& frame) {} void QuicDispatcher::OnStopSendingReceived(const QuicStopSendingFrame& frame) {} void QuicDispatcher::OnConnectionAddedToTimeWaitList( - QuicConnectionId connection_id) { - QUIC_DLOG(INFO) << "Connection " << connection_id + QuicConnectionId server_connection_id) { + QUIC_DLOG(INFO) << "Connection " << server_connection_id << " added to time wait list."; } void QuicDispatcher::StatelesslyTerminateConnection( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, PacketHeaderFormat format, + bool version_flag, ParsedQuicVersion version, QuicErrorCode error_code, const std::string& error_details, QuicTimeWaitListManager::TimeWaitAction action) { - if (format != IETF_QUIC_LONG_HEADER_PACKET) { - QUIC_DVLOG(1) << "Statelessly terminating " << connection_id + if (format != IETF_QUIC_LONG_HEADER_PACKET && + (!GetQuicReloadableFlag(quic_terminate_gquic_connection_as_ietf) || + !version_flag)) { + QUIC_DVLOG(1) << "Statelessly terminating " << server_connection_id << " based on a non-ietf-long packet, action:" << action << ", error_code:" << error_code << ", error_details:" << error_details; time_wait_list_manager_->AddConnectionIdToTimeWait( - connection_id, format != GOOGLE_QUIC_PACKET, action, ENCRYPTION_INITIAL, - nullptr); + server_connection_id, format != GOOGLE_QUIC_PACKET, action, + ENCRYPTION_INITIAL, nullptr); return; } // If the version is known and supported by framer, send a connection close. - if (framer_.IsSupportedVersion(version)) { + if (IsSupportedVersion(version)) { QUIC_DVLOG(1) - << "Statelessly terminating " << connection_id + << "Statelessly terminating " << server_connection_id << " based on an ietf-long packet, which has a supported version:" << version << ", error_code:" << error_code << ", error_details:" << error_details; - // Set framer_ to the packet's version such that the connection close can be - // processed by the client. - ParsedQuicVersion original_version = framer_.version(); - framer_.set_version(version); - StatelessConnectionTerminator terminator( - connection_id, &framer_, helper_.get(), time_wait_list_manager_.get()); + StatelessConnectionTerminator terminator(server_connection_id, version, + helper_.get(), + time_wait_list_manager_.get()); // This also adds the connection to time wait list. - terminator.CloseConnection(error_code, error_details, true); - - // Restore framer_ to the original version, as if nothing changed in it. - framer_.set_version(original_version); + if (format == GOOGLE_QUIC_PACKET) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_terminate_gquic_connection_as_ietf, 1, + 2); + } + terminator.CloseConnection(error_code, error_details, + format != GOOGLE_QUIC_PACKET); return; } QUIC_DVLOG(1) - << "Statelessly terminating " << connection_id + << "Statelessly terminating " << server_connection_id << " based on an ietf-long packet, which has an unsupported version:" << version << ", error_code:" << error_code << ", error_details:" << error_details; @@ -802,10 +841,14 @@ void QuicDispatcher::StatelesslyTerminateConnection( // with an empty version list, which can be understood by the client. std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets; termination_packets.push_back(QuicFramer::BuildVersionNegotiationPacket( - connection_id, /*ietf_quic=*/true, + server_connection_id, EmptyQuicConnectionId(), + /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, ParsedQuicVersionVector{UnsupportedQuicVersion()})); + if (format == GOOGLE_QUIC_PACKET) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_terminate_gquic_connection_as_ietf, 2, 2); + } time_wait_list_manager()->AddConnectionIdToTimeWait( - connection_id, /*ietf_quic=*/true, + server_connection_id, /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, ENCRYPTION_INITIAL, &termination_packets); } @@ -826,9 +869,10 @@ bool QuicDispatcher::ShouldCreateSessionForUnknownVersion( bool QuicDispatcher::OnProtocolVersionMismatch( ParsedQuicVersion /*received_version*/, PacketHeaderFormat /*form*/) { + DCHECK(!no_framer_); QUIC_BUG_IF( !time_wait_list_manager_->IsConnectionIdInTimeWait( - current_connection_id_) && + current_server_connection_id_) && !ShouldCreateSessionForUnknownVersion(framer_.last_version_label())) << "Unexpected version mismatch: " << QuicVersionLabelToString(framer_.last_version_label()); @@ -848,6 +892,12 @@ void QuicDispatcher::OnVersionNegotiationPacket( DCHECK(false); } +void QuicDispatcher::OnRetryPacket(QuicConnectionId /*original_connection_id*/, + QuicConnectionId /*new_connection_id*/, + QuicStringPiece /*retry_token*/) { + DCHECK(false); +} + void QuicDispatcher::OnDecryptedPacket(EncryptionLevel level) { DCHECK(false); } @@ -920,12 +970,12 @@ bool QuicDispatcher::OnConnectionCloseFrame( return false; } -bool QuicDispatcher::OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) { +bool QuicDispatcher::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) { return true; } -bool QuicDispatcher::OnStreamIdBlockedFrame( - const QuicStreamIdBlockedFrame& frame) { +bool QuicDispatcher::OnStreamsBlockedFrame( + const QuicStreamsBlockedFrame& frame) { return true; } @@ -999,15 +1049,15 @@ void QuicDispatcher::OnAuthenticatedIetfStatelessResetPacket( } void QuicDispatcher::OnExpiredPackets( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, BufferedPacketList early_arrived_packets) { QUIC_CODE_COUNT(quic_reject_buffered_packets_expired); StatelesslyTerminateConnection( - connection_id, + server_connection_id, early_arrived_packets.ietf_quic ? IETF_QUIC_LONG_HEADER_PACKET : GOOGLE_QUIC_PACKET, - early_arrived_packets.version, QUIC_HANDSHAKE_FAILED, - "Packets buffered for too long", + /*version_flag=*/true, early_arrived_packets.version, + QUIC_HANDSHAKE_FAILED, "Packets buffered for too long", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); } @@ -1016,24 +1066,26 @@ void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) { new_sessions_allowed_per_event_loop_ = max_connections_to_create; for (; new_sessions_allowed_per_event_loop_ > 0; --new_sessions_allowed_per_event_loop_) { - QuicConnectionId connection_id; + QuicConnectionId server_connection_id; BufferedPacketList packet_list = - buffered_packets_.DeliverPacketsForNextConnection(&connection_id); + buffered_packets_.DeliverPacketsForNextConnection( + &server_connection_id); const std::list<BufferedPacket>& packets = packet_list.buffered_packets; if (packets.empty()) { return; } - QuicConnectionId original_connection_id = connection_id; - connection_id = - MaybeReplaceConnectionId(connection_id, packet_list.version); + QuicConnectionId original_connection_id = server_connection_id; + server_connection_id = MaybeReplaceServerConnectionId(server_connection_id, + packet_list.version); QuicSession* session = - CreateQuicSession(connection_id, packets.front().peer_address, + CreateQuicSession(server_connection_id, packets.front().peer_address, packet_list.alpn, packet_list.version); - if (original_connection_id != connection_id) { + if (original_connection_id != server_connection_id) { session->connection()->AddIncomingConnectionId(original_connection_id); } - QUIC_DLOG(INFO) << "Created new session for " << connection_id; - session_map_.insert(std::make_pair(connection_id, QuicWrapUnique(session))); + QUIC_DLOG(INFO) << "Created new session for " << server_connection_id; + session_map_.insert( + std::make_pair(server_connection_id, QuicWrapUnique(session))); DeliverPacketsToSession(packets, session); } } @@ -1043,25 +1095,23 @@ bool QuicDispatcher::HasChlosBuffered() const { } bool QuicDispatcher::ShouldCreateOrBufferPacketForConnection( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, bool ietf_quic) { - VLOG(1) << "Received packet from new connection " << connection_id; + QUIC_VLOG(1) << "Received packet from new connection " + << server_connection_id; return true; } // Return true if there is any packet buffered in the store. -bool QuicDispatcher::HasBufferedPackets(QuicConnectionId connection_id) { - return buffered_packets_.HasBufferedPackets(connection_id); +bool QuicDispatcher::HasBufferedPackets(QuicConnectionId server_connection_id) { + return buffered_packets_.HasBufferedPackets(server_connection_id); } -void QuicDispatcher::OnBufferPacketFailure(EnqueuePacketResult result, - QuicConnectionId connection_id) { - QUIC_DLOG(INFO) << "Fail to buffer packet on connection " << connection_id - << " because of " << result; -} - -bool QuicDispatcher::ShouldAttemptCheapStatelessRejection() { - return true; +void QuicDispatcher::OnBufferPacketFailure( + EnqueuePacketResult result, + QuicConnectionId server_connection_id) { + QUIC_DLOG(INFO) << "Fail to buffer packet on connection " + << server_connection_id << " because of " << result; } QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() { @@ -1069,21 +1119,22 @@ QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() { alarm_factory_.get()); } -void QuicDispatcher::BufferEarlyPacket(QuicConnectionId connection_id, +void QuicDispatcher::BufferEarlyPacket(QuicConnectionId server_connection_id, bool ietf_quic, ParsedQuicVersion version) { - bool is_new_connection = !buffered_packets_.HasBufferedPackets(connection_id); - if (is_new_connection && - !ShouldCreateOrBufferPacketForConnection(connection_id, ietf_quic)) { + bool is_new_connection = + !buffered_packets_.HasBufferedPackets(server_connection_id); + if (is_new_connection && !ShouldCreateOrBufferPacketForConnection( + server_connection_id, ietf_quic)) { return; } EnqueuePacketResult rs = buffered_packets_.EnqueuePacket( - connection_id, ietf_quic, *current_packet_, current_self_address_, + server_connection_id, ietf_quic, *current_packet_, current_self_address_, current_peer_address_, /*is_chlo=*/false, /*alpn=*/"", version); if (rs != EnqueuePacketResult::SUCCESS) { - OnBufferPacketFailure(rs, connection_id); + OnBufferPacketFailure(rs, server_connection_id); } } @@ -1093,49 +1144,52 @@ void QuicDispatcher::ProcessChlo(PacketHeaderFormat form, // Don't any create new connection. QUIC_CODE_COUNT(quic_reject_stop_accepting_new_connections); StatelesslyTerminateConnection( - current_connection_id(), form, version, QUIC_HANDSHAKE_FAILED, - "Stop accepting new connections", + current_server_connection_id(), form, /*version_flag=*/true, version, + QUIC_HANDSHAKE_FAILED, "Stop accepting new connections", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); // Time wait list will reject the packet correspondingly. time_wait_list_manager()->ProcessPacket( - current_self_address(), current_peer_address(), current_connection_id(), - form, GetPerPacketContext()); + current_self_address(), current_peer_address(), + current_server_connection_id(), form, GetPerPacketContext()); return; } - if (!buffered_packets_.HasBufferedPackets(current_connection_id_) && - !ShouldCreateOrBufferPacketForConnection(current_connection_id_, + if (!buffered_packets_.HasBufferedPackets(current_server_connection_id_) && + !ShouldCreateOrBufferPacketForConnection(current_server_connection_id_, form != GOOGLE_QUIC_PACKET)) { return; } if (FLAGS_quic_allow_chlo_buffering && new_sessions_allowed_per_event_loop_ <= 0) { // Can't create new session any more. Wait till next event loop. - QUIC_BUG_IF(buffered_packets_.HasChloForConnection(current_connection_id_)); + QUIC_BUG_IF( + buffered_packets_.HasChloForConnection(current_server_connection_id_)); EnqueuePacketResult rs = buffered_packets_.EnqueuePacket( - current_connection_id_, form != GOOGLE_QUIC_PACKET, *current_packet_, - current_self_address_, current_peer_address_, - /*is_chlo=*/true, current_alpn_, framer_.version()); + current_server_connection_id_, form != GOOGLE_QUIC_PACKET, + *current_packet_, current_self_address_, current_peer_address_, + /*is_chlo=*/true, current_alpn_, version); if (rs != EnqueuePacketResult::SUCCESS) { - OnBufferPacketFailure(rs, current_connection_id_); + OnBufferPacketFailure(rs, current_server_connection_id_); } return; } - QuicConnectionId original_connection_id = current_connection_id_; - current_connection_id_ = - MaybeReplaceConnectionId(current_connection_id_, framer_.version()); + QuicConnectionId original_connection_id = current_server_connection_id_; + current_server_connection_id_ = + MaybeReplaceServerConnectionId(current_server_connection_id_, version); // Creates a new session and process all buffered packets for this connection. QuicSession* session = - CreateQuicSession(current_connection_id_, current_peer_address_, - current_alpn_, framer_.version()); - if (original_connection_id != current_connection_id_) { + CreateQuicSession(current_server_connection_id_, current_peer_address_, + current_alpn_, version); + if (original_connection_id != current_server_connection_id_) { session->connection()->AddIncomingConnectionId(original_connection_id); } - QUIC_DLOG(INFO) << "Created new session for " << current_connection_id_; + QUIC_DLOG(INFO) << "Created new session for " + << current_server_connection_id_; session_map_.insert( - std::make_pair(current_connection_id_, QuicWrapUnique(session))); + std::make_pair(current_server_connection_id_, QuicWrapUnique(session))); std::list<BufferedPacket> packets = - buffered_packets_.DeliverPackets(current_connection_id_).buffered_packets; + buffered_packets_.DeliverPackets(current_server_connection_id_) + .buffered_packets; // Process CHLO at first. session->ProcessUdpPacket(current_self_address_, current_peer_address_, *current_packet_); @@ -1163,221 +1217,31 @@ bool QuicDispatcher::OnUnauthenticatedUnknownPublicHeader( return true; } -class StatelessRejectorProcessDoneCallback - : public StatelessRejector::ProcessDoneCallback { - public: - StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher, - ParsedQuicVersion first_version, - PacketHeaderFormat form) - : dispatcher_(dispatcher), - current_client_address_(dispatcher->current_client_address_), - current_peer_address_(dispatcher->current_peer_address_), - current_self_address_(dispatcher->current_self_address_), - additional_context_(dispatcher->GetPerPacketContext()), - current_packet_( - dispatcher->current_packet_->Clone()), // Note: copies the packet - first_version_(first_version), - current_packet_format_(form) {} - - void Run(std::unique_ptr<StatelessRejector> rejector) override { - if (additional_context_ != nullptr) { - dispatcher_->RestorePerPacketContext(std::move(additional_context_)); - } - dispatcher_->OnStatelessRejectorProcessDone( - std::move(rejector), current_client_address_, current_peer_address_, - current_self_address_, std::move(current_packet_), first_version_, - current_packet_format_); - } - - private: - QuicDispatcher* dispatcher_; - QuicSocketAddress current_client_address_; - QuicSocketAddress current_peer_address_; - QuicSocketAddress current_self_address_; - // TODO(wub): Wrap all current_* variables into PerPacketContext. And rename - // |additional_context_| to |context_|. - std::unique_ptr<QuicPerPacketContext> additional_context_; - std::unique_ptr<QuicReceivedPacket> current_packet_; - ParsedQuicVersion first_version_; - const PacketHeaderFormat current_packet_format_; -}; - -void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id, - - PacketHeaderFormat form, - ParsedQuicVersion version) { +void QuicDispatcher::ProcessOrBufferPacket( + QuicConnectionId server_connection_id, + PacketHeaderFormat form, + bool version_flag, + ParsedQuicVersion version) { if (version.handshake_protocol == PROTOCOL_TLS1_3) { - ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id, form, - version); + ProcessUnauthenticatedHeaderFate(kFateProcess, server_connection_id, form, + version_flag, version); return; // TODO(nharper): Support buffering non-ClientHello packets when using TLS. } - // TODO(rch): This logic should probably live completely inside the rejector. - if (!FLAGS_quic_allow_chlo_buffering || - !GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) || - !GetQuicReloadableFlag(enable_quic_stateless_reject_support) || - !ShouldAttemptCheapStatelessRejection()) { - // Not use cheap stateless reject. - ChloAlpnExtractor alpn_extractor; - if (FLAGS_quic_allow_chlo_buffering && - !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), - config_->create_session_tag_indicators(), - &alpn_extractor, connection_id.length())) { - // Buffer non-CHLO packets. - ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form, - version); - return; - } - current_alpn_ = alpn_extractor.ConsumeAlpn(); - ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id, form, - version); - return; - } - std::unique_ptr<StatelessRejector> rejector(new StatelessRejector( - version, GetSupportedVersions(), crypto_config_, &compressed_certs_cache_, - helper()->GetClock(), helper()->GetRandomGenerator(), - current_packet_->length(), current_client_address_, - current_self_address_)); - ChloValidator validator(session_helper_.get(), current_client_address_, - current_peer_address_, current_self_address_, - rejector.get()); - if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), + ChloAlpnExtractor alpn_extractor; + if (FLAGS_quic_allow_chlo_buffering && + !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), config_->create_session_tag_indicators(), - &validator, connection_id.length())) { - ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form, version); - return; - } - current_alpn_ = validator.ConsumeAlpn(); - - if (!validator.can_accept()) { - // This CHLO is prohibited by policy. - QUIC_CODE_COUNT(quic_reject_cant_accept_chlo); - StatelessConnectionTerminator terminator(connection_id, &framer_, helper(), - time_wait_list_manager_.get()); - terminator.CloseConnection(QUIC_HANDSHAKE_FAILED, validator.error_details(), - form != GOOGLE_QUIC_PACKET); - QuicSession::RecordConnectionCloseAtServer( - QUIC_HANDSHAKE_FAILED, ConnectionCloseSource::FROM_SELF); - ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, form, - version); + &alpn_extractor, server_connection_id.length())) { + // Buffer non-CHLO packets. + ProcessUnauthenticatedHeaderFate(kFateBuffer, server_connection_id, form, + version_flag, version); return; } - - // If we were able to make a decision about this CHLO based purely on the - // information available in OnChlo, just invoke the done callback immediately. - if (rejector->state() != StatelessRejector::UNKNOWN) { - ProcessStatelessRejectorState(std::move(rejector), - version.transport_version, form); - return; - } - - // Insert into set of connection IDs to buffer - const bool ok = - temporarily_buffered_connections_.insert(connection_id).second; - QUIC_BUG_IF(!ok) - << "Processing multiple stateless rejections for connection ID " - << connection_id; - - // Continue stateless rejector processing - std::unique_ptr<StatelessRejectorProcessDoneCallback> cb( - new StatelessRejectorProcessDoneCallback(this, version, form)); - StatelessRejector::Process(std::move(rejector), std::move(cb)); -} - -void QuicDispatcher::OnStatelessRejectorProcessDone( - std::unique_ptr<StatelessRejector> rejector, - const QuicSocketAddress& current_client_address, - const QuicSocketAddress& current_peer_address, - const QuicSocketAddress& current_self_address, - std::unique_ptr<QuicReceivedPacket> current_packet, - ParsedQuicVersion first_version, - PacketHeaderFormat current_packet_format) { - // Reset current_* to correspond to the packet which initiated the stateless - // reject logic. - current_client_address_ = current_client_address; - current_peer_address_ = current_peer_address; - current_self_address_ = current_self_address; - current_packet_ = current_packet.get(); - current_connection_id_ = rejector->connection_id(); - framer_.set_version(first_version); - - // Stop buffering packets on this connection - const auto num_erased = - temporarily_buffered_connections_.erase(rejector->connection_id()); - QUIC_BUG_IF(num_erased != 1) << "Completing stateless rejection logic for " - "non-buffered connection ID " - << rejector->connection_id(); - - // If this connection has gone into time-wait during the async processing, - // don't proceed. - if (time_wait_list_manager_->IsConnectionIdInTimeWait( - rejector->connection_id())) { - time_wait_list_manager_->ProcessPacket( - current_self_address, current_peer_address, rejector->connection_id(), - current_packet_format, GetPerPacketContext()); - return; - } - - ProcessStatelessRejectorState(std::move(rejector), - first_version.transport_version, - current_packet_format); -} - -void QuicDispatcher::ProcessStatelessRejectorState( - std::unique_ptr<StatelessRejector> rejector, - QuicTransportVersion first_version, - PacketHeaderFormat form) { - QuicPacketFate fate; - switch (rejector->state()) { - case StatelessRejector::FAILED: { - // There was an error processing the client hello. - QUIC_CODE_COUNT(quic_reject_error_processing_chlo); - StatelessConnectionTerminator terminator(rejector->connection_id(), - &framer_, helper(), - time_wait_list_manager_.get()); - terminator.CloseConnection(rejector->error(), rejector->error_details(), - form != GOOGLE_QUIC_PACKET); - fate = kFateTimeWait; - break; - } - - case StatelessRejector::UNSUPPORTED: - // Cheap stateless rejects are not supported so process the packet. - fate = kFateProcess; - break; - - case StatelessRejector::ACCEPTED: - // Contains a valid CHLO, so process the packet and create a connection. - fate = kFateProcess; - break; - - case StatelessRejector::REJECTED: { - QUIC_BUG_IF(first_version != framer_.transport_version()) - << "SREJ: Client's version: " << QuicVersionToString(first_version) - << " is different from current dispatcher framer's version: " - << QuicVersionToString(framer_.transport_version()); - StatelessConnectionTerminator terminator(rejector->connection_id(), - &framer_, helper(), - time_wait_list_manager_.get()); - terminator.RejectConnection( - rejector->reply().GetSerialized().AsStringPiece(), - form != GOOGLE_QUIC_PACKET); - QuicSession::RecordConnectionCloseAtServer( - QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, - ConnectionCloseSource::FROM_SELF); - OnConnectionRejectedStatelessly(); - fate = kFateTimeWait; - break; - } - - default: - QUIC_BUG << "Rejector has invalid state " << rejector->state(); - fate = kFateDrop; - break; - } - ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(), form, - rejector->version()); + current_alpn_ = alpn_extractor.ConsumeAlpn(); + ProcessUnauthenticatedHeaderFate(kFateProcess, server_connection_id, form, + version_flag, version); } const QuicTransportVersionVector& @@ -1399,7 +1263,22 @@ void QuicDispatcher::DeliverPacketsToSession( } void QuicDispatcher::DisableFlagValidation() { - framer_.set_validate_flags(false); + if (!no_framer_) { + framer_.set_validate_flags(false); + } +} + +bool QuicDispatcher::IsSupportedVersion(const ParsedQuicVersion version) { + if (!no_framer_) { + return framer_.IsSupportedVersion(version); + } + for (const ParsedQuicVersion& supported_version : + version_manager_->GetSupportedVersions()) { + if (version == supported_version) { + return true; + } + } + return false; } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h index a6d7e37ca21..790d4d2b8ad 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h @@ -23,7 +23,6 @@ #include "net/third_party/quiche/src/quic/core/quic_session.h" #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h" #include "net/third_party/quiche/src/quic/core/quic_version_manager.h" -#include "net/third_party/quiche/src/quic/core/stateless_rejector.h" #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" @@ -49,7 +48,7 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, std::unique_ptr<QuicConnectionHelperInterface> helper, std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, std::unique_ptr<QuicAlarmFactory> alarm_factory, - uint8_t expected_connection_id_length); + uint8_t expected_server_connection_id_length); QuicDispatcher(const QuicDispatcher&) = delete; QuicDispatcher& operator=(const QuicDispatcher&) = delete; @@ -76,7 +75,7 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // QuicSession::Visitor interface implementation (via inheritance of // QuicTimeWaitListManager::Visitor): // Ensure that the closed connection is cleaned up asynchronously. - void OnConnectionClosed(QuicConnectionId connection_id, + void OnConnectionClosed(QuicConnectionId server_connection_id, QuicErrorCode error, const std::string& error_details, ConnectionCloseSource source) override; @@ -99,7 +98,8 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // QuicTimeWaitListManager::Visitor interface implementation // Called whenever the time wait list manager adds a new connection to the // time-wait list. - void OnConnectionAddedToTimeWaitList(QuicConnectionId connection_id) override; + void OnConnectionAddedToTimeWaitList( + QuicConnectionId server_connection_id) override; using SessionMap = QuicUnorderedMap<QuicConnectionId, std::unique_ptr<QuicSession>, @@ -131,11 +131,15 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // QuicFramerVisitorInterface implementation. Not expected to be called // outside of this class. + // TODO(fayang): Make QuicDispatcher no longer implement + // QuicFramerVisitorInterface when deprecating + // quic_no_framer_object_in_dispatcher. void OnPacket() override; - // Called when the public header has been parsed. + // Called when the public header has been parsed. Returns false when just the + // public header is enough to dispatch the packet; true if the framer needs to + // continue parsing the packet. bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override; - // Called when the private header has been parsed of a data packet that is - // destined for the time wait manager. + // Called when the private header has been parsed. bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; void OnError(QuicFramer* framer) override; bool OnProtocolVersionMismatch(ParsedQuicVersion received_version, @@ -149,6 +153,9 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, void OnPublicResetPacket(const QuicPublicResetPacket& packet) override; void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override; + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override; void OnDecryptedPacket(EncryptionLevel level) override; bool OnPacketHeader(const QuicPacketHeader& header) override; void OnCoalescedPacket(const QuicEncryptedPacket& packet) override; @@ -169,8 +176,8 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override; bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override; bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override; - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override; - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override; + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override; + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override; bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; bool OnBlockedFrame(const QuicBlockedFrame& frame) override; bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override; @@ -184,7 +191,7 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, const QuicIetfStatelessResetPacket& packet) override; // QuicBufferedPacketStore::VisitorInterface implementation. - void OnExpiredPackets(QuicConnectionId connection_id, + void OnExpiredPackets(QuicConnectionId server_connection_id, QuicBufferedPacketStore::BufferedPacketList early_arrived_packets) override; @@ -195,17 +202,11 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, virtual bool HasChlosBuffered() const; protected: - virtual QuicSession* CreateQuicSession(QuicConnectionId connection_id, + virtual QuicSession* CreateQuicSession(QuicConnectionId server_connection_id, const QuicSocketAddress& peer_address, QuicStringPiece alpn, const ParsedQuicVersion& version) = 0; - // Called when a connection is rejected statelessly. - virtual void OnConnectionRejectedStatelessly() {} - - // Returns true if cheap stateless rejection should be attempted. - virtual bool ShouldAttemptCheapStatelessRejection(); - // Values to be returned by ValidityChecks() to indicate what should be done // with a packet. Fates with greater values are considered to be higher // priority, in that if one validity check indicates a lower-valued fate and @@ -231,9 +232,9 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // will be owned by the dispatcher as time_wait_list_manager_ virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager(); - // Called when |connection_id| doesn't have an open connection yet, to buffer - // |current_packet_| until it can be delivered to the connection. - void BufferEarlyPacket(QuicConnectionId connection_id, + // Called when |server_connection_id| doesn't have an open connection yet, + // to buffer |current_packet_| until it can be delivered to the connection. + void BufferEarlyPacket(QuicConnectionId server_connection_id, bool ietf_quic, ParsedQuicVersion version); @@ -262,8 +263,8 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, const ParsedQuicVersionVector& GetSupportedVersions(); - QuicConnectionId current_connection_id() const { - return current_connection_id_; + QuicConnectionId current_server_connection_id() const { + return current_server_connection_id_; } const QuicSocketAddress& current_self_address() const { return current_self_address_; @@ -312,15 +313,15 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // for CHLO. Returns true if a new connection should be created or its packets // should be buffered, false otherwise. virtual bool ShouldCreateOrBufferPacketForConnection( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, bool ietf_quic); - bool HasBufferedPackets(QuicConnectionId connection_id); + bool HasBufferedPackets(QuicConnectionId server_connection_id); // Called when BufferEarlyPacket() fail to buffer the packet. virtual void OnBufferPacketFailure( QuicBufferedPacketStore::EnqueuePacketResult result, - QuicConnectionId connection_id); + QuicConnectionId server_connection_id); // Removes the session from the session map and write blocked list, and adds // the ConnectionId to the time-wait list. If |session_closed_statelessly| is @@ -337,8 +338,9 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // connection to time wait list or 2) directly add connection to time wait // list with |action|. void StatelesslyTerminateConnection( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, PacketHeaderFormat format, + bool version_flag, ParsedQuicVersion version, QuicErrorCode error_code, const std::string& error_details, @@ -354,33 +356,42 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // If true, our framer will change its expected connection ID length // to the received destination connection ID length of all IETF long headers. - void SetShouldUpdateExpectedConnectionIdLength( - bool should_update_expected_connection_id_length) { - framer_.SetShouldUpdateExpectedConnectionIdLength( - should_update_expected_connection_id_length); + void SetShouldUpdateExpectedServerConnectionIdLength( + bool should_update_expected_server_connection_id_length) { + if (!no_framer_) { + framer_.SetShouldUpdateExpectedServerConnectionIdLength( + should_update_expected_server_connection_id_length); + return; + } + should_update_expected_server_connection_id_length_ = + should_update_expected_server_connection_id_length; } // If true, the dispatcher will allow incoming initial packets that have - // connection IDs shorter than 64 bits. - void SetAllowShortInitialConnectionIds( - bool allow_short_initial_connection_ids) { - allow_short_initial_connection_ids_ = allow_short_initial_connection_ids; + // destination connection IDs shorter than 64 bits. + void SetAllowShortInitialServerConnectionIds( + bool allow_short_initial_server_connection_ids) { + allow_short_initial_server_connection_ids_ = + allow_short_initial_server_connection_ids; } private: friend class test::QuicDispatcherPeer; - friend class StatelessRejectorProcessDoneCallback; typedef QuicUnorderedSet<QuicConnectionId, QuicConnectionIdHash> QuicConnectionIdSet; - // Attempts to reject the connection statelessly, if stateless rejects are - // possible and if the current packet contains a CHLO message. Determines a - // fate which describes what subsequent processing should be performed on the - // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate. - void MaybeRejectStatelessly(QuicConnectionId connection_id, - PacketHeaderFormat form, - ParsedQuicVersion version); + // Based on an unauthenticated packet header |header|, calls ValidityChecks + // and then ProcessUnauthenticatedHeaderFate. + void ProcessHeader(const QuicPacketHeader& header); + + // TODO(wub): Move the body to ProcessHeader, then remove this function. + // Determine whether the current packet needs to be processed now or buffered + // for later processing, then invokes ProcessUnauthenticatedHeaderFate. + void ProcessOrBufferPacket(QuicConnectionId server_connection_id, + PacketHeaderFormat form, + bool version_flag, + ParsedQuicVersion version); // Deliver |packets| to |session| for further processing. void DeliverPacketsToSession( @@ -390,37 +401,20 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // Perform the appropriate actions on the current packet based on |fate| - // either process, buffer, or drop it. void ProcessUnauthenticatedHeaderFate(QuicPacketFate fate, - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, PacketHeaderFormat form, + bool version_flag, ParsedQuicVersion version); - // Invoked when StatelessRejector::Process completes. |first_version| is the - // version of the packet which initiated the stateless reject. - // WARNING: This function can be called when a async proof returns, i.e. not - // from a stack traceable to ProcessPacket(). - // TODO(fayang): maybe consider not using callback when there is no crypto - // involved. - void OnStatelessRejectorProcessDone( - std::unique_ptr<StatelessRejector> rejector, - const QuicSocketAddress& current_client_address, - const QuicSocketAddress& current_peer_address, - const QuicSocketAddress& current_self_address, - std::unique_ptr<QuicReceivedPacket> current_packet, - ParsedQuicVersion first_version, - PacketHeaderFormat current_packet_format); - - // Examine the state of the rejector and decide what to do with the current - // packet. - void ProcessStatelessRejectorState( - std::unique_ptr<StatelessRejector> rejector, - QuicTransportVersion first_version, - PacketHeaderFormat form); - // If the connection ID length is different from what the dispatcher expects, // replace the connection ID with a random one of the right length, // and save it to make sure the mapping is persistent. - QuicConnectionId MaybeReplaceConnectionId(QuicConnectionId connection_id, - ParsedQuicVersion version); + QuicConnectionId MaybeReplaceServerConnectionId( + QuicConnectionId server_connection_id, + ParsedQuicVersion version); + + // Returns true if |version| is a supported protocol version. + bool IsSupportedVersion(const ParsedQuicVersion version); void set_new_sessions_allowed_per_event_loop( int16_t new_sessions_allowed_per_event_loop) { @@ -481,7 +475,7 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, const QuicReceivedPacket* current_packet_; // If |current_packet_| is a CHLO packet, the extracted alpn. std::string current_alpn_; - QuicConnectionId current_connection_id_; + QuicConnectionId current_server_connection_id_; // Used to get the supported versions based on flag. Does not own. QuicVersionManager* version_manager_; @@ -500,8 +494,32 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, bool accept_new_connections_; // If false, the dispatcher follows the IETF spec and rejects packets with - // invalid connection IDs lengths below 64 bits. If true they are allowed. - bool allow_short_initial_connection_ids_; + // invalid destination connection IDs lengths below 64 bits. + // If true they are allowed. + bool allow_short_initial_server_connection_ids_; + + // The last QUIC version label received. Used when no_framer_ is true. + // TODO(fayang): remove this member variable, instead, add an argument to + // OnUnauthenticatedPublicHeader when deprecating + // quic_no_framer_object_in_dispatcher. + QuicVersionLabel last_version_label_; + + // IETF short headers contain a destination connection ID but do not + // encode its length. This variable contains the length we expect to read. + // This is also used to signal an error when a long header packet with + // different destination connection ID length is received when + // should_update_expected_server_connection_id_length_ is false and packet's + // version does not allow variable length connection ID. Used when no_framer_ + // is true. + uint8_t expected_server_connection_id_length_; + + // If true, change expected_server_connection_id_length_ to be the received + // destination connection ID length of all IETF long headers. Used when + // no_framer_ is true. + bool should_update_expected_server_connection_id_length_; + + // Latched value of quic_no_framer_object_in_dispatcher. + const bool no_framer_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc index 1e646af3445..105bd0028d6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc @@ -19,7 +19,6 @@ #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/stateless_rejector.h" #include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" @@ -86,10 +85,8 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase { QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, QuicCompressedCertsCache* compressed_certs_cache) override { - return new QuicCryptoServerStream( - crypto_config, compressed_certs_cache, - GetQuicReloadableFlag(enable_quic_stateless_reject_support), this, - stream_helper()); + return new QuicCryptoServerStream(crypto_config, compressed_certs_cache, + this, stream_helper()); } void SetCryptoStream(QuicCryptoServerStream* crypto_stream) { @@ -158,7 +155,7 @@ class TestDispatcher : public QuicDispatcher { using QuicDispatcher::current_client_address; using QuicDispatcher::current_peer_address; using QuicDispatcher::current_self_address; - using QuicDispatcher::SetAllowShortInitialConnectionIds; + using QuicDispatcher::SetAllowShortInitialServerConnectionIds; using QuicDispatcher::writer; }; @@ -195,7 +192,7 @@ class QuicDispatcherTest : public QuicTest { : QuicDispatcherTest(crypto_test_utils::ProofSourceForTesting()) {} ParsedQuicVersionVector AllSupportedVersionsIncludingTls() { - SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); return AllSupportedVersions(); } @@ -380,7 +377,7 @@ TEST_F(QuicDispatcherTest, TlsClientHelloCreatesSession) { // TLS is only supported in versions 47 and greater. return; } - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); EXPECT_CALL(*dispatcher_, @@ -495,7 +492,7 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) { EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _)) + SendVersionNegotiationPacket(_, _, _, _, _, _, _)) .Times(1); QuicTransportVersion version = static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1); @@ -514,7 +511,7 @@ TEST_F(QuicDispatcherTest, NoVersionNegotiationWithSmallPacket) { EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _)) + SendVersionNegotiationPacket(_, _, _, _, _, _, _)) .Times(0); QuicTransportVersion version = static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1); @@ -540,7 +537,7 @@ TEST_F(QuicDispatcherTest, VersionNegotiationWithoutChloSizeValidation) { EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _)) + SendVersionNegotiationPacket(_, _, _, _, _, _, _)) .Times(1); QuicTransportVersion version = static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1); @@ -688,7 +685,7 @@ TEST_F(QuicDispatcherTest, InvalidShortConnectionIdLengthReplaced) { QuicUtils::CreateRandomConnectionId(mock_helper_.GetRandomGenerator()); // Disable validation of invalid short connection IDs. - dispatcher_->SetAllowShortInitialConnectionIds(true); + dispatcher_->SetAllowShortInitialServerConnectionIds(true); // Note that StrayPacketTruncatedConnectionId covers the case where the // validation is still enabled. @@ -815,6 +812,12 @@ TEST_F(QuicDispatcherTest, OKSeqNoPacketProcessed) { } TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) { + if (CurrentSupportedVersions().front().HasHeaderProtection() || + GetQuicRestartFlag(quic_no_framer_object_in_dispatcher)) { + // When header protection is in use, we don't put packets in the time wait + // list manager based on packet number. + return; + } CreateTimeWaitListManager(); SetQuicRestartFlag(quic_enable_accept_random_ipn, false); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); @@ -850,7 +853,6 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); SetQuicReloadableFlag(quic_enable_version_46, true); SetQuicReloadableFlag(quic_enable_version_47, true); @@ -1005,39 +1007,6 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { SerializeCHLO(), CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1); - // Turn off version 43. - SetQuicReloadableFlag(quic_enable_version_43, false); - connection_id = TestConnectionId(++conn_id); - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"), _)) - .Times(0); - ProcessPacket(client_address, connection_id, true, - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - - // Turn on version 43. - SetQuicReloadableFlag(quic_enable_version_43, true); - connection_id = TestConnectionId(++conn_id); - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"), _)) - .WillOnce(testing::Return(CreateSession( - dispatcher_.get(), config_, connection_id, client_address, - &mock_helper_, &mock_alarm_factory_, &crypto_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id, _)); - ProcessPacket(client_address, connection_id, true, - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - // Turn off version 39. SetQuicReloadableFlag(quic_disable_version_39, true); connection_id = TestConnectionId(++conn_id); @@ -1079,12 +1048,10 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { QuicCompressedCertsCache* compressed_certs_cache, QuicServerSessionBase* session, QuicCryptoServerStream::Helper* helper) - : QuicCryptoServerStream( - &crypto_config, - compressed_certs_cache, - GetQuicReloadableFlag(enable_quic_stateless_reject_support), - session, - helper), + : QuicCryptoServerStream(&crypto_config, + compressed_certs_cache, + session, + helper), handshake_confirmed_(false) {} MockQuicCryptoServerStream(const MockQuicCryptoServerStream&) = delete; MockQuicCryptoServerStream& operator=(const MockQuicCryptoServerStream&) = @@ -1100,262 +1067,6 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { bool handshake_confirmed_; }; -struct StatelessRejectTestParams { - StatelessRejectTestParams(bool enable_stateless_rejects_via_flag, - bool client_supports_statelesss_rejects, - bool crypto_handshake_successful) - : enable_stateless_rejects_via_flag(enable_stateless_rejects_via_flag), - client_supports_statelesss_rejects(client_supports_statelesss_rejects), - crypto_handshake_successful(crypto_handshake_successful) {} - - friend std::ostream& operator<<(std::ostream& os, - const StatelessRejectTestParams& p) { - os << "{ enable_stateless_rejects_via_flag: " - << p.enable_stateless_rejects_via_flag << std::endl; - os << " client_supports_statelesss_rejects: " - << p.client_supports_statelesss_rejects << std::endl; - os << " crypto_handshake_successful: " << p.crypto_handshake_successful - << " }"; - return os; - } - - // This only enables the stateless reject feature via the feature-flag. - // This should be a no-op if the peer does not support them. - bool enable_stateless_rejects_via_flag; - // Whether or not the client supports stateless rejects. - bool client_supports_statelesss_rejects; - // Should the initial crypto handshake succeed or not. - bool crypto_handshake_successful; -}; - -// Constructs various test permutations for stateless rejects. -std::vector<StatelessRejectTestParams> GetStatelessRejectTestParams() { - std::vector<StatelessRejectTestParams> params; - for (bool enable_stateless_rejects_via_flag : {true, false}) { - for (bool client_supports_statelesss_rejects : {true, false}) { - for (bool crypto_handshake_successful : {true, false}) { - params.push_back(StatelessRejectTestParams( - enable_stateless_rejects_via_flag, - client_supports_statelesss_rejects, crypto_handshake_successful)); - } - } - } - return params; -} - -class QuicDispatcherStatelessRejectTest - : public QuicDispatcherTest, - public testing::WithParamInterface<StatelessRejectTestParams> { - public: - QuicDispatcherStatelessRejectTest() - : QuicDispatcherTest(), crypto_stream1_(nullptr) {} - - ~QuicDispatcherStatelessRejectTest() override { - if (crypto_stream1_) { - delete crypto_stream1_; - } - } - - // This test setup assumes that all testing will be done using - // crypto_stream1_. - void SetUp() override { - QuicDispatcherTest::SetUp(); - SetQuicReloadableFlag(enable_quic_stateless_reject_support, - GetParam().enable_stateless_rejects_via_flag); - } - - // Returns true or false, depending on whether the server will emit - // a stateless reject, depending upon the parameters of the test. - bool ExpectStatelessReject() { - return GetParam().enable_stateless_rejects_via_flag && - !GetParam().crypto_handshake_successful && - GetParam().client_supports_statelesss_rejects; - } - - // Sets up dispatcher_, session1_, and crypto_stream1_ based on - // the test parameters. - QuicServerSessionBase* CreateSessionBasedOnTestParams( - QuicConnectionId connection_id, - const QuicSocketAddress& client_address) { - CreateSession(dispatcher_.get(), config_, connection_id, client_address, - &mock_helper_, &mock_alarm_factory_, &crypto_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_); - - crypto_stream1_ = new MockQuicCryptoServerStream( - crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), - session1_, session1_->stream_helper()); - session1_->SetCryptoStream(crypto_stream1_); - crypto_stream1_->set_handshake_confirmed_for_testing( - GetParam().crypto_handshake_successful); - crypto_stream1_->SetPeerSupportsStatelessRejects( - GetParam().client_supports_statelesss_rejects); - return session1_; - } - - MockQuicCryptoServerStream* crypto_stream1_; -}; - -// Parameterized test for stateless rejects. Should test all -// combinations of enabling/disabling, reject/no-reject for stateless -// rejects. -INSTANTIATE_TEST_SUITE_P(QuicDispatcherStatelessRejectTests, - QuicDispatcherStatelessRejectTest, - ::testing::ValuesIn(GetStatelessRejectTestParams())); - -TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) { - CreateTimeWaitListManager(); - - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - QuicConnectionId connection_id = TestConnectionId(1); - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"), _)) - .WillOnce(testing::Return( - CreateSessionBasedOnTestParams(connection_id, client_address))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id, _)) - .Times(1); - - // Process the first packet for the connection. - ProcessPacket(client_address, connection_id, true, SerializeCHLO()); - if (ExpectStatelessReject()) { - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - // If this is a stateless reject, the crypto stream will close the - // connection. - session1_->connection()->CloseConnection( - QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject", - ConnectionCloseBehavior::SILENT_CLOSE); - } - - // Send a second packet and check the results. If this is a stateless reject, - // the existing connection_id will go on the time-wait list. - EXPECT_EQ(ExpectStatelessReject(), - time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); - if (ExpectStatelessReject()) { - // The second packet will be processed on the time-wait list. - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) - .Times(1); - } else { - // The second packet will trigger a packet-validation - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .Times(1) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - } - ProcessPacket(client_address, connection_id, true, "data"); -} - -TEST_P(QuicDispatcherStatelessRejectTest, CheapRejects) { - SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); - CreateTimeWaitListManager(); - - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - QuicConnectionId connection_id = TestConnectionId(1); - if (GetParam().enable_stateless_rejects_via_flag) { - EXPECT_CALL(*dispatcher_, - CreateQuicSession(connection_id, client_address, _, _)) - .Times(0); - } else { - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("h2"), _)) - .WillOnce(testing::Return( - CreateSessionBasedOnTestParams(connection_id, client_address))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - } - - QUIC_LOG(INFO) << "ExpectStatelessReject: " << ExpectStatelessReject(); - QUIC_LOG(INFO) << "Params: " << GetParam(); - // Process the first packet for the connection. - CryptoHandshakeMessage client_hello = - crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, - {"KEXS", "C255"}, - {"COPT", "SREJ"}, - {"NONC", "1234567890123456789012"}, - {"ALPN", "h2"}, - {"VER\0", "Q025"}}, - kClientHelloMinimumSize); - - if (GetParam().enable_stateless_rejects_via_flag) { - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) - .Times(1); - } else { - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id, _)) - .Times(1); - } - ProcessPacket(client_address, connection_id, true, - std::string(client_hello.GetSerialized().AsStringPiece())); - - if (GetParam().enable_stateless_rejects_via_flag) { - EXPECT_EQ(true, - time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); - } -} - -TEST_P(QuicDispatcherStatelessRejectTest, BufferNonChlo) { - SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); - CreateTimeWaitListManager(); - - const QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - const QuicConnectionId connection_id = TestConnectionId(1); - - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id, _)) - .Times(1); - ProcessPacket(client_address, connection_id, true, "NOT DATA FOR A CHLO"); - - // Process the first packet for the connection. - CryptoHandshakeMessage client_hello = - crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, - {"KEXS", "C255"}, - {"NONC", "1234567890123456789012"}, - {"ALPN", "h3"}, - {"VER\0", "Q025"}}, - kClientHelloMinimumSize); - - // If stateless rejects are enabled then a connection will be created now - // and the buffered packet will be processed - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("h3"), _)) - .WillOnce(testing::Return( - CreateSessionBasedOnTestParams(connection_id, client_address))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, client_address, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - // Expect both packets to be passed to ProcessUdpPacket(). And one of them - // is already expected in CreateSessionBasedOnTestParams(). - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, client_address, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))) - .RetiresOnSaturation(); - ProcessPacket(client_address, connection_id, true, - std::string(client_hello.GetSerialized().AsStringPiece())); - EXPECT_FALSE( - time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); -} - // Verify the stopgap test: Packets with truncated connection IDs should be // dropped. class QuicDispatcherTestStrayPacketConnectionId : public QuicDispatcherTest {}; @@ -1689,56 +1400,14 @@ TEST_F(QuicDispatcherWriteBlockedListTest, MarkSession1Deleted(); } -// Tests that bufferring packets works in stateful reject, expensive stateless -// reject and cheap stateless reject. -struct BufferedPacketStoreTestParams { - BufferedPacketStoreTestParams(bool enable_stateless_rejects_via_flag, - bool support_cheap_stateless_reject) - : enable_stateless_rejects_via_flag(enable_stateless_rejects_via_flag), - support_cheap_stateless_reject(support_cheap_stateless_reject) {} - - friend std::ostream& operator<<(std::ostream& os, - const BufferedPacketStoreTestParams& p) { - os << "{ enable_stateless_rejects_via_flag: " - << p.enable_stateless_rejects_via_flag << std::endl; - os << " support_cheap_stateless_reject: " - << p.support_cheap_stateless_reject << " }"; - return os; - } - - // This only enables the stateless reject feature via the feature-flag. - // This should be a no-op if the peer does not support them. - bool enable_stateless_rejects_via_flag; - // Whether to do cheap stateless or not. - bool support_cheap_stateless_reject; -}; - -std::vector<BufferedPacketStoreTestParams> GetBufferedPacketStoreTestParams() { - std::vector<BufferedPacketStoreTestParams> params; - for (bool enable_stateless_rejects_via_flag : {true, false}) { - for (bool support_cheap_stateless_reject : {true, false}) { - params.push_back(BufferedPacketStoreTestParams( - enable_stateless_rejects_via_flag, support_cheap_stateless_reject)); - } - } - return params; -} - // A dispatcher whose stateless rejector will always ACCEPTs CHLO. -class BufferedPacketStoreTest - : public QuicDispatcherTest, - public testing::WithParamInterface<BufferedPacketStoreTestParams> { +class BufferedPacketStoreTest : public QuicDispatcherTest { public: BufferedPacketStoreTest() : QuicDispatcherTest(), server_addr_(QuicSocketAddress(QuicIpAddress::Any4(), 5)), client_addr_(QuicIpAddress::Loopback4(), 1234), - signed_config_(new QuicSignedServerConfig) { - SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, - GetParam().support_cheap_stateless_reject); - SetQuicReloadableFlag(enable_quic_stateless_reject_support, - GetParam().enable_stateless_rejects_via_flag); - } + signed_config_(new QuicSignedServerConfig) {} void SetUp() override { QuicDispatcherTest::SetUp(); @@ -1748,7 +1417,6 @@ class BufferedPacketStoreTest CryptoHandshakeMessage chlo = crypto_test_utils::GenerateDefaultInchoateCHLO(clock_, version, &crypto_config_); - chlo.SetVector(kCOPT, QuicTagVector{kSREJ}); // Pass an inchoate CHLO. crypto_test_utils::GenerateFullCHLO( chlo, &crypto_config_, server_addr_, client_addr_, version, clock_, @@ -1768,12 +1436,7 @@ class BufferedPacketStoreTest CryptoHandshakeMessage full_chlo_; }; -INSTANTIATE_TEST_SUITE_P( - BufferedPacketStoreTests, - BufferedPacketStoreTest, - ::testing::ValuesIn(GetBufferedPacketStoreTestParams())); - -TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) { +TEST_F(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) { InSequence s; QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); QuicConnectionId conn_id = TestConnectionId(1); @@ -1812,7 +1475,7 @@ TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) { ProcessPacket(client_address, conn_id, true, SerializeFullCHLO()); } -TEST_P(BufferedPacketStoreTest, +TEST_F(BufferedPacketStoreTest, ProcessNonChloPacketsForDifferentConnectionsUptoLimit) { InSequence s; // A bunch of non-CHLO should be buffered upon arrival. @@ -1866,7 +1529,7 @@ TEST_P(BufferedPacketStoreTest, } // Tests that store delivers empty packet list if CHLO arrives firstly. -TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) { +TEST_F(BufferedPacketStoreTest, DeliverEmptyPackets) { QuicConnectionId conn_id = TestConnectionId(1); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); EXPECT_CALL(*dispatcher_, @@ -1884,7 +1547,7 @@ TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) { // Tests that a retransmitted CHLO arrives after a connection for the // CHLO has been created. -TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) { +TEST_F(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) { InSequence s; QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); QuicConnectionId conn_id = TestConnectionId(1); @@ -1914,7 +1577,7 @@ TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) { } // Tests that expiration of a connection add connection id to time wait list. -TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) { +TEST_F(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) { InSequence s; CreateTimeWaitListManager(); QuicBufferedPacketStore* store = @@ -1940,7 +1603,7 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) { ProcessPacket(client_address, conn_id, true, SerializeFullCHLO()); } -TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) { +TEST_F(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) { // Process more than (|kMaxNumSessionsToCreate| + // |kDefaultMaxConnectionsInStore|) CHLOs, // the first |kMaxNumSessionsToCreate| should create connections immediately, @@ -2017,7 +1680,7 @@ TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) { } // Duplicated CHLO shouldn't be buffered. -TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) { +TEST_F(BufferedPacketStoreTest, BufferDuplicatedCHLO) { for (uint64_t conn_id = 1; conn_id <= kMaxNumSessionsToCreate + 1; ++conn_id) { // Last CHLO will be buffered. Others will create connection right away. @@ -2066,7 +1729,7 @@ TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) { dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate); } -TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) { +TEST_F(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) { uint64_t last_conn_id = kMaxNumSessionsToCreate + 1; QuicConnectionId last_connection_id = TestConnectionId(last_conn_id); for (uint64_t conn_id = 1; conn_id <= last_conn_id; ++conn_id) { @@ -2120,7 +1783,7 @@ TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) { // Tests that when dispatcher's packet buffer is full, a CHLO on connection // which doesn't have buffered CHLO should be buffered. -TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) { +TEST_F(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) { QuicBufferedPacketStore* store = QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); @@ -2165,7 +1828,7 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) { } // Regression test for b/117874922. -TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) { +TEST_F(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) { // Turn off version 99, such that the preferred version is not supported by // the server. SetQuicReloadableFlag(quic_enable_version_99, false); @@ -2219,667 +1882,6 @@ TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) { dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate); } -// Test which exercises the async GetProof codepaths, especially in the context -// of stateless rejection. -class AsyncGetProofTest : public QuicDispatcherTest { - public: - AsyncGetProofTest() - : QuicDispatcherTest( - std::unique_ptr<FakeProofSource>(new FakeProofSource())), - client_addr_(QuicIpAddress::Loopback4(), 1234), - client_addr_2_(QuicIpAddress::Loopback4(), 1357), - crypto_config_peer_(&crypto_config_), - server_addr_(QuicIpAddress::Any4(), 5), - signed_config_(new QuicSignedServerConfig) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); - } - - void SetUp() override { - QuicDispatcherTest::SetUp(); - - clock_ = QuicDispatcherPeer::GetHelper(dispatcher_.get())->GetClock(); - QuicTransportVersion version = AllSupportedTransportVersions().front(); - chlo_ = crypto_test_utils::GenerateDefaultInchoateCHLO(clock_, version, - &crypto_config_); - chlo_.SetVector(kCOPT, QuicTagVector{kSREJ}); - chlo_.SetStringPiece(kALPN, "HTTP/1"); - // Pass an inchoate CHLO. - crypto_test_utils::GenerateFullCHLO( - chlo_, &crypto_config_, server_addr_, client_addr_, version, clock_, - signed_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), - &full_chlo_); - - crypto_test_utils::GenerateFullCHLO( - chlo_, &crypto_config_, server_addr_, client_addr_2_, version, clock_, - signed_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), - &full_chlo_2_); - - GetFakeProofSource()->Activate(); - } - - FakeProofSource* GetFakeProofSource() const { - return static_cast<FakeProofSource*>(crypto_config_peer_.GetProofSource()); - } - - std::string SerializeFullCHLO() { - return std::string(full_chlo_.GetSerialized().AsStringPiece()); - } - - std::string SerializeFullCHLOForClient2() { - return std::string(full_chlo_2_.GetSerialized().AsStringPiece()); - } - - std::string SerializeCHLO() { - return std::string(chlo_.GetSerialized().AsStringPiece()); - } - - // Sets up a session, and crypto stream based on the test parameters. - QuicServerSessionBase* GetSession(QuicConnectionId connection_id, - QuicSocketAddress client_address) { - auto it = sessions_.find(connection_id); - if (it != sessions_.end()) { - return it->second.session; - } - - TestQuicSpdyServerSession* session; - CreateSession(dispatcher_.get(), config_, connection_id, client_address, - &mock_helper_, &mock_alarm_factory_, &crypto_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &session); - - std::unique_ptr<MockQuicCryptoServerStream> crypto_stream( - new MockQuicCryptoServerStream( - crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), - session, session->stream_helper())); - session->SetCryptoStream(crypto_stream.get()); - crypto_stream->SetPeerSupportsStatelessRejects(true); - const bool ok = - sessions_ - .insert(std::make_pair( - connection_id, SessionInfo{session, std::move(crypto_stream)})) - .second; - CHECK(ok); - return session; - } - - protected: - const QuicSocketAddress client_addr_; - const QuicSocketAddress client_addr_2_; - CryptoHandshakeMessage chlo_; - - private: - QuicCryptoServerConfigPeer crypto_config_peer_; - QuicSocketAddress server_addr_; - QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_; - const QuicClock* clock_; - CryptoHandshakeMessage full_chlo_; // CHLO for client_addr_ - CryptoHandshakeMessage full_chlo_2_; // CHLO for client_addr_2_ - - struct SessionInfo { - TestQuicSpdyServerSession* session; - std::unique_ptr<MockQuicCryptoServerStream> crypto_stream; - }; - std::map<QuicConnectionId, SessionInfo> sessions_; -}; - -// Test a simple situation of connections which the StatelessRejector will -// accept. -TEST_F(AsyncGetProofTest, BasicAccept) { - QuicConnectionId conn_id = TestConnectionId(1); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id, _)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id, packet); - }))); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id, packet); - }))); - } - - // Send a CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - check.Call(1); - // Complete the ProofSource::GetProof call and verify that a session is - // created. - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - - check.Call(2); - // Verify that a data packet gets processed immediately. - ProcessPacket(client_addr_, conn_id, true, "My name is Data"); -} - -TEST_F(AsyncGetProofTest, RestorePacketContext) { - QuicConnectionId conn_id_1 = TestConnectionId(1); - QuicConnectionId conn_id_2 = TestConnectionId(2); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_1, _)); - - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_1, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id_1, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_1, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillRepeatedly(WithArg<2>( - Invoke([this, conn_id_1](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_1, packet); - }))); - - EXPECT_CALL(check, Call(2)); - - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_2, _)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_2_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id_2, client_addr_2_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_2, client_addr_2_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id_2](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_2, packet); - }))); - } - - // Send a CHLO that the StatelessRejector will accept. - dispatcher_->custom_packet_context_ = "connection 1"; - ProcessPacket(client_addr_, conn_id_1, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Send another CHLO that the StatelessRejector will accept. - dispatcher_->custom_packet_context_ = "connection 2"; - ProcessPacket(client_addr_2_, conn_id_2, true, SerializeFullCHLOForClient2()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the first ProofSource::GetProof call and verify that a session is - // created. - check.Call(1); - - EXPECT_EQ(client_addr_2_, dispatcher_->current_client_address()); - EXPECT_EQ(client_addr_2_, dispatcher_->current_peer_address()); - EXPECT_EQ("connection 2", dispatcher_->custom_packet_context_); - - // Runs the async proof callback for conn_id_1 from client_addr_. - GetFakeProofSource()->InvokePendingCallback(0); - - EXPECT_EQ(client_addr_, dispatcher_->current_client_address()); - EXPECT_EQ(client_addr_, dispatcher_->current_peer_address()); - EXPECT_EQ("connection 1", dispatcher_->custom_packet_context_); - - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Complete the second ProofSource::GetProof call and verify that a session is - // created. - check.Call(2); - - EXPECT_EQ(client_addr_, dispatcher_->current_client_address()); - EXPECT_EQ(client_addr_, dispatcher_->current_peer_address()); - EXPECT_EQ("connection 1", dispatcher_->custom_packet_context_); - - // Runs the async proof callback for conn_id_2 from client_addr_2_. - GetFakeProofSource()->InvokePendingCallback(0); - - EXPECT_EQ(client_addr_2_, dispatcher_->current_client_address()); - EXPECT_EQ(client_addr_2_, dispatcher_->current_peer_address()); - EXPECT_EQ("connection 2", dispatcher_->custom_packet_context_); - - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); -} - -// Test a simple situation of connections which the StatelessRejector will -// reject. -TEST_F(AsyncGetProofTest, BasicReject) { - CreateTimeWaitListManager(); - - QuicConnectionId conn_id = TestConnectionId(1); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(conn_id, _, _, _, _)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id, _, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_, - QuicStringPiece("hq"), _)) - .Times(0); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id, _, _)); - } - - // Send a CHLO that the StatelessRejector will reject. - ProcessPacket(client_addr_, conn_id, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Complete the ProofSource::GetProof call and verify that the connection and - // packet are processed by the time wait list manager. - check.Call(1); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - - // Verify that a data packet is passed to the time wait list manager. - check.Call(2); - ProcessPacket(client_addr_, conn_id, true, "My name is Data"); -} - -// Test a situation with multiple interleaved connections which the -// StatelessRejector will accept. -TEST_F(AsyncGetProofTest, MultipleAccept) { - QuicConnectionId conn_id_1 = TestConnectionId(1); - QuicConnectionId conn_id_2 = TestConnectionId(2); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_2, _)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id_2, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_2, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id_2](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_2, packet); - }))); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_2, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id_2](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_2, packet); - }))); - - EXPECT_CALL(check, Call(3)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_1, _)); - - EXPECT_CALL(check, Call(4)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_1, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id_1, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_1, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillRepeatedly(WithArg<2>( - Invoke([this, conn_id_1](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_1, packet); - }))); - } - - // Send a CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id_1, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Send another CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id_2, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the second ProofSource::GetProof call and verify that a session is - // created. - check.Call(1); - GetFakeProofSource()->InvokePendingCallback(1); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Verify that a data packet on that connection gets processed immediately. - check.Call(2); - ProcessPacket(client_addr_, conn_id_2, true, "My name is Data"); - - // Verify that a data packet on the other connection does not get processed - // yet. - check.Call(3); - ProcessPacket(client_addr_, conn_id_1, true, "My name is Data"); - EXPECT_TRUE(store->HasBufferedPackets(conn_id_1)); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_2)); - - // Complete the first ProofSource::GetProof call and verify that a session is - // created and the buffered packet is processed. - check.Call(4); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); -} - -// Test a situation with multiple interleaved connections which the -// StatelessRejector will reject. -TEST_F(AsyncGetProofTest, MultipleReject) { - CreateTimeWaitListManager(); - - QuicConnectionId conn_id_1 = TestConnectionId(1); - QuicConnectionId conn_id_2 = TestConnectionId(2); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_, _, _)) - .Times(0); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(conn_id_2, _, _, _, _)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_2, _, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_2, _, _)); - - EXPECT_CALL(check, Call(3)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_1, _)); - - EXPECT_CALL(check, Call(4)); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(conn_id_1, _, _, _, _)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_1, _, _)); - } - - // Send a CHLO that the StatelessRejector will reject. - ProcessPacket(client_addr_, conn_id_1, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Send another CHLO that the StatelessRejector will reject. - ProcessPacket(client_addr_, conn_id_2, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the second ProofSource::GetProof call and verify that the - // connection and packet are processed by the time wait manager. - check.Call(1); - GetFakeProofSource()->InvokePendingCallback(1); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Verify that a data packet on that connection gets processed immediately by - // the time wait manager. - check.Call(2); - ProcessPacket(client_addr_, conn_id_2, true, "My name is Data"); - - // Verify that a data packet on the first connection gets buffered. - check.Call(3); - ProcessPacket(client_addr_, conn_id_1, true, "My name is Data"); - EXPECT_TRUE(store->HasBufferedPackets(conn_id_1)); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_2)); - - // Complete the first ProofSource::GetProof call and verify that the CHLO is - // processed by the time wait manager and the remaining packets are discarded. - check.Call(4); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_1)); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_2)); -} - -// Test a situation with multiple identical CHLOs which the StatelessRejector -// will reject. -TEST_F(AsyncGetProofTest, MultipleIdenticalReject) { - CreateTimeWaitListManager(); - - QuicConnectionId conn_id_1 = TestConnectionId(1); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_1, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_1, client_addr_, - QuicStringPiece(), _)) - .Times(0); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(conn_id_1, _, _, _, _)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_1, _, _)); - } - - // Send a CHLO that the StatelessRejector will reject. - ProcessPacket(client_addr_, conn_id_1, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_1)); - - // Send an identical CHLO which should get buffered. - check.Call(1); - ProcessPacket(client_addr_, conn_id_1, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - EXPECT_TRUE(store->HasBufferedPackets(conn_id_1)); - - // Complete the ProofSource::GetProof call and verify that the CHLO is - // rejected and the copy is discarded. - check.Call(2); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_1)); -} - -// Test dispatcher behavior when packets time out of the buffer while CHLO -// validation is still pending. -TEST_F(AsyncGetProofTest, BufferTimeout) { - CreateTimeWaitListManager(); - - QuicConnectionId conn_id = TestConnectionId(1); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id, _, _)); - EXPECT_CALL(*dispatcher_, - CreateQuicSession(conn_id, client_addr_, QuicStringPiece(), _)) - .Times(0); - } - - // Send a CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - - // Send a data packet that will get buffered - check.Call(1); - ProcessPacket(client_addr_, conn_id, true, "My name is Data"); - EXPECT_TRUE(store->HasBufferedPackets(conn_id)); - - // Pretend that enough time has gone by for the packets to get expired out of - // the buffer - mock_helper_.AdvanceTime( - QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)); - QuicBufferedPacketStorePeer::expiration_alarm(store)->Cancel(); - store->OnExpirationTimeout(); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); - - // Now allow the CHLO validation to complete, and verify that no connection - // gets created. - check.Call(2); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); -} - -// Test behavior when packets time out of the buffer *and* the connection times -// out of the time wait manager while CHLO validation is still pending. This -// *should* be impossible, but anything can happen with timing conditions. -TEST_F(AsyncGetProofTest, TimeWaitTimeout) { - QuicConnectionId conn_id = TestConnectionId(1); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock()); - CreateTimeWaitListManager(); - QuicTimeWaitListManagerPeer::set_clock(time_wait_list_manager_, - mock_helper_.GetClock()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id, _)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id, packet); - }))); - } - - // Send a CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - - // Send a data packet that will get buffered - check.Call(1); - ProcessPacket(client_addr_, conn_id, true, "My name is Data"); - EXPECT_TRUE(store->HasBufferedPackets(conn_id)); - - // Pretend that enough time has gone by for the packets to get expired out of - // the buffer - mock_helper_.AdvanceTime( - QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)); - QuicBufferedPacketStorePeer::expiration_alarm(store)->Cancel(); - store->OnExpirationTimeout(); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); - - // Pretend that enough time has gone by for the connection ID to be removed - // from the time wait manager - mock_helper_.AdvanceTime( - QuicTimeWaitListManagerPeer::time_wait_period(time_wait_list_manager_)); - QuicTimeWaitListManagerPeer::expiration_alarm(time_wait_list_manager_) - ->Cancel(); - time_wait_list_manager_->CleanUpOldConnectionIds(); - EXPECT_FALSE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); - - // Now allow the CHLO validation to complete. Expect that a connection is - // indeed created, since QUIC has forgotten that this connection ever existed. - // This is a miniscule corner case which should never happen in the wild, so - // really we are just verifying that the dispatcher does not explode in this - // situation. - check.Call(2); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - EXPECT_FALSE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); -} - -// Regression test for -// https://bugs.chromium.org/p/chromium/issues/detail?id=748289 -TEST_F(AsyncGetProofTest, DispatcherFailedToPickUpVersionForAsyncProof) { - // This test mimics the scenario that dispatcher's framer can have different - // version when async proof returns. - // When dispatcher sends SREJ, the SREJ frame can be serialized in - // different endianness which causes the client to close the connection - // because of QUIC_INVALID_STREAM_DATA. - - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_43, true); - ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43); - chlo_.SetVersion(kVER, chlo_version); - // Send a CHLO with v43. Dispatcher framer's version is set to v43. - ProcessPacket(client_addr_, TestConnectionId(1), true, chlo_version, - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - - // Send another CHLO with v39. Dispatcher framer's version is set to v39. - chlo_version.transport_version = QUIC_VERSION_39; - chlo_.SetVersion(kVER, chlo_version); - // Invalidate the cached serialized form. - chlo_.MarkDirty(); - ProcessPacket(client_addr_, TestConnectionId(2), true, chlo_version, - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the ProofSource::GetProof call for v43. This would cause the - // version mismatch between the CHLO packet and the dispatcher. - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); -} - -// Regression test for b/116200989. -TEST_F(AsyncGetProofTest, DispatcherHasWrongLastPacketIsIetfQuic) { - // Process a packet of v44. - ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44); - chlo_.SetVersion(kVER, chlo_version); - ProcessPacket(client_addr_, TestConnectionId(1), true, chlo_version, - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - - // Process another packet of v43. - chlo_version.transport_version = QUIC_VERSION_43; - chlo_.SetVersion(kVER, chlo_version); - // Invalidate the cached serialized form. - chlo_.MarkDirty(); - ProcessPacket(client_addr_, TestConnectionId(2), true, chlo_version, - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the ProofSource::GetProof call for v44. - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Complete the ProofSource::GetProof call for v43. - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); -} - } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc index e2a14ade998..86c0896f22e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc @@ -138,8 +138,8 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_INVALID_MAX_DATA_FRAME_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_BLOCKED_DATA); - RETURN_STRING_LITERAL(QUIC_MAX_STREAM_ID_DATA); - RETURN_STRING_LITERAL(QUIC_STREAM_ID_BLOCKED_DATA); + RETURN_STRING_LITERAL(QUIC_MAX_STREAMS_DATA); + RETURN_STRING_LITERAL(QUIC_STREAMS_BLOCKED_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_NEW_CONNECTION_ID_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_RETIRE_CONNECTION_ID_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_STOP_SENDING_FRAME_DATA); @@ -151,8 +151,8 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_INVALID_NEW_TOKEN); RETURN_STRING_LITERAL(QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM); RETURN_STRING_LITERAL(QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM); - RETURN_STRING_LITERAL(QUIC_STREAM_ID_BLOCKED_ERROR); - RETURN_STRING_LITERAL(QUIC_MAX_STREAM_ID_ERROR); + RETURN_STRING_LITERAL(QUIC_STREAMS_BLOCKED_ERROR); + RETURN_STRING_LITERAL(QUIC_MAX_STREAMS_ERROR); RETURN_STRING_LITERAL(QUIC_HTTP_DECODER_ERROR); RETURN_STRING_LITERAL(QUIC_STALE_CONNECTION_CANCELLED); RETURN_STRING_LITERAL(QUIC_IETF_GQUIC_ERROR_MISSING); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h index b06cc7f57d3..c8259f723c3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h @@ -290,10 +290,10 @@ enum QuicErrorCode { QUIC_INVALID_MAX_DATA_FRAME_DATA = 102, // Received a MAX STREAM DATA frame with errors. QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA = 103, - // Received a MAX_STREAM_ID frame with bad data - QUIC_MAX_STREAM_ID_DATA = 104, - // Received a STREAM_ID_BLOCKED frame with bad data - QUIC_STREAM_ID_BLOCKED_DATA = 105, + // Received a MAX_STREAMS frame with bad data + QUIC_MAX_STREAMS_DATA = 104, + // Received a STREAMS_BLOCKED frame with bad data + QUIC_STREAMS_BLOCKED_DATA = 105, // Error deframing a STREAM BLOCKED frame. QUIC_INVALID_STREAM_BLOCKED_DATA = 106, // NEW CONNECTION ID frame data is malformed. @@ -315,13 +315,11 @@ enum QuicErrorCode { // RETIRE CONNECTION ID frame data is malformed. QUIC_INVALID_RETIRE_CONNECTION_ID_DATA = 117, - // - // Error in a received STREAM ID BLOCKED frame. -- the stream ID is not - // consistent with the state of the endpoint. - QUIC_STREAM_ID_BLOCKED_ERROR = 118, - // Error in a received MAX STREAM ID frame -- the stream ID is not - // consistent with the state of the endpoint. - QUIC_MAX_STREAM_ID_ERROR = 119, + + // Error in a received STREAMS BLOCKED frame. + QUIC_STREAMS_BLOCKED_ERROR = 118, + // Error in a received MAX STREAMS frame + QUIC_MAX_STREAMS_ERROR = 119, // Error in Http decoder QUIC_HTTP_DECODER_ERROR = 120, // Connection from stale host needs to be cancelled. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc index 0c65dc226e4..7e34b3b6259 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc @@ -10,8 +10,10 @@ #include <string> #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" @@ -21,6 +23,7 @@ #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h" #include "net/third_party/quiche/src/quic/core/quic_stream_frame_data_producer.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" @@ -280,7 +283,7 @@ bool GetLongHeaderType(QuicTransportVersion version, break; default: QUIC_BUG << "Unreachable statement"; - *long_header_type = VERSION_NEGOTIATION; + *long_header_type = INVALID_PACKET_TYPE; return false; } return true; @@ -404,67 +407,10 @@ bool IsValidFullPacketNumber(uint64_t full_packet_number, return full_packet_number > 0 || version == QUIC_VERSION_99; } -// Convert a stream ID to a count of streams, for IETF QUIC/Version 99 only. -// There is no need to take into account whether the ID is for uni- or -// bi-directional streams, or whether it's server- or client- initiated. It -// always returns a valid count. -QuicStreamId StreamIdToCount(QuicTransportVersion version, - QuicStreamId stream_id) { - DCHECK_EQ(QUIC_VERSION_99, version); - if ((stream_id & 0x3) == 0) { - return (stream_id / QuicUtils::StreamIdDelta(version)); - } - return (stream_id / QuicUtils::StreamIdDelta(version)) + 1; -} - -// Returns the maximum value that a stream count may have, taking into account -// the fact that bidirectional, client initiated, streams have one fewer stream -// available than the others. This is because the old crypto streams, with ID == -// 0 are not included in the count. -// The version is not included in the call, nor does the method take the version -// into account, because this is called only from code used for IETF QUIC. -// TODO(fkastenholz): Remove this method and replace calls to it with direct -// references to kMaxQuicStreamIdCount when streamid 0 becomes a normal stream -// id. -QuicStreamId GetMaxStreamCount(bool unidirectional, Perspective perspective) { - if (!unidirectional && perspective == Perspective::IS_CLIENT) { - return kMaxQuicStreamId >> 2; - } - return (kMaxQuicStreamId >> 2) + 1; -} - -// Convert a stream count to the maximum stream ID for that count. -// Needs to know whether the resulting stream ID should be uni-directional, -// bi-directional, server-initiated, or client-initiated. -// Returns true if it works, false if not. The only error condition is that -// the stream_count is too big and it would generate a stream id that is larger -// than the implementation's maximum stream id value. -bool StreamCountToId(QuicStreamId stream_count, - bool unidirectional, - Perspective perspective, - QuicTransportVersion version, - QuicStreamId* generated_stream_id) { - DCHECK_EQ(QUIC_VERSION_99, version); - // TODO(fkastenholz): when the MAX_STREAMS and STREAMS_BLOCKED frames - // are connected all the way up to the stream_id_manager, handle count==0 - // properly (interpret it as "can open 0 streams") and the count being too - // large (close the connection). - if ((stream_count == 0) || - (stream_count > GetMaxStreamCount(unidirectional, perspective))) { - return false; - } - *generated_stream_id = - ((unidirectional) - ? QuicUtils::GetFirstUnidirectionalStreamId(version, perspective) - : QuicUtils::GetFirstBidirectionalStreamId(version, perspective)) + - ((stream_count - 1) * QuicUtils::StreamIdDelta(version)); - return true; -} - -bool AppendIetfConnectionIdsNew(bool version_flag, - QuicConnectionId destination_connection_id, - QuicConnectionId source_connection_id, - QuicDataWriter* writer) { +bool AppendIetfConnectionIds(bool version_flag, + QuicConnectionId destination_connection_id, + QuicConnectionId source_connection_id, + QuicDataWriter* writer) { if (!version_flag) { return writer->WriteConnectionId(destination_connection_id); } @@ -503,15 +449,20 @@ void RecordDroppedPacketReason(DroppedPacketReason reason) { "each time such a packet is dropped"); } +PacketHeaderFormat GetIetfPacketHeaderFormat(uint8_t type_byte) { + return type_byte & FLAGS_LONG_HEADER ? IETF_QUIC_LONG_HEADER_PACKET + : IETF_QUIC_SHORT_HEADER_PACKET; +} + } // namespace QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions, QuicTime creation_time, Perspective perspective, - uint8_t expected_connection_id_length) + uint8_t expected_server_connection_id_length) : visitor_(nullptr), error_(QUIC_NO_ERROR), - last_serialized_connection_id_(EmptyQuicConnectionId()), + last_serialized_server_connection_id_(EmptyQuicConnectionId()), last_version_label_(0), version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), supported_versions_(supported_versions), @@ -527,9 +478,11 @@ QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions, data_producer_(nullptr), infer_packet_header_type_from_version_(perspective == Perspective::IS_CLIENT), - expected_connection_id_length_(expected_connection_id_length), - should_update_expected_connection_id_length_(false), - supports_multiple_packet_number_spaces_(false) { + expected_server_connection_id_length_( + expected_server_connection_id_length), + should_update_expected_server_connection_id_length_(false), + supports_multiple_packet_number_spaces_(false), + last_written_packet_number_length_(0) { DCHECK(!supported_versions.empty()); version_ = supported_versions_[0]; decrypter_[ENCRYPTION_INITIAL] = QuicMakeUnique<NullDecrypter>(perspective); @@ -610,31 +563,31 @@ size_t QuicFramer::GetRstStreamFrameSize(QuicTransportVersion version, } // static -size_t QuicFramer::GetMinConnectionCloseFrameSize( +size_t QuicFramer::GetConnectionCloseFrameSize( QuicTransportVersion version, const QuicConnectionCloseFrame& frame) { - if (version == QUIC_VERSION_99) { - // TODO(fkastenholz): For complete support of IETF QUIC CONNECTION_CLOSE, - // check if the frame is a Transport close and if the frame's - // extracted_error_code is not QUIC_IETF_GQUIC_ERROR_MISSING. If so, - // extend the error string to include " QuicErrorCode: #" - if (frame.close_type == IETF_QUIC_APPLICATION_CONNECTION_CLOSE) { - // Application close variant does not include the transport close frame - // type field. - return QuicDataWriter::GetVarInt62Len( - TruncatedErrorStringSize(frame.error_details)) + - kQuicFrameTypeSize + kQuicIetfQuicErrorCodeSize; - } - QUIC_BUG_IF(frame.close_type != IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) - << "IETF QUIC Connection close and QuicConnectionCloseFrame type is " - "not IETF ConnectionClose"; - return QuicDataWriter::GetVarInt62Len( - TruncatedErrorStringSize(frame.error_details)) + - QuicDataWriter::GetVarInt62Len(frame.transport_close_frame_type) + - kQuicFrameTypeSize + kQuicIetfQuicErrorCodeSize; - } - // Not version 99/IETF QUIC, return Google QUIC CONNECTION CLOSE frame size. - return kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicErrorDetailsLengthSize; + if (version != QUIC_VERSION_99) { + // Not version 99/IETF QUIC, return Google QUIC CONNECTION CLOSE frame size. + return kQuicFrameTypeSize + kQuicErrorCodeSize + + kQuicErrorDetailsLengthSize + + TruncatedErrorStringSize(frame.error_details); + } + // TODO(fkastenholz): For complete support of IETF QUIC CONNECTION_CLOSE, + // check if the frame is a Transport close and if the frame's + // extracted_error_code is not QUIC_IETF_GQUIC_ERROR_MISSING. If so, + // extend the error string to include " QuicErrorCode: #" + const size_t truncated_error_string_size = + TruncatedErrorStringSize(frame.error_details); + const size_t frame_size = + truncated_error_string_size + + QuicDataWriter::GetVarInt62Len(truncated_error_string_size) + + kQuicFrameTypeSize + kQuicIetfQuicErrorCodeSize; + if (frame.close_type == IETF_QUIC_APPLICATION_CONNECTION_CLOSE) { + return frame_size; + } + // frame includes the transport_close_frame_type, so include its length. + return frame_size + + QuicDataWriter::GetVarInt62Len(frame.transport_close_frame_type); } // static @@ -664,31 +617,26 @@ size_t QuicFramer::GetWindowUpdateFrameSize( // static size_t QuicFramer::GetMaxStreamsFrameSize(QuicTransportVersion version, - const QuicMaxStreamIdFrame& frame) { + const QuicMaxStreamsFrame& frame) { if (version != QUIC_VERSION_99) { QUIC_BUG << "In version " << version - << " - not 99 - and tried to serialize MaxStreamId Frame."; + << " - not 99 - and tried to serialize MaxStreams Frame."; } - - // Convert from the stream id on which the connection is blocked to a count - QuicStreamId stream_count = StreamIdToCount(version, frame.max_stream_id); - - return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(stream_count); + return kQuicFrameTypeSize + + QuicDataWriter::GetVarInt62Len(frame.stream_count); } // static size_t QuicFramer::GetStreamsBlockedFrameSize( QuicTransportVersion version, - const QuicStreamIdBlockedFrame& frame) { + const QuicStreamsBlockedFrame& frame) { if (version != QUIC_VERSION_99) { QUIC_BUG << "In version " << version - << " - not 99 - and tried to serialize StreamIdBlocked Frame."; + << " - not 99 - and tried to serialize StreamsBlocked Frame."; } - // Convert from the stream id on which the connection is blocked to a count - QuicStreamId stream_count = StreamIdToCount(version, frame.stream_id); - - return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(stream_count); + return kQuicFrameTypeSize + + QuicDataWriter::GetVarInt62Len(frame.stream_count); } // static @@ -735,10 +683,8 @@ size_t QuicFramer::GetRetransmittableControlFrameSize( case RST_STREAM_FRAME: return GetRstStreamFrameSize(version, *frame.rst_stream_frame); case CONNECTION_CLOSE_FRAME: - return GetMinConnectionCloseFrameSize(version, - *frame.connection_close_frame) + - TruncatedErrorStringSize( - frame.connection_close_frame->error_details); + return GetConnectionCloseFrameSize(version, + *frame.connection_close_frame); case GOAWAY_FRAME: return GetMinGoAwayFrameSize() + TruncatedErrorStringSize(frame.goaway_frame->reason_phrase); @@ -755,10 +701,10 @@ size_t QuicFramer::GetRetransmittableControlFrameSize( return GetRetireConnectionIdFrameSize(*frame.retire_connection_id_frame); case NEW_TOKEN_FRAME: return GetNewTokenFrameSize(*frame.new_token_frame); - case MAX_STREAM_ID_FRAME: - return GetMaxStreamsFrameSize(version, frame.max_stream_id_frame); - case STREAM_ID_BLOCKED_FRAME: - return GetStreamsBlockedFrameSize(version, frame.stream_id_blocked_frame); + case MAX_STREAMS_FRAME: + return GetMaxStreamsFrameSize(version, frame.max_streams_frame); + case STREAMS_BLOCKED_FRAME: + return GetStreamsBlockedFrameSize(version, frame.streams_blocked_frame); case PATH_RESPONSE_FRAME: return GetPathResponseFrameSize(*frame.path_response_frame); case PATH_CHALLENGE_FRAME: @@ -1063,13 +1009,13 @@ size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header, set_detailed_error( "Attempt to append NEW_TOKEN_ID frame and not in version 99."); return RaiseError(QUIC_INTERNAL_ERROR); - case MAX_STREAM_ID_FRAME: + case MAX_STREAMS_FRAME: set_detailed_error( - "Attempt to append MAX_STREAM_ID frame and not in version 99."); + "Attempt to append MAX_STREAMS frame and not in version 99."); return RaiseError(QUIC_INTERNAL_ERROR); - case STREAM_ID_BLOCKED_FRAME: + case STREAMS_BLOCKED_FRAME: set_detailed_error( - "Attempt to append STREAM_ID_BLOCKED frame and not in version 99."); + "Attempt to append STREAMS_BLOCKED frame and not in version 99."); return RaiseError(QUIC_INTERNAL_ERROR); case PATH_RESPONSE_FRAME: set_detailed_error( @@ -1195,14 +1141,14 @@ size_t QuicFramer::AppendIetfFrames(const QuicFrames& frames, return 0; } break; - case MAX_STREAM_ID_FRAME: - if (!AppendMaxStreamsFrame(frame.max_stream_id_frame, writer)) { + case MAX_STREAMS_FRAME: + if (!AppendMaxStreamsFrame(frame.max_streams_frame, writer)) { QUIC_BUG << "AppendMaxStreamsFrame failed" << detailed_error(); return 0; } break; - case STREAM_ID_BLOCKED_FRAME: - if (!AppendStreamsBlockedFrame(frame.stream_id_blocked_frame, writer)) { + case STREAMS_BLOCKED_FRAME: + if (!AppendStreamsBlockedFrame(frame.streams_blocked_frame, writer)) { QUIC_BUG << "AppendStreamsBlockedFrame failed" << detailed_error(); return 0; } @@ -1442,14 +1388,20 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfStatelessResetPacket( // static std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, + QuicConnectionId client_connection_id, bool ietf_quic, const ParsedQuicVersionVector& versions) { if (ietf_quic) { - return BuildIetfVersionNegotiationPacket(connection_id, versions); + return BuildIetfVersionNegotiationPacket(server_connection_id, + client_connection_id, versions); } + + // The GQUIC encoding does not support encoding client connection IDs. + DCHECK(client_connection_id.IsEmpty()); + DCHECK(!versions.empty()); - size_t len = kPublicFlagsSize + connection_id.length() + + size_t len = kPublicFlagsSize + server_connection_id.length() + versions.size() * kQuicVersionSize; std::unique_ptr<char[]> buffer(new char[len]); // Endianness is not a concern here, version negotiation packet does not have @@ -1464,7 +1416,7 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket( return nullptr; } - if (!writer.WriteConnectionId(connection_id)) { + if (!writer.WriteConnectionId(server_connection_id)) { return nullptr; } @@ -1482,18 +1434,26 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket( // static std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfVersionNegotiationPacket( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, + QuicConnectionId client_connection_id, const ParsedQuicVersionVector& versions) { - QUIC_DVLOG(1) << "Building IETF version negotiation packet."; + QUIC_DVLOG(1) << "Building IETF version negotiation packet: " + << ParsedQuicVersionVectorToString(versions); + DCHECK(client_connection_id.IsEmpty() || + GetQuicRestartFlag(quic_do_not_override_connection_id)); DCHECK(!versions.empty()); size_t len = kPacketHeaderTypeSize + kConnectionIdLengthSize + - connection_id.length() + + client_connection_id.length() + server_connection_id.length() + (versions.size() + 1) * kQuicVersionSize; std::unique_ptr<char[]> buffer(new char[len]); QuicDataWriter writer(len, buffer.get()); // TODO(fayang): Randomly select a value for the type. - uint8_t type = static_cast<uint8_t>(FLAGS_LONG_HEADER | VERSION_NEGOTIATION); + uint8_t type = static_cast<uint8_t>(FLAGS_LONG_HEADER); + if (GetQuicReloadableFlag(quic_send_version_negotiation_fixed_bit)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_send_version_negotiation_fixed_bit); + type |= static_cast<uint8_t>(FLAGS_FIXED_BIT); + } if (!writer.WriteUInt8(type)) { return nullptr; } @@ -1502,18 +1462,9 @@ QuicFramer::BuildIetfVersionNegotiationPacket( return nullptr; } - if (!GetQuicReloadableFlag(quic_use_new_append_connection_id)) { - if (!AppendIetfConnectionId(true, EmptyQuicConnectionId(), - PACKET_0BYTE_CONNECTION_ID, connection_id, - PACKET_8BYTE_CONNECTION_ID, &writer)) { - return nullptr; - } - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_new_append_connection_id, 1, 2); - if (!AppendIetfConnectionIdsNew(true, EmptyQuicConnectionId(), - connection_id, &writer)) { - return nullptr; - } + if (!AppendIetfConnectionIds(true, client_connection_id, server_connection_id, + &writer)) { + return nullptr; } for (const ParsedQuicVersion& version : versions) { @@ -1559,18 +1510,42 @@ bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) { return true; } - if (perspective_ == Perspective::IS_SERVER && header.version_flag && - header.version != version_) { - if (!visitor_->OnProtocolVersionMismatch(header.version, header.form)) { - RecordDroppedPacketReason(DroppedPacketReason::VERSION_MISMATCH); - return true; + if (IsVersionNegotiation(header, packet_has_ietf_packet_header)) { + if (!GetQuicRestartFlag(quic_server_drop_version_negotiation)) { + QUIC_DVLOG(1) << ENDPOINT << "Received version negotiation packet"; + return ProcessVersionNegotiationPacket(&reader, header); + } + QUIC_RESTART_FLAG_COUNT_N(quic_server_drop_version_negotiation, 1, 2); + if (perspective_ == Perspective::IS_CLIENT) { + QUIC_DVLOG(1) << "Client received version negotiation packet"; + return ProcessVersionNegotiationPacket(&reader, header); + } else { + QUIC_DLOG(ERROR) << "Server received version negotiation packet"; + set_detailed_error("Server received version negotiation packet."); + return RaiseError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET); + } + } + + if (header.version_flag && header.version != version_) { + if (perspective_ == Perspective::IS_SERVER) { + if (!visitor_->OnProtocolVersionMismatch(header.version, header.form)) { + RecordDroppedPacketReason(DroppedPacketReason::VERSION_MISMATCH); + return true; + } + } else { + // A client received a packet of a different version but that packet is + // not a version negotiation packet. It is therefore invalid and dropped. + QUIC_DLOG(ERROR) << "Client received unexpected version " + << ParsedQuicVersionToString(header.version) + << " instead of " << ParsedQuicVersionToString(version_); + set_detailed_error("Client received unexpected version."); + return RaiseError(QUIC_INVALID_VERSION); } } bool rv; - if (IsVersionNegotiation(header, packet_has_ietf_packet_header)) { - QUIC_DVLOG(1) << ENDPOINT << "Received version negotiation packet"; - rv = ProcessVersionNegotiationPacket(&reader, header); + if (header.long_packet_type == RETRY) { + rv = ProcessRetryPacket(&reader, header); } else if (header.reset_flag) { rv = ProcessPublicResetPacket(&reader, header); } else if (packet.length() <= kMaxIncomingPacketSize) { @@ -1605,25 +1580,50 @@ bool QuicFramer::ProcessVersionNegotiationPacket( const QuicPacketHeader& header) { DCHECK_EQ(Perspective::IS_CLIENT, perspective_); - QuicVersionNegotiationPacket packet(header.destination_connection_id); + QuicVersionNegotiationPacket packet( + GetServerConnectionIdAsRecipient(header, perspective_)); // Try reading at least once to raise error if the packet is invalid. do { QuicVersionLabel version_label; - if (!reader->ReadTag(&version_label)) { + if (!ProcessVersionLabel(reader, &version_label)) { set_detailed_error("Unable to read supported version in negotiation."); RecordDroppedPacketReason( DroppedPacketReason::INVALID_VERSION_NEGOTIATION_PACKET); return RaiseError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET); } - // TODO(rch): Use ReadUInt32() once QUIC_VERSION_35 is removed. - version_label = QuicEndian::NetToHost32(version_label); packet.versions.push_back(ParseQuicVersionLabel(version_label)); } while (!reader->IsDoneReading()); + QUIC_DLOG(INFO) << ENDPOINT << "parsed version negotiation: " + << ParsedQuicVersionVectorToString(packet.versions); + visitor_->OnVersionNegotiationPacket(packet); return true; } +bool QuicFramer::ProcessRetryPacket(QuicDataReader* reader, + const QuicPacketHeader& header) { + DCHECK_EQ(Perspective::IS_CLIENT, perspective_); + + // Parse Original Destination Connection ID Length. + uint8_t odcil = header.type_byte & 0xf; + if (odcil != 0) { + odcil += kConnectionIdLengthAdjustment; + } + + // Parse Original Destination Connection ID. + QuicConnectionId original_destination_connection_id; + if (!reader->ReadConnectionId(&original_destination_connection_id, odcil)) { + set_detailed_error("Unable to read Original Destination ConnectionId."); + return false; + } + + QuicStringPiece retry_token = reader->ReadRemainingPayload(); + visitor_->OnRetryPacket(original_destination_connection_id, + header.source_connection_id, retry_token); + return true; +} + bool QuicFramer::MaybeProcessIetfInitialRetryToken( QuicDataReader* encrypted_reader, QuicPacketHeader* header) { @@ -1770,26 +1770,43 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader, return false; } + QuicStringPiece associated_data; + std::vector<char> ad_storage; if (header->form == IETF_QUIC_SHORT_HEADER_PACKET || header->long_packet_type != VERSION_NEGOTIATION) { + DCHECK(header->form == IETF_QUIC_SHORT_HEADER_PACKET || + header->long_packet_type == INITIAL || + header->long_packet_type == HANDSHAKE || + header->long_packet_type == ZERO_RTT_PROTECTED); // Process packet number. QuicPacketNumber base_packet_number; if (supports_multiple_packet_number_spaces_) { - base_packet_number = - largest_decrypted_packet_numbers_[GetPacketNumberSpace(*header)]; + PacketNumberSpace pn_space = GetPacketNumberSpace(*header); + if (pn_space == NUM_PACKET_NUMBER_SPACES) { + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + base_packet_number = largest_decrypted_packet_numbers_[pn_space]; } else { base_packet_number = largest_packet_number_; } uint64_t full_packet_number; - if (!ProcessAndCalculatePacketNumber( - encrypted_reader, header->packet_number_length, base_packet_number, - &full_packet_number)) { + bool hp_removal_failed = false; + if (version_.HasHeaderProtection()) { + if (!RemoveHeaderProtection(encrypted_reader, packet, header, + &full_packet_number, &ad_storage)) { + hp_removal_failed = true; + } + associated_data = QuicStringPiece(ad_storage.data(), ad_storage.size()); + } else if (!ProcessAndCalculatePacketNumber( + encrypted_reader, header->packet_number_length, + base_packet_number, &full_packet_number)) { set_detailed_error("Unable to read packet number."); RecordDroppedPacketReason(DroppedPacketReason::INVALID_PACKET_NUMBER); return RaiseError(QUIC_INVALID_PACKET_HEADER); } - if (!IsValidFullPacketNumber(full_packet_number, transport_version())) { + if (hp_removal_failed || + !IsValidFullPacketNumber(full_packet_number, transport_version())) { if (IsIetfStatelessResetPacket(*header)) { // This is a stateless reset packet. QuicIetfStatelessResetPacket packet( @@ -1797,6 +1814,10 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader, visitor_->OnAuthenticatedIetfStatelessResetPacket(packet); return true; } + if (hp_removal_failed) { + set_detailed_error("Unable to decrypt header protection."); + return RaiseError(QUIC_DECRYPTION_FAILURE); + } RecordDroppedPacketReason(DroppedPacketReason::INVALID_PACKET_NUMBER); set_detailed_error("packet numbers cannot be 0."); return RaiseError(QUIC_INVALID_PACKET_HEADER); @@ -1831,13 +1852,15 @@ bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader, } QuicStringPiece encrypted = encrypted_reader->ReadRemainingPayload(); - QuicStringPiece associated_data = GetAssociatedDataFromEncryptedPacket( - version_.transport_version, packet, - GetIncludedDestinationConnectionIdLength(*header), - GetIncludedSourceConnectionIdLength(*header), header->version_flag, - header->nonce != nullptr, header->packet_number_length, - header->retry_token_length_length, header->retry_token.length(), - header->length_length); + if (!version_.HasHeaderProtection()) { + associated_data = GetAssociatedDataFromEncryptedPacket( + version_.transport_version, packet, + GetIncludedDestinationConnectionIdLength(*header), + GetIncludedSourceConnectionIdLength(*header), header->version_flag, + header->nonce != nullptr, header->packet_number_length, + header->retry_token_length_length, header->retry_token.length(), + header->length_length); + } size_t decrypted_length = 0; EncryptionLevel decrypted_level; @@ -1970,7 +1993,8 @@ bool QuicFramer::ProcessDataPacket(QuicDataReader* encrypted_reader, bool QuicFramer::ProcessPublicResetPacket(QuicDataReader* reader, const QuicPacketHeader& header) { - QuicPublicResetPacket packet(header.destination_connection_id); + QuicPublicResetPacket packet( + GetServerConnectionIdAsRecipient(header, perspective_)); std::unique_ptr<CryptoHandshakeMessage> reset( CryptoFramer::ParseMessage(reader->ReadRemainingPayload())); @@ -2049,8 +2073,15 @@ bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header, DCHECK_EQ(Perspective::IS_SERVER, perspective_); public_flags |= PACKET_PUBLIC_FLAGS_NONCE; } - DCHECK_EQ(CONNECTION_ID_ABSENT, header.source_connection_id_included); - switch (header.destination_connection_id_included) { + + QuicConnectionId server_connection_id = + GetServerConnectionIdAsSender(header, perspective_); + QuicConnectionIdIncluded server_connection_id_included = + GetServerConnectionIdIncludedAsSender(header, perspective_); + DCHECK_EQ(CONNECTION_ID_ABSENT, + GetClientConnectionIdIncludedAsSender(header, perspective_)); + + switch (server_connection_id_included) { case CONNECTION_ID_ABSENT: if (!writer->WriteUInt8(public_flags | PACKET_PUBLIC_FLAGS_0BYTE_CONNECTION_ID)) { @@ -2059,10 +2090,9 @@ bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header, break; case CONNECTION_ID_PRESENT: QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion( - header.destination_connection_id, transport_version())) + server_connection_id, transport_version())) << "AppendPacketHeader: attempted to use connection ID " - << header.destination_connection_id - << " which is invalid with version " + << server_connection_id << " which is invalid with version " << QuicVersionToString(transport_version()); public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID; @@ -2070,12 +2100,12 @@ bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header, public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD; } if (!writer->WriteUInt8(public_flags) || - !writer->WriteConnectionId(header.destination_connection_id)) { + !writer->WriteConnectionId(server_connection_id)) { return false; } break; } - last_serialized_connection_id_ = header.destination_connection_id; + last_serialized_server_connection_id_ = server_connection_id; if (header.version_flag) { DCHECK_EQ(Perspective::IS_CLIENT, perspective_); @@ -2141,10 +2171,12 @@ bool QuicFramer::AppendIetfPacketHeader(const QuicPacketHeader& header, QuicDataWriter* writer, size_t* length_field_offset) { QUIC_DVLOG(1) << ENDPOINT << "Appending IETF header: " << header; - QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion( - header.destination_connection_id, transport_version())) + QuicConnectionId server_connection_id = + GetServerConnectionIdAsSender(header, perspective_); + QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(server_connection_id, + transport_version())) << "AppendIetfPacketHeader: attempted to use connection ID " - << header.destination_connection_id << " which is invalid with version " + << server_connection_id << " which is invalid with version " << QuicVersionToString(transport_version()); if (!AppendIetfHeaderTypeByte(header, writer)) { return false; @@ -2160,31 +2192,19 @@ bool QuicFramer::AppendIetfPacketHeader(const QuicPacketHeader& header, } // Append connection ID. - if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( - transport_version()) && - !GetQuicReloadableFlag(quic_use_new_append_connection_id)) { - if (!AppendIetfConnectionId( - header.version_flag, header.destination_connection_id, - GetIncludedDestinationConnectionIdLength(header), - header.source_connection_id, - GetIncludedSourceConnectionIdLength(header), writer)) { - return false; - } - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_new_append_connection_id, 2, 2); - if (!AppendIetfConnectionIdsNew( - header.version_flag, - header.destination_connection_id_included != CONNECTION_ID_ABSENT - ? header.destination_connection_id - : EmptyQuicConnectionId(), - header.source_connection_id_included != CONNECTION_ID_ABSENT - ? header.source_connection_id - : EmptyQuicConnectionId(), - writer)) { - return false; - } + if (!AppendIetfConnectionIds( + header.version_flag, + header.destination_connection_id_included != CONNECTION_ID_ABSENT + ? header.destination_connection_id + : EmptyQuicConnectionId(), + header.source_connection_id_included != CONNECTION_ID_ABSENT + ? header.source_connection_id + : EmptyQuicConnectionId(), + writer)) { + return false; } - last_serialized_connection_id_ = header.destination_connection_id; + + last_serialized_server_connection_id_ = server_connection_id; if (QuicVersionHasLongHeaderLengths(transport_version()) && header.version_flag) { @@ -2214,6 +2234,7 @@ bool QuicFramer::AppendIetfPacketHeader(const QuicPacketHeader& header, writer)) { return false; } + last_written_packet_number_length_ = header.packet_number_length; if (!header.version_flag) { return true; @@ -2306,18 +2327,26 @@ bool QuicFramer::ProcessPublicHeader(QuicDataReader* reader, return false; } + QuicConnectionId* header_connection_id = &header->destination_connection_id; + QuicConnectionIdIncluded* header_connection_id_included = + &header->destination_connection_id_included; + if (perspective_ == Perspective::IS_CLIENT && + GetQuicRestartFlag(quic_do_not_override_connection_id)) { + header_connection_id = &header->source_connection_id; + header_connection_id_included = &header->source_connection_id_included; + } switch (public_flags & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) { case PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID: - if (!reader->ReadConnectionId(&header->destination_connection_id, + if (!reader->ReadConnectionId(header_connection_id, kQuicDefaultConnectionIdLength)) { set_detailed_error("Unable to read ConnectionId."); return false; } - header->destination_connection_id_included = CONNECTION_ID_PRESENT; + *header_connection_id_included = CONNECTION_ID_PRESENT; break; case PACKET_PUBLIC_FLAGS_0BYTE_CONNECTION_ID: - header->destination_connection_id_included = CONNECTION_ID_ABSENT; - header->destination_connection_id = last_serialized_connection_id_; + *header_connection_id_included = CONNECTION_ID_ABSENT; + *header_connection_id = last_serialized_server_connection_id_; break; } @@ -2328,13 +2357,10 @@ bool QuicFramer::ProcessPublicHeader(QuicDataReader* reader, // version flag from the server means version negotiation packet. if (header->version_flag && perspective_ == Perspective::IS_SERVER) { QuicVersionLabel version_label; - if (!reader->ReadTag(&version_label)) { + if (!ProcessVersionLabel(reader, &version_label)) { set_detailed_error("Unable to read protocol version."); return false; } - // TODO(rch): Use ReadUInt32() once QUIC_VERSION_35 is removed. - version_label = QuicEndian::NetToHost32(version_label); - // If the version from the new packet is the same as the version of this // framer, then the public flags should be set to something we understand. // If not, this raises an error. @@ -2441,8 +2467,12 @@ bool QuicFramer::ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader, QuicPacketHeader* header) { QuicPacketNumber base_packet_number; if (supports_multiple_packet_number_spaces_) { - base_packet_number = - largest_decrypted_packet_numbers_[GetPacketNumberSpace(*header)]; + PacketNumberSpace pn_space = GetPacketNumberSpace(*header); + if (pn_space == NUM_PACKET_NUMBER_SPACES) { + set_detailed_error("Unable to determine packet number space."); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + base_packet_number = largest_decrypted_packet_numbers_[pn_space]; } else { base_packet_number = largest_packet_number_; } @@ -2465,6 +2495,22 @@ bool QuicFramer::ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader, "Visitor asked to stop processing of unauthenticated header."); return false; } + // The function we are in is called because the framer believes that it is + // processing a packet that uses the non-IETF (i.e. Google QUIC) packet header + // type. Usually, the framer makes that decision based on the framer's + // version, but when the framer is used with Perspective::IS_SERVER, then + // before version negotiation is complete (specifically, before + // InferPacketHeaderTypeFromVersion is called), this decision is made based on + // the type byte of the packet. + // + // If the framer's version KnowsWhichDecrypterToUse, then that version expects + // to use the IETF packet header type. If that's the case and we're in this + // function, then the packet received is invalid: the framer was expecting an + // IETF packet header and didn't get one. + if (version().KnowsWhichDecrypterToUse()) { + set_detailed_error("Invalid public header type for expected version."); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } return true; } @@ -2475,9 +2521,9 @@ bool QuicFramer::ProcessIetfHeaderTypeByte(QuicDataReader* reader, set_detailed_error("Unable to read type."); return false; } + header->type_byte = type; // Determine whether this is a long or short header. - header->form = type & FLAGS_LONG_HEADER ? IETF_QUIC_LONG_HEADER_PACKET - : IETF_QUIC_SHORT_HEADER_PACKET; + header->form = GetIetfPacketHeaderFormat(type); if (header->form == IETF_QUIC_LONG_HEADER_PACKET) { // Version is always present in long headers. header->version_flag = true; @@ -2492,12 +2538,10 @@ bool QuicFramer::ProcessIetfHeaderTypeByte(QuicDataReader* reader, : CONNECTION_ID_ABSENT; // Read version tag. QuicVersionLabel version_label; - if (!reader->ReadTag(&version_label)) { + if (!ProcessVersionLabel(reader, &version_label)) { set_detailed_error("Unable to read protocol version."); return false; } - // TODO(rch): Use ReadUInt32() once QUIC_VERSION_35 is removed. - version_label = QuicEndian::NetToHost32(version_label); if (!version_label) { // Version label is 0 indicating this is a version negotiation packet. header->long_packet_type = VERSION_NEGOTIATION; @@ -2514,8 +2558,19 @@ bool QuicFramer::ProcessIetfHeaderTypeByte(QuicDataReader* reader, set_detailed_error("Illegal long header type value."); return false; } - header->packet_number_length = GetLongHeaderPacketNumberLength( - header->version.transport_version, type); + if (header->long_packet_type == RETRY) { + if (!version().SupportsRetry()) { + set_detailed_error("RETRY not supported in this version."); + return false; + } + if (perspective_ == Perspective::IS_SERVER) { + set_detailed_error("Client-initiated RETRY is invalid."); + return false; + } + } else if (!header->version.HasHeaderProtection()) { + header->packet_number_length = GetLongHeaderPacketNumberLength( + header->version.transport_version, type); + } } } if (header->long_packet_type != VERSION_NEGOTIATION) { @@ -2543,7 +2598,8 @@ bool QuicFramer::ProcessIetfHeaderTypeByte(QuicDataReader* reader, set_detailed_error("Fixed bit is 0 in short header."); return false; } - if (!GetShortHeaderPacketNumberLength(transport_version(), type, + if (!header->version.HasHeaderProtection() && + !GetShortHeaderPacketNumberLength(transport_version(), type, infer_packet_header_type_from_version_, &header->packet_number_length)) { set_detailed_error("Illegal short header type value."); @@ -2553,6 +2609,64 @@ bool QuicFramer::ProcessIetfHeaderTypeByte(QuicDataReader* reader, return true; } +// static +bool QuicFramer::ProcessVersionLabel(QuicDataReader* reader, + QuicVersionLabel* version_label) { + if (!reader->ReadTag(version_label)) { + return false; + } + // TODO(rch): Use ReadUInt32() once QUIC_VERSION_35 is removed. + *version_label = QuicEndian::NetToHost32(*version_label); + return true; +} + +// static +bool QuicFramer::ProcessAndValidateIetfConnectionIdLength( + QuicDataReader* reader, + ParsedQuicVersion version, + bool should_update_expected_server_connection_id_length, + uint8_t* expected_server_connection_id_length, + uint8_t* destination_connection_id_length, + uint8_t* source_connection_id_length, + std::string* detailed_error) { + uint8_t connection_id_lengths_byte; + if (!reader->ReadBytes(&connection_id_lengths_byte, 1)) { + *detailed_error = "Unable to read ConnectionId length."; + return false; + } + uint8_t dcil = + (connection_id_lengths_byte & kDestinationConnectionIdLengthMask) >> 4; + if (dcil != 0) { + dcil += kConnectionIdLengthAdjustment; + } + if (should_update_expected_server_connection_id_length && + *expected_server_connection_id_length != dcil) { + QUIC_DVLOG(1) << "Updating expected_server_connection_id_length: " + << static_cast<int>(*expected_server_connection_id_length) + << " -> " << static_cast<int>(dcil); + *expected_server_connection_id_length = dcil; + } + uint8_t scil = connection_id_lengths_byte & kSourceConnectionIdLengthMask; + if (scil != 0) { + scil += kConnectionIdLengthAdjustment; + } + if (!should_update_expected_server_connection_id_length && + (dcil != *destination_connection_id_length || + scil != *source_connection_id_length) && + !QuicUtils::VariableLengthConnectionIdAllowedForVersion( + version.transport_version)) { + // TODO(dschinazi): use the framer's version once the + // OnProtocolVersionMismatch call is moved to before this is run. + QUIC_DVLOG(1) << "dcil: " << static_cast<uint32_t>(dcil) + << ", scil: " << static_cast<uint32_t>(scil); + *detailed_error = "Invalid ConnectionId length."; + return false; + } + *destination_connection_id_length = dcil; + *source_connection_id_length = scil; + return true; +} + bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader, QuicPacketHeader* header) { if (!ProcessIetfHeaderTypeByte(reader, header)) { @@ -2561,49 +2675,21 @@ bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader, uint8_t destination_connection_id_length = header->destination_connection_id_included == CONNECTION_ID_PRESENT - ? expected_connection_id_length_ + ? expected_server_connection_id_length_ : 0; uint8_t source_connection_id_length = header->source_connection_id_included == CONNECTION_ID_PRESENT - ? expected_connection_id_length_ + ? expected_server_connection_id_length_ : 0; if (header->form == IETF_QUIC_LONG_HEADER_PACKET) { - // Read and validate connection ID length. - uint8_t connection_id_lengths_byte; - if (!reader->ReadBytes(&connection_id_lengths_byte, 1)) { - set_detailed_error("Unable to read ConnectionId length."); + if (!ProcessAndValidateIetfConnectionIdLength( + reader, header->version, + should_update_expected_server_connection_id_length_, + &expected_server_connection_id_length_, + &destination_connection_id_length, &source_connection_id_length, + &detailed_error_)) { return false; } - uint8_t dcil = - (connection_id_lengths_byte & kDestinationConnectionIdLengthMask) >> 4; - if (dcil != 0) { - dcil += kConnectionIdLengthAdjustment; - } - if (should_update_expected_connection_id_length_ && - expected_connection_id_length_ != dcil) { - QUIC_DVLOG(1) << ENDPOINT << "Updating expected_connection_id_length: " - << static_cast<int>(expected_connection_id_length_) - << " -> " << static_cast<int>(dcil); - expected_connection_id_length_ = dcil; - } - uint8_t scil = connection_id_lengths_byte & kSourceConnectionIdLengthMask; - if (scil != 0) { - scil += kConnectionIdLengthAdjustment; - } - if ((dcil != destination_connection_id_length || - scil != source_connection_id_length) && - !should_update_expected_connection_id_length_ && - !QuicUtils::VariableLengthConnectionIdAllowedForVersion( - header->version.transport_version)) { - // TODO(dschinazi): use the framer's version once the - // OnProtocolVersionMismatch call is moved to before this is run. - QUIC_DVLOG(1) << "dcil: " << static_cast<uint32_t>(dcil) - << ", scil: " << static_cast<uint32_t>(scil); - set_detailed_error("Invalid ConnectionId length."); - return false; - } - destination_connection_id_length = dcil; - source_connection_id_length = scil; } DCHECK_LE(destination_connection_id_length, kQuicMaxConnectionIdLength); @@ -2622,13 +2708,26 @@ bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader, return false; } - if (header->source_connection_id_included == CONNECTION_ID_PRESENT) { - // Set destination connection ID to source connection ID. - DCHECK_EQ(EmptyQuicConnectionId(), header->destination_connection_id); - header->destination_connection_id = header->source_connection_id; - } else if (header->destination_connection_id_included == - CONNECTION_ID_ABSENT) { - header->destination_connection_id = last_serialized_connection_id_; + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + if (header->source_connection_id_included == CONNECTION_ID_PRESENT) { + DCHECK_EQ(Perspective::IS_CLIENT, perspective_); + DCHECK_EQ(IETF_QUIC_LONG_HEADER_PACKET, header->form); + if (!header->destination_connection_id.IsEmpty()) { + set_detailed_error("Client connection ID not supported yet."); + return false; + } + // Set destination connection ID to source connection ID. + header->destination_connection_id = header->source_connection_id; + } else if (header->destination_connection_id_included == + CONNECTION_ID_ABSENT) { + header->destination_connection_id = last_serialized_server_connection_id_; + } + } else { + QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 5, 5); + if (header->source_connection_id_included == CONNECTION_ID_ABSENT) { + DCHECK_EQ(EmptyQuicConnectionId(), header->source_connection_id); + header->source_connection_id = last_serialized_server_connection_id_; + } } return true; @@ -2783,6 +2882,12 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader, } case STOP_WAITING_FRAME: { + if (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) && + version_.transport_version >= QUIC_VERSION_44) { + QUIC_RELOADABLE_FLAG_COUNT(quic_do_not_accept_stop_waiting); + set_detailed_error("STOP WAITING not supported in version 44+."); + return RaiseError(QUIC_INVALID_STOP_WAITING_DATA); + } QuicStopWaitingFrame stop_waiting_frame; if (!ProcessStopWaitingFrame(reader, header, &stop_waiting_frame)) { return RaiseError(QUIC_INVALID_STOP_WAITING_DATA); @@ -2963,12 +3068,12 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader, } case IETF_MAX_STREAMS_BIDIRECTIONAL: case IETF_MAX_STREAMS_UNIDIRECTIONAL: { - QuicMaxStreamIdFrame frame; + QuicMaxStreamsFrame frame; if (!ProcessMaxStreamsFrame(reader, &frame, frame_type)) { - return RaiseError(QUIC_MAX_STREAM_ID_DATA); + return RaiseError(QUIC_MAX_STREAMS_DATA); } - QUIC_CODE_COUNT_N(max_stream_id_received, 1, 2); - if (!visitor_->OnMaxStreamIdFrame(frame)) { + QUIC_CODE_COUNT_N(quic_max_streams_received, 1, 2); + if (!visitor_->OnMaxStreamsFrame(frame)) { QUIC_DVLOG(1) << "Visitor asked to stop further processing."; // Returning true since there was no parsing error. return true; @@ -3011,12 +3116,12 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader, } case IETF_STREAMS_BLOCKED_UNIDIRECTIONAL: case IETF_STREAMS_BLOCKED_BIDIRECTIONAL: { - QuicStreamIdBlockedFrame frame; + QuicStreamsBlockedFrame frame; if (!ProcessStreamsBlockedFrame(reader, &frame, frame_type)) { - return RaiseError(QUIC_STREAM_ID_BLOCKED_DATA); + return RaiseError(QUIC_STREAMS_BLOCKED_DATA); } - QUIC_CODE_COUNT_N(stream_id_blocked_received, 1, 2); - if (!visitor_->OnStreamIdBlockedFrame(frame)) { + QUIC_CODE_COUNT_N(quic_streams_blocked_received, 1, 2); + if (!visitor_->OnStreamsBlockedFrame(frame)) { QUIC_DVLOG(1) << "Visitor asked to stop further processing."; // Returning true since there was no parsing error. return true; @@ -3235,7 +3340,7 @@ bool QuicFramer::ProcessIetfStreamFrame(QuicDataReader* reader, uint8_t frame_type, QuicStreamFrame* frame) { // Read stream id from the frame. It's always present. - if (!reader->ReadVarIntStreamId(&frame->stream_id)) { + if (!reader->ReadVarIntU32(&frame->stream_id)) { set_detailed_error("Unable to read stream_id."); return false; } @@ -3958,10 +4063,228 @@ size_t QuicFramer::EncryptInPlace(EncryptionLevel level, RaiseError(QUIC_ENCRYPTION_FAILURE); return 0; } + if (version_.HasHeaderProtection() && + !ApplyHeaderProtection(level, buffer, ad_len + output_length, ad_len)) { + QUIC_DLOG(ERROR) << "Applying header protection failed."; + RaiseError(QUIC_ENCRYPTION_FAILURE); + return 0; + } return ad_len + output_length; } +namespace { + +const size_t kHPSampleLen = 16; + +constexpr bool IsLongHeader(uint8_t type_byte) { + return (type_byte & FLAGS_LONG_HEADER) != 0; +} + +} // namespace + +bool QuicFramer::ApplyHeaderProtection(EncryptionLevel level, + char* buffer, + size_t buffer_len, + size_t ad_len) { + QuicDataReader buffer_reader(buffer, buffer_len); + QuicDataWriter buffer_writer(buffer_len, buffer); + // The sample starts 4 bytes after the start of the packet number. + if (ad_len < last_written_packet_number_length_) { + return false; + } + size_t pn_offset = ad_len - last_written_packet_number_length_; + // Sample the ciphertext and generate the mask to use for header protection. + size_t sample_offset = pn_offset + 4; + QuicDataReader sample_reader(buffer, buffer_len); + QuicStringPiece sample; + if (!sample_reader.Seek(sample_offset) || + !sample_reader.ReadStringPiece(&sample, kHPSampleLen)) { + QUIC_BUG << "Not enough bytes to sample: sample_offset " << sample_offset + << ", sample len: " << kHPSampleLen + << ", buffer len: " << buffer_len; + return false; + } + + std::string mask = encrypter_[level]->GenerateHeaderProtectionMask(sample); + if (mask.empty()) { + QUIC_BUG << "Unable to generate header protection mask."; + return false; + } + QuicDataReader mask_reader(mask.data(), mask.size()); + + // Apply the mask to the 4 or 5 least significant bits of the first byte. + uint8_t bitmask = 0x1f; + uint8_t type_byte; + if (!buffer_reader.ReadUInt8(&type_byte)) { + return false; + } + QuicLongHeaderType header_type; + if (IsLongHeader(type_byte)) { + bitmask = 0x0f; + if (!GetLongHeaderType(version_.transport_version, type_byte, + &header_type)) { + return false; + } + } + uint8_t mask_byte; + if (!mask_reader.ReadUInt8(&mask_byte) || + !buffer_writer.WriteUInt8(type_byte ^ (mask_byte & bitmask))) { + return false; + } + + // Adjust |pn_offset| to account for the diversification nonce. + if (IsLongHeader(type_byte) && header_type == ZERO_RTT_PROTECTED && + perspective_ == Perspective::IS_SERVER && + version_.handshake_protocol == PROTOCOL_QUIC_CRYPTO) { + if (pn_offset <= kDiversificationNonceSize) { + QUIC_BUG << "Expected diversification nonce, but not enough bytes"; + return false; + } + pn_offset -= kDiversificationNonceSize; + } + // Advance the reader and writer to the packet number. Both the reader and + // writer have each read/written one byte. + if (!buffer_writer.Seek(pn_offset - 1) || + !buffer_reader.Seek(pn_offset - 1)) { + return false; + } + // Apply the rest of the mask to the packet number. + for (size_t i = 0; i < last_written_packet_number_length_; ++i) { + uint8_t buffer_byte; + uint8_t mask_byte; + if (!mask_reader.ReadUInt8(&mask_byte) || + !buffer_reader.ReadUInt8(&buffer_byte) || + !buffer_writer.WriteUInt8(buffer_byte ^ mask_byte)) { + return false; + } + } + return true; +} + +bool QuicFramer::RemoveHeaderProtection(QuicDataReader* reader, + const QuicEncryptedPacket& packet, + QuicPacketHeader* header, + uint64_t* full_packet_number, + std::vector<char>* associated_data) { + EncryptionLevel expected_decryption_level = GetEncryptionLevel(*header); + QuicDecrypter* decrypter = decrypter_[expected_decryption_level].get(); + if (decrypter == nullptr) { + QUIC_DVLOG(1) + << "No decrypter available for removing header protection at level " + << expected_decryption_level; + return false; + } + + bool has_diversification_nonce = + header->form == IETF_QUIC_LONG_HEADER_PACKET && + header->long_packet_type == ZERO_RTT_PROTECTED && + perspective_ == Perspective::IS_CLIENT && + version_.handshake_protocol == PROTOCOL_QUIC_CRYPTO; + + // Read a sample from the ciphertext and compute the mask to use for header + // protection. + QuicStringPiece remaining_packet = reader->PeekRemainingPayload(); + QuicDataReader sample_reader(remaining_packet); + + // The sample starts 4 bytes after the start of the packet number. + QuicStringPiece pn; + if (!sample_reader.ReadStringPiece(&pn, 4)) { + QUIC_DVLOG(1) << "Not enough data to sample"; + return false; + } + if (has_diversification_nonce) { + // In Google QUIC, the diversification nonce comes between the packet number + // and the sample. + if (!sample_reader.Seek(kDiversificationNonceSize)) { + QUIC_DVLOG(1) << "No diversification nonce to skip over"; + return false; + } + } + std::string mask = decrypter->GenerateHeaderProtectionMask(&sample_reader); + QuicDataReader mask_reader(mask.data(), mask.size()); + if (mask.empty()) { + QUIC_DVLOG(1) << "Failed to compute mask"; + return false; + } + + // Unmask the rest of the type byte. + uint8_t bitmask = 0x1f; + if (IsLongHeader(header->type_byte)) { + bitmask = 0x0f; + } + uint8_t mask_byte; + if (!mask_reader.ReadUInt8(&mask_byte)) { + QUIC_DVLOG(1) << "No first byte to read from mask"; + return false; + } + header->type_byte ^= (mask_byte & bitmask); + + // Compute the packet number length. + header->packet_number_length = + static_cast<QuicPacketNumberLength>((header->type_byte & 0x03) + 1); + + char pn_buffer[IETF_MAX_PACKET_NUMBER_LENGTH] = {}; + QuicDataWriter pn_writer(QUIC_ARRAYSIZE(pn_buffer), pn_buffer); + + // Read the (protected) packet number from the reader and unmask the packet + // number. + for (size_t i = 0; i < header->packet_number_length; ++i) { + uint8_t protected_pn_byte, mask_byte; + if (!mask_reader.ReadUInt8(&mask_byte) || + !reader->ReadUInt8(&protected_pn_byte) || + !pn_writer.WriteUInt8(protected_pn_byte ^ mask_byte)) { + QUIC_DVLOG(1) << "Failed to unmask packet number"; + return false; + } + } + QuicDataReader packet_number_reader(pn_writer.data(), pn_writer.length()); + QuicPacketNumber base_packet_number; + if (supports_multiple_packet_number_spaces_) { + PacketNumberSpace pn_space = GetPacketNumberSpace(*header); + if (pn_space == NUM_PACKET_NUMBER_SPACES) { + return false; + } + base_packet_number = largest_decrypted_packet_numbers_[pn_space]; + } else { + base_packet_number = largest_packet_number_; + } + if (!ProcessAndCalculatePacketNumber( + &packet_number_reader, header->packet_number_length, + base_packet_number, full_packet_number)) { + return false; + } + + // Get the associated data, and apply the same unmasking operations to it. + QuicStringPiece ad = GetAssociatedDataFromEncryptedPacket( + version_.transport_version, packet, + GetIncludedDestinationConnectionIdLength(*header), + GetIncludedSourceConnectionIdLength(*header), header->version_flag, + has_diversification_nonce, header->packet_number_length, + header->retry_token_length_length, header->retry_token.length(), + header->length_length); + *associated_data = std::vector<char>(ad.begin(), ad.end()); + QuicDataWriter ad_writer(associated_data->size(), associated_data->data()); + + // Apply the unmasked type byte and packet number to |associated_data|. + if (!ad_writer.WriteUInt8(header->type_byte)) { + return false; + } + // Put the packet number at the end of the AD, or if there's a diversification + // nonce, before that (which is at the end of the AD). + size_t seek_len = ad_writer.remaining() - header->packet_number_length; + if (has_diversification_nonce) { + seek_len -= kDiversificationNonceSize; + } + if (!ad_writer.Seek(seek_len) || + !ad_writer.WriteBytes(pn_writer.data(), pn_writer.length())) { + QUIC_DVLOG(1) << "Failed to apply unmasking operations to AD"; + return false; + } + + return true; +} + size_t QuicFramer::EncryptPayload(EncryptionLevel level, QuicPacketNumber packet_number, const QuicPacket& packet, @@ -3990,6 +4313,12 @@ size_t QuicFramer::EncryptPayload(EncryptionLevel level, RaiseError(QUIC_ENCRYPTION_FAILURE); return 0; } + if (version_.HasHeaderProtection() && + !ApplyHeaderProtection(level, buffer, ad_len + output_length, ad_len)) { + QUIC_DLOG(ERROR) << "Applying header protection failed."; + RaiseError(QUIC_ENCRYPTION_FAILURE); + return 0; + } return ad_len + output_length; } @@ -4023,11 +4352,24 @@ bool QuicFramer::DecryptPayload(QuicStringPiece encrypted, size_t buffer_length, size_t* decrypted_length, EncryptionLevel* decrypted_level) { + if (!EncryptionLevelIsValid(decrypter_level_)) { + QUIC_BUG << "Attempted to decrypt with bad decrypter_level_"; + return false; + } EncryptionLevel level = decrypter_level_; QuicDecrypter* decrypter = decrypter_[level].get(); QuicDecrypter* alternative_decrypter = nullptr; if (version().KnowsWhichDecrypterToUse()) { + if (header.form == GOOGLE_QUIC_PACKET) { + QUIC_BUG << "Attempted to decrypt GOOGLE_QUIC_PACKET with a version that " + "knows which decrypter to use"; + return false; + } level = GetEncryptionLevel(header); + if (!EncryptionLevelIsValid(level)) { + QUIC_BUG << "Attempted to decrypt with bad level"; + return false; + } decrypter = decrypter_[level].get(); if (decrypter == nullptr) { return false; @@ -4037,10 +4379,18 @@ bool QuicFramer::DecryptPayload(QuicStringPiece encrypted, decrypter->SetDiversificationNonce(*header.nonce); } } else if (alternative_decrypter_level_ != NUM_ENCRYPTION_LEVELS) { + if (!EncryptionLevelIsValid(alternative_decrypter_level_)) { + QUIC_BUG << "Attempted to decrypt with bad alternative_decrypter_level_"; + return false; + } alternative_decrypter = decrypter_[alternative_decrypter_level_].get(); } - DCHECK(decrypter != nullptr); + if (decrypter == nullptr) { + QUIC_BUG << "Attempting to decrypt without decrypter, encryption level:" + << level << " version:" << version(); + return false; + } bool success = decrypter->DecryptPacket( header.packet_number.ToUint64(), associated_data, encrypted, @@ -4074,11 +4424,14 @@ bool QuicFramer::DecryptPayload(QuicStringPiece encrypted, visitor_->OnDecryptedPacket(alternative_decrypter_level_); *decrypted_level = decrypter_level_; if (alternative_decrypter_latch_) { + if (!EncryptionLevelIsValid(alternative_decrypter_level_)) { + QUIC_BUG << "Attempted to latch alternate decrypter with bad " + "alternative_decrypter_level_"; + return false; + } // Switch to the alternative decrypter and latch so that we cannot // switch back. decrypter_level_ = alternative_decrypter_level_; - decrypter_[decrypter_level_] = - std::move(decrypter_[alternative_decrypter_level_]); alternative_decrypter_level_ = NUM_ENCRYPTION_LEVELS; } else { // Switch the alternative decrypter so that we use it first next time. @@ -4090,8 +4443,7 @@ bool QuicFramer::DecryptPayload(QuicStringPiece encrypted, } if (!success) { - QUIC_DVLOG(1) << ENDPOINT << "DecryptPacket failed for packet_number:" - << header.packet_number; + QUIC_DVLOG(1) << ENDPOINT << "DecryptPacket failed for: " << header; return false; } @@ -4296,13 +4648,13 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame, set_detailed_error( "Attempt to append NEW_TOKEN frame and not in version 99."); return RaiseError(QUIC_INTERNAL_ERROR); - case MAX_STREAM_ID_FRAME: + case MAX_STREAMS_FRAME: set_detailed_error( - "Attempt to append MAX_STREAM_ID frame and not in version 99."); + "Attempt to append MAX_STREAMS frame and not in version 99."); return RaiseError(QUIC_INTERNAL_ERROR); - case STREAM_ID_BLOCKED_FRAME: + case STREAMS_BLOCKED_FRAME: set_detailed_error( - "Attempt to append STREAM_ID_BLOCKED frame and not in version 99."); + "Attempt to append STREAMS_BLOCKED frame and not in version 99."); return RaiseError(QUIC_INTERNAL_ERROR); case PATH_RESPONSE_FRAME: set_detailed_error( @@ -4401,20 +4753,18 @@ bool QuicFramer::AppendIetfTypeByte(const QuicFrame& frame, case NEW_TOKEN_FRAME: type_byte = IETF_NEW_TOKEN; break; - case MAX_STREAM_ID_FRAME: - if (QuicUtils::IsBidirectionalStreamId( - frame.max_stream_id_frame.max_stream_id)) { - type_byte = IETF_MAX_STREAMS_BIDIRECTIONAL; - } else { + case MAX_STREAMS_FRAME: + if (frame.max_streams_frame.unidirectional) { type_byte = IETF_MAX_STREAMS_UNIDIRECTIONAL; + } else { + type_byte = IETF_MAX_STREAMS_BIDIRECTIONAL; } break; - case STREAM_ID_BLOCKED_FRAME: - if (QuicUtils::IsBidirectionalStreamId( - frame.max_stream_id_frame.max_stream_id)) { - type_byte = IETF_STREAMS_BLOCKED_BIDIRECTIONAL; - } else { + case STREAMS_BLOCKED_FRAME: + if (frame.streams_blocked_frame.unidirectional) { type_byte = IETF_STREAMS_BLOCKED_UNIDIRECTIONAL; + } else { + type_byte = IETF_STREAMS_BLOCKED_BIDIRECTIONAL; } break; case PATH_RESPONSE_FRAME: @@ -4538,34 +4888,6 @@ bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame, return true; } -// static -bool QuicFramer::AppendIetfConnectionId( - bool version_flag, - QuicConnectionId destination_connection_id, - QuicConnectionIdLength destination_connection_id_length, - QuicConnectionId source_connection_id, - QuicConnectionIdLength source_connection_id_length, - QuicDataWriter* writer) { - if (version_flag) { - // Append connection ID length byte. - uint8_t dcil = GetConnectionIdLengthValue(destination_connection_id_length); - uint8_t scil = GetConnectionIdLengthValue(source_connection_id_length); - uint8_t connection_id_length = dcil << 4 | scil; - if (!writer->WriteBytes(&connection_id_length, 1)) { - return false; - } - } - if (destination_connection_id_length == PACKET_8BYTE_CONNECTION_ID && - !writer->WriteConnectionId(destination_connection_id)) { - return false; - } - if (source_connection_id_length == PACKET_8BYTE_CONNECTION_ID && - !writer->WriteConnectionId(source_connection_id)) { - return false; - } - return true; -} - bool QuicFramer::AppendNewTokenFrame(const QuicNewTokenFrame& frame, QuicDataWriter* writer) { if (!writer->WriteVarInt62(static_cast<uint64_t>(frame.token.length()))) { @@ -5212,7 +5534,9 @@ bool QuicFramer::RaiseError(QuicErrorCode error) { QUIC_DLOG(INFO) << ENDPOINT << "Error: " << QuicErrorCodeToString(error) << " detail: " << detailed_error_; set_error(error); - visitor_->OnError(this); + if (visitor_) { + visitor_->OnError(this); + } return false; } @@ -5220,9 +5544,13 @@ bool QuicFramer::IsVersionNegotiation( const QuicPacketHeader& header, bool packet_has_ietf_packet_header) const { if (perspective_ == Perspective::IS_SERVER) { - return false; + if (!GetQuicRestartFlag(quic_server_drop_version_negotiation)) { + return false; + } + QUIC_RESTART_FLAG_COUNT_N(quic_server_drop_version_negotiation, 2, 2); } - if (!packet_has_ietf_packet_header) { + if (!packet_has_ietf_packet_header && + perspective_ == Perspective::IS_CLIENT) { return header.version_flag; } if (header.form == IETF_QUIC_SHORT_HEADER_PACKET) { @@ -5372,7 +5700,7 @@ bool QuicFramer::ProcessIetfResetStreamFrame(QuicDataReader* reader, // Get Stream ID from frame. ReadVarIntStreamID returns false // if either A) there is a read error or B) the resulting value of // the Stream ID is larger than the maximum allowed value. - if (!reader->ReadVarIntStreamId(&frame->stream_id)) { + if (!reader->ReadVarIntU32(&frame->stream_id)) { set_detailed_error("Unable to read rst stream stream id."); return false; } @@ -5392,7 +5720,7 @@ bool QuicFramer::ProcessIetfResetStreamFrame(QuicDataReader* reader, bool QuicFramer::ProcessStopSendingFrame( QuicDataReader* reader, QuicStopSendingFrame* stop_sending_frame) { - if (!reader->ReadVarIntStreamId(&stop_sending_frame->stream_id)) { + if (!reader->ReadVarIntU32(&stop_sending_frame->stream_id)) { set_detailed_error("Unable to read stop sending stream id."); return false; } @@ -5454,7 +5782,7 @@ bool QuicFramer::AppendMaxStreamDataFrame(const QuicWindowUpdateFrame& frame, bool QuicFramer::ProcessMaxStreamDataFrame(QuicDataReader* reader, QuicWindowUpdateFrame* frame) { - if (!reader->ReadVarIntStreamId(&frame->stream_id)) { + if (!reader->ReadVarIntU32(&frame->stream_id)) { set_detailed_error("Can not read MAX_STREAM_DATA stream id"); return false; } @@ -5465,13 +5793,9 @@ bool QuicFramer::ProcessMaxStreamDataFrame(QuicDataReader* reader, return true; } -bool QuicFramer::AppendMaxStreamsFrame(const QuicMaxStreamIdFrame& frame, +bool QuicFramer::AppendMaxStreamsFrame(const QuicMaxStreamsFrame& frame, QuicDataWriter* writer) { - // Convert from the stream id on which the connection is blocked to a count - QuicStreamId stream_count = - StreamIdToCount(version_.transport_version, frame.max_stream_id); - - if (!writer->WriteVarInt62(stream_count)) { + if (!writer->WriteVarInt62(frame.stream_count)) { set_detailed_error("Can not write MAX_STREAMS stream count"); return false; } @@ -5479,33 +5803,14 @@ bool QuicFramer::AppendMaxStreamsFrame(const QuicMaxStreamIdFrame& frame, } bool QuicFramer::ProcessMaxStreamsFrame(QuicDataReader* reader, - QuicMaxStreamIdFrame* frame, + QuicMaxStreamsFrame* frame, uint64_t frame_type) { - QuicStreamId received_stream_count; - if (!reader->ReadVarIntStreamId(&received_stream_count)) { + if (!reader->ReadVarIntU32(&frame->stream_count)) { set_detailed_error("Can not read MAX_STREAMS stream count."); return false; } - // TODO(fkastenholz): handle properly when the STREAMS_BLOCKED - // frame is implemented and passed up to the stream ID manager. - if (received_stream_count == 0) { - set_detailed_error("MAX_STREAMS stream count of 0 not supported."); - return false; - } - // Note that this code assumes that the only possible error that - // StreamCountToId can detect is that the stream count is too big or is 0. - // Too big is prevented by passing in the minimum of the received count - // and the maximum supported count, ensuring that the stream ID is - // pegged at the maximum allowed ID. - // count==0 is handled above, so that detailed_error_ may be set - // properly. - return StreamCountToId( - std::min( - received_stream_count, - GetMaxStreamCount((frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL), - perspective_)), - /*unidirectional=*/(frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL), - perspective_, version_.transport_version, &frame->max_stream_id); + frame->unidirectional = (frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL); + return true; } bool QuicFramer::AppendIetfBlockedFrame(const QuicBlockedFrame& frame, @@ -5543,7 +5848,7 @@ bool QuicFramer::AppendStreamBlockedFrame(const QuicBlockedFrame& frame, bool QuicFramer::ProcessStreamBlockedFrame(QuicDataReader* reader, QuicBlockedFrame* frame) { - if (!reader->ReadVarIntStreamId(&frame->stream_id)) { + if (!reader->ReadVarIntU32(&frame->stream_id)) { set_detailed_error("Can not read stream blocked stream id."); return false; } @@ -5554,14 +5859,9 @@ bool QuicFramer::ProcessStreamBlockedFrame(QuicDataReader* reader, return true; } -bool QuicFramer::AppendStreamsBlockedFrame( - const QuicStreamIdBlockedFrame& frame, - QuicDataWriter* writer) { - // Convert from the stream id on which the connection is blocked to a count - QuicStreamId stream_count = - StreamIdToCount(version_.transport_version, frame.stream_id); - - if (!writer->WriteVarInt62(stream_count)) { +bool QuicFramer::AppendStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteVarInt62(frame.stream_count)) { set_detailed_error("Can not write STREAMS_BLOCKED stream count"); return false; } @@ -5569,43 +5869,29 @@ bool QuicFramer::AppendStreamsBlockedFrame( } bool QuicFramer::ProcessStreamsBlockedFrame(QuicDataReader* reader, - QuicStreamIdBlockedFrame* frame, + QuicStreamsBlockedFrame* frame, uint64_t frame_type) { - QuicStreamId received_stream_count; - if (!reader->ReadVarIntStreamId(&received_stream_count)) { - set_detailed_error("Can not read STREAMS_BLOCKED stream id."); - return false; - } - // TODO(fkastenholz): handle properly when the STREAMS_BLOCKED - // frame is implemented and passed up to the stream ID manager. - if (received_stream_count == 0) { - set_detailed_error("STREAMS_BLOCKED stream count 0 not supported."); + if (!reader->ReadVarIntU32(&frame->stream_count)) { + set_detailed_error("Can not read STREAMS_BLOCKED stream count."); return false; } + frame->unidirectional = (frame_type == IETF_STREAMS_BLOCKED_UNIDIRECTIONAL); + // TODO(fkastenholz): handle properly when the STREAMS_BLOCKED // frame is implemented and passed up to the stream ID manager. - if (received_stream_count > - GetMaxStreamCount((frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL), - ((perspective_ == Perspective::IS_CLIENT) - ? Perspective::IS_SERVER - : Perspective::IS_CLIENT))) { + if (frame->stream_count > + QuicUtils::GetMaxStreamCount( + (frame_type == IETF_STREAMS_BLOCKED_UNIDIRECTIONAL), + ((perspective_ == Perspective::IS_CLIENT) + ? Perspective::IS_SERVER + : Perspective::IS_CLIENT))) { // If stream count is such that the resulting stream ID would exceed our // implementation limit, generate an error. set_detailed_error( "STREAMS_BLOCKED stream count exceeds implementation limit."); return false; } - // Convert the stream count to an ID that can be used. - // The STREAMS_BLOCKED frame is a request for more streams - // that the peer will initiate. If this node is a client, it - // means that the peer is a server, and wants server-initiated - // stream IDs. - return StreamCountToId( - received_stream_count, - /*unidirectional=*/(frame_type == IETF_STREAMS_BLOCKED_UNIDIRECTIONAL), - (perspective_ == Perspective::IS_CLIENT) ? Perspective::IS_SERVER - : Perspective::IS_CLIENT, - version_.transport_version, &frame->stream_id); + return true; } bool QuicFramer::AppendNewConnectionIdFrame( @@ -5763,5 +6049,233 @@ void QuicFramer::EnableMultiplePacketNumberSpacesSupport() { supports_multiple_packet_number_spaces_ = true; } +// static +QuicErrorCode QuicFramer::ProcessPacketDispatcher( + const QuicEncryptedPacket& packet, + uint8_t expected_connection_id_length, + PacketHeaderFormat* format, + bool* version_flag, + QuicVersionLabel* version_label, + uint8_t* destination_connection_id_length, + QuicConnectionId* destination_connection_id, + std::string* detailed_error) { + QuicDataReader reader(packet.data(), packet.length()); + + uint8_t first_byte; + if (!reader.ReadBytes(&first_byte, 1)) { + *detailed_error = "Unable to read first byte."; + return QUIC_INVALID_PACKET_HEADER; + } + if (!QuicUtils::IsIetfPacketHeader(first_byte)) { + *format = GOOGLE_QUIC_PACKET; + *version_flag = (first_byte & PACKET_PUBLIC_FLAGS_VERSION) != 0; + *destination_connection_id_length = + first_byte & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID; + if (*destination_connection_id_length == 0 || + !reader.ReadConnectionId(destination_connection_id, + *destination_connection_id_length)) { + *detailed_error = "Unable to read ConnectionId."; + return QUIC_INVALID_PACKET_HEADER; + } + if (*version_flag && !ProcessVersionLabel(&reader, version_label)) { + *detailed_error = "Unable to read protocol version."; + return QUIC_INVALID_PACKET_HEADER; + } + return QUIC_NO_ERROR; + } + + *format = GetIetfPacketHeaderFormat(first_byte); + QUIC_DVLOG(1) << "Dispatcher: Processing IETF QUIC packet, format: " + << *format; + *version_flag = *format == IETF_QUIC_LONG_HEADER_PACKET; + if (*format == IETF_QUIC_LONG_HEADER_PACKET) { + if (!ProcessVersionLabel(&reader, version_label)) { + *detailed_error = "Unable to read protocol version."; + return QUIC_INVALID_PACKET_HEADER; + } + // Set should_update_expected_server_connection_id_length to true to bypass + // connection ID lengths validation. + uint8_t unused_source_connection_id_length = 0; + uint8_t unused_expected_server_connection_id_length = 0; + if (!ProcessAndValidateIetfConnectionIdLength( + &reader, ParseQuicVersionLabel(*version_label), + /*should_update_expected_server_connection_id_length=*/true, + &unused_expected_server_connection_id_length, + destination_connection_id_length, + &unused_source_connection_id_length, detailed_error)) { + return QUIC_INVALID_PACKET_HEADER; + } + } else { + // For short header packets, expected_connection_id_length is used to + // determine the destination_connection_id_length. + *destination_connection_id_length = expected_connection_id_length; + } + // Read destination connection ID. + if (!reader.ReadConnectionId(destination_connection_id, + *destination_connection_id_length)) { + *detailed_error = "Unable to read Destination ConnectionId."; + return QUIC_INVALID_PACKET_HEADER; + } + return QUIC_NO_ERROR; +} + +// static +bool QuicFramer::WriteClientVersionNegotiationProbePacket( + char* packet_bytes, + QuicByteCount packet_length, + const char* destination_connection_id_bytes, + uint8_t destination_connection_id_length) { + if (packet_bytes == nullptr) { + QUIC_BUG << "Invalid packet_bytes"; + return false; + } + if (packet_length < kMinPacketSizeForVersionNegotiation || + packet_length > 65535) { + QUIC_BUG << "Invalid packet_length"; + return false; + } + if (destination_connection_id_length > kQuicMaxConnectionIdLength || + (destination_connection_id_length > 0 && + destination_connection_id_length < 4)) { + QUIC_BUG << "Invalid connection_id_length"; + return false; + } + // clang-format off + static const unsigned char packet_start_bytes[] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version, part of the IETF space reserved for negotiation. + // This intentionally differs from QuicVersionReservedForNegotiation() + // to allow differentiating them over the wire. + 0xca, 0xba, 0xda, 0xba, + }; + // clang-format on + static_assert(sizeof(packet_start_bytes) == 5, "bad packet_start_bytes size"); + QuicDataWriter writer(packet_length, packet_bytes); + if (!writer.WriteBytes(packet_start_bytes, sizeof(packet_start_bytes))) { + QUIC_BUG << "Failed to write packet start"; + return false; + } + + QuicConnectionId destination_connection_id(destination_connection_id_bytes, + destination_connection_id_length); + if (!AppendIetfConnectionIds(/*version_flag=*/true, destination_connection_id, + EmptyQuicConnectionId(), &writer)) { + QUIC_BUG << "Failed to write connection IDs"; + return false; + } + // Add 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does + // not parse with any known version. The zeroes make sure that packet numbers, + // retry token lengths and payload lengths are parsed as zero, and if the + // zeroes are treated as padding frames, 0xff is known to not parse as a + // valid frame type. + if (!writer.WriteUInt64(0) || + !writer.WriteUInt64(std::numeric_limits<uint64_t>::max())) { + QUIC_BUG << "Failed to write 18 bytes"; + return false; + } + // Make sure the polite greeting below is padded to a 16-byte boundary to + // make it easier to read in tcpdump. + while (writer.length() % 16 != 0) { + if (!writer.WriteUInt8(0)) { + QUIC_BUG << "Failed to write padding byte"; + return false; + } + } + // Add a polite greeting in case a human sees this in tcpdump. + static const char polite_greeting[] = + "This packet only exists to trigger IETF QUIC version negotiation. " + "Please respond with a Version Negotiation packet indicating what " + "versions you support. Thank you and have a nice day."; + if (!writer.WriteBytes(polite_greeting, sizeof(polite_greeting))) { + QUIC_BUG << "Failed to write polite greeting"; + return false; + } + // Fill the rest of the packet with zeroes. + writer.WritePadding(); + DCHECK_EQ(0u, writer.remaining()); + return true; +} + +// static +bool QuicFramer::ParseServerVersionNegotiationProbeResponse( + const char* packet_bytes, + QuicByteCount packet_length, + char* source_connection_id_bytes, + uint8_t* source_connection_id_length_out, + std::string* detailed_error) { + if (detailed_error == nullptr) { + QUIC_BUG << "Invalid error_details"; + return false; + } + *detailed_error = ""; + if (packet_bytes == nullptr) { + *detailed_error = "Invalid packet_bytes"; + return false; + } + if (packet_length < 6) { + *detailed_error = "Invalid packet_length"; + return false; + } + if (source_connection_id_bytes == nullptr) { + *detailed_error = "Invalid source_connection_id_bytes"; + return false; + } + if (source_connection_id_length_out == nullptr) { + *detailed_error = "Invalid source_connection_id_length_out"; + return false; + } + QuicDataReader reader(packet_bytes, packet_length); + uint8_t type_byte = 0; + if (!reader.ReadUInt8(&type_byte)) { + *detailed_error = "Failed to read type byte"; + return false; + } + if ((type_byte & 0x80) == 0) { + *detailed_error = "Packet does not have long header"; + return false; + } + uint32_t version = 0; + if (!reader.ReadUInt32(&version)) { + *detailed_error = "Failed to read version"; + return false; + } + if (version != 0) { + *detailed_error = "Packet is not a version negotiation packet"; + return false; + } + uint8_t expected_server_connection_id_length = 0, + destination_connection_id_length = 0, source_connection_id_length = 0; + if (!ProcessAndValidateIetfConnectionIdLength( + &reader, UnsupportedQuicVersion(), + /*should_update_expected_server_connection_id_length=*/true, + &expected_server_connection_id_length, + &destination_connection_id_length, &source_connection_id_length, + detailed_error)) { + return false; + } + if (destination_connection_id_length != 0) { + *detailed_error = "Received unexpected destination connection ID length"; + return false; + } + QuicConnectionId destination_connection_id, source_connection_id; + if (!reader.ReadConnectionId(&destination_connection_id, + destination_connection_id_length)) { + *detailed_error = "Failed to read destination connection ID"; + return false; + } + if (!reader.ReadConnectionId(&source_connection_id, + source_connection_id_length)) { + *detailed_error = "Failed to read source connection ID"; + return false; + } + + memcpy(source_connection_id_bytes, source_connection_id.data(), + source_connection_id_length); + *source_connection_id_length_out = source_connection_id_length; + + return true; +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h index 90ef99815f1..11d48bbafb2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h @@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" @@ -92,6 +93,12 @@ class QUIC_EXPORT_PRIVATE QuicFramerVisitorInterface { virtual void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) = 0; + // Called only when |perspective_| is IS_CLIENT and a retry packet has been + // parsed. + virtual void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) = 0; + // Called when all fields except packet number has been parsed, but has not // been authenticated. If it returns false, framing for this packet will // cease. @@ -201,12 +208,11 @@ class QUIC_EXPORT_PRIVATE QuicFramerVisitorInterface { virtual void OnAuthenticatedIetfStatelessResetPacket( const QuicIetfStatelessResetPacket& packet) = 0; - // Called when an IETF MaxStreamId frame has been parsed. - virtual bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) = 0; + // Called when an IETF MaxStreams frame has been parsed. + virtual bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) = 0; - // Called when an IETF StreamIdBlocked frame has been parsed. - virtual bool OnStreamIdBlockedFrame( - const QuicStreamIdBlockedFrame& frame) = 0; + // Called when an IETF StreamsBlocked frame has been parsed. + virtual bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) = 0; }; // Class for parsing and constructing QUIC packets. It has a @@ -220,7 +226,7 @@ class QUIC_EXPORT_PRIVATE QuicFramer { QuicFramer(const ParsedQuicVersionVector& supported_versions, QuicTime creation_time, Perspective perspective, - uint8_t expected_connection_id_length); + uint8_t expected_server_connection_id_length); QuicFramer(const QuicFramer&) = delete; QuicFramer& operator=(const QuicFramer&) = delete; @@ -264,7 +270,7 @@ class QUIC_EXPORT_PRIVATE QuicFramer { } // Pass a UDP packet into the framer for parsing. - // Return true if the packet was processed succesfully. |packet| must be a + // Return true if the packet was processed successfully. |packet| must be a // single, complete UDP packet (not a frame of a packet). This packet // might be null padded past the end of the payload, which will be correctly // ignored. @@ -295,9 +301,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Size in bytes of all reset stream frame fields. static size_t GetRstStreamFrameSize(QuicTransportVersion version, const QuicRstStreamFrame& frame); - // Size in bytes of all connection close frame fields without the error - // details and the missing packets from the enclosed ack frame. - static size_t GetMinConnectionCloseFrameSize( + // Size in bytes of all connection close frame fields, including the error + // details. + static size_t GetConnectionCloseFrameSize( QuicTransportVersion version, const QuicConnectionCloseFrame& frame); // Size in bytes of all GoAway frame fields without the reason phrase. @@ -309,11 +315,11 @@ class QUIC_EXPORT_PRIVATE QuicFramer { const QuicWindowUpdateFrame& frame); // Size in bytes of all MaxStreams frame fields. static size_t GetMaxStreamsFrameSize(QuicTransportVersion version, - const QuicMaxStreamIdFrame& frame); + const QuicMaxStreamsFrame& frame); // Size in bytes of all StreamsBlocked frame fields. static size_t GetStreamsBlockedFrameSize( QuicTransportVersion version, - const QuicStreamIdBlockedFrame& frame); + const QuicStreamsBlockedFrame& frame); // Size in bytes of all Blocked frame fields. static size_t GetBlockedFrameSize(QuicTransportVersion version, const QuicBlockedFrame& frame); @@ -367,6 +373,21 @@ class QUIC_EXPORT_PRIVATE QuicFramer { uint64_t retry_token_length, QuicVariableLengthIntegerLength length_length); + // Lightweight parsing of |packet| and populates |format|, |version_flag|, + // |version_label|, |destination_connection_id_length|, + // |destination_connection_id| and |detailed_error|. Please note, + // |expected_connection_id_length| is only used to determine IETF short header + // packet's destination connection ID length. + static QuicErrorCode ProcessPacketDispatcher( + const QuicEncryptedPacket& packet, + uint8_t expected_connection_id_length, + PacketHeaderFormat* format, + bool* version_flag, + QuicVersionLabel* version_label, + uint8_t* destination_connection_id_length, + QuicConnectionId* destination_connection_id, + std::string* detailed_error); + // Serializes a packet containing |frames| into |buffer|. // Returns the length of the packet, which must not be longer than // |packet_length|. Returns 0 if it fails to serialize. @@ -414,13 +435,15 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Returns a new version negotiation packet. static std::unique_ptr<QuicEncryptedPacket> BuildVersionNegotiationPacket( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, + QuicConnectionId client_connection_id, bool ietf_quic, const ParsedQuicVersionVector& versions); // Returns a new IETF version negotiation packet. static std::unique_ptr<QuicEncryptedPacket> BuildIetfVersionNegotiationPacket( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, + QuicConnectionId client_connection_id, const ParsedQuicVersionVector& versions); // If header.version_flag is set, the version in the @@ -554,19 +577,52 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // If true, QuicFramer will change its expected connection ID length // to the received destination connection ID length of all IETF long headers. - void SetShouldUpdateExpectedConnectionIdLength( - bool should_update_expected_connection_id_length) { - should_update_expected_connection_id_length_ = - should_update_expected_connection_id_length; + void SetShouldUpdateExpectedServerConnectionIdLength( + bool should_update_expected_server_connection_id_length) { + should_update_expected_server_connection_id_length_ = + should_update_expected_server_connection_id_length; } - // The connection ID length the framer expects on incoming IETF short headers. - uint8_t GetExpectedConnectionIdLength() { - return expected_connection_id_length_; + // The connection ID length the framer expects on incoming IETF short headers + // on the server. + uint8_t GetExpectedServerConnectionIdLength() { + return expected_server_connection_id_length_; } void EnableMultiplePacketNumberSpacesSupport(); + // Writes an array of bytes that, if sent as a UDP datagram, will trigger + // IETF QUIC Version Negotiation on servers. The bytes will be written to + // |packet_bytes|, which must point to |packet_length| bytes of memory. + // |packet_length| must be in the range [1200, 65535]. + // |destination_connection_id_bytes| will be sent as the destination + // connection ID, and must point to |destination_connection_id_length| bytes + // of memory. |destination_connection_id_length| must be either 0 or in the + // range [4,18]. When targeting Google servers, it is recommended to use a + // |destination_connection_id_length| of 8. + static bool WriteClientVersionNegotiationProbePacket( + char* packet_bytes, + QuicByteCount packet_length, + const char* destination_connection_id_bytes, + uint8_t destination_connection_id_length); + + // Parses a packet which a QUIC server sent in response to a packet sent by + // WriteClientVersionNegotiationProbePacket. |packet_bytes| must point to + // |packet_length| bytes in memory which represent the response. + // |packet_length| must be greater or equal to 6. This method will fill in + // |source_connection_id_bytes| which must point to at least 18 bytes in + // memory. |source_connection_id_length_out| will contain the length of the + // received source connection ID, which on success will match the contents of + // the destination connection ID passed in to + // WriteClientVersionNegotiationProbePacket. In the case of a failure, + // |detailed_error| will be filled in with an explanation of what failed. + static bool ParseServerVersionNegotiationProbeResponse( + const char* packet_bytes, + QuicByteCount packet_length, + char* source_connection_id_bytes, + uint8_t* source_connection_id_length_out, + std::string* detailed_error); + private: friend class test::QuicFramerPeer; @@ -585,6 +641,34 @@ class QUIC_EXPORT_PRIVATE QuicFramer { size_t num_ack_blocks; }; + // Applies header protection to an IETF QUIC packet header in |buffer| using + // the encrypter for level |level|. The buffer has |buffer_len| bytes of data, + // with the first protected packet bytes starting at |ad_len|. + bool ApplyHeaderProtection(EncryptionLevel level, + char* buffer, + size_t buffer_len, + size_t ad_len); + + // Removes header protection from an IETF QUIC packet header. + // + // The packet number from the header is read from |reader|, where the packet + // number is the next contents in |reader|. |reader| is only advanced by the + // length of the packet number, but it is also used to peek the sample needed + // for removing header protection. + // + // Properties needed for removing header protection are read from |header|. + // The packet number length and type byte are written to |header|. + // + // The packet number, after removing header protection and decoding it, is + // written to |full_packet_number|. Finally, the header, with header + // protection removed, is written to |associated_data| to be used in packet + // decryption. |packet| is used in computing the asociated data. + bool RemoveHeaderProtection(QuicDataReader* reader, + const QuicEncryptedPacket& packet, + QuicPacketHeader* header, + uint64_t* full_packet_number, + std::vector<char>* associated_data); + bool ProcessDataPacket(QuicDataReader* reader, QuicPacketHeader* header, const QuicEncryptedPacket& packet, @@ -603,6 +687,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer { bool ProcessVersionNegotiationPacket(QuicDataReader* reader, const QuicPacketHeader& header); + bool ProcessRetryPacket(QuicDataReader* reader, + const QuicPacketHeader& header); + bool MaybeProcessIetfInitialRetryToken(QuicDataReader* encrypted_reader, QuicPacketHeader* header); @@ -622,6 +709,21 @@ class QUIC_EXPORT_PRIVATE QuicFramer { bool ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader, QuicPacketHeader* header); + // Processes the version label in the packet header. + static bool ProcessVersionLabel(QuicDataReader* reader, + QuicVersionLabel* version_label); + + // Validates and updates |destination_connection_id_length| and + // |source_connection_id_length|. + static bool ProcessAndValidateIetfConnectionIdLength( + QuicDataReader* reader, + ParsedQuicVersion version, + bool should_update_expected_server_connection_id_length, + uint8_t* expected_server_connection_id_length, + uint8_t* destination_connection_id_length, + uint8_t* source_connection_id_length, + std::string* detailed_error); + bool ProcessIetfHeaderTypeByte(QuicDataReader* reader, QuicPacketHeader* header); bool ProcessIetfPacketHeader(QuicDataReader* reader, @@ -721,14 +823,6 @@ class QUIC_EXPORT_PRIVATE QuicFramer { static AckFrameInfo GetAckFrameInfo(const QuicAckFrame& frame); - static bool AppendIetfConnectionId( - bool version_flag, - QuicConnectionId destination_connection_id, - QuicConnectionIdLength destination_connection_id_length, - QuicConnectionId source_connection_id, - QuicConnectionIdLength source_connection_id_length, - QuicDataWriter* writer); - // The Append* methods attempt to write the provided header or frame using the // |writer|, and return true if successful. @@ -809,10 +903,10 @@ class QUIC_EXPORT_PRIVATE QuicFramer { bool ProcessMaxStreamDataFrame(QuicDataReader* reader, QuicWindowUpdateFrame* frame); - bool AppendMaxStreamsFrame(const QuicMaxStreamIdFrame& frame, + bool AppendMaxStreamsFrame(const QuicMaxStreamsFrame& frame, QuicDataWriter* writer); bool ProcessMaxStreamsFrame(QuicDataReader* reader, - QuicMaxStreamIdFrame* frame, + QuicMaxStreamsFrame* frame, uint64_t frame_type); bool AppendIetfBlockedFrame(const QuicBlockedFrame& frame, @@ -824,10 +918,10 @@ class QUIC_EXPORT_PRIVATE QuicFramer { bool ProcessStreamBlockedFrame(QuicDataReader* reader, QuicBlockedFrame* frame); - bool AppendStreamsBlockedFrame(const QuicStreamIdBlockedFrame& frame, + bool AppendStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame, QuicDataWriter* writer); bool ProcessStreamsBlockedFrame(QuicDataReader* reader, - QuicStreamIdBlockedFrame* frame, + QuicStreamsBlockedFrame* frame, uint64_t frame_type); bool AppendNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame, @@ -867,9 +961,11 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Largest successfully decrypted packet number per packet number space. Only // used when supports_multiple_packet_number_spaces_ is true. QuicPacketNumber largest_decrypted_packet_numbers_[NUM_PACKET_NUMBER_SPACES]; - // Updated by WritePacketHeader. - QuicConnectionId last_serialized_connection_id_; + // Last server connection ID seen on the wire. + QuicConnectionId last_serialized_server_connection_id_; // The last QUIC version label received. + // TODO(fayang): Remove this when deprecating + // quic_no_framer_object_in_dispatcher. QuicVersionLabel last_version_label_; // Version of the protocol being used. ParsedQuicVersion version_; @@ -924,14 +1020,21 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // encode its length. This variable contains the length we expect to read. // This is also used to validate the long header connection ID lengths in // older versions of QUIC. - uint8_t expected_connection_id_length_; + uint8_t expected_server_connection_id_length_; - // When this is true, QuicFramer will change expected_connection_id_length_ - // to the received destination connection ID length of all IETF long headers. - bool should_update_expected_connection_id_length_; + // When this is true, QuicFramer will change + // expected_server_connection_id_length_ to the received destination + // connection ID length of all IETF long headers. + // TODO(fayang): Remove this when deprecating + // quic_no_framer_object_in_dispatcher. + bool should_update_expected_server_connection_id_length_; // Indicates whether this framer supports multiple packet number spaces. bool supports_multiple_packet_number_spaces_; + + // The length in bytes of the last packet number written to an IETF-framed + // packet. + size_t last_written_packet_number_length_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc index 2ffe54e02d2..13e448260c4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc @@ -198,6 +198,16 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { QuicMakeUnique<QuicVersionNegotiationPacket>((packet)); } + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override { + retry_original_connection_id_ = + QuicMakeUnique<QuicConnectionId>(original_connection_id); + retry_new_connection_id_ = + QuicMakeUnique<QuicConnectionId>(new_connection_id); + retry_token_ = QuicMakeUnique<std::string>(std::string(retry_token)); + } + bool OnProtocolVersionMismatch(ParsedQuicVersion received_version, PacketHeaderFormat /*form*/) override { QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: " @@ -335,13 +345,13 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { return true; } - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override { - max_stream_id_frame_ = frame; + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override { + max_streams_frame_ = frame; return true; } - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override { - stream_id_blocked_frame_ = frame; + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override { + streams_blocked_frame_ = frame; return true; } @@ -394,6 +404,9 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { std::unique_ptr<QuicPublicResetPacket> public_reset_packet_; std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_; std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_; + std::unique_ptr<QuicConnectionId> retry_original_connection_id_; + std::unique_ptr<QuicConnectionId> retry_new_connection_id_; + std::unique_ptr<std::string> retry_token_; std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_; std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_; std::vector<std::unique_ptr<QuicAckFrame>> ack_frames_; @@ -410,8 +423,8 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { QuicPathResponseFrame path_response_frame_; QuicWindowUpdateFrame window_update_frame_; QuicBlockedFrame blocked_frame_; - QuicStreamIdBlockedFrame stream_id_blocked_frame_; - QuicMaxStreamIdFrame max_stream_id_frame_; + QuicStreamsBlockedFrame streams_blocked_frame_; + QuicMaxStreamsFrame max_streams_frame_; QuicNewConnectionIdFrame new_connection_id_; QuicRetireConnectionIdFrame retire_connection_id_; QuicNewTokenFrame new_token_; @@ -430,7 +443,7 @@ using PacketFragments = std::vector<struct PacketFragment>; ParsedQuicVersionVector AllSupportedVersionsIncludingTls() { QuicFlagSaver flags; - SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); return AllSupportedVersions(); } @@ -445,7 +458,7 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { start_, Perspective::IS_SERVER, kQuicDefaultConnectionIdLength) { - SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); framer_.set_version(version_); if (framer_.version().KnowsWhichDecrypterToUse()) { framer_.InstallDecrypter(ENCRYPTION_INITIAL, @@ -900,6 +913,22 @@ TEST_P(QuicFramerTest, PacketHeader) { EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); + + PacketHeaderFormat format; + bool version_flag; + uint8_t destination_connection_id_length; + QuicConnectionId destination_connection_id; + QuicVersionLabel version_label; + std::string detailed_error; + EXPECT_EQ(QUIC_NO_ERROR, QuicFramer::ProcessPacketDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, + &format, &version_flag, &version_label, + &destination_connection_id_length, + &destination_connection_id, &detailed_error)); + EXPECT_EQ(GOOGLE_QUIC_PACKET, format); + EXPECT_FALSE(version_flag); + EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id_length); + EXPECT_EQ(FramerTestConnectionId(), destination_connection_id); } TEST_P(QuicFramerTest, LongPacketHeader) { @@ -962,12 +991,28 @@ TEST_P(QuicFramerTest, LongPacketHeader) { CheckFramingBoundaries( framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44, QUIC_INVALID_PACKET_HEADER); + + PacketHeaderFormat format; + bool version_flag; + uint8_t destination_connection_id_length; + QuicConnectionId destination_connection_id; + QuicVersionLabel version_label; + std::string detailed_error; + EXPECT_EQ(QUIC_NO_ERROR, QuicFramer::ProcessPacketDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, + &format, &version_flag, &version_label, + &destination_connection_id_length, + &destination_connection_id, &detailed_error)); + EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); + EXPECT_TRUE(version_flag); + EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id_length); + EXPECT_EQ(FramerTestConnectionId(), destination_connection_id); } TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); - QuicFramerPeer::SetLastSerializedConnectionId(&framer_, - FramerTestConnectionId()); + QuicFramerPeer::SetLastSerializedServerConnectionId(&framer_, + FramerTestConnectionId()); QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); // clang-format off @@ -1000,19 +1045,36 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { {"Unable to read packet number.", {0x12, 0x34, 0x56, 0x78}}, }; + + PacketFragments packet_hp = { + // type (short header, 4 byte packet number) + {"Unable to read type.", + {0x43}}, + // connection_id + // packet number + {"", + {0x12, 0x34, 0x56, 0x78}}, + }; // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_44 - ? packet46 - : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); + framer_.version().HasHeaderProtection() + ? packet_hp + : framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_EQ(FramerTestConnectionId(), - visitor_.header_->destination_connection_id); + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + EXPECT_EQ(FramerTestConnectionId(), + visitor_.header_->destination_connection_id); + } else { + EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->source_connection_id); + } EXPECT_FALSE(visitor_.header_->reset_flag); EXPECT_FALSE(visitor_.header_->version_flag); EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); @@ -1160,12 +1222,27 @@ TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) { {"Unable to read packet number.", {0x12, 0x34, 0x56, 0x78}}, }; + + PacketFragments packet_hp = { + // type (short header, 4 byte packet number) + {"Unable to read type.", + {0x43}}, + // connection_id + {"Unable to read Destination ConnectionId.", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x56, 0x78}}, + }; // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_44 - ? packet46 - : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); + framer_.version().HasHeaderProtection() + ? packet_hp + : framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); @@ -1220,16 +1297,38 @@ TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) { {"Unable to read packet number.", {0x56, 0x78}}, }; + + PacketFragments packet_hp = { + // type (short header, 2 byte packet number) + {"Unable to read type.", + {0x41}}, + // connection_id + {"Unable to read Destination ConnectionId.", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x56, 0x78}}, + // padding + {"", {0x00, 0x00}}, + }; // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_44 - ? packet46 - : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); + framer_.version().HasHeaderProtection() + ? packet_hp + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); - EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + if (framer_.version().HasHeaderProtection()) { + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + } else { + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + } ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->destination_connection_id); @@ -1282,16 +1381,38 @@ TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) { {0x78}}, }; + PacketFragments packet_hp = { + // type (8 byte connection_id and 1 byte packet number) + {"Unable to read type.", + {0x40}}, + // connection_id + {"Unable to read Destination ConnectionId.", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x78}}, + // padding + {"", {0x00, 0x00, 0x00}}, + }; + // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_44 - ? packet46 - : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); + framer_.version().HasHeaderProtection() + ? packet_hp + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); - EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + if (framer_.version().HasHeaderProtection()) { + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + } else { + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + } ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(FramerTestConnectionId(), visitor_.header_->destination_connection_id); @@ -1523,20 +1644,41 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char packet45[] = { + // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) + 0xD3, + // version tag + 'Q', '0', '0', '0', + // connection_id length + 0x50, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; // clang-format on - QuicEncryptedPacket encrypted( - AsChars(framer_.transport_version() > QUIC_VERSION_43 ? packet44 - : packet), - framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) - : QUIC_ARRAYSIZE(packet), - false); + unsigned char* p = packet; + size_t p_size = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet45; + p_size = QUIC_ARRAYSIZE(packet45); + } else if (framer_.transport_version() > QUIC_VERSION_43) { + p = packet44; + p_size = QUIC_ARRAYSIZE(packet44); + } + QuicEncryptedPacket encrypted(AsChars(p), p_size, false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(0, visitor_.frame_count_); EXPECT_EQ(1, visitor_.version_mismatch_); - EXPECT_EQ(1u, visitor_.padding_frames_.size()); + ASSERT_EQ(1u, visitor_.padding_frames_.size()); EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); } @@ -1984,7 +2126,10 @@ TEST_P(QuicFramerTest, MissingDiversificationNonce) { } QuicEncryptedPacket encrypted(AsChars(p), p_length, false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - if (framer_.transport_version() >= QUIC_VERSION_44) { + if (framer_.version().HasHeaderProtection()) { + EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); + EXPECT_EQ("Unable to decrypt header protection.", framer_.detailed_error()); + } else if (framer_.transport_version() >= QUIC_VERSION_44) { // Cannot read diversification nonce. EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); EXPECT_EQ("Unable to read nonce.", framer_.detailed_error()); @@ -3252,6 +3397,7 @@ TEST_P(QuicFramerTest, AckFrameFirstAckBlockLengthZero) { // not arise. return; } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); // clang-format off PacketFragments packet = { @@ -3833,6 +3979,7 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) { } TEST_P(QuicFramerTest, AckFrameTimeStampDeltaTooHigh) { + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) @@ -3924,6 +4071,7 @@ TEST_P(QuicFramerTest, AckFrameTimeStampDeltaTooHigh) { } TEST_P(QuicFramerTest, AckFrameTimeStampSecondDeltaTooHigh) { + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) @@ -4030,6 +4178,7 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) { if (version_.transport_version == QUIC_VERSION_99) { return; } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); // clang-format off PacketFragments packet = { // public flags (8 byte connection_id) @@ -4093,6 +4242,15 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) { std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); + if (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) && + version_.transport_version >= QUIC_VERSION_44) { + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_INVALID_STOP_WAITING_DATA, framer_.error()); + EXPECT_EQ("STOP WAITING not supported in version 44+.", + framer_.detailed_error()); + return; + } + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -4110,9 +4268,12 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) { } TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) { - if (version_.transport_version == QUIC_VERSION_99) { + if (version_.transport_version == QUIC_VERSION_99 || + (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) && + version_.transport_version >= QUIC_VERSION_44)) { return; } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) @@ -4509,6 +4670,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) { // This frame is not supported in version 99. return; } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); // clang-format off PacketFragments packet = { // public flags (8 byte connection_id) @@ -4634,6 +4796,7 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) { // for Version 99 equivalents. return; } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); // clang-format off PacketFragments packet = { // public flags (8 byte connection_id) @@ -5367,7 +5530,7 @@ TEST_P(QuicFramerTest, IetfStatelessResetPacketInvalidStatelessResetToken) { ASSERT_FALSE(visitor_.stateless_reset_packet_); } -TEST_P(QuicFramerTest, VersionNegotiationPacket) { +TEST_P(QuicFramerTest, VersionNegotiationPacketClient) { // clang-format off PacketFragments packet = { // public flags (version, 8 byte connection_id) @@ -5422,6 +5585,39 @@ TEST_P(QuicFramerTest, VersionNegotiationPacket) { CheckFramingBoundaries(fragments, QUIC_INVALID_VERSION_NEGOTIATION_PACKET); } +TEST_P(QuicFramerTest, VersionNegotiationPacketServer) { + if (!GetQuicRestartFlag(quic_server_drop_version_negotiation)) { + return; + } + if (framer_.transport_version() < QUIC_VERSION_44) { + return; + } + + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); + // clang-format off + unsigned char packet[] = { + // public flags (long header with all ignored bits set) + 0xFF, + // version + 0x00, 0x00, 0x00, 0x00, + // connection ID lengths + 0x50, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // supported versions + QUIC_VERSION_BYTES, + 'Q', '2', '.', '0', + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, framer_.error()); + EXPECT_EQ("Server received version negotiation packet.", + framer_.detailed_error()); + EXPECT_FALSE(visitor_.version_negotiation_packet_.get()); +} + TEST_P(QuicFramerTest, OldVersionNegotiationPacket) { // clang-format off PacketFragments packet = { @@ -5461,7 +5657,80 @@ TEST_P(QuicFramerTest, OldVersionNegotiationPacket) { CheckFramingBoundaries(packet, QUIC_INVALID_VERSION_NEGOTIATION_PACKET); } +TEST_P(QuicFramerTest, ParseIetfRetryPacket) { + if (!framer_.version().SupportsRetry()) { + return; + } + // IETF RETRY is only sent from client to server. + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + // clang-format off + unsigned char packet[] = { + // public flags (long header with packet type RETRY and ODCIL=8) + 0xF5, + // version + QUIC_VERSION_BYTES, + // connection ID lengths + 0x05, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // original destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // retry token + 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's', + ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!', + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + + ASSERT_TRUE(visitor_.retry_original_connection_id_.get()); + ASSERT_TRUE(visitor_.retry_new_connection_id_.get()); + ASSERT_TRUE(visitor_.retry_token_.get()); + + EXPECT_EQ(FramerTestConnectionId(), + *visitor_.retry_original_connection_id_.get()); + EXPECT_EQ(FramerTestConnectionIdPlusOne(), + *visitor_.retry_new_connection_id_.get()); + EXPECT_EQ("Hello this is RETRY!", *visitor_.retry_token_.get()); +} + +TEST_P(QuicFramerTest, RejectIetfRetryPacketAsServer) { + if (!framer_.version().SupportsRetry()) { + return; + } + // IETF RETRY is only sent from client to server. + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); + // clang-format off + unsigned char packet[] = { + // public flags (long header with packet type RETRY and ODCIL=8) + 0xF5, + // version + QUIC_VERSION_BYTES, + // connection ID lengths + 0x05, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // original destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // retry token + 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's', + ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!', + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_EQ("Client-initiated RETRY is invalid.", framer_.detailed_error()); +} + TEST_P(QuicFramerTest, BuildPaddingFramePacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -5473,7 +5742,7 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) { // clang-format off unsigned char packet[kMaxOutgoingPacketSize] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -5550,6 +5819,7 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) { } TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -5564,7 +5834,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -5693,6 +5963,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { } TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -5705,7 +5976,7 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { // clang-format off unsigned char packet[kMaxOutgoingPacketSize] = { // public flags (8 byte connection_id and 4 byte packet number) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -5782,6 +6053,7 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { } TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -5794,7 +6066,7 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { // clang-format off unsigned char packet[kMaxOutgoingPacketSize] = { // public flags (8 byte connection_id and 2 byte packet number) - 0x18, + 0x1C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -5871,6 +6143,7 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { } TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -5883,7 +6156,7 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { // clang-format off unsigned char packet[kMaxOutgoingPacketSize] = { // public flags (8 byte connection_id and 1 byte packet number) - 0x08, + 0x0C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -5960,6 +6233,7 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { } TEST_P(QuicFramerTest, BuildStreamFramePacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -5977,7 +6251,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -6211,6 +6485,7 @@ TEST_P(QuicFramerTest, BuildCryptoFramePacket) { // CRYPTO frames aren't supported prior to v46. return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -6324,9 +6599,13 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { // version tag QUIC_VERSION_BYTES, }; + unsigned char type44 = 0x80; + if (GetQuicReloadableFlag(quic_send_version_negotiation_fixed_bit)) { + type44 = 0xC0; + } unsigned char packet44[] = { // type (long header) - 0x80, + type44, // version tag 0x00, 0x00, 0x00, 0x00, // connection_id length @@ -6346,14 +6625,57 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { QuicConnectionId connection_id = FramerTestConnectionId(); std::unique_ptr<QuicEncryptedPacket> data( - framer_.BuildVersionNegotiationPacket( - connection_id, framer_.transport_version() > QUIC_VERSION_43, + QuicFramer::BuildVersionNegotiationPacket( + connection_id, EmptyQuicConnectionId(), + framer_.transport_version() > QUIC_VERSION_43, SupportedVersions(GetParam()))); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), p_size); } +TEST_P(QuicFramerTest, BuildVersionNegotiationPacketWithClientConnectionId) { + if (framer_.transport_version() <= QUIC_VERSION_43) { + // The GQUIC encoding does not support encoding client connection IDs. + return; + } + + // Client connection IDs cannot be used unless this flag is true. + SetQuicRestartFlag(quic_do_not_override_connection_id, true); + + unsigned char type_byte = 0x80; + if (GetQuicReloadableFlag(quic_send_version_negotiation_fixed_bit)) { + type_byte = 0xC0; + } + // clang-format off + unsigned char packet[] = { + // type (long header) + type_byte, + // version tag + 0x00, 0x00, 0x00, 0x00, + // connection ID lengths + 0x55, + // client/destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // server/source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // version tag + QUIC_VERSION_BYTES, + }; + // clang-format on + + QuicConnectionId server_connection_id = FramerTestConnectionId(); + QuicConnectionId client_connection_id = FramerTestConnectionIdPlusOne(); + std::unique_ptr<QuicEncryptedPacket> data( + QuicFramer::BuildVersionNegotiationPacket(server_connection_id, + client_connection_id, true, + SupportedVersions(GetParam()))); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + QUIC_ARRAYSIZE(packet)); +} + TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -6369,7 +6691,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -6470,6 +6792,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) { } TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -6484,7 +6807,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -6586,6 +6909,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) { } TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -6605,7 +6929,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -6776,6 +7100,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) { } TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -6797,7 +7122,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -7183,6 +7508,7 @@ TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) { if (version_.transport_version > QUIC_VERSION_43) { return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -7197,7 +7523,7 @@ TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -7220,6 +7546,7 @@ TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) { } TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -7238,7 +7565,7 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -7336,6 +7663,7 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { } TEST_P(QuicFramerTest, BuildCloseFramePacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -7358,7 +7686,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -7464,6 +7792,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { } TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -7484,7 +7813,7 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -7706,6 +8035,7 @@ TEST_P(QuicFramerTest, BuildApplicationCloseFramePacket) { // Versions other than 99 do not have ApplicationClose return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -7756,6 +8086,7 @@ TEST_P(QuicFramerTest, BuildTruncatedApplicationCloseFramePacket) { // Versions other than 99 do not have this frame. return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -7833,6 +8164,7 @@ TEST_P(QuicFramerTest, BuildGoAwayPacket) { // This frame type is not supported in version 99. return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -7849,7 +8181,7 @@ TEST_P(QuicFramerTest, BuildGoAwayPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -7940,6 +8272,7 @@ TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) { // This frame type is not supported in version 99. return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -7956,7 +8289,7 @@ TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -8126,6 +8459,7 @@ TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) { } TEST_P(QuicFramerTest, BuildWindowUpdatePacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -8141,7 +8475,7 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -8233,6 +8567,7 @@ TEST_P(QuicFramerTest, BuildMaxStreamDataPacket) { // This frame is available only in this version. return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -8277,6 +8612,7 @@ TEST_P(QuicFramerTest, BuildMaxDataPacket) { // This frame is available only in this version. return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -8316,6 +8652,7 @@ TEST_P(QuicFramerTest, BuildMaxDataPacket) { } TEST_P(QuicFramerTest, BuildBlockedPacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -8339,7 +8676,7 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -8415,6 +8752,7 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) { } TEST_P(QuicFramerTest, BuildPingPacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -8426,7 +8764,7 @@ TEST_P(QuicFramerTest, BuildPingPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -8495,6 +8833,7 @@ TEST_P(QuicFramerTest, BuildMessagePacket) { if (framer_.transport_version() <= QUIC_VERSION_44) { return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -8586,6 +8925,7 @@ TEST_P(QuicFramerTest, BuildMessagePacket) { // Test that the connectivity probing packet is serialized correctly as a // padded PING packet. TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -8595,7 +8935,7 @@ TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -8933,6 +9273,7 @@ TEST_P(QuicFramerTest, BuildPathResponsePacket3ResponsesPadded) { // Test that the MTU discovery packet is serialized correctly as a PING packet. TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -8944,7 +9285,7 @@ TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x28, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number @@ -9268,12 +9609,15 @@ TEST_P(QuicFramerTest, EncryptPacket) { 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', }; // clang-format on unsigned char* p = packet; + size_t p_size = QUIC_ARRAYSIZE(packet); if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); } else if (framer_.transport_version() > QUIC_VERSION_44) { p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { @@ -9281,7 +9625,7 @@ TEST_P(QuicFramerTest, EncryptPacket) { } std::unique_ptr<QuicPacket> raw(new QuicPacket( - AsChars(p), QUIC_ARRAYSIZE(packet), false, PACKET_8BYTE_CONNECTION_ID, + AsChars(p), p_size, false, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0)); @@ -9294,6 +9638,7 @@ TEST_P(QuicFramerTest, EncryptPacket) { } TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketNumber packet_number = kPacketNumber; // clang-format off unsigned char packet[] = { @@ -9368,26 +9713,28 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', }; // clang-format on unsigned char* p = packet; + size_t p_size = QUIC_ARRAYSIZE(packet); if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); } else if (framer_.transport_version() > QUIC_VERSION_44) { p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; + p_size = QUIC_ARRAYSIZE(packet44); } std::unique_ptr<QuicPacket> raw(new QuicPacket( - AsChars(p), - framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) - : QUIC_ARRAYSIZE(packet), - false, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, - kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_4BYTE_PACKET_NUMBER, VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, - VARIABLE_LENGTH_INTEGER_LENGTH_0)); + AsChars(p), p_size, false, PACKET_8BYTE_CONNECTION_ID, + PACKET_0BYTE_CONNECTION_ID, kIncludeVersion, + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0)); char buffer[kMaxOutgoingPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_INITIAL, packet_number, *raw, buffer, kMaxOutgoingPacketSize); @@ -9402,6 +9749,7 @@ TEST_P(QuicFramerTest, AckTruncationLargePacket) { // effectively unlimited return; } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); @@ -9441,6 +9789,7 @@ TEST_P(QuicFramerTest, AckTruncationSmallPacket) { // effectively unlimited return; } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); @@ -9481,6 +9830,7 @@ TEST_P(QuicFramerTest, CleanTruncation) { // effectively unlimited return; } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); @@ -9704,7 +10054,7 @@ static char kTestString[] = "At least 20 characters."; static QuicStreamId kTestQuicStreamId = 1; static bool ExpectedStreamFrame(const QuicStreamFrame& frame) { return (frame.stream_id == kTestQuicStreamId || - frame.stream_id == QuicUtils::GetCryptoStreamId(QUIC_VERSION_99)) && + QuicUtils::IsCryptoStreamId(QUIC_VERSION_99, frame.stream_id)) && !frame.fin && frame.offset == 0 && std::string(frame.data_buffer, frame.data_length) == kTestString; // FIN is hard-coded false in ConstructEncryptedPacket. @@ -9758,12 +10108,12 @@ TEST_P(QuicFramerTest, ConstructEncryptedPacket) { // Verify that the packet returned by ConstructMisFramedEncryptedPacket() // does cause the framer to return an error. TEST_P(QuicFramerTest, ConstructMisFramedEncryptedPacket) { - SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); // Since we are using ConstructEncryptedPacket, we have to set the framer's // crypto to be Null. if (framer_.version().KnowsWhichDecrypterToUse()) { - framer_.InstallDecrypter(ENCRYPTION_INITIAL, QuicMakeUnique<NullDecrypter>( - framer_.perspective())); + framer_.InstallDecrypter( + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<NullDecrypter>(framer_.perspective())); } else { framer_.SetDecrypter(ENCRYPTION_INITIAL, QuicMakeUnique<NullDecrypter>(framer_.perspective())); @@ -10106,7 +10456,7 @@ TEST_P(QuicFramerTest, BuildIetfStreamBlockedPacket) { QUIC_ARRAYSIZE(packet99)); } -TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrame) { +TEST_P(QuicFramerTest, BiDiMaxStreamsFrame) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -10143,18 +10493,12 @@ TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrame) { *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a server receiving a MAX_STREAMS frame. The - // stream ID that it generates should be a server-initiated - // stream ID. The expected Stream ID is - // ((0x3-1) * 4) | 0x1 = 0x9 - // count-to-id server inited, bidi - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/true, 3), - visitor_.max_stream_id_frame_.max_stream_id); - CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); + EXPECT_EQ(3u, visitor_.max_streams_frame_.stream_count); + EXPECT_FALSE(visitor_.max_streams_frame_.unidirectional); + CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA); } -TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrame) { +TEST_P(QuicFramerTest, UniDiMaxStreamsFrame) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -10170,9 +10514,9 @@ TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrame) { // packet number {"", {0x12, 0x34, 0x9A, 0xBC}}, - // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) + // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL) {"", - {0x12}}, + {0x13}}, // max. streams {"Can not read MAX_STREAMS stream count.", {kVarInt62OneByte + 0x03}}, @@ -10190,19 +10534,9 @@ TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrame) { *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a client receiving a MAX_STREAMS frame. The - // stream ID that it generates should be a client-initiated - // stream ID. The expected Stream ID is - // ((0x3-1) * 4) = 0xc - // It is not 8 because a client-initiated, bidi stream ID's - // low bits are 00 - which means that the old crypto stream - // falls into this category, and the first stream is streamid=4, - // not streamid=0. - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/true, 3), - visitor_.max_stream_id_frame_.max_stream_id); - - CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); + EXPECT_EQ(3u, visitor_.max_streams_frame_.stream_count); + EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional); + CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA); } TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) { @@ -10242,16 +10576,9 @@ TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) { *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a server receiving a MAX_STREAMS frame. The - // stream ID that it generates should be a server-initiated - // stream ID. The expected Stream ID is - // ((0x3-1) * 4) | 0x1 | 0x2 = 0xb - // count-to-id server inited, unidi - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/false, 3), - visitor_.max_stream_id_frame_.max_stream_id); - - CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); + EXPECT_EQ(3u, visitor_.max_streams_frame_.stream_count); + EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional); + CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA); } TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) { @@ -10290,16 +10617,9 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) { *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a client receiving a MAX_STREAMS frame. The - // stream ID that it generates should be a client-initiated - // stream ID. The expected Stream ID is - // ((0x3-1) * 4) | 0x02= 0xa - // count-to-id client/unidi - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/false, 3), - visitor_.max_stream_id_frame_.max_stream_id); - - CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); + EXPECT_EQ(3u, visitor_.max_streams_frame_.stream_count); + EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional); + CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA); } // The following four tests ensure that the framer can deserialize a stream @@ -10308,7 +10628,7 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) { // the stream limit is pegged to the maximum supported value. There are four // tests, for the four combinations of uni- and bi-directional, server- and // client- initiated. -TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrameTooBig) { +TEST_P(QuicFramerTest, BiDiMaxStreamsFrameTooBig) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -10342,14 +10662,8 @@ TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrameTooBig) { encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a server receiving a MAX_STREAMS frame. The - // stream ID that it generates should be a server-initiated - // stream ID. The expected Stream ID is - // 0xfffffffc | 0x01 --> 0xfffffffd - // maxid server inited, bidi - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/true, 0x40000000), - visitor_.max_stream_id_frame_.max_stream_id); + EXPECT_EQ(0x40000000u, visitor_.max_streams_frame_.stream_count); + EXPECT_FALSE(visitor_.max_streams_frame_.unidirectional); } TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrameTooBig) { @@ -10387,19 +10701,8 @@ TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrameTooBig) { encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a client receiving a MAX_STREAMS frame. The - // stream ID that it generates should be a client-initiated - // stream ID. The expected Stream ID is - // 0xfffffffc --> 0xfffffffc - // max id bidi/client-inited - // TODO(fkastenholz): Change -2 to -1 when stream id 0 is no longer - // special. - // Subtract 1 because client/bidi stream ids start counting at - // 4, not 0. If we didn;t subtract 1, the resulting math would wrap to stream - // id 0, not 0xfffffffc. - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/true, (0x40000000 - 1)), - visitor_.max_stream_id_frame_.max_stream_id); + EXPECT_EQ(0x40000000u, visitor_.max_streams_frame_.stream_count); + EXPECT_FALSE(visitor_.max_streams_frame_.unidirectional); } TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrameTooBig) { @@ -10437,14 +10740,8 @@ TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrameTooBig) { encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a server receiving a MAX_STREAMS frame. The - // stream ID that it generates should be a server-initiated - // stream ID. The expected Stream ID is - // 0xfffffffc | 0x1 | 0x2 = 0xffffffff - // maxid server inited, unidi - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/false, 0x40000000), - visitor_.max_stream_id_frame_.max_stream_id); + EXPECT_EQ(0x40000000u, visitor_.max_streams_frame_.stream_count); + EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional); } TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrameTooBig) { @@ -10482,19 +10779,11 @@ TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrameTooBig) { encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a client receiving a MAX_STREAMS frame. The - // stream ID that it generates should be a client-initiated - // stream ID. The expected Stream ID is - // 0xfffffffc | 0x02= 0xfffffffe - // maxid client/unidi - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/false, 0x40000000), - visitor_.max_stream_id_frame_.max_stream_id); + EXPECT_EQ(0x40000000u, visitor_.max_streams_frame_.stream_count); + EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional); } -// Check that a stream count of 0 is rejected. -// Directionality and intiation are not important for -// this test. +// Specifically test that count==0 is accepted. TEST_P(QuicFramerTest, MaxStreamsFrameZeroCount) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { @@ -10519,10 +10808,7 @@ TEST_P(QuicFramerTest, MaxStreamsFrameZeroCount) { QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), false); - EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_MAX_STREAM_ID_DATA, framer_.error()); - EXPECT_EQ(framer_.detailed_error(), - "MAX_STREAMS stream count of 0 not supported."); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); } TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) { @@ -10543,12 +10829,12 @@ TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) { // packet number {"", {0x12, 0x34, 0x9A, 0xBC}}, - // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame) + // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL frame) {"", - {0x16}}, - // stream id - {"Can not read STREAMS_BLOCKED stream id.", - {kVarInt62OneByte + 0x03}}, + {0x13}}, + // stream count + {"Can not read MAX_STREAMS stream count.", + {kVarInt62OneByte + 0x00}}, }; // clang-format on @@ -10562,23 +10848,13 @@ TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) { *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a server receiving a STREAMS_BLOCKED frame. The - // stream ID that it generates should be a client-initiated - // stream ID. The expected Stream ID is - // ((0x3-1) * 4) = 0xc - // count-to-id client inited, bidi - // It is not 8 because a client-initiated, bidi stream ID's - // low bits are 00 - which means that the old crypto stream - // falls into this category, and the first stream is streamid=4, - // not streamid=0. - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/true, 3), - visitor_.stream_id_blocked_frame_.stream_id); + EXPECT_EQ(0u, visitor_.max_streams_frame_.stream_count); + EXPECT_TRUE(visitor_.max_streams_frame_.unidirectional); - CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); + CheckFramingBoundaries(packet99, QUIC_MAX_STREAMS_DATA); } -TEST_P(QuicFramerTest, ClientBiDiStreamsBlockedFrame) { +TEST_P(QuicFramerTest, BiDiStreamsBlockedFrame) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -10590,7 +10866,9 @@ TEST_P(QuicFramerTest, ClientBiDiStreamsBlockedFrame) { // type (short header, 4 byte packet number) {"", {0x43}}, - // Test runs in client mode, no connection id + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", {0x12, 0x34, 0x9A, 0xBC}}, @@ -10598,35 +10876,28 @@ TEST_P(QuicFramerTest, ClientBiDiStreamsBlockedFrame) { {"", {0x16}}, // stream id - {"Can not read STREAMS_BLOCKED stream id.", + {"Can not read STREAMS_BLOCKED stream count.", {kVarInt62OneByte + 0x03}}, }; // clang-format on std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(packet99)); - QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a client receiving a STREAMS_BLOCKED frame. The - // stream ID that it generates should be a server-initiated - // stream ID. The expected Stream ID is - // ((0x3-1) * 4) | 0x01 = 0x9 - // count-to-id server inited, bidi - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/true, 3), - visitor_.stream_id_blocked_frame_.stream_id); + EXPECT_EQ(3u, visitor_.streams_blocked_frame_.stream_count); + EXPECT_FALSE(visitor_.streams_blocked_frame_.unidirectional); - CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); + CheckFramingBoundaries(packet99, QUIC_STREAMS_BLOCKED_DATA); } -TEST_P(QuicFramerTest, ServerUniDiStreamsBlockedFrame) { +TEST_P(QuicFramerTest, UniDiStreamsBlockedFrame) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -10648,7 +10919,7 @@ TEST_P(QuicFramerTest, ServerUniDiStreamsBlockedFrame) { {"", {0x17}}, // stream id - {"Can not read STREAMS_BLOCKED stream id.", + {"Can not read STREAMS_BLOCKED stream count.", {kVarInt62OneByte + 0x03}}, }; // clang-format on @@ -10663,16 +10934,9 @@ TEST_P(QuicFramerTest, ServerUniDiStreamsBlockedFrame) { *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a server receiving a STREAMS_BLOCKED frame. The - // stream ID that it generates should be a client-initiated - // stream ID. The expected Stream ID is - // ((0x3-1) * 4) | 0x2 = 0xa - // count-to-id client inited, unidi - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/false, 3), - visitor_.stream_id_blocked_frame_.stream_id); - - CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); + EXPECT_EQ(3u, visitor_.streams_blocked_frame_.stream_count); + EXPECT_TRUE(visitor_.streams_blocked_frame_.unidirectional); + CheckFramingBoundaries(packet99, QUIC_STREAMS_BLOCKED_DATA); } TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) { @@ -10695,7 +10959,7 @@ TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) { {"", {0x17}}, // stream id - {"Can not read STREAMS_BLOCKED stream id.", + {"Can not read STREAMS_BLOCKED stream count.", {kVarInt62OneByte + 0x03}}, }; // clang-format on @@ -10711,16 +10975,9 @@ TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) { *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - // This test is a client receiving a STREAMS_BLOCKED frame. The - // stream ID that it generates should be a server-initiated - // stream ID. The expected Stream ID is - // ((0x3-1) * 4) | 0x01 | 0x2 = 0xb - // count-to-id server inited, bidi - EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/false, 3), - visitor_.stream_id_blocked_frame_.stream_id); - - CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); + EXPECT_EQ(3u, visitor_.streams_blocked_frame_.stream_count); + EXPECT_TRUE(visitor_.streams_blocked_frame_.unidirectional); + CheckFramingBoundaries(packet99, QUIC_STREAMS_BLOCKED_DATA); } // Check that when we get a STREAMS_BLOCKED frame that specifies too large @@ -10742,7 +10999,7 @@ TEST_P(QuicFramerTest, StreamsBlockedFrameTooBig) { // packet number 0x12, 0x34, 0x9A, 0xBC, // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL) - 0x17, + 0x16, // max. streams. Max stream ID allowed is 0xffffffff // This encodes a count of 0x40000000, leading to stream @@ -10756,111 +11013,72 @@ TEST_P(QuicFramerTest, StreamsBlockedFrameTooBig) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_STREAM_ID_BLOCKED_DATA, framer_.error()); + EXPECT_EQ(QUIC_STREAMS_BLOCKED_DATA, framer_.error()); EXPECT_EQ(framer_.detailed_error(), "STREAMS_BLOCKED stream count exceeds implementation limit."); } -// Test that count==0 is rejected. +// Specifically test that count==0 is accepted. TEST_P(QuicFramerTest, StreamsBlockedFrameZeroCount) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); // clang-format off - unsigned char packet99[] = { - // type (short header, 4 byte packet number) - 0x43, - // Test runs in client mode, no connection id - // packet number - 0x12, 0x34, 0x9A, 0xBC, - // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL) - 0x17, - - // max. streams = 0 - kVarInt62OneByte + 0x00 + PacketFragments packet99 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x9A, 0xBC}}, + // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame) + {"", + {0x17}}, + // stream id + {"Can not read STREAMS_BLOCKED stream count.", + {kVarInt62OneByte + 0x00}}, }; // clang-format on - QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), - false); - QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); - EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - - EXPECT_EQ(QUIC_STREAM_ID_BLOCKED_DATA, framer_.error()); - EXPECT_EQ(framer_.detailed_error(), - "STREAMS_BLOCKED stream count 0 not supported."); -} - -TEST_P(QuicFramerTest, BuildServerBiDiStreamsBlockedPacket) { - // This test only for version 99. - if (framer_.transport_version() != QUIC_VERSION_99) { - return; - } - - QuicPacketHeader header; - header.destination_connection_id = FramerTestConnectionId(); - header.reset_flag = false; - header.version_flag = false; - header.packet_number = kPacketNumber; - - QuicStreamIdBlockedFrame frame; - // A server building a STREAMS_BLOCKED frame generates - // a server-initiated stream ID. This test is bidirectional. - // The low two bits of the stream ID are 01 - // Expected value is 0x8u | 0x1u; - frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/true, 3); - - QuicFrames frames = {QuicFrame(frame)}; - - // clang-format off - unsigned char packet99[] = { - // type (short header, 4 byte packet number) - 0x43, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number - 0x12, 0x34, 0x56, 0x78, + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet99)); + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame) - 0x16, - // Stream count - kVarInt62OneByte + 0x03 - }; - // clang-format on + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); - ASSERT_TRUE(data != nullptr); + EXPECT_EQ(0u, visitor_.streams_blocked_frame_.stream_count); + EXPECT_TRUE(visitor_.streams_blocked_frame_.unidirectional); - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet99), - QUIC_ARRAYSIZE(packet99)); + CheckFramingBoundaries(packet99, QUIC_STREAMS_BLOCKED_DATA); } -TEST_P(QuicFramerTest, BuildClientBiDiStreamsBlockedPacket) { +TEST_P(QuicFramerTest, BuildBiDiStreamsBlockedPacket) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; } - // This test runs in client mode. - QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); - QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; header.version_flag = false; header.packet_number = kPacketNumber; - QuicStreamIdBlockedFrame frame; - // A client building a STREAMS_BLOCKED frame generates - // a client-initiated stream ID. This test is bidirectional. - // The low two bits of the stream ID are 00. Expected value is 0x8 - frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/true, 3); + QuicStreamsBlockedFrame frame; + frame.stream_count = 3; + frame.unidirectional = false; + QuicFrames frames = {QuicFrame(frame)}; // clang-format off @@ -10887,7 +11105,7 @@ TEST_P(QuicFramerTest, BuildClientBiDiStreamsBlockedPacket) { QUIC_ARRAYSIZE(packet99)); } -TEST_P(QuicFramerTest, BuildServerUniStreamsBlockedPacket) { +TEST_P(QuicFramerTest, BuildUniStreamsBlockedPacket) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -10899,59 +11117,10 @@ TEST_P(QuicFramerTest, BuildServerUniStreamsBlockedPacket) { header.version_flag = false; header.packet_number = kPacketNumber; - QuicStreamIdBlockedFrame frame; - // A server building a STREAMS_BLOCKED frame generates - // a server-initiated stream ID. This test is bidirectional. - // The low two bits of the stream ID are 11. Expected value is 0xb - frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/false, 3); - QuicFrames frames = {QuicFrame(frame)}; + QuicStreamsBlockedFrame frame; + frame.stream_count = 3; + frame.unidirectional = true; - // clang-format off - unsigned char packet99[] = { - // type (short header, 4 byte packet number) - 0x43, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number - 0x12, 0x34, 0x56, 0x78, - - // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame) - 0x17, - // Stream count - kVarInt62OneByte + 0x03 - }; - // clang-format on - - std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); - ASSERT_TRUE(data != nullptr); - - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet99), - QUIC_ARRAYSIZE(packet99)); -} - -TEST_P(QuicFramerTest, BuildClientUniDiStreamsBlockedPacket) { - // This test only for version 99. - if (framer_.transport_version() != QUIC_VERSION_99) { - return; - } - - // This test runs in client mode. - QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); - - QuicPacketHeader header; - header.destination_connection_id = FramerTestConnectionId(); - header.reset_flag = false; - header.version_flag = false; - header.packet_number = kPacketNumber; - - QuicStreamIdBlockedFrame frame; - // A client building a STREAMS_BLOCKED frame generates - // a client-initiated stream ID. This test is bidirectional. - // The low two bits of the stream ID are 10. Expected value is 0xa - frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/false, 3); QuicFrames frames = {QuicFrame(frame)}; // clang-format off @@ -10978,7 +11147,7 @@ TEST_P(QuicFramerTest, BuildClientUniDiStreamsBlockedPacket) { QUIC_ARRAYSIZE(packet99)); } -TEST_P(QuicFramerTest, BuildServerBiDiMaxStreamsPacket) { +TEST_P(QuicFramerTest, BuildBiDiMaxStreamsPacket) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -10990,61 +11159,10 @@ TEST_P(QuicFramerTest, BuildServerBiDiMaxStreamsPacket) { header.version_flag = false; header.packet_number = kPacketNumber; - QuicMaxStreamIdFrame frame; - // A server building a MAX_STREAMS frame generates - // a client-initiated stream ID. This test is bidirectional. - // The low two bits of the stream ID are 00. Expected value is 0xc - // because streamid==0 is special and the first client/bidi - // stream is 4, not 0. - frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/true, 3); - QuicFrames frames = {QuicFrame(frame)}; + QuicMaxStreamsFrame frame; + frame.stream_count = 3; + frame.unidirectional = false; - // clang-format off - unsigned char packet99[] = { - // type (short header, 4 byte packet number) - 0x43, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number - 0x12, 0x34, 0x56, 0x78, - - // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL frame) - 0x12, - // Stream count - kVarInt62OneByte + 0x03 - }; - // clang-format on - - std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); - ASSERT_TRUE(data != nullptr); - - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet99), - QUIC_ARRAYSIZE(packet99)); -} - -TEST_P(QuicFramerTest, BuildClientBiDiMaxStreamsPacket) { - // This test only for version 99. - if (framer_.transport_version() != QUIC_VERSION_99) { - return; - } - - // This test runs in client mode. - QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); - - QuicPacketHeader header; - header.destination_connection_id = FramerTestConnectionId(); - header.reset_flag = false; - header.version_flag = false; - header.packet_number = kPacketNumber; - - QuicMaxStreamIdFrame frame; - // A client building a MAX_STREAMS frame generates - // a server-initiated stream ID. This test is bidirectional. - // The low two bits of the stream ID are 01. Expected value is 0x9 - frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/true, 3); QuicFrames frames = {QuicFrame(frame)}; // clang-format off @@ -11071,51 +11189,7 @@ TEST_P(QuicFramerTest, BuildClientBiDiMaxStreamsPacket) { QUIC_ARRAYSIZE(packet99)); } -TEST_P(QuicFramerTest, BuildServerUniMaxStreamsPacket) { - // This test only for version 99. - if (framer_.transport_version() != QUIC_VERSION_99) { - return; - } - - QuicPacketHeader header; - header.destination_connection_id = FramerTestConnectionId(); - header.reset_flag = false; - header.version_flag = false; - header.packet_number = kPacketNumber; - - QuicMaxStreamIdFrame frame; - // A server building a MAX_STREAMS frame generates - // a client-initiated stream ID. This test is bidirectional. - // The low two bits of the stream ID are 10. Expected value is 0xa - frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, - /*bidirectional=*/false, 3); - QuicFrames frames = {QuicFrame(frame)}; - - // clang-format off - unsigned char packet99[] = { - // type (short header, 4 byte packet number) - 0x43, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number - 0x12, 0x34, 0x56, 0x78, - - // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL frame) - 0x13, - // Stream count - kVarInt62OneByte + 0x03 - }; - // clang-format on - - std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); - ASSERT_TRUE(data != nullptr); - - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet99), - QUIC_ARRAYSIZE(packet99)); -} - -TEST_P(QuicFramerTest, BuildClientUniDiMaxStreamsPacket) { +TEST_P(QuicFramerTest, BuildUniDiMaxStreamsPacket) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -11130,12 +11204,10 @@ TEST_P(QuicFramerTest, BuildClientUniDiMaxStreamsPacket) { header.version_flag = false; header.packet_number = kPacketNumber; - QuicMaxStreamIdFrame frame; - // A client building a MAX_STREAMS frame generates - // a server-initiated stream ID. This test is bidirectional. - // The low two bits of the stream ID are 11. Expected value is 0xb - frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, - /*bidirectional=*/false, 3); + QuicMaxStreamsFrame frame; + frame.stream_count = 3; + frame.unidirectional = true; + QuicFrames frames = {QuicFrame(frame)}; // clang-format off @@ -11323,6 +11395,7 @@ TEST_P(QuicFramerTest, BuildNewConnectionIdFramePacket) { // This frame is only for version 99. return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -11423,6 +11496,7 @@ TEST_P(QuicFramerTest, BuildNewTokenFramePacket) { // This frame is only for version 99. return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -11730,9 +11804,8 @@ TEST_P(QuicFramerTest, GetRetransmittableControlFrameSize) { connection_close.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE; } - EXPECT_EQ(QuicFramer::GetMinConnectionCloseFrameSize( - framer_.transport_version(), connection_close) + - 256, + EXPECT_EQ(QuicFramer::GetConnectionCloseFrameSize(framer_.transport_version(), + connection_close), QuicFramer::GetRetransmittableControlFrameSize( framer_.transport_version(), QuicFrame(&connection_close))); @@ -11762,17 +11835,17 @@ TEST_P(QuicFramerTest, GetRetransmittableControlFrameSize) { QuicFramer::GetRetransmittableControlFrameSize( framer_.transport_version(), QuicFrame(&new_connection_id))); - QuicMaxStreamIdFrame max_stream_id(6, 3); + QuicMaxStreamsFrame max_streams(6, 3, /*unidirectional=*/false); EXPECT_EQ(QuicFramer::GetMaxStreamsFrameSize(framer_.transport_version(), - max_stream_id), + max_streams), QuicFramer::GetRetransmittableControlFrameSize( - framer_.transport_version(), QuicFrame(max_stream_id))); + framer_.transport_version(), QuicFrame(max_streams))); - QuicStreamIdBlockedFrame stream_id_blocked(7, 3); + QuicStreamsBlockedFrame streams_blocked(7, 3, /*unidirectional=*/false); EXPECT_EQ(QuicFramer::GetStreamsBlockedFrameSize(framer_.transport_version(), - stream_id_blocked), + streams_blocked), QuicFramer::GetRetransmittableControlFrameSize( - framer_.transport_version(), QuicFrame(stream_id_blocked))); + framer_.transport_version(), QuicFrame(streams_blocked))); QuicPathFrameBuffer buffer = { {0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe5, 0xf7}}; @@ -12486,6 +12559,7 @@ TEST_P(QuicFramerTest, BuildRetireConnectionIdFramePacket) { // This frame is only for version 99. return; } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -13110,6 +13184,90 @@ TEST_P(QuicFramerTest, InvalidCoalescedPacket) { ASSERT_EQ(visitor_.coalesced_packets_.size(), 0u); } +// Some IETF implementations send an initial followed by zeroes instead of +// padding inside the initial. We need to make sure that we still process +// the initial correctly and ignore the zeroes. +TEST_P(QuicFramerTest, CoalescedPacketWithZeroesRoundTrip) { + if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) { + return; + } + ASSERT_TRUE(framer_.version().KnowsWhichDecrypterToUse()); + QuicConnectionId connection_id = FramerTestConnectionId(); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + + CrypterPair client_crypters; + CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_CLIENT, + framer_.transport_version(), + connection_id, &client_crypters); + framer_.SetEncrypter(ENCRYPTION_INITIAL, + std::move(client_crypters.encrypter)); + + QuicPacketHeader header; + header.destination_connection_id = connection_id; + header.version_flag = true; + header.packet_number = kPacketNumber; + header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; + header.long_packet_type = INITIAL; + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + QuicFrames frames = {QuicFrame(QuicPingFrame())}; + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_NE(nullptr, data); + + // Add zeroes after the valid initial packet. + unsigned char packet[kMaxOutgoingPacketSize] = {}; + size_t encrypted_length = + framer_.EncryptPayload(ENCRYPTION_INITIAL, header.packet_number, *data, + AsChars(packet), QUIC_ARRAYSIZE(packet)); + ASSERT_NE(0u, encrypted_length); + + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); + CrypterPair server_crypters; + CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_SERVER, + framer_.transport_version(), + connection_id, &server_crypters); + framer_.InstallDecrypter(ENCRYPTION_INITIAL, + std::move(server_crypters.decrypter)); + + // Make sure the first long header initial packet parses correctly. + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + + // Make sure we discard the subsequent zeroes. + EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), + "Server: Received mismatched coalesced header.*"); +} + +TEST_P(QuicFramerTest, ClientReceivesInvalidVersion) { + if (framer_.transport_version() < QUIC_VERSION_44) { + return; + } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + + // clang-format off + unsigned char packet[] = { + // public flags (long header with packet type INITIAL) + 0xFF, + // version that is different from the framer's version + 'Q', '0', '4', '3', + // connection ID lengths + 0x05, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x01, + // padding frame + 0x00, + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_INVALID_VERSION, framer_.error()); + EXPECT_EQ("Client received unexpected version.", framer_.detailed_error()); +} + TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) { if (framer_.transport_version() < QUIC_VERSION_46) { return; @@ -13120,8 +13278,8 @@ TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) { QuicConnectionId connection_id(connection_id_bytes, sizeof(connection_id_bytes)); QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); - QuicFramerPeer::SetExpectedConnectionIDLength(&framer_, - connection_id.length()); + QuicFramerPeer::SetExpectedServerConnectionIDLength(&framer_, + connection_id.length()); // clang-format off PacketFragments packet = { @@ -13135,12 +13293,33 @@ TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) { {"Unable to read packet number.", {0x78}}, }; + + PacketFragments packet_with_padding = { + // type (8 byte connection_id and 1 byte packet number) + {"Unable to read type.", + {0x40}}, + // connection_id + {"Unable to read Destination ConnectionId.", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}}, + // packet number + {"", + {0x78}}, + // padding + {"", {0x00, 0x00, 0x00}}, + }; // clang-format on + PacketFragments& fragments = + framer_.version().HasHeaderProtection() ? packet_with_padding : packet; std::unique_ptr<QuicEncryptedPacket> encrypted( - AssemblePacketFromFragments(packet)); - EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + AssemblePacketFromFragments(fragments)); + if (framer_.version().HasHeaderProtection()) { + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + } else { + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + } ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(connection_id, visitor_.header_->destination_connection_id); EXPECT_FALSE(visitor_.header_->reset_flag); @@ -13148,7 +13327,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVariableLengthConnectionId) { EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); - CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER); + CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); } TEST_P(QuicFramerTest, UpdateExpectedConnectionIdLength) { @@ -13156,7 +13335,7 @@ TEST_P(QuicFramerTest, UpdateExpectedConnectionIdLength) { return; } SetDecrypterLevel(ENCRYPTION_ZERO_RTT); - framer_.SetShouldUpdateExpectedConnectionIdLength(true); + framer_.SetShouldUpdateExpectedServerConnectionIdLength(true); // clang-format off unsigned char long_header_packet[] = { @@ -13234,13 +13413,41 @@ TEST_P(QuicFramerTest, UpdateExpectedConnectionIdLength) { FramerTestConnectionIdNineBytes()); EXPECT_EQ(visitor_.header_.get()->packet_number, QuicPacketNumber(UINT64_C(0x13374233))); + + PacketHeaderFormat format; + bool version_flag; + uint8_t destination_connection_id_length; + QuicConnectionId destination_connection_id; + QuicVersionLabel version_label; + std::string detailed_error; + EXPECT_EQ(QUIC_NO_ERROR, + QuicFramer::ProcessPacketDispatcher( + QuicEncryptedPacket(AsChars(long_header_packet), + QUIC_ARRAYSIZE(long_header_packet)), + kQuicDefaultConnectionIdLength, &format, &version_flag, + &version_label, &destination_connection_id_length, + &destination_connection_id, &detailed_error)); + EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); + EXPECT_TRUE(version_flag); + EXPECT_EQ(9, destination_connection_id_length); + EXPECT_EQ(FramerTestConnectionIdNineBytes(), destination_connection_id); + + EXPECT_EQ(QUIC_NO_ERROR, + QuicFramer::ProcessPacketDispatcher( + short_header_encrypted, 9, &format, &version_flag, + &version_label, &destination_connection_id_length, + &destination_connection_id, &detailed_error)); + EXPECT_EQ(IETF_QUIC_SHORT_HEADER_PACKET, format); + EXPECT_FALSE(version_flag); + EXPECT_EQ(9, destination_connection_id_length); + EXPECT_EQ(FramerTestConnectionIdNineBytes(), destination_connection_id); } TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) { if (framer_.transport_version() < QUIC_VERSION_46) { return; } - framer_.SetShouldUpdateExpectedConnectionIdLength(true); + framer_.SetShouldUpdateExpectedServerConnectionIdLength(true); framer_.EnableMultiplePacketNumberSpacesSupport(); // clang-format off @@ -13314,7 +13521,7 @@ TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) { // packet number 0x79, // padding frame - 0x00, + 0x00, 0x00, 0x00, }; // clang-format on @@ -13341,6 +13548,298 @@ TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) { &framer_, APPLICATION_DATA)); } +TEST_P(QuicFramerTest, IetfRetryPacketRejected) { + if (!framer_.version().KnowsWhichDecrypterToUse() || + framer_.version().SupportsRetry()) { + return; + } + + // clang-format off + PacketFragments packet = { + // public flags (IETF Retry packet, 0-length original destination CID) + {"Unable to read type.", + {0xf0}}, + // version tag + {"Unable to read protocol version.", + {QUIC_VERSION_BYTES}}, + // connection_id length + {"Illegal long header type value.", + {0x00}}, + }; + // clang-format on + + // clang-format off + PacketFragments packet45 = { + // public flags (IETF Retry packet, 0-length original destination CID) + {"Unable to read type.", + {0xf0}}, + // version tag + {"Unable to read protocol version.", + {QUIC_VERSION_BYTES}}, + // connection_id length + {"RETRY not supported in this version.", + {0x00}}, + }; + // clang-format on + + PacketFragments& fragments = + framer_.transport_version() > QUIC_VERSION_44 ? packet45 : packet; + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(fragments)); + + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); +} + +TEST_P(QuicFramerTest, RetryPacketRejectedWithMultiplePacketNumberSpaces) { + if (framer_.transport_version() < QUIC_VERSION_46 || + framer_.version().SupportsRetry()) { + return; + } + framer_.EnableMultiplePacketNumberSpacesSupport(); + + // clang-format off + PacketFragments packet = { + // public flags (IETF Retry packet, 0-length original destination CID) + {"Unable to read type.", + {0xf0}}, + // version tag + {"Unable to read protocol version.", + {QUIC_VERSION_BYTES}}, + // connection_id length + {"RETRY not supported in this version.", + {0x00}}, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet)); + + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER); +} + +TEST_P(QuicFramerTest, ProcessPublicHeaderNoVersionInferredType) { + // The framer needs to have Perspective::IS_SERVER and configured to infer the + // packet header type from the packet (not the version). The framer's version + // needs to be one that uses the IETF packet format. + if (!framer_.version().KnowsWhichDecrypterToUse()) { + return; + } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); + + // Prepare a packet that uses the Google QUIC packet header but has no version + // field. + + // clang-format off + PacketFragments packet = { + // public flags (1-byte packet number, 8-byte connection_id, no version) + {"Unable to read public flags.", + {0x08}}, + // connection_id + {"Unable to read ConnectionId.", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"Unable to read packet number.", + {0x01}}, + // padding + {"Invalid public header type for expected version.", + {0x00}}, + }; + // clang-format on + + PacketFragments& fragments = packet; + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(fragments)); + + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_EQ("Invalid public header type for expected version.", + framer_.detailed_error()); + CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); +} + +TEST_P(QuicFramerTest, ProcessMismatchedHeaderVersion) { + // The framer needs to have Perspective::IS_SERVER and configured to infer the + // packet header type from the packet (not the version). The framer's version + // needs to be one that uses the IETF packet format. + if (!framer_.version().KnowsWhichDecrypterToUse()) { + return; + } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); + + // clang-format off + PacketFragments packet = { + // public flags (Google QUIC header with version present) + {"Unable to read public flags.", + {0x09}}, + // connection_id + {"Unable to read ConnectionId.", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // version tag + {"Unable to read protocol version.", + {QUIC_VERSION_BYTES}}, + // packet number + {"Unable to read packet number.", + {0x01}}, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet)); + framer_.ProcessPacket(*encrypted); + + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_EQ("Invalid public header type for expected version.", + framer_.detailed_error()); + CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER); +} + +TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacket) { + // clang-format off + static const char expected_packet[1200] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version, part of the IETF space reserved for negotiation. + 0xca, 0xba, 0xda, 0xba, + // Destination connection ID length 8, source connection ID length 0. + 0x50, + // 8-byte destination connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does + // not parse with any known version. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // 2 bytes of zeroes to pad to 16 byte boundary. + 0x00, 0x00, + // A polite greeting in case a human sees this in tcpdump. + 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, + 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69, + 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00, + }; + // clang-format on + char packet[1200]; + char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70, + 0x6c, 0x7a, 0x20, 0x21}; + EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket( + packet, sizeof(packet), destination_connection_id_bytes, + sizeof(destination_connection_id_bytes))); + test::CompareCharArraysWithHexError("constructed packet", expected_packet, + sizeof(expected_packet), packet, + sizeof(packet)); + QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), + sizeof(packet), false); + // Make sure we fail to parse this packet for the version under test. + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + if (framer_.transport_version() <= QUIC_VERSION_43) { + // We can only parse the connection ID with an IETF parser. + return; + } + ASSERT_TRUE(visitor_.header_.get()); + QuicConnectionId probe_payload_connection_id( + reinterpret_cast<const char*>(destination_connection_id_bytes), + sizeof(destination_connection_id_bytes)); + EXPECT_EQ(probe_payload_connection_id, + visitor_.header_.get()->destination_connection_id); +} + +TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponse) { + // clang-format off + const char packet[] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version of 0, indicating version negotiation. + 0x00, 0x00, 0x00, 0x00, + // Destination connection ID length 0, source connection ID length 8. + 0x05, + // 8-byte source connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // A few supported versions. + 0xaa, 0xaa, 0xaa, 0xaa, + QUIC_VERSION_BYTES, + }; + // clang-format on + char probe_payload_bytes[] = {0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21}; + char parsed_probe_payload_bytes[kQuicMaxConnectionIdLength] = {}; + uint8_t parsed_probe_payload_length = 0; + std::string parse_detailed_error = ""; + EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse( + reinterpret_cast<const char*>(packet), sizeof(packet), + reinterpret_cast<char*>(parsed_probe_payload_bytes), + &parsed_probe_payload_length, &parse_detailed_error)); + EXPECT_EQ("", parse_detailed_error); + test::CompareCharArraysWithHexError( + "parsed probe", probe_payload_bytes, sizeof(probe_payload_bytes), + parsed_probe_payload_bytes, parsed_probe_payload_length); +} + +TEST_P(QuicFramerTest, ClientConnectionIdNotSupportedYet) { + if (GetQuicRestartFlag(quic_do_not_override_connection_id)) { + // This check is currently only performed when this flag is disabled. + return; + } + if (framer_.transport_version() <= QUIC_VERSION_43) { + // This test requires an IETF long header. + return; + } + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + const unsigned char type_byte = + framer_.transport_version() == QUIC_VERSION_44 ? 0xFC : 0xD3; + // clang-format off + unsigned char packet[] = { + // public flags (long header with packet type ZERO_RTT_PROTECTED and + // 4-byte packet number) + type_byte, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x50, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // long header packet length + 0x05, + // packet number + 0x12, 0x34, 0x56, 0x00, + // padding frame + 0x00, + }; + // clang-format on + EXPECT_FALSE(framer_.ProcessPacket( + QuicEncryptedPacket(AsChars(packet), QUIC_ARRAYSIZE(packet), false))); + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( + framer_.transport_version())) { + EXPECT_EQ("Invalid ConnectionId length.", framer_.detailed_error()); + } else { + EXPECT_EQ("Client connection ID not supported yet.", + framer_.detailed_error()); + } +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc index b0c01257356..f30fc99cb55 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_ietf_framer_test.cc @@ -96,6 +96,10 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override {} + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override {} + bool OnProtocolVersionMismatch(ParsedQuicVersion received_version, PacketHeaderFormat form) override { return true; @@ -192,11 +196,11 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { void OnAuthenticatedIetfStatelessResetPacket( const QuicIetfStatelessResetPacket& packet) override {} - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override { + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override { return true; } - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override { + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override { return true; } }; @@ -455,28 +459,16 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { EXPECT_EQ(receive_frame.byte_offset, transmit_frame.byte_offset); } - void TryMaxStreamsFrame(QuicStreamId stream_id, + void TryMaxStreamsFrame(QuicStreamCount stream_count, bool unidirectional, bool stream_id_server_initiated) { - if (!unidirectional && !stream_id_server_initiated && stream_id == 0) { - // For bidirectional, client initiated, streams, 0 is not allowed, - // it's used for the crypto stream and is not included in the counting. - return; - } - char packet_buffer[kNormalPacketBufferSize]; memset(packet_buffer, 0, sizeof(packet_buffer)); Perspective old_perspective = framer_.perspective(); - // Set up the writer and transmit QuicMaxStreamIdFrame + // Set up the writer and transmit QuicMaxStreamsFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, NETWORK_BYTE_ORDER); - if (stream_id_server_initiated) { - stream_id |= 0x01; - } - if (unidirectional) { - stream_id |= 0x02; - } // Set the perspective of the sender. If the stream id is supposed to // be server-initiated, then the sender of the MAX_STREAMS should be @@ -485,7 +477,7 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated) ? Perspective::IS_CLIENT : Perspective::IS_SERVER); - QuicMaxStreamIdFrame transmit_frame(0, stream_id); + QuicMaxStreamsFrame transmit_frame(0, stream_count, unidirectional); // Add the frame. EXPECT_TRUE(QuicFramerPeer::AppendMaxStreamsFrame(&framer_, transmit_frame, @@ -502,7 +494,7 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { // Set up reader and empty receive QuicPaddingFrame. QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); - QuicMaxStreamIdFrame receive_frame; + QuicMaxStreamsFrame receive_frame; // Deframe it EXPECT_TRUE(QuicFramerPeer::ProcessMaxStreamsFrame( @@ -512,42 +504,30 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { << " Error: " << framer_.detailed_error(); // Now check that received and sent data are equivalent - EXPECT_EQ(stream_id, receive_frame.max_stream_id); - EXPECT_EQ(transmit_frame.max_stream_id, receive_frame.max_stream_id); + EXPECT_EQ(stream_count, receive_frame.stream_count); + EXPECT_EQ(transmit_frame.stream_count, receive_frame.stream_count); QuicFramerPeer::SetPerspective(&framer_, old_perspective); } - void TryStreamsBlockedFrame(QuicStreamId stream_id, + void TryStreamsBlockedFrame(QuicStreamCount stream_count, bool unidirectional, bool stream_id_server_initiated) { - if (!unidirectional && !stream_id_server_initiated && stream_id == 0) { - // For bidirectional, client initiated, streams, 0 is not allowed, - // it's used for the crypto stream and is not included in the counting. - return; - } - char packet_buffer[kNormalPacketBufferSize]; memset(packet_buffer, 0, sizeof(packet_buffer)); Perspective old_perspective = framer_.perspective(); - // Set up the writer and transmit QuicMaxStreamIdFrame + // Set up the writer and transmit QuicStreamsBlockedFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, NETWORK_BYTE_ORDER); - if (stream_id_server_initiated) { - stream_id |= 0x01; - } - if (unidirectional) { - stream_id |= 0x02; - } // Set the perspective of the sender. If the stream id is supposed to - // be server-initiated, then the sender of the MAX_STREAMS should be + // be server-initiated, then the sender of the STREAMS_BLOCKED should be // a client, and vice versa. Do this prior to constructing the frame or // generating the packet, so that any internal dependencies are satisfied. QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated) ? Perspective::IS_SERVER : Perspective::IS_CLIENT); - QuicStreamIdBlockedFrame transmit_frame(0, stream_id); + QuicStreamsBlockedFrame transmit_frame(0, stream_count, unidirectional); // Add the frame. EXPECT_TRUE(QuicFramerPeer::AppendStreamsBlockedFrame( @@ -564,7 +544,7 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { // Set up reader and empty receive QuicPaddingFrame. QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); - QuicStreamIdBlockedFrame receive_frame; + QuicStreamsBlockedFrame receive_frame; // Deframe it EXPECT_TRUE(QuicFramerPeer::ProcessStreamsBlockedFrame( @@ -573,8 +553,8 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { : IETF_STREAMS_BLOCKED_BIDIRECTIONAL)); // Now check that received and sent data are equivalent - EXPECT_EQ(stream_id, receive_frame.stream_id); - EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id); + EXPECT_EQ(stream_count, receive_frame.stream_count); + EXPECT_EQ(transmit_frame.stream_count, receive_frame.stream_count); QuicFramerPeer::SetPerspective(&framer_, old_perspective); } @@ -1264,19 +1244,18 @@ TEST_F(QuicIetfFramerTest, MaxStreamDataFrame) { } TEST_F(QuicIetfFramerTest, MaxStreamsFrame) { - QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, - kStreamId0}; + QuicStreamCount stream_counts[] = {0x3fffffff, 0x3fff, 0x3f, 0x1}; - for (QuicIetfStreamId stream_id : stream_ids) { + for (QuicStreamCount stream_count : stream_counts) { // Cover all four combinations of uni/bi-directional and // server-/client- initiation. - TryMaxStreamsFrame(stream_id, /*unidirectional=*/true, + TryMaxStreamsFrame(stream_count, /*unidirectional=*/true, /*stream_id_server_initiated=*/true); - TryMaxStreamsFrame(stream_id, /*unidirectional=*/true, + TryMaxStreamsFrame(stream_count, /*unidirectional=*/true, /*stream_id_server_initiated=*/false); - TryMaxStreamsFrame(stream_id, /*unidirectional=*/false, + TryMaxStreamsFrame(stream_count, /*unidirectional=*/false, /*stream_id_server_initiated=*/true); - TryMaxStreamsFrame(stream_id, /*unidirectional=*/false, + TryMaxStreamsFrame(stream_count, /*unidirectional=*/false, /*stream_id_server_initiated=*/false); } } @@ -1362,20 +1341,19 @@ TEST_F(QuicIetfFramerTest, StreamBlockedFrame) { } TEST_F(QuicIetfFramerTest, StreamsBlockedFrame) { - QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, - kStreamId0}; + QuicStreamCount stream_counts[] = {0x3fffffff, 0x3fff, 0x3f, 0x1}; - for (QuicIetfStreamId stream_id : stream_ids) { - TryStreamsBlockedFrame(stream_id, + for (QuicStreamCount stream_count : stream_counts) { + TryStreamsBlockedFrame(stream_count, /*unidirectional=*/false, /*stream_id_server_initiated=*/false); - TryStreamsBlockedFrame(stream_id, + TryStreamsBlockedFrame(stream_count, /*unidirectional=*/false, /*stream_id_server_initiated=*/true); - TryStreamsBlockedFrame(stream_id, + TryStreamsBlockedFrame(stream_count, /*unidirectional=*/true, /*stream_id_server_initiated=*/false); - TryStreamsBlockedFrame(stream_id, + TryStreamsBlockedFrame(stream_count, /*unidirectional=*/true, /*stream_id_server_initiated=*/true); } @@ -1401,7 +1379,7 @@ TEST_F(QuicIetfFramerTest, NewConnectionIdFrame) { memset(packet_buffer, 0, sizeof(packet_buffer)); - // Set up the writer and transmit QuicStreamIdBlockedFrame + // Set up the writer and transmit a QuicNewConnectionIdFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, NETWORK_BYTE_ORDER); @@ -1449,7 +1427,7 @@ TEST_F(QuicIetfFramerTest, RetireConnectionIdFrame) { memset(packet_buffer, 0, sizeof(packet_buffer)); - // Set up the writer and transmit QuicStreamIdBlockedFrame + // Set up the writer and transmit QuicRetireConnectionIdFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, NETWORK_BYTE_ORDER); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc index 96b5bc6e089..7420c723074 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc @@ -22,6 +22,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" @@ -52,15 +53,15 @@ QuicLongHeaderType EncryptionlevelToLongHeaderType(EncryptionLevel level) { #define ENDPOINT \ (framer_->perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ") -QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id, +QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id, QuicFramer* framer, DelegateInterface* delegate) - : QuicPacketCreator(connection_id, + : QuicPacketCreator(server_connection_id, framer, QuicRandom::GetInstance(), delegate) {} -QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id, +QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id, QuicFramer* framer, QuicRandom* random, DelegateInterface* delegate) @@ -71,9 +72,9 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id, send_version_in_packet_(framer->perspective() == Perspective::IS_CLIENT), have_diversification_nonce_(false), max_packet_length_(0), - connection_id_included_(CONNECTION_ID_PRESENT), + server_connection_id_included_(CONNECTION_ID_PRESENT), packet_size_(0), - connection_id_(connection_id), + server_connection_id_(server_connection_id), packet_(QuicPacketNumber(), PACKET_1BYTE_PACKET_NUMBER, nullptr, @@ -82,9 +83,7 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id, false), pending_padding_bytes_(0), needs_full_padding_(false), - can_set_transmission_type_(false), - set_transmission_type_for_next_frame_( - GetQuicReloadableFlag(quic_set_transmission_type_for_next_frame)) { + can_set_transmission_type_(false) { SetMaxPacketLength(kDefaultMaxPacketSize); } @@ -114,6 +113,9 @@ void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) { max_packet_length_ = length; max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_); + QUIC_BUG_IF(max_plaintext_size_ - PacketHeaderSize() < + MinPlaintextPacketSize(framer_->version())) + << "Attempted to set max packet length too small"; } // Stops serializing version of the protocol in packets sent after this call. @@ -159,6 +161,7 @@ void QuicPacketCreator::UpdatePacketNumberLength( bool QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, size_t write_length, QuicStreamOffset offset, + bool needs_full_padding, TransmissionType transmission_type, QuicFrame* frame) { if (!CreateCryptoFrame(level, write_length, offset, frame)) { @@ -170,7 +173,9 @@ bool QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, // // TODO(nharper): Check what the IETF drafts say about padding out initial // messages and change this as appropriate. - needs_full_padding_ = true; + if (needs_full_padding) { + needs_full_padding_ = true; + } return AddFrame(*frame, /*save_retransmittable_frames*/ true, transmission_type); } @@ -195,8 +200,7 @@ bool QuicPacketCreator::ConsumeData(QuicStreamId id, QUIC_BUG << error_details << " Constructed stream frame length: " << frame->stream_frame.data_length << " CHLO length: " << data_size; - delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details, - ConnectionCloseSource::FROM_SELF); + delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details); return false; } if (!AddFrame(*frame, /*save_retransmittable_frames=*/true, @@ -379,8 +383,7 @@ void QuicPacketCreator::OnSerializedPacket() { const std::string error_details = "Failed to SerializePacket."; QUIC_BUG << error_details; delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, - error_details, - ConnectionCloseSource::FROM_SELF); + error_details); return; } @@ -395,9 +398,7 @@ void QuicPacketCreator::ClearPacket() { packet_.has_crypto_handshake = NOT_HANDSHAKE; packet_.num_padding_bytes = 0; packet_.original_packet_number.Clear(); - if (!can_set_transmission_type_ || ShouldSetTransmissionTypeForNextFrame()) { - packet_.transmission_type = NOT_RETRANSMISSION; - } + packet_.transmission_type = NOT_RETRANSMISSION; packet_.encrypted_buffer = nullptr; packet_.encrypted_length = 0; DCHECK(packet_.retransmittable_frames.empty()); @@ -442,6 +443,7 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( max_plaintext_size_ - writer.length() - min_frame_size; const size_t bytes_consumed = std::min<size_t>(available_size, remaining_data_size); + const size_t plaintext_bytes_written = min_frame_size + bytes_consumed; const bool set_fin = fin && (bytes_consumed == remaining_data_size); QuicStreamFrame frame(id, set_fin, stream_offset, bytes_consumed); @@ -462,15 +464,19 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( QUIC_BUG << "AppendStreamFrame failed"; return; } + if (plaintext_bytes_written < MinPlaintextPacketSize(framer_->version()) && + !writer.WritePaddingBytes(MinPlaintextPacketSize(framer_->version()) - + plaintext_bytes_written)) { + QUIC_BUG << "Unable to add padding bytes"; + return; + } if (!framer_->WriteIetfLongHeaderLength(header, &writer, length_field_offset, packet_.encryption_level)) { return; } - if (ShouldSetTransmissionTypeForNextFrame()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_set_transmission_type_for_next_frame, 1, - 2); + if (can_set_transmission_type()) { packet_.transmission_type = transmission_type; } @@ -542,11 +548,7 @@ size_t QuicPacketCreator::PacketSize() { if (!queued_frames_.empty()) { return packet_size_; } - packet_size_ = GetPacketHeaderSize( - framer_->transport_version(), GetDestinationConnectionIdLength(), - GetSourceConnectionIdLength(), IncludeVersionInHeader(), - IncludeNonceInPublicHeader(), GetPacketNumberLength(), - GetRetryTokenLengthLength(), GetRetryToken().length(), GetLengthLength()); + packet_size_ = PacketHeaderSize(); return packet_size_; } @@ -622,8 +624,9 @@ QuicPacketCreator::SerializeVersionNegotiationPacket( const ParsedQuicVersionVector& supported_versions) { DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); std::unique_ptr<QuicEncryptedPacket> encrypted = - QuicFramer::BuildVersionNegotiationPacket(connection_id_, ietf_quic, - supported_versions); + QuicFramer::BuildVersionNegotiationPacket(server_connection_id_, + EmptyQuicConnectionId(), + ietf_quic, supported_versions); DCHECK(encrypted); DCHECK_GE(max_packet_length_, encrypted->length()); return encrypted; @@ -731,16 +734,39 @@ SerializedPacket QuicPacketCreator::NoPacket() { nullptr, 0, false, false); } +QuicConnectionId QuicPacketCreator::GetDestinationConnectionId() const { + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + return server_connection_id_; + } + QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 1, 5); + if (framer_->perspective() == Perspective::IS_SERVER) { + return EmptyQuicConnectionId(); + } + return server_connection_id_; +} + +QuicConnectionId QuicPacketCreator::GetSourceConnectionId() const { + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + return server_connection_id_; + } + QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 6, 6); + if (framer_->perspective() == Perspective::IS_CLIENT) { + return EmptyQuicConnectionId(); + } + return server_connection_id_; +} + QuicConnectionIdIncluded QuicPacketCreator::GetDestinationConnectionIdIncluded() const { - if (framer_->transport_version() > QUIC_VERSION_43) { + if (framer_->transport_version() > QUIC_VERSION_43 || + GetQuicRestartFlag(quic_do_not_override_connection_id)) { // Packets sent by client always include destination connection ID, and // those sent by the server do not include destination connection ID. return framer_->perspective() == Perspective::IS_CLIENT ? CONNECTION_ID_PRESENT : CONNECTION_ID_ABSENT; } - return connection_id_included_; + return server_connection_id_included_; } QuicConnectionIdIncluded QuicPacketCreator::GetSourceConnectionIdIncluded() @@ -749,23 +775,30 @@ QuicConnectionIdIncluded QuicPacketCreator::GetSourceConnectionIdIncluded() if (HasIetfLongHeader() && framer_->perspective() == Perspective::IS_SERVER) { return CONNECTION_ID_PRESENT; } + if (GetQuicRestartFlag(quic_do_not_override_connection_id) && + framer_->perspective() == Perspective::IS_SERVER) { + QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 2, 5); + return server_connection_id_included_; + } return CONNECTION_ID_ABSENT; } QuicConnectionIdLength QuicPacketCreator::GetDestinationConnectionIdLength() const { - DCHECK(QuicUtils::IsConnectionIdValidForVersion(connection_id_, + DCHECK(QuicUtils::IsConnectionIdValidForVersion(server_connection_id_, transport_version())); return GetDestinationConnectionIdIncluded() == CONNECTION_ID_PRESENT - ? static_cast<QuicConnectionIdLength>(connection_id_.length()) + ? static_cast<QuicConnectionIdLength>( + GetDestinationConnectionId().length()) : PACKET_0BYTE_CONNECTION_ID; } QuicConnectionIdLength QuicPacketCreator::GetSourceConnectionIdLength() const { - DCHECK(QuicUtils::IsConnectionIdValidForVersion(connection_id_, + DCHECK(QuicUtils::IsConnectionIdValidForVersion(server_connection_id_, transport_version())); return GetSourceConnectionIdIncluded() == CONNECTION_ID_PRESENT - ? static_cast<QuicConnectionIdLength>(connection_id_.length()) + ? static_cast<QuicConnectionIdLength>( + GetSourceConnectionId().length()) : PACKET_0BYTE_CONNECTION_ID; } @@ -776,6 +809,14 @@ QuicPacketNumberLength QuicPacketCreator::GetPacketNumberLength() const { return packet_.packet_number_length; } +size_t QuicPacketCreator::PacketHeaderSize() const { + return GetPacketHeaderSize( + framer_->transport_version(), GetDestinationConnectionIdLength(), + GetSourceConnectionIdLength(), IncludeVersionInHeader(), + IncludeNonceInPublicHeader(), GetPacketNumberLength(), + GetRetryTokenLengthLength(), GetRetryToken().length(), GetLengthLength()); +} + QuicVariableLengthIntegerLength QuicPacketCreator::GetRetryTokenLengthLength() const { if (QuicVersionHasLongHeaderLengths(framer_->transport_version()) && @@ -787,7 +828,12 @@ QuicVariableLengthIntegerLength QuicPacketCreator::GetRetryTokenLengthLength() } QuicStringPiece QuicPacketCreator::GetRetryToken() const { - return retry_token_; + if (QuicVersionHasLongHeaderLengths(framer_->transport_version()) && + HasIetfLongHeader() && + EncryptionlevelToLongHeaderType(packet_.encryption_level) == INITIAL) { + return retry_token_; + } + return QuicStringPiece(); } void QuicPacketCreator::SetRetryToken(QuicStringPiece retry_token) { @@ -808,10 +854,10 @@ QuicVariableLengthIntegerLength QuicPacketCreator::GetLengthLength() const { } void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { - header->destination_connection_id = connection_id_; + header->destination_connection_id = GetDestinationConnectionId(); header->destination_connection_id_included = GetDestinationConnectionIdIncluded(); - header->source_connection_id = connection_id_; + header->source_connection_id = GetSourceConnectionId(); header->source_connection_id_included = GetSourceConnectionIdIncluded(); header->reset_flag = false; header->version_flag = IncludeVersionInHeader(); @@ -821,11 +867,7 @@ void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { } else { header->nonce = nullptr; } - if (!packet_.packet_number.IsInitialized()) { - packet_.packet_number = framer_->first_sending_packet_number(); - } else { - ++packet_.packet_number; - } + packet_.packet_number = NextSendingPacketNumber(); header->packet_number = packet_.packet_number; header->packet_number_length = GetPacketNumberLength(); header->retry_token_length_length = GetRetryTokenLengthLength(); @@ -845,15 +887,16 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, QUIC_DVLOG(1) << ENDPOINT << "Adding frame with transmission type " << transmission_type << ": " << frame; if (frame.type == STREAM_FRAME && - frame.stream_frame.stream_id != - QuicUtils::GetCryptoStreamId(framer_->transport_version()) && - packet_.encryption_level == ENCRYPTION_INITIAL) { - const std::string error_details = - "Cannot send stream data without encryption."; + !QuicUtils::IsCryptoStreamId(framer_->transport_version(), + frame.stream_frame.stream_id) && + (packet_.encryption_level == ENCRYPTION_INITIAL || + packet_.encryption_level == ENCRYPTION_HANDSHAKE)) { + const std::string error_details = QuicStrCat( + "Cannot send stream data with level: ", + QuicUtils::EncryptionLevelToString(packet_.encryption_level)); QUIC_BUG << error_details; delegate_->OnUnrecoverableError( - QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, error_details, - ConnectionCloseSource::FROM_SELF); + QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, error_details); return false; } size_t frame_len = framer_->GetSerializedFrameLength( @@ -892,10 +935,8 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, // Packet transmission type is determined by the last added retransmittable // frame. - if (ShouldSetTransmissionTypeForNextFrame() && + if (can_set_transmission_type() && QuicUtils::IsRetransmittableFrame(frame.type)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_set_transmission_type_for_next_frame, 2, - 2); packet_.transmission_type = transmission_type; } return true; @@ -914,11 +955,26 @@ void QuicPacketCreator::MaybeAddPadding() { needs_full_padding_ = true; } - if (!needs_full_padding_ && pending_padding_bytes_ == 0) { + // Header protection requires a minimum plaintext packet size. + size_t extra_padding_bytes = 0; + if (framer_->version().HasHeaderProtection()) { + size_t frame_bytes = PacketSize() - PacketHeaderSize(); + + if (frame_bytes + pending_padding_bytes_ < + MinPlaintextPacketSize(framer_->version()) && + !needs_full_padding_) { + extra_padding_bytes = + MinPlaintextPacketSize(framer_->version()) - frame_bytes; + } + } + + if (!needs_full_padding_ && pending_padding_bytes_ == 0 && + extra_padding_bytes == 0) { // Do not need padding. return; } + int padding_bytes = -1; if (needs_full_padding_) { // Full padding does not consume pending padding bytes. packet_.num_padding_bytes = -1; @@ -926,11 +982,12 @@ void QuicPacketCreator::MaybeAddPadding() { packet_.num_padding_bytes = std::min<int16_t>(pending_padding_bytes_, BytesFree()); pending_padding_bytes_ -= packet_.num_padding_bytes; + padding_bytes = + std::max<int16_t>(packet_.num_padding_bytes, extra_padding_bytes); } - bool success = - AddFrame(QuicFrame(QuicPaddingFrame(packet_.num_padding_bytes)), false, - packet_.transmission_type); + bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)), false, + packet_.transmission_type); DCHECK(success); } @@ -953,31 +1010,32 @@ void QuicPacketCreator::AddPendingPadding(QuicByteCount size) { bool QuicPacketCreator::StreamFrameIsClientHello( const QuicStreamFrame& frame) const { if (framer_->perspective() == Perspective::IS_SERVER || - frame.stream_id != - QuicUtils::GetCryptoStreamId(framer_->transport_version())) { + !QuicUtils::IsCryptoStreamId(framer_->transport_version(), + frame.stream_id)) { return false; } // The ClientHello is always sent with INITIAL encryption. return packet_.encryption_level == ENCRYPTION_INITIAL; } -void QuicPacketCreator::SetConnectionIdIncluded( - QuicConnectionIdIncluded connection_id_included) { - DCHECK(connection_id_included == CONNECTION_ID_PRESENT || - connection_id_included == CONNECTION_ID_ABSENT); +void QuicPacketCreator::SetServerConnectionIdIncluded( + QuicConnectionIdIncluded server_connection_id_included) { + DCHECK(server_connection_id_included == CONNECTION_ID_PRESENT || + server_connection_id_included == CONNECTION_ID_ABSENT); DCHECK(framer_->perspective() == Perspective::IS_SERVER || - connection_id_included != CONNECTION_ID_ABSENT); - connection_id_included_ = connection_id_included; + server_connection_id_included != CONNECTION_ID_ABSENT); + server_connection_id_included_ = server_connection_id_included; } -void QuicPacketCreator::SetConnectionId(QuicConnectionId connection_id) { - connection_id_ = connection_id; +void QuicPacketCreator::SetServerConnectionId( + QuicConnectionId server_connection_id) { + server_connection_id_ = server_connection_id; } void QuicPacketCreator::SetTransmissionType(TransmissionType type) { DCHECK(can_set_transmission_type_); - if (!ShouldSetTransmissionTypeForNextFrame()) { + if (!can_set_transmission_type()) { QUIC_DVLOG_IF(1, type != packet_.transmission_type) << ENDPOINT << "Setting Transmission type to " << QuicUtils::TransmissionTypeToString(type); @@ -1037,5 +1095,39 @@ bool QuicPacketCreator::HasIetfLongHeader() const { packet_.encryption_level < ENCRYPTION_FORWARD_SECURE; } +size_t QuicPacketCreator::MinPlaintextPacketSize( + const ParsedQuicVersion& version) { + if (!version.HasHeaderProtection()) { + return 0; + } + // Header protection samples 16 bytes of ciphertext starting 4 bytes after the + // packet number. In IETF QUIC, all AEAD algorithms have a 16-byte auth tag + // (i.e. the ciphertext is 16 bytes larger than the plaintext). Since packet + // numbers could be as small as 1 byte, but the sample starts 4 bytes after + // the packet number, at least 3 bytes of plaintext are needed to make sure + // that there is enough ciphertext to sample. + // + // Google QUIC crypto uses different AEAD algorithms - in particular the auth + // tags are only 12 bytes instead of 16 bytes. Since the auth tag is 4 bytes + // shorter, 4 more bytes of plaintext are needed to guarantee there is enough + // ciphertext to sample. + // + // This method could check for PROTOCOL_TLS1_3 vs PROTOCOL_QUIC_CRYPTO and + // return 3 when TLS 1.3 is in use (the use of IETF vs Google QUIC crypters is + // determined based on the handshake protocol used). However, even when TLS + // 1.3 is used, unittests still use NullEncrypter/NullDecrypter (and other + // test crypters) which also only use 12 byte tags. + // + // TODO(nharper): Set this based on the handshake protocol in use. + return 7; +} + +QuicPacketNumber QuicPacketCreator::NextSendingPacketNumber() const { + if (!packet_number().IsInitialized()) { + return framer_->first_sending_packet_number(); + } + return packet_number() + 1; +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h index 85e00917a15..a7b1d5cb3e3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h @@ -13,7 +13,6 @@ #include <utility> #include <vector> -#include "net/third_party/quiche/src/quic/core/quic_connection_close_delegate_interface.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.h" @@ -28,10 +27,9 @@ class QuicPacketCreatorPeer; class QUIC_EXPORT_PRIVATE QuicPacketCreator { public: // A delegate interface for further processing serialized packet. - class QUIC_EXPORT_PRIVATE DelegateInterface - : public QuicConnectionCloseDelegateInterface { + class QUIC_EXPORT_PRIVATE DelegateInterface { public: - ~DelegateInterface() override {} + virtual ~DelegateInterface() {} // Get a buffer of kMaxOutgoingPacketSize bytes to serialize the next // packet. If return nullptr, QuicPacketCreator will serialize on a stack // buffer. @@ -40,6 +38,10 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // of |serialized_packet|, but takes ownership of any frames it removes // from |packet.retransmittable_frames|. virtual void OnSerializedPacket(SerializedPacket* serialized_packet) = 0; + + // Called when an unrecoverable error is encountered. + virtual void OnUnrecoverableError(QuicErrorCode error, + const std::string& error_details) = 0; }; // Interface which gets callbacks from the QuicPacketCreator at interesting @@ -53,10 +55,10 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { virtual void OnFrameAddedToPacket(const QuicFrame& frame) {} }; - QuicPacketCreator(QuicConnectionId connection_id, + QuicPacketCreator(QuicConnectionId server_connection_id, QuicFramer* framer, DelegateInterface* delegate); - QuicPacketCreator(QuicConnectionId connection_id, + QuicPacketCreator(QuicConnectionId server_connection_id, QuicFramer* framer, QuicRandom* random, DelegateInterface* delegate); @@ -109,6 +111,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { bool ConsumeCryptoData(EncryptionLevel level, size_t write_length, QuicStreamOffset offset, + bool needs_full_padding, TransmissionType transmission_type, QuicFrame* frame); @@ -206,17 +209,24 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Returns a dummy packet that is valid but contains no useful information. static SerializedPacket NoPacket(); + // Returns the destination connection ID to send over the wire. + QuicConnectionId GetDestinationConnectionId() const; + + // Returns the source connection ID to send over the wire. + QuicConnectionId GetSourceConnectionId() const; + // Returns length of destination connection ID to send over the wire. QuicConnectionIdLength GetDestinationConnectionIdLength() const; // Returns length of source connection ID to send over the wire. QuicConnectionIdLength GetSourceConnectionIdLength() const; - // Sets whether the connection ID should be sent over the wire. - void SetConnectionIdIncluded(QuicConnectionIdIncluded connection_id_included); + // Sets whether the server connection ID should be sent over the wire. + void SetServerConnectionIdIncluded( + QuicConnectionIdIncluded server_connection_id_included); - // Update the connection ID used in outgoing packets. - void SetConnectionId(QuicConnectionId connection_id); + // Update the server connection ID used in outgoing packets. + void SetServerConnectionId(QuicConnectionId server_connection_id); // Sets the encryption level that will be applied to new packets. void set_encryption_level(EncryptionLevel level) { @@ -252,7 +262,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Sets transmission type of next constructed packets. void SetTransmissionType(TransmissionType type); - // Sets the retry token to be sent over the wire in v99 IETF Initial packets. + // Sets the retry token to be sent over the wire in IETF Initial packets. void SetRetryToken(QuicStringPiece retry_token); // Returns the largest payload that will fit into a single MESSAGE frame. @@ -262,6 +272,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // connection ID lengths do not change. QuicPacketLength GetGuaranteedLargestMessagePayload() const; + // Packet number of next created packet. + QuicPacketNumber NextSendingPacketNumber() const; + void set_debug_delegate(DebugDelegate* debug_delegate) { debug_delegate_ = debug_delegate; } @@ -270,9 +283,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { can_set_transmission_type_ = can_set_transmission_type; } - bool ShouldSetTransmissionTypeForNextFrame() const { - return can_set_transmission_type_ && set_transmission_type_for_next_frame_; - } + bool can_set_transmission_type() const { return can_set_transmission_type_; } QuicByteCount pending_padding_bytes() const { return pending_padding_bytes_; } @@ -280,6 +291,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { return framer_->transport_version(); } + // Returns the minimum size that the plaintext of a packet must be. + static size_t MinPlaintextPacketSize(const ParsedQuicVersion& version); + private: friend class test::QuicPacketCreatorPeer; @@ -338,6 +352,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // function instead. QuicPacketNumberLength GetPacketNumberLength() const; + // Returns the size in bytes of the packet header. + size_t PacketHeaderSize() const; + // Returns whether the destination connection ID is sent over the wire. QuicConnectionIdIncluded GetDestinationConnectionIdIncluded() const; @@ -379,8 +396,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Maximum length including headers and encryption (UDP payload length.) QuicByteCount max_packet_length_; size_t max_plaintext_size_; - // Whether the connection_id is sent over the wire. - QuicConnectionIdIncluded connection_id_included_; + // Whether the server_connection_id is sent over the wire. + QuicConnectionIdIncluded server_connection_id_included_; // Frames to be added to the next SerializedPacket QuicFrames queued_frames_; @@ -389,7 +406,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // TODO(ianswett): Move packet_size_ into SerializedPacket once // QuicEncryptedPacket has been flattened into SerializedPacket. size_t packet_size_; - QuicConnectionId connection_id_; + QuicConnectionId server_connection_id_; // Packet used to invoke OnSerializedPacket. SerializedPacket packet_; @@ -410,10 +427,6 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // If true, packet_'s transmission type is only set by // SetPacketTransmissionType and does not get cleared in ClearPacket. bool can_set_transmission_type_; - - // Latched value of --quic_set_transmission_type_for_next_frame. Don't use - // this variable directly, use ShouldSetTransmissionTypeForNextFrame instead. - bool set_transmission_type_for_next_frame_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc index 2b71b06e684..bf695637322 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc @@ -295,7 +295,7 @@ TEST_P(QuicPacketCreatorTest, SerializeFrames) { frames_.push_back(QuicFrame(new QuicAckFrame(InitAckFrame(1)))); QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( client_framer_.transport_version(), Perspective::IS_CLIENT); - if (level != ENCRYPTION_INITIAL) { + if (level != ENCRYPTION_INITIAL && level != ENCRYPTION_HANDSHAKE) { frames_.push_back( QuicFrame(QuicStreamFrame(stream_id, false, 0u, QuicStringPiece()))); frames_.push_back( @@ -320,7 +320,7 @@ TEST_P(QuicPacketCreatorTest, SerializeFrames) { .WillOnce(Return(true)); EXPECT_CALL(framer_visitor_, OnAckFrameEnd(QuicPacketNumber(1))) .WillOnce(Return(true)); - if (level != ENCRYPTION_INITIAL) { + if (level != ENCRYPTION_INITIAL && level != ENCRYPTION_HANDSHAKE) { EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); } @@ -601,6 +601,7 @@ TEST_P(QuicPacketCreatorTest, ConsumeCryptoData) { std::string data = "crypto data"; QuicFrame frame; ASSERT_TRUE(creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data.length(), 0, + /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)); EXPECT_EQ(frame.crypto_frame->data_length, data.length()); EXPECT_TRUE(creator_.HasPendingFrames()); @@ -652,7 +653,10 @@ TEST_P(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) { const size_t overhead = GetPacketHeaderOverhead(client_framer_.transport_version()) + GetEncryptionOverhead(); - for (size_t i = overhead; i < overhead + 100; ++i) { + for (size_t i = overhead + QuicPacketCreator::MinPlaintextPacketSize( + client_framer_.version()); + i < overhead + 100; ++i) { + SCOPED_TRACE(i); creator_.SetMaxPacketLength(i); const bool should_have_room = i > @@ -743,9 +747,9 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) { EXPECT_LT(0u, bytes_consumed); } else { producer_.SaveCryptoData(ENCRYPTION_INITIAL, kOffset, data); - ASSERT_TRUE(creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data.length(), - kOffset, NOT_RETRANSMISSION, - &frame)); + ASSERT_TRUE(creator_.ConsumeCryptoData( + ENCRYPTION_INITIAL, data.length(), kOffset, + /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)); size_t bytes_consumed = frame.crypto_frame->data_length; EXPECT_LT(0u, bytes_consumed); } @@ -1176,6 +1180,44 @@ TEST_P(QuicPacketCreatorTest, SerializeFrame) { if (!GetParam().version_serialization) { creator_.StopSendingVersion(); } + std::string data("test data"); + if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { + QuicStreamFrame stream_frame( + QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), + /*fin=*/false, 0u, QuicStringPiece()); + frames_.push_back(QuicFrame(stream_frame)); + } else { + producer_.SaveCryptoData(ENCRYPTION_INITIAL, 0, data); + frames_.push_back( + QuicFrame(new QuicCryptoFrame(ENCRYPTION_INITIAL, 0, data.length()))); + } + SerializedPacket serialized = SerializeAllFrames(frames_); + + QuicPacketHeader header; + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)) + .WillOnce(DoAll(SaveArg<0>(&header), Return(true))); + if (QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { + EXPECT_CALL(framer_visitor_, OnCryptoFrame(_)); + } else { + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + } + EXPECT_CALL(framer_visitor_, OnPacketComplete()); + } + ProcessPacket(serialized); + EXPECT_EQ(GetParam().version_serialization, header.version_flag); + DeleteFrames(&frames_); +} + +TEST_P(QuicPacketCreatorTest, SerializeFrameShortData) { + if (!GetParam().version_serialization) { + creator_.StopSendingVersion(); + } std::string data("a"); if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { QuicStreamFrame stream_frame( @@ -1203,6 +1245,9 @@ TEST_P(QuicPacketCreatorTest, SerializeFrame) { } else { EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); } + if (client_framer_.version().HasHeaderProtection()) { + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); + } EXPECT_CALL(framer_visitor_, OnPacketComplete()); } ProcessPacket(serialized); @@ -1240,8 +1285,14 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) { const size_t max_plaintext_size = client_framer_.GetMaxPlaintextSize(creator_.max_packet_length()); EXPECT_FALSE(creator_.HasPendingFrames()); - EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()))); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( + client_framer_.transport_version(), Perspective::IS_CLIENT); + if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { + stream_id = + QuicUtils::GetCryptoStreamId(client_framer_.transport_version()); + } + EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id)); EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize( client_framer_.transport_version(), @@ -1262,20 +1313,17 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) { EXPECT_TRUE( creator_.AddSavedFrame(QuicFrame(&ack_frame), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); - EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()))); + EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id)); QuicFrame frame; MakeIOVector("test", &iov_); EXPECT_CALL(debug, OnFrameAddedToPacket(_)); - ASSERT_TRUE(creator_.ConsumeData( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_, - 1u, iov_.iov_len, 0u, 0u, false, false, NOT_RETRANSMISSION, &frame)); + ASSERT_TRUE(creator_.ConsumeData(stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, + false, false, NOT_RETRANSMISSION, &frame)); size_t consumed = frame.stream_frame.data_length; EXPECT_EQ(4u, consumed); EXPECT_TRUE(creator_.HasPendingFrames()); - EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()))); + EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(stream_id)); QuicPaddingFrame padding_frame; EXPECT_CALL(debug, OnFrameAddedToPacket(_)); @@ -1301,8 +1349,7 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) { DeleteSerializedPacket(); EXPECT_FALSE(creator_.HasPendingFrames()); - EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()))); + EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id)); EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize( client_framer_.transport_version(), @@ -1355,13 +1402,29 @@ TEST_P(QuicPacketCreatorTest, AddUnencryptedStreamDataClosesConnection) { } creator_.set_encryption_level(ENCRYPTION_INITIAL); - EXPECT_CALL(delegate_, OnUnrecoverableError(_, _, _)); + EXPECT_CALL(delegate_, OnUnrecoverableError(_, _)); QuicStreamFrame stream_frame( QuicUtils::GetHeadersStreamId(client_framer_.transport_version()), /*fin=*/false, 0u, QuicStringPiece()); EXPECT_QUIC_BUG( creator_.AddSavedFrame(QuicFrame(stream_frame), NOT_RETRANSMISSION), - "Cannot send stream data without encryption."); + "Cannot send stream data with level: ENCRYPTION_INITIAL"); +} + +TEST_P(QuicPacketCreatorTest, SendStreamDataWithEncryptionHandshake) { + // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. + if (!IsDefaultTestConfiguration()) { + return; + } + + creator_.set_encryption_level(ENCRYPTION_HANDSHAKE); + EXPECT_CALL(delegate_, OnUnrecoverableError(_, _)); + QuicStreamFrame stream_frame( + QuicUtils::GetHeadersStreamId(client_framer_.transport_version()), + /*fin=*/false, 0u, QuicStringPiece()); + EXPECT_QUIC_BUG( + creator_.AddSavedFrame(QuicFrame(stream_frame), NOT_RETRANSMISSION), + "Cannot send stream data with level: ENCRYPTION_HANDSHAKE"); } TEST_P(QuicPacketCreatorTest, ChloTooLarge) { @@ -1388,8 +1451,7 @@ TEST_P(QuicPacketCreatorTest, ChloTooLarge) { MakeIOVector(QuicStringPiece(message_data->data(), message_data->length()), &iov); QuicFrame frame; - EXPECT_CALL(delegate_, - OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, _, _)); + EXPECT_CALL(delegate_, OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, _)); EXPECT_QUIC_BUG(creator_.ConsumeData(QuicUtils::GetCryptoStreamId( client_framer_.transport_version()), &iov, 1u, iov.iov_len, 0u, 0u, false, @@ -1738,7 +1800,7 @@ TEST_P(QuicPacketCreatorTest, PacketTransmissionType) { creator_.Flush(); ASSERT_TRUE(serialized_packet_.encrypted_buffer); - if (creator_.ShouldSetTransmissionTypeForNextFrame()) { + if (creator_.can_set_transmission_type()) { // The last retransmittable frame on packet is a stream frame, the packet's // transmission type should be the same as the stream frame's. EXPECT_EQ(serialized_packet_.transmission_type, RTO_RETRANSMISSION); @@ -1787,6 +1849,9 @@ TEST_P(QuicPacketCreatorTest, RetryToken) { } else { EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); } + if (client_framer_.version().HasHeaderProtection()) { + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); + } EXPECT_CALL(framer_visitor_, OnPacketComplete()); } ProcessPacket(serialized); @@ -1799,6 +1864,16 @@ TEST_P(QuicPacketCreatorTest, RetryToken) { DeleteFrames(&frames_); } +TEST_P(QuicPacketCreatorTest, GetConnectionId) { + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + EXPECT_EQ(TestConnectionId(2), creator_.GetDestinationConnectionId()); + EXPECT_EQ(TestConnectionId(2), creator_.GetSourceConnectionId()); + return; + } + EXPECT_EQ(TestConnectionId(2), creator_.GetDestinationConnectionId()); + EXPECT_EQ(EmptyQuicConnectionId(), creator_.GetSourceConnectionId()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc index 6efadcf12c6..d57aad41f47 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.cc @@ -14,15 +14,16 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.h" namespace quic { -QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId connection_id, +QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId server_connection_id, QuicFramer* framer, QuicRandom* random_generator, DelegateInterface* delegate) : delegate_(delegate), - packet_creator_(connection_id, framer, random_generator, delegate), + packet_creator_(server_connection_id, framer, random_generator, delegate), next_transmission_type_(NOT_RETRANSMISSION), flusher_attached_(false), should_send_ack_(false), @@ -30,7 +31,10 @@ QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId connection_id, random_generator_(random_generator), fully_pad_crypto_handshake_packets_(true), deprecate_ack_bundling_mode_( - GetQuicReloadableFlag(quic_deprecate_ack_bundling_mode)) {} + GetQuicReloadableFlag(quic_deprecate_ack_bundling_mode)), + deprecate_queued_control_frames_( + deprecate_ack_bundling_mode_ && + GetQuicReloadableFlag(quic_deprecate_queued_control_frames)) {} QuicPacketGenerator::~QuicPacketGenerator() { DeleteFrames(&queued_control_frames_); @@ -53,14 +57,37 @@ void QuicPacketGenerator::SetShouldSendAck(bool also_send_stop_waiting) { SendQueuedFrames(/*flush=*/false); } -void QuicPacketGenerator::AddControlFrame(const QuicFrame& frame) { +bool QuicPacketGenerator::ConsumeRetransmittableControlFrame( + const QuicFrame& frame) { QUIC_BUG_IF(IsControlFrame(frame.type) && !GetControlFrameId(frame)) << "Adding a control frame with no control frame id: " << frame; + DCHECK(QuicUtils::IsRetransmittableFrame(frame.type)) << frame; if (deprecate_ack_bundling_mode_) { MaybeBundleAckOpportunistically(); } + if (deprecate_queued_control_frames_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_deprecate_queued_control_frames); + if (packet_creator_.HasPendingFrames()) { + if (packet_creator_.AddSavedFrame(frame, next_transmission_type_)) { + // There is pending frames and current frame fits. + return true; + } + } + DCHECK(!packet_creator_.HasPendingFrames()); + if (frame.type != PING_FRAME && frame.type != CONNECTION_CLOSE_FRAME && + !delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, + NOT_HANDSHAKE)) { + // Do not check congestion window for ping or connection close frames. + return false; + } + const bool success = + packet_creator_.AddSavedFrame(frame, next_transmission_type_); + DCHECK(success); + return success; + } queued_control_frames_.push_back(frame); SendQueuedFrames(/*flush=*/false); + return true; } size_t QuicPacketGenerator::ConsumeCryptoData(EncryptionLevel level, @@ -85,7 +112,8 @@ size_t QuicPacketGenerator::ConsumeCryptoData(EncryptionLevel level, QuicFrame frame; if (!packet_creator_.ConsumeCryptoData( level, write_length - total_bytes_consumed, - offset + total_bytes_consumed, next_transmission_type_, &frame)) { + offset + total_bytes_consumed, fully_pad_crypto_handshake_packets_, + next_transmission_type_, &frame)) { // The only pending data in the packet is non-retransmittable frames. I'm // assuming here that they won't occupy so much of the packet that a // CRYPTO frame won't fit. @@ -111,7 +139,7 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to write stream data."; bool has_handshake = - (id == QuicUtils::GetCryptoStreamId(packet_creator_.transport_version())); + QuicUtils::IsCryptoStreamId(packet_creator_.transport_version(), id); if (deprecate_ack_bundling_mode_) { MaybeBundleAckOpportunistically(); } @@ -201,8 +229,7 @@ QuicConsumedData QuicPacketGenerator::ConsumeDataFastPath( QuicStreamOffset offset, bool fin, size_t total_bytes_consumed) { - DCHECK_NE(id, - QuicUtils::GetCryptoStreamId(packet_creator_.transport_version())); + DCHECK(!QuicUtils::IsCryptoStreamId(packet_creator_.transport_version(), id)); while (total_bytes_consumed < write_length && delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, @@ -275,8 +302,7 @@ void QuicPacketGenerator::SendQueuedFrames(bool flush) { QUIC_LOG(INFO) << queued_control_frames_[0]; } delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, - "Single frame cannot fit into a packet", - ConnectionCloseSource::FROM_SELF); + "Single frame cannot fit into a packet"); return; } } @@ -291,6 +317,9 @@ bool QuicPacketGenerator::PacketFlusherAttached() const { void QuicPacketGenerator::AttachPacketFlusher() { flusher_attached_ = true; + if (!write_start_packet_number_.IsInitialized()) { + write_start_packet_number_ = packet_creator_.NextSendingPacketNumber(); + } } void QuicPacketGenerator::Flush() { @@ -298,6 +327,17 @@ void QuicPacketGenerator::Flush() { packet_creator_.Flush(); SendRemainingPendingPadding(); flusher_attached_ = false; + if (GetQuicFlag(FLAGS_quic_export_server_num_packets_per_write_histogram)) { + if (!write_start_packet_number_.IsInitialized()) { + QUIC_BUG << "write_start_packet_number is not initialized"; + return; + } + QUIC_SERVER_HISTOGRAM_COUNTS( + "quic_server_num_written_packets_per_write", + packet_creator_.NextSendingPacketNumber() - write_start_packet_number_, + 1, 200, 50, "Number of QUIC packets written per write operation"); + } + write_start_packet_number_.Clear(); } void QuicPacketGenerator::FlushAllQueuedFrames() { @@ -412,11 +452,11 @@ void QuicPacketGenerator::UpdatePacketNumberLength( max_packets_in_flight); } -void QuicPacketGenerator::SetConnectionIdLength(uint32_t length) { +void QuicPacketGenerator::SetServerConnectionIdLength(uint32_t length) { if (length == 0) { - packet_creator_.SetConnectionIdIncluded(CONNECTION_ID_ABSENT); + packet_creator_.SetServerConnectionIdIncluded(CONNECTION_ID_ABSENT); } else { - packet_creator_.SetConnectionIdIncluded(CONNECTION_ID_PRESENT); + packet_creator_.SetServerConnectionIdIncluded(CONNECTION_ID_PRESENT); } } @@ -454,11 +494,15 @@ bool QuicPacketGenerator::HasPendingStreamFramesOfStream( void QuicPacketGenerator::SetTransmissionType(TransmissionType type) { packet_creator_.SetTransmissionType(type); - if (packet_creator_.ShouldSetTransmissionTypeForNextFrame()) { + if (packet_creator_.can_set_transmission_type()) { next_transmission_type_ = type; } } +void QuicPacketGenerator::SetRetryToken(QuicStringPiece retry_token) { + packet_creator_.SetRetryToken(retry_token); +} + void QuicPacketGenerator::SetCanSetTransmissionType( bool can_set_transmission_type) { packet_creator_.set_can_set_transmission_type(can_set_transmission_type); @@ -539,8 +583,9 @@ QuicPacketLength QuicPacketGenerator::GetGuaranteedLargestMessagePayload() return packet_creator_.GetGuaranteedLargestMessagePayload(); } -void QuicPacketGenerator::SetConnectionId(QuicConnectionId connection_id) { - packet_creator_.SetConnectionId(connection_id); +void QuicPacketGenerator::SetServerConnectionId( + QuicConnectionId server_connection_id) { + packet_creator_.SetServerConnectionId(server_connection_id); } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h index dc191a0eba2..327cc47238b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator.h @@ -76,7 +76,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { QuicStopWaitingFrame* stop_waiting) = 0; }; - QuicPacketGenerator(QuicConnectionId connection_id, + QuicPacketGenerator(QuicConnectionId server_connection_id, QuicFramer* framer, QuicRandom* random_generator, DelegateInterface* delegate); @@ -92,7 +92,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { // CreateAckFrame() when the packet is serialized. void SetShouldSendAck(bool also_send_stop_waiting); - void AddControlFrame(const QuicFrame& frame); + // Consumes retransmittable control |frame|. Returns true if the frame is + // successfully consumed. Returns false otherwise. + bool ConsumeRetransmittableControlFrame(const QuicFrame& frame); // Given some data, may consume part or all of it and pass it to the // packet creator to be serialized into packets. If not in batch @@ -183,8 +185,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { void UpdatePacketNumberLength(QuicPacketNumber least_packet_awaited_by_peer, QuicPacketCount max_packets_in_flight); - // Set the minimum number of bytes for the connection id length; - void SetConnectionIdLength(uint32_t length); + // Set the minimum number of bytes for the server connection id length; + void SetServerConnectionIdLength(uint32_t length); // Sets the encrypter to use for the encryption level. void SetEncrypter(EncryptionLevel level, @@ -215,6 +217,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { // Set transmission type of next constructed packets. void SetTransmissionType(TransmissionType type); + // Sets the retry token to be sent over the wire in IETF Initial packets. + void SetRetryToken(QuicStringPiece retry_token); + // Allow/Disallow setting transmission type of next constructed packets. void SetCanSetTransmissionType(bool can_set_transmission_type); @@ -230,8 +235,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { QuicPacketLength GetCurrentLargestMessagePayload() const; QuicPacketLength GetGuaranteedLargestMessagePayload() const; - // Update the connection ID used in outgoing packets. - void SetConnectionId(QuicConnectionId connection_id); + // Update the server connection ID used in outgoing packets. + void SetServerConnectionId(QuicConnectionId server_connection_id); void set_debug_delegate(QuicPacketCreator::DebugDelegate* debug_delegate) { packet_creator_.set_debug_delegate(debug_delegate); @@ -251,6 +256,10 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { return deprecate_ack_bundling_mode_; } + bool deprecate_queued_control_frames() const { + return deprecate_queued_control_frames_; + } + private: friend class test::QuicPacketGeneratorPeer; @@ -281,6 +290,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { DelegateInterface* delegate_; QuicPacketCreator packet_creator_; + // TODO(fayang): remove this when deprecating + // quic_deprecate_queued_control_frames. QuicFrames queued_control_frames_; // Transmission type of the next serialized packet. @@ -307,8 +318,16 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { // Whether crypto handshake packets should be fully padded. bool fully_pad_crypto_handshake_packets_; + // Packet number of the first packet of a write operation. This gets set + // when the out-most flusher attaches and gets cleared when the out-most + // flusher detaches. + QuicPacketNumber write_start_packet_number_; + // Latched value of quic_deprecate_ack_bundling_mode. const bool deprecate_ack_bundling_mode_; + + // Latched value of quic_deprecate_queued_control_frames. + const bool deprecate_queued_control_frames_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc index 1e12424743e..7212e22f76a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_generator_test.cc @@ -51,8 +51,7 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface { MOCK_METHOD1(PopulateStopWaitingFrame, void(QuicStopWaitingFrame*)); MOCK_METHOD0(GetPacketBuffer, char*()); MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet)); - MOCK_METHOD3(OnUnrecoverableError, - void(QuicErrorCode, const std::string&, ConnectionCloseSource)); + MOCK_METHOD2(OnUnrecoverableError, void(QuicErrorCode, const std::string&)); void SetCanWriteAnything() { EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true)); @@ -118,7 +117,8 @@ class TestPacketGenerator : public QuicPacketGenerator { delegate_(static_cast<MockDelegate*>(delegate)), producer_(producer) {} - void AddControlFrame(const QuicFrame& frame, bool bundle_ack) { + bool ConsumeRetransmittableControlFrame(const QuicFrame& frame, + bool bundle_ack) { if (GetQuicReloadableFlag(quic_deprecate_ack_bundling_mode) && !QuicPacketGeneratorPeer::GetPacketCreator(this)->has_ack()) { QuicFrames frames; @@ -131,7 +131,7 @@ class TestPacketGenerator : public QuicPacketGenerator { .WillOnce(Return(frames)); } } - QuicPacketGenerator::AddControlFrame(frame); + return QuicPacketGenerator::ConsumeRetransmittableControlFrame(frame); } QuicConsumedData ConsumeDataFastPath(QuicStreamId id, @@ -271,7 +271,11 @@ class QuicPacketGeneratorTest : public QuicTest { ASSERT_TRUE(packet.encrypted_buffer != nullptr); ASSERT_TRUE(simple_framer_.ProcessPacket( QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length))); - EXPECT_EQ(num_frames, simple_framer_.num_frames()); + size_t num_padding_frames = 0; + if (contents.num_padding_frames == 0) { + num_padding_frames = simple_framer_.padding_frames().size(); + } + EXPECT_EQ(num_frames + num_padding_frames, simple_framer_.num_frames()); EXPECT_EQ(contents.num_ack_frames, simple_framer_.ack_frames().size()); EXPECT_EQ(contents.num_connection_close_frames, simple_framer_.connection_close_frames().size()); @@ -285,8 +289,10 @@ class QuicPacketGeneratorTest : public QuicTest { simple_framer_.crypto_frames().size()); EXPECT_EQ(contents.num_stop_waiting_frames, simple_framer_.stop_waiting_frames().size()); - EXPECT_EQ(contents.num_padding_frames, - simple_framer_.padding_frames().size()); + if (contents.num_padding_frames != 0) { + EXPECT_EQ(contents.num_padding_frames, + simple_framer_.padding_frames().size()); + } // From the receiver's perspective, MTU discovery frames are ping frames. EXPECT_EQ(contents.num_ping_frames + contents.num_mtu_discovery_frames, @@ -414,26 +420,45 @@ TEST_F(QuicPacketGeneratorTest, ShouldSendAck_MultipleCalls) { TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) { delegate_.SetCanNotWrite(); - generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/false); - EXPECT_TRUE(generator_.HasQueuedFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool consumed = + generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false); + if (generator_.deprecate_queued_control_frames()) { + EXPECT_FALSE(consumed); + EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); + delete rst_frame; + } else { + EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); + } } TEST_F(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) { delegate_.SetCanWriteOnlyNonRetransmittable(); - generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/false); - EXPECT_TRUE(generator_.HasQueuedFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool consumed = + generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false); + if (generator_.deprecate_queued_control_frames()) { + EXPECT_FALSE(consumed); + EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); + delete rst_frame; + } else { + EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); + } } TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) { delegate_.SetCanWriteAnything(); - generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/false); + generator_.ConsumeRetransmittableControlFrame( + QuicFrame(CreateRstStreamFrame()), + /*bundle_ack=*/false); EXPECT_TRUE(generator_.HasQueuedFrames()); EXPECT_TRUE(generator_.HasRetransmittableFrames()); } @@ -441,8 +466,17 @@ TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) { TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) { delegate_.SetCanNotWrite(); - generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/false); + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool consumed = + generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false); + if (generator_.deprecate_queued_control_frames()) { + EXPECT_FALSE(consumed); + EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); + delete rst_frame; + return; + } EXPECT_TRUE(generator_.HasQueuedFrames()); EXPECT_TRUE(generator_.HasRetransmittableFrames()); generator_.Flush(); @@ -467,8 +501,9 @@ TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) { EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/false); + generator_.ConsumeRetransmittableControlFrame( + QuicFrame(CreateRstStreamFrame()), + /*bundle_ack=*/false); generator_.Flush(); EXPECT_FALSE(generator_.HasQueuedFrames()); EXPECT_FALSE(generator_.HasRetransmittableFrames()); @@ -551,16 +586,29 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake) { EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - MakeIOVector("foo", &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetCryptoStreamId(framer_.transport_version()), &iov_, 1u, - iov_.iov_len, 0, NO_FIN); - EXPECT_EQ(3u, consumed.bytes_consumed); + std::string data = "foo bar"; + MakeIOVector(data, &iov_); + size_t consumed_bytes = 0; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + consumed_bytes = generator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); + } else { + consumed_bytes = + generator_ + .ConsumeData( + QuicUtils::GetCryptoStreamId(framer_.transport_version()), + &iov_, 1u, iov_.iov_len, 0, NO_FIN) + .bytes_consumed; + } + EXPECT_EQ(7u, consumed_bytes); EXPECT_FALSE(generator_.HasQueuedFrames()); EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; - contents.num_stream_frames = 1; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + contents.num_crypto_frames = 1; + } else { + contents.num_stream_frames = 1; + } contents.num_padding_frames = 1; CheckPacketContains(contents, 0); @@ -578,16 +626,29 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake_PaddingDisabled) { EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - MakeIOVector("foo", &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetCryptoStreamId(framer_.transport_version()), &iov_, 1u, - iov_.iov_len, 0, NO_FIN); - EXPECT_EQ(3u, consumed.bytes_consumed); + std::string data = "foo"; + MakeIOVector(data, &iov_); + size_t bytes_consumed = 0; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + bytes_consumed = generator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); + } else { + bytes_consumed = + generator_ + .ConsumeData( + QuicUtils::GetCryptoStreamId(framer_.transport_version()), + &iov_, 1u, iov_.iov_len, 0, NO_FIN) + .bytes_consumed; + } + EXPECT_EQ(3u, bytes_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; - contents.num_stream_frames = 1; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + contents.num_crypto_frames = 1; + } else { + contents.num_stream_frames = 1; + } contents.num_padding_frames = 0; CheckPacketContains(contents, 0); @@ -595,7 +656,16 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake_PaddingDisabled) { // Packet is not fully padded, but we want to future packets to be larger. ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength()); - EXPECT_EQ(27, packets_[0].encrypted_length); + size_t expected_packet_length = 27; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + // The framing of CRYPTO frames is slightly different than that of stream + // frames, so the expected packet length differs slightly. + expected_packet_length = 28; + } + if (framer_.version().HasHeaderProtection()) { + expected_packet_length = 29; + } + EXPECT_EQ(expected_packet_length, packets_[0].encrypted_length); } TEST_F(QuicPacketGeneratorTest, ConsumeData_EmptyData) { @@ -778,10 +848,18 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataLargeSendAckFalse) { if (!GetQuicReloadableFlag(quic_deprecate_ack_bundling_mode)) { generator_.SetShouldSendAck(false); } - generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/true); - EXPECT_TRUE(generator_.HasQueuedFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool success = + generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/true); + if (generator_.deprecate_queued_control_frames()) { + EXPECT_FALSE(success); + EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); + } else { + EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); + } delegate_.SetCanWriteAnything(); @@ -789,11 +867,20 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataLargeSendAckFalse) { EXPECT_CALL(delegate_, GetUpdatedAckFrame()) .WillOnce(Return(QuicFrame(&ack_frame_))); } + if (generator_.deprecate_queued_control_frames()) { + generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false); + } // Create a 10000 byte IOVector. CreateData(10000); EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); + if (generator_.deprecate_queued_control_frames()) { + generator_.ConsumeRetransmittableControlFrame( + QuicFrame(CreateRstStreamFrame()), + /*bundle_ack=*/true); + } QuicConsumedData consumed = generator_.ConsumeData( QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, iov_.iov_len, 0, FIN); @@ -863,10 +950,18 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) { if (!GetQuicReloadableFlag(quic_deprecate_ack_bundling_mode)) { generator_.SetShouldSendAck(false); } - generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/true); - EXPECT_TRUE(generator_.HasQueuedFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool consumed = + generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/true); + if (generator_.deprecate_queued_control_frames()) { + EXPECT_FALSE(consumed); + EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); + } else { + EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); + } EXPECT_FALSE(generator_.HasPendingStreamFramesOfStream(3)); delegate_.SetCanWriteAnything(); @@ -877,13 +972,18 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) { EXPECT_CALL(delegate_, GetUpdatedAckFrame()) .WillOnce(Return(QuicFrame(&ack_frame_))); } - + if (generator_.deprecate_queued_control_frames()) { + EXPECT_TRUE( + generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false)); + } // Send some data and a control frame MakeIOVector("quux", &iov_); generator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, NO_FIN); if (framer_.transport_version() != QUIC_VERSION_99) { - generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame()), - /*bundle_ack=*/false); + generator_.ConsumeRetransmittableControlFrame( + QuicFrame(CreateGoAwayFrame()), + /*bundle_ack=*/false); } EXPECT_TRUE(generator_.HasPendingStreamFramesOfStream(3)); @@ -918,10 +1018,18 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) { if (!GetQuicReloadableFlag(quic_deprecate_ack_bundling_mode)) { generator_.SetShouldSendAck(false); } - generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()), - /*bundle_ack=*/true); - EXPECT_TRUE(generator_.HasQueuedFrames()); - EXPECT_TRUE(generator_.HasRetransmittableFrames()); + QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); + const bool success = + generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/true); + if (generator_.deprecate_queued_control_frames()) { + EXPECT_FALSE(success); + EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); + } else { + EXPECT_TRUE(generator_.HasQueuedFrames()); + EXPECT_TRUE(generator_.HasRetransmittableFrames()); + } delegate_.SetCanWriteAnything(); @@ -940,7 +1048,11 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) { EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); } - + if (generator_.deprecate_queued_control_frames()) { + EXPECT_TRUE( + generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), + /*bundle_ack=*/false)); + } // Send enough data to exceed one packet size_t data_len = kDefaultMaxPacketSize + 100; CreateData(data_len); @@ -949,8 +1061,9 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) { EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); if (framer_.transport_version() != QUIC_VERSION_99) { - generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame()), - /*bundle_ack=*/false); + generator_.ConsumeRetransmittableControlFrame( + QuicFrame(CreateGoAwayFrame()), + /*bundle_ack=*/false); } generator_.Flush(); @@ -1017,23 +1130,20 @@ TEST_F(QuicPacketGeneratorTest, PacketTransmissionType) { ASSERT_EQ(1u, packets_[0].retransmittable_frames.size()); EXPECT_EQ(stream1_id, packets_[0].retransmittable_frames[0].stream_frame.stream_id); - if (GetQuicReloadableFlag(quic_set_transmission_type_for_next_frame)) { - // Since the second frame was not added, the packet's transmission type - // should be the first frame's type. - EXPECT_EQ(packets_[0].transmission_type, LOSS_RETRANSMISSION); - } else { - EXPECT_EQ(packets_[0].transmission_type, NOT_RETRANSMISSION); - } + + // Since the second frame was not added, the packet's transmission type + // should be the first frame's type. + EXPECT_EQ(packets_[0].transmission_type, LOSS_RETRANSMISSION); } TEST_F(QuicPacketGeneratorTest, TestConnectionIdLength) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); - generator_.SetConnectionIdLength(0); + generator_.SetServerConnectionIdLength(0); EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, creator_->GetDestinationConnectionIdLength()); for (size_t i = 1; i < 10; i++) { - generator_.SetConnectionIdLength(i); + generator_.SetServerConnectionIdLength(i); if (framer_.transport_version() > QUIC_VERSION_43) { EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, creator_->GetDestinationConnectionIdLength()); @@ -1341,8 +1451,7 @@ TEST_F(QuicPacketGeneratorTest, DontCrashOnInvalidStopWaiting) { // This will not serialize any packets, because of the invalid frame. EXPECT_CALL(delegate_, - OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, _, - ConnectionCloseSource::FROM_SELF)); + OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, _)); EXPECT_QUIC_BUG(generator_.Flush(), "packet_number_length 1 is too small " "for least_unacked_delta: 1001"); @@ -1358,7 +1467,8 @@ TEST_F(QuicPacketGeneratorTest, ConnectionCloseFrameLargerThanPacketSize) { if (framer_.transport_version() == QUIC_VERSION_99) { frame->close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE; } - generator_.AddControlFrame(QuicFrame(frame), /*bundle_ack=*/false); + generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame), + /*bundle_ack=*/false); EXPECT_TRUE(generator_.HasQueuedFrames()); EXPECT_TRUE(generator_.HasRetransmittableFrames()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.h index 5348abd7c69..0cf7f15d9f7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_number.h @@ -10,7 +10,6 @@ #include <string> #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_reader.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_reader.cc index f03aa6d80fe..d2dfd2245fb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_reader.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_reader.cc @@ -86,7 +86,7 @@ bool QuicPacketReader::ReadAndDispatchManyPackets( DCHECK_LE(kMaxOutgoingPacketSize, packets_[i].iov.iov_len); msghdr* hdr = &mmsg_hdr_[i].msg_hdr; hdr->msg_namelen = sizeof(sockaddr_storage); - DCHECK_EQ(1, hdr->msg_iovlen); + DCHECK_EQ(1u, hdr->msg_iovlen); hdr->msg_controllen = kCmsgSpaceForReadPacket; hdr->msg_flags = 0; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc index 9b2cb097a34..57bda5476a6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc @@ -8,6 +8,7 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" @@ -16,6 +17,47 @@ namespace quic { +QuicConnectionId GetServerConnectionIdAsRecipient( + const QuicPacketHeader& header, + Perspective perspective) { + if (perspective == Perspective::IS_SERVER || + !GetQuicRestartFlag(quic_do_not_override_connection_id)) { + return header.destination_connection_id; + } + return header.source_connection_id; +} + +QuicConnectionId GetServerConnectionIdAsSender(const QuicPacketHeader& header, + Perspective perspective) { + if (perspective == Perspective::IS_CLIENT || + !GetQuicRestartFlag(quic_do_not_override_connection_id)) { + return header.destination_connection_id; + } + QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 3, 5); + return header.source_connection_id; +} + +QuicConnectionIdIncluded GetServerConnectionIdIncludedAsSender( + const QuicPacketHeader& header, + Perspective perspective) { + if (perspective == Perspective::IS_CLIENT || + !GetQuicRestartFlag(quic_do_not_override_connection_id)) { + return header.destination_connection_id_included; + } + QUIC_RESTART_FLAG_COUNT_N(quic_do_not_override_connection_id, 4, 5); + return header.source_connection_id_included; +} + +QuicConnectionIdIncluded GetClientConnectionIdIncludedAsSender( + const QuicPacketHeader& header, + Perspective perspective) { + if (perspective == Perspective::IS_CLIENT || + !GetQuicRestartFlag(quic_do_not_override_connection_id)) { + return header.source_connection_id_included; + } + return header.destination_connection_id_included; +} + QuicConnectionIdLength GetIncludedConnectionIdLength( QuicConnectionId connection_id, QuicConnectionIdIncluded connection_id_included) { @@ -74,7 +116,13 @@ size_t GetPacketHeaderSize( return kPacketHeaderTypeSize + destination_connection_id_length + packet_number_length; } + // Google QUIC versions <= 43 can only carry one connection ID. + DCHECK(destination_connection_id_length == 0 || + source_connection_id_length == 0); + DCHECK(source_connection_id_length == 0 || + GetQuicRestartFlag(quic_do_not_override_connection_id)); return kPublicFlagsSize + destination_connection_id_length + + source_connection_id_length + (include_version ? kQuicVersionSize : 0) + packet_number_length + (include_diversification_nonce ? kDiversificationNonceSize : 0); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h index e745e072ced..d3c2600e818 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h @@ -32,6 +32,32 @@ namespace quic { class QuicPacket; struct QuicPacketHeader; +// Returns the destination connection ID of |header| when |perspective| is +// server, and the source connection ID when |perspective| is client. +QUIC_EXPORT_PRIVATE QuicConnectionId +GetServerConnectionIdAsRecipient(const QuicPacketHeader& header, + Perspective perspective); + +// Returns the destination connection ID of |header| when |perspective| is +// client, and the source connection ID when |perspective| is server. +QUIC_EXPORT_PRIVATE QuicConnectionId +GetServerConnectionIdAsSender(const QuicPacketHeader& header, + Perspective perspective); + +// Returns the destination connection ID included of |header| when |perspective| +// is client, and the source connection ID included when |perspective| is +// server. +QUIC_EXPORT_PRIVATE QuicConnectionIdIncluded +GetServerConnectionIdIncludedAsSender(const QuicPacketHeader& header, + Perspective perspective); + +// Returns the destination connection ID included of |header| when |perspective| +// is server, and the source connection ID included when |perspective| is +// client. +QUIC_EXPORT_PRIVATE QuicConnectionIdIncluded +GetClientConnectionIdIncludedAsSender(const QuicPacketHeader& header, + Perspective perspective); + // Number of connection ID bytes that are actually included over the wire. QUIC_EXPORT_PRIVATE QuicConnectionIdLength GetIncludedConnectionIdLength(QuicConnectionId connection_id, @@ -102,6 +128,7 @@ struct QUIC_EXPORT_PRIVATE QuicPacketHeader { // parsed from the packet buffer. IETF QUIC only, always false for GQUIC. bool has_possible_stateless_reset_token; QuicPacketNumberLength packet_number_length; + uint8_t type_byte; ParsedQuicVersion version; // nonce contains an optional, 32-byte nonce value. If not included in the // packet, |nonce| will be empty. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc new file mode 100644 index 00000000000..9ea369e874b --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets_test.cc @@ -0,0 +1,91 @@ +// Copyright (c) 2019 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/third_party/quiche/src/quic/core/quic_packets.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { +namespace { + +QuicPacketHeader CreateFakePacketHeader() { + QuicPacketHeader header; + header.destination_connection_id = TestConnectionId(1); + header.destination_connection_id_included = CONNECTION_ID_PRESENT; + header.source_connection_id = TestConnectionId(2); + header.source_connection_id_included = CONNECTION_ID_ABSENT; + return header; +} + +class QuicPacketsTest : public QuicTest {}; + +TEST_F(QuicPacketsTest, GetServerConnectionIdAsRecipient) { + QuicPacketHeader header = CreateFakePacketHeader(); + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + EXPECT_EQ(TestConnectionId(1), + GetServerConnectionIdAsRecipient(header, Perspective::IS_SERVER)); + EXPECT_EQ(TestConnectionId(1), + GetServerConnectionIdAsRecipient(header, Perspective::IS_CLIENT)); + return; + } + + EXPECT_EQ(TestConnectionId(1), + GetServerConnectionIdAsRecipient(header, Perspective::IS_SERVER)); + EXPECT_EQ(TestConnectionId(2), + GetServerConnectionIdAsRecipient(header, Perspective::IS_CLIENT)); +} + +TEST_F(QuicPacketsTest, GetServerConnectionIdAsSender) { + QuicPacketHeader header = CreateFakePacketHeader(); + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + EXPECT_EQ(TestConnectionId(1), + GetServerConnectionIdAsSender(header, Perspective::IS_SERVER)); + EXPECT_EQ(TestConnectionId(1), + GetServerConnectionIdAsSender(header, Perspective::IS_CLIENT)); + return; + } + + EXPECT_EQ(TestConnectionId(2), + GetServerConnectionIdAsSender(header, Perspective::IS_SERVER)); + EXPECT_EQ(TestConnectionId(1), + GetServerConnectionIdAsSender(header, Perspective::IS_CLIENT)); +} + +TEST_F(QuicPacketsTest, GetServerConnectionIdIncludedAsSender) { + QuicPacketHeader header = CreateFakePacketHeader(); + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + EXPECT_EQ(CONNECTION_ID_PRESENT, GetServerConnectionIdIncludedAsSender( + header, Perspective::IS_SERVER)); + EXPECT_EQ(CONNECTION_ID_PRESENT, GetServerConnectionIdIncludedAsSender( + header, Perspective::IS_CLIENT)); + return; + } + + EXPECT_EQ(CONNECTION_ID_ABSENT, GetServerConnectionIdIncludedAsSender( + header, Perspective::IS_SERVER)); + EXPECT_EQ(CONNECTION_ID_PRESENT, GetServerConnectionIdIncludedAsSender( + header, Perspective::IS_CLIENT)); +} + +TEST_F(QuicPacketsTest, GetClientConnectionIdIncludedAsSender) { + QuicPacketHeader header = CreateFakePacketHeader(); + if (!GetQuicRestartFlag(quic_do_not_override_connection_id)) { + EXPECT_EQ(CONNECTION_ID_ABSENT, GetClientConnectionIdIncludedAsSender( + header, Perspective::IS_SERVER)); + EXPECT_EQ(CONNECTION_ID_ABSENT, GetClientConnectionIdIncludedAsSender( + header, Perspective::IS_CLIENT)); + return; + } + + EXPECT_EQ(CONNECTION_ID_PRESENT, GetClientConnectionIdIncludedAsSender( + header, Perspective::IS_SERVER)); + EXPECT_EQ(CONNECTION_ID_ABSENT, GetClientConnectionIdIncludedAsSender( + header, Perspective::IS_CLIENT)); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc index 528b8665bb6..6fb8c493afa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc @@ -132,7 +132,7 @@ void QuicReceivedPacketManager::RecordPacketReceived( // The timestamp format only handles packets in time order. if (!ack_frame_.received_packet_times.empty() && ack_frame_.received_packet_times.back().second > receipt_time) { - LOG(WARNING) + QUIC_LOG(WARNING) << "Receive time went backwards from: " << ack_frame_.received_packet_times.back().second.ToDebuggingValue() << " to " << receipt_time.ToDebuggingValue(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc index 456e81c18dd..527f820745b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc @@ -66,6 +66,11 @@ inline bool ShouldForceRetransmission(TransmissionType transmission_type) { transmission_type == RTO_RETRANSMISSION; } +// If pacing rate is accurate, > 2 burst token is not likely to help first ACK +// to arrive earlier, and overly large burst token could cause incast packet +// losses. +static const uint32_t kConservativeUnpacedBurst = 2; + } // namespace #define ENDPOINT \ @@ -75,11 +80,13 @@ inline bool ShouldForceRetransmission(TransmissionType transmission_type) { QuicSentPacketManager::QuicSentPacketManager( Perspective perspective, const QuicClock* clock, + QuicRandom* random, QuicConnectionStats* stats, CongestionControlType congestion_control_type, LossDetectionType loss_type) : unacked_packets_(perspective), clock_(clock), + random_(random), stats_(stats), debug_delegate_(nullptr), network_change_visitor_(nullptr), @@ -109,10 +116,15 @@ QuicSentPacketManager::QuicSentPacketManager( QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)), rtt_updated_(false), acked_packets_iter_(last_ack_frame_.packets.rbegin()), - tolerate_reneging_(GetQuicReloadableFlag(quic_tolerate_reneging)) { + tolerate_reneging_(GetQuicReloadableFlag(quic_tolerate_reneging)), + loss_removes_from_inflight_( + GetQuicReloadableFlag(quic_loss_removes_from_inflight)) { if (tolerate_reneging_) { QUIC_RELOADABLE_FLAG_COUNT(quic_tolerate_reneging); } + if (loss_removes_from_inflight_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_loss_removes_from_inflight); + } SetSendAlgorithm(congestion_control_type); } @@ -252,17 +264,28 @@ void QuicSentPacketManager::ResumeConnectionState( : cached_network_params.bandwidth_estimate_bytes_per_second()); QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); - AdjustNetworkParameters(bandwidth, rtt); + AdjustNetworkParameters(bandwidth, rtt, /*allow_cwnd_to_decrease=*/false); } -void QuicSentPacketManager::AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) { +void QuicSentPacketManager::AdjustNetworkParameters( + QuicBandwidth bandwidth, + QuicTime::Delta rtt, + bool allow_cwnd_to_decrease) { if (!rtt.IsZero()) { SetInitialRtt(rtt); } - send_algorithm_->AdjustNetworkParameters(bandwidth, rtt); + const QuicByteCount old_cwnd = send_algorithm_->GetCongestionWindow(); + if (GetQuicReloadableFlag(quic_conservative_bursts) && using_pacing_ && + !bandwidth.IsZero()) { + QUIC_RELOADABLE_FLAG_COUNT(quic_conservative_bursts); + pacing_sender_.SetBurstTokens(kConservativeUnpacedBurst); + } + send_algorithm_->AdjustNetworkParameters(bandwidth, rtt, + allow_cwnd_to_decrease); if (debug_delegate_ != nullptr) { - debug_delegate_->OnAdjustNetworkParameters(bandwidth, rtt); + debug_delegate_->OnAdjustNetworkParameters( + bandwidth, rtt.IsZero() ? rtt_stats_.SmoothedOrInitialRtt() : rtt, + old_cwnd, send_algorithm_->GetCongestionWindow()); } } @@ -355,14 +378,25 @@ void QuicSentPacketManager::RetransmitUnackedPackets( DCHECK(retransmission_type == ALL_UNACKED_RETRANSMISSION || retransmission_type == ALL_INITIAL_RETRANSMISSION); QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked(); - for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); + for (QuicUnackedPacketMap::iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it, ++packet_number) { if ((retransmission_type == ALL_UNACKED_RETRANSMISSION || - it->encryption_level == ENCRYPTION_ZERO_RTT) && - unacked_packets_.HasRetransmittableFrames(*it)) { - MarkForRetransmission(packet_number, retransmission_type); + it->encryption_level == ENCRYPTION_ZERO_RTT)) { + if (loss_removes_from_inflight_ && it->in_flight) { + // Remove 0-RTT packets and packets of the wrong version from flight, + // because neither can be processed by the peer. + unacked_packets_.RemoveFromInFlight(&*it); + } + if (unacked_packets_.HasRetransmittableFrames(*it)) { + MarkForRetransmission(packet_number, retransmission_type); + } } } + if (retransmission_type == ALL_UNACKED_RETRANSMISSION && + unacked_packets_.bytes_in_flight() > 0) { + QUIC_BUG << "RetransmitUnackedPackets should remove all packets from flight" + << ", bytes_in_flight:" << unacked_packets_.bytes_in_flight(); + } } void QuicSentPacketManager::NeuterUnencryptedPackets() { @@ -382,15 +416,17 @@ void QuicSentPacketManager::NeuterUnencryptedPackets() { } for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it, ++packet_number) { - if (it->encryption_level == ENCRYPTION_INITIAL && - unacked_packets_.HasRetransmittableFrames(*it)) { - // Once you're forward secure, no unencrypted packets will be sent, crypto - // or otherwise. Unencrypted packets are neutered and abandoned, to ensure - // they are not retransmitted or considered lost from a congestion control - // perspective. - pending_retransmissions_.erase(packet_number); - unacked_packets_.RemoveFromInFlight(packet_number); - unacked_packets_.RemoveRetransmittability(packet_number); + if (it->encryption_level == ENCRYPTION_INITIAL) { + if (loss_removes_from_inflight_ || + unacked_packets_.HasRetransmittableFrames(*it)) { + // Once you're forward secure, no unencrypted packets will be sent, + // crypto or otherwise. Unencrypted packets are neutered and abandoned, + // to ensure they are not retransmitted or considered lost from a + // congestion control perspective. + pending_retransmissions_.erase(packet_number); + unacked_packets_.RemoveFromInFlight(packet_number); + unacked_packets_.RemoveRetransmittability(packet_number); + } } } } @@ -435,7 +471,8 @@ void QuicSentPacketManager::MarkForRetransmission( // Handshake packets should never be sent as probing retransmissions. DCHECK(!transmission_info->has_crypto_handshake || transmission_type != PROBING_RETRANSMISSION); - if (!RetransmissionLeavesBytesInFlight(transmission_type)) { + if (!loss_removes_from_inflight_ && + !RetransmissionLeavesBytesInFlight(transmission_type)) { unacked_packets_.RemoveFromInFlight(transmission_info); } @@ -852,6 +889,9 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) { time); } + if (loss_removes_from_inflight_) { + unacked_packets_.RemoveFromInFlight(packet.packet_number); + } MarkForRetransmission(packet.packet_number, LOSS_RETRANSMISSION); } } @@ -1054,8 +1094,8 @@ void QuicSentPacketManager::CancelRetransmissionsForStream( void QuicSentPacketManager::SetSendAlgorithm( CongestionControlType congestion_control_type) { SetSendAlgorithm(SendAlgorithmInterface::Create( - clock_, &rtt_stats_, &unacked_packets_, congestion_control_type, - QuicRandom::GetInstance(), stats_, initial_congestion_window_)); + clock_, &rtt_stats_, &unacked_packets_, congestion_control_type, random_, + stats_, initial_congestion_window_)); } void QuicSentPacketManager::SetSendAlgorithm( diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h index 7e10b77048c..3df874dd873 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h @@ -70,7 +70,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { virtual void OnApplicationLimited() {} virtual void OnAdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) {} + QuicTime::Delta rtt, + QuicByteCount old_cwnd, + QuicByteCount new_cwnd) {} }; // Interface which gets callbacks from the QuicSentPacketManager when @@ -89,6 +91,7 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { QuicSentPacketManager(Perspective perspective, const QuicClock* clock, + QuicRandom* random, QuicConnectionStats* stats, CongestionControlType congestion_control_type, LossDetectionType loss_type); @@ -127,7 +130,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Notify the sent packet manager of an external network measurement or // prediction for either |bandwidth| or |rtt|; either can be empty. - void AdjustNetworkParameters(QuicBandwidth bandwidth, QuicTime::Delta rtt); + void AdjustNetworkParameters(QuicBandwidth bandwidth, + QuicTime::Delta rtt, + bool allow_cwnd_to_decrease); // Retransmits the oldest pending packet there is still a tail loss probe // pending. Invoked after OnRetransmissionTimeout. @@ -535,6 +540,7 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { PendingRetransmissionMap pending_retransmissions_; const QuicClock* clock_; + QuicRandom* random_; QuicConnectionStats* stats_; DebugDelegate* debug_delegate_; @@ -627,6 +633,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Latched value of quic_tolerate_reneging. const bool tolerate_reneging_; + + // Latched value of quic_loss_removes_from_inflight. + const bool loss_removes_from_inflight_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc index 08e307c1a06..c508cca89dc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc @@ -80,7 +80,12 @@ class QuicSentPacketManagerTest : public QuicTestWithParam<bool> { protected: QuicSentPacketManagerTest() - : manager_(Perspective::IS_SERVER, &clock_, &stats_, kCubicBytes, kNack), + : manager_(Perspective::IS_SERVER, + &clock_, + QuicRandom::GetInstance(), + &stats_, + kCubicBytes, + kNack), send_algorithm_(new StrictMock<MockSendAlgorithm>), network_change_visitor_(new StrictMock<MockNetworkChangeVisitor>) { QuicSentPacketManagerPeer::SetSendAlgorithm(&manager_, send_algorithm_); @@ -110,9 +115,7 @@ class QuicSentPacketManagerTest : public QuicTestWithParam<bool> { ~QuicSentPacketManagerTest() override {} - QuicByteCount BytesInFlight() { - return QuicSentPacketManagerPeer::GetBytesInFlight(&manager_); - } + QuicByteCount BytesInFlight() { return manager_.GetBytesInFlight(); } void VerifyUnackedPackets(uint64_t* packets, size_t num_packets) { if (num_packets == 0) { EXPECT_TRUE(manager_.unacked_packets().empty()); @@ -124,7 +127,8 @@ class QuicSentPacketManagerTest : public QuicTestWithParam<bool> { EXPECT_FALSE(manager_.unacked_packets().empty()); EXPECT_EQ(QuicPacketNumber(packets[0]), manager_.GetLeastUnacked()); for (size_t i = 0; i < num_packets; ++i) { - EXPECT_TRUE(QuicSentPacketManagerPeer::IsUnacked(&manager_, packets[i])) + EXPECT_TRUE( + manager_.unacked_packets().IsUnacked(QuicPacketNumber(packets[i]))) << packets[i]; } } @@ -374,7 +378,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAck) { // Packet 1 is unacked, pending, but not retransmittable. uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_TRUE(manager_.HasInFlightPackets()); VerifyRetransmittablePackets(nullptr, 0); } @@ -461,7 +465,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPrevious) { // 2 remains unacked, but no packets have retransmittable data. uint64_t unacked[] = {2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_TRUE(manager_.HasInFlightPackets()); VerifyRetransmittablePackets(nullptr, 0); if (manager_.session_decides_what_to_write()) { // Ack 2 causes 2 be considered as spurious retransmission. @@ -535,7 +539,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { // No packets remain unacked. VerifyUnackedPackets(nullptr, 0); } - EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_FALSE(manager_.HasInFlightPackets()); VerifyRetransmittablePackets(nullptr, 0); // Verify that the retransmission alarm would not fire, @@ -568,7 +572,7 @@ TEST_P(QuicSentPacketManagerTest, // Since 2 was marked for retransmit, when 1 is acked, 2 is kept for RTT. uint64_t unacked[] = {2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); - EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_FALSE(manager_.HasInFlightPackets()); VerifyRetransmittablePackets(nullptr, 0); // Verify that the retransmission alarm would not fire, @@ -612,7 +616,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { // 2 and 3 remain unacked, but no packets have retransmittable data. uint64_t unacked[] = {2, 3}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_TRUE(manager_.HasInFlightPackets()); VerifyRetransmittablePackets(nullptr, 0); // Ensure packet 2 is lost when 4 is sent and 3 and 4 are acked. @@ -634,7 +638,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { uint64_t unacked2[] = {2}; VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2)); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_TRUE(manager_.HasInFlightPackets()); SendDataPacket(5); ExpectAckAndLoss(true, 5, 2); @@ -660,7 +664,7 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { } else { VerifyUnackedPackets(nullptr, 0); } - EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_FALSE(manager_.HasInFlightPackets()); if (manager_.session_decides_what_to_write()) { // Spurious retransmission is detected when packet 3 gets acked. We cannot // know packet 2 is a spurious until it gets acked. @@ -884,7 +888,7 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL)); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_TRUE(manager_.HasInFlightPackets()); // Acking two more packets will lose both of them due to nacks. SendDataPacket(4); @@ -907,7 +911,7 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) { manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL)); EXPECT_FALSE(manager_.HasPendingRetransmissions()); - EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_FALSE(manager_.HasInFlightPackets()); EXPECT_EQ(2u, stats_.tlp_count); EXPECT_EQ(0u, stats_.rto_count); } @@ -985,13 +989,11 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeThenRTO) { EXPECT_EQ(1u, stats_.rto_count); if (manager_.session_decides_what_to_write()) { // There are 2 RTO retransmissions. - EXPECT_EQ(104 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(104 * kDefaultLength, manager_.GetBytesInFlight()); } if (!manager_.session_decides_what_to_write()) { // Send and Ack the RTO and ensure OnRetransmissionTimeout is called. - EXPECT_EQ(102 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(102 * kDefaultLength, manager_.GetBytesInFlight()); EXPECT_TRUE(manager_.HasPendingRetransmissions()); RetransmitNextPacket(103); } @@ -1017,9 +1019,9 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeThenRTO) { // All packets before 103 should be lost. if (manager_.session_decides_what_to_write()) { // Packet 104 is still in flight. - EXPECT_EQ(1000u, QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(1000u, manager_.GetBytesInFlight()); } else { - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(0u, manager_.GetBytesInFlight()); } } @@ -1033,7 +1035,8 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { for (size_t i = 1; i <= kNumSentDataPackets; ++i) { SendDataPacket(kNumSentCryptoPackets + i); } - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); + EXPECT_EQ(5 * kDefaultLength, manager_.GetBytesInFlight()); // The first retransmits 2 packets. if (manager_.session_decides_what_to_write()) { @@ -1049,7 +1052,11 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { RetransmitNextPacket(7); EXPECT_FALSE(manager_.HasPendingRetransmissions()); } - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + // Expect all 4 handshake packets to be in flight and 3 data packets. + if (GetQuicReloadableFlag(quic_loss_removes_from_inflight)) { + EXPECT_EQ(7 * kDefaultLength, manager_.GetBytesInFlight()); + } + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // The second retransmits 2 packets. if (manager_.session_decides_what_to_write()) { @@ -1065,12 +1072,26 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { RetransmitNextPacket(9); EXPECT_FALSE(manager_.HasPendingRetransmissions()); } - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + if (GetQuicReloadableFlag(quic_loss_removes_from_inflight)) { + EXPECT_EQ(9 * kDefaultLength, manager_.GetBytesInFlight()); + } + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Now ack the two crypto packets and the speculatively encrypted request, // and ensure the first four crypto packets get abandoned, but not lost. - uint64_t acked[] = {3, 4, 5, 8, 9}; - ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); + if (GetQuicReloadableFlag(quic_loss_removes_from_inflight)) { + // Crypto packets remain in flight, so any that aren't acked will be lost. + uint64_t acked[] = {3, 4, 5, 8, 9}; + uint64_t lost[] = {1, 2, 6}; + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), lost, + QUIC_ARRAYSIZE(lost)); + if (manager_.session_decides_what_to_write()) { + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(3); + } + } else { + uint64_t acked[] = {3, 4, 5, 8, 9}; + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); + } if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, HasUnackedCryptoData()) .WillRepeatedly(Return(false)); @@ -1082,7 +1103,7 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL)); - EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_FALSE(manager_.HasUnackedCryptoPackets()); } TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { @@ -1095,7 +1116,7 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { for (size_t i = 1; i <= kNumSentDataPackets; ++i) { SendDataPacket(kNumSentCryptoPackets + i); } - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, RetransmitFrames(_, _)) @@ -1109,7 +1130,7 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { RetransmitNextPacket(7); EXPECT_FALSE(manager_.HasPendingRetransmissions()); } - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Now act like a version negotiation packet arrived, which would cause all // unacked packets to be retransmitted. @@ -1163,7 +1184,7 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { TEST_P(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) { // Send 1 crypto packet. SendCryptoPacket(1); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit the crypto packet as 2. if (manager_.session_decides_what_to_write()) { @@ -1200,9 +1221,14 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL)); - EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); - uint64_t unacked[] = {3}; - VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + EXPECT_FALSE(manager_.HasUnackedCryptoPackets()); + if (GetQuicReloadableFlag(quic_loss_removes_from_inflight)) { + uint64_t unacked[] = {1, 3}; + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + } else { + uint64_t unacked[] = {3}; + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + } } TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) { @@ -1212,7 +1238,7 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) { SendCryptoPacket(i); } SendDataPacket(3); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit 2 crypto packets, but not the serialized packet. if (manager_.session_decides_what_to_write()) { @@ -1227,7 +1253,7 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) { RetransmitNextPacket(5); EXPECT_FALSE(manager_.HasPendingRetransmissions()); } - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); } TEST_P(QuicSentPacketManagerTest, @@ -1235,7 +1261,7 @@ TEST_P(QuicSentPacketManagerTest, // Send 1 crypto packet. SendCryptoPacket(1); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit the crypto packet as 2. if (manager_.session_decides_what_to_write()) { @@ -1254,8 +1280,8 @@ TEST_P(QuicSentPacketManagerTest, manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); if (manager_.session_decides_what_to_write()) { // Both packets 1 and 2 are unackable. - EXPECT_FALSE(QuicSentPacketManagerPeer::IsUnacked(&manager_, 1)); - EXPECT_FALSE(QuicSentPacketManagerPeer::IsUnacked(&manager_, 2)); + EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(1))); + EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(2))); } else { // Packet 2 is useful because it does not get retransmitted and still has // retransmittable frames. @@ -1263,8 +1289,8 @@ TEST_P(QuicSentPacketManagerTest, VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); EXPECT_TRUE(manager_.HasPendingRetransmissions()); } - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); - EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); + EXPECT_FALSE(manager_.HasInFlightPackets()); } TEST_P(QuicSentPacketManagerTest, @@ -1272,7 +1298,7 @@ TEST_P(QuicSentPacketManagerTest, // Send 1 crypto packet. SendCryptoPacket(1); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit the crypto packet as 2. if (manager_.session_decides_what_to_write()) { @@ -1283,7 +1309,7 @@ TEST_P(QuicSentPacketManagerTest, if (!manager_.session_decides_what_to_write()) { RetransmitNextPacket(2); } - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Retransmit the crypto packet as 3. if (manager_.session_decides_what_to_write()) { @@ -1294,7 +1320,7 @@ TEST_P(QuicSentPacketManagerTest, if (!manager_.session_decides_what_to_write()) { RetransmitNextPacket(3); } - EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); // Now neuter all unacked unencrypted packets, which occurs when the // connection goes forward secure. @@ -1304,13 +1330,13 @@ TEST_P(QuicSentPacketManagerTest, .WillRepeatedly(Return(false)); EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); } - EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + EXPECT_FALSE(manager_.HasUnackedCryptoPackets()); uint64_t unacked[] = {1, 2, 3}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); EXPECT_FALSE(manager_.HasPendingRetransmissions()); - EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); - EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); + EXPECT_FALSE(manager_.HasUnackedCryptoPackets()); + EXPECT_FALSE(manager_.HasInFlightPackets()); // Ensure both packets get discarded when packet 2 is acked. uint64_t acked[] = {3}; @@ -1347,12 +1373,10 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionTimeout) { } manager_.OnRetransmissionTimeout(); if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(102 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(102 * kDefaultLength, manager_.GetBytesInFlight()); } else { ASSERT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(100 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(100 * kDefaultLength, manager_.GetBytesInFlight()); RetransmitNextPacket(101); ASSERT_TRUE(manager_.HasPendingRetransmissions()); RetransmitNextPacket(102); @@ -1422,12 +1446,10 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) { } manager_.OnRetransmissionTimeout(); if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(101 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(101 * kDefaultLength, manager_.GetBytesInFlight()); } else { ASSERT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(100 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(100 * kDefaultLength, manager_.GetBytesInFlight()); RetransmitNextPacket(101); EXPECT_FALSE(manager_.HasPendingRetransmissions()); } @@ -1468,12 +1490,10 @@ TEST_P(QuicSentPacketManagerTest, NewRetransmissionTimeout) { } manager_.OnRetransmissionTimeout(); if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(102 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(102 * kDefaultLength, manager_.GetBytesInFlight()); } else { EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(100 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(100 * kDefaultLength, manager_.GetBytesInFlight()); RetransmitNextPacket(101); RetransmitNextPacket(102); EXPECT_FALSE(manager_.HasPendingRetransmissions()); @@ -1511,12 +1531,10 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { } manager_.OnRetransmissionTimeout(); if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(2 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); } else { EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(kDefaultLength, manager_.GetBytesInFlight()); RetransmitNextPacket(2); EXPECT_FALSE(manager_.HasPendingRetransmissions()); } @@ -1529,12 +1547,10 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { } manager_.OnRetransmissionTimeout(); if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(3 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(3 * kDefaultLength, manager_.GetBytesInFlight()); } else { EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(2 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); RetransmitNextPacket(3); EXPECT_FALSE(manager_.HasPendingRetransmissions()); } @@ -1549,8 +1565,7 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL)); // The original packet and newest should be outstanding. - EXPECT_EQ(2 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); } TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { @@ -1564,12 +1579,10 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { } manager_.OnRetransmissionTimeout(); if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(2 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); } else { EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(kDefaultLength, manager_.GetBytesInFlight()); RetransmitNextPacket(2); EXPECT_FALSE(manager_.HasPendingRetransmissions()); } @@ -1582,12 +1595,10 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { } manager_.OnRetransmissionTimeout(); if (manager_.session_decides_what_to_write()) { - EXPECT_EQ(3 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(3 * kDefaultLength, manager_.GetBytesInFlight()); } else { EXPECT_TRUE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(2 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); RetransmitNextPacket(3); EXPECT_FALSE(manager_.HasPendingRetransmissions()); } @@ -1602,8 +1613,7 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL)); // The first two packets should still be outstanding. - EXPECT_EQ(2 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight()); } TEST_P(QuicSentPacketManagerTest, GetTransmissionTime) { @@ -1779,14 +1789,12 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { manager_.OnRetransmissionTimeout(); if (!manager_.session_decides_what_to_write()) { // All packets are still considered inflight. - EXPECT_EQ(4 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(4 * kDefaultLength, manager_.GetBytesInFlight()); RetransmitNextPacket(5); RetransmitNextPacket(6); } // All previous packets are inflight, plus two rto retransmissions. - EXPECT_EQ(6 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(6 * kDefaultLength, manager_.GetBytesInFlight()); EXPECT_FALSE(manager_.HasPendingRetransmissions()); // The delay should double the second time. @@ -1804,8 +1812,7 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { EXPECT_EQ(PACKETS_NEWLY_ACKED, manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL)); EXPECT_FALSE(manager_.HasPendingRetransmissions()); - EXPECT_EQ(5 * kDefaultLength, - QuicSentPacketManagerPeer::GetBytesInFlight(&manager_)); + EXPECT_EQ(5 * kDefaultLength, manager_.GetBytesInFlight()); // Wait 2RTTs from now for the RTO, since it's the max of the RTO time // and the TLP time. In production, there would always be two TLP's first. @@ -2364,7 +2371,9 @@ TEST_P(QuicSentPacketManagerTest, ResumeConnectionState) { cached_network_params.set_min_rtt_ms(kRtt.ToMilliseconds()); EXPECT_CALL(*send_algorithm_, - AdjustNetworkParameters(QuicBandwidth::Zero(), kRtt)); + AdjustNetworkParameters(QuicBandwidth::Zero(), kRtt, false)); + EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) + .Times(testing::AnyNumber()); manager_.ResumeConnectionState(cached_network_params, false); EXPECT_EQ(kRtt, manager_.GetRttStats()->initial_rtt()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc index 36070a4c5b5..89e08efb3ad 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc @@ -51,23 +51,30 @@ QuicSession::QuicSession(QuicConnection* connection, const ParsedQuicVersionVector& supported_versions) : connection_(connection), visitor_(owner), - write_blocked_streams_(), + write_blocked_streams_(connection->transport_version()), config_(config), stream_id_manager_(this, kDefaultMaxStreamsPerConnection, - config_.GetMaxIncomingDynamicStreamsToSend()), - v99_streamid_manager_(this, - kDefaultMaxStreamsPerConnection, - config_.GetMaxIncomingDynamicStreamsToSend()), + config_.GetMaxIncomingBidirectionalStreamsToSend()), + v99_streamid_manager_( + this, + kDefaultMaxStreamsPerConnection, + kDefaultMaxStreamsPerConnection, + config_.GetMaxIncomingBidirectionalStreamsToSend(), + config_.GetMaxIncomingUnidirectionalStreamsToSend()), num_dynamic_incoming_streams_(0), num_draining_incoming_streams_(0), + num_outgoing_static_streams_(0), + num_incoming_static_streams_(0), num_locally_closed_incoming_streams_highest_offset_(0), error_(QUIC_NO_ERROR), flow_controller_( this, QuicUtils::GetInvalidStreamId(connection->transport_version()), /*is_connection_flow_controller*/ true, - kMinimumFlowControlSendWindow, + connection->version().AllowsLowFlowControlLimits() + ? 0 + : kMinimumFlowControlSendWindow, config_.GetInitialSessionFlowControlWindowToSend(), kSessionReceiveWindowLimit, perspective() == Perspective::IS_SERVER, @@ -80,7 +87,10 @@ QuicSession::QuicSession(QuicConnection* connection, control_frame_manager_(this), last_message_id_(0), closed_streams_clean_up_alarm_(nullptr), - supported_versions_(supported_versions) { + supported_versions_(supported_versions), + eliminate_static_stream_map_( + GetQuicReloadableFlag(quic_eliminate_static_stream_map_3) || + QuicVersionUsesCryptoFrames(connection->transport_version())) { closed_streams_clean_up_alarm_ = QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm( new ClosedStreamsCleanUpDelegate(this))); @@ -92,11 +102,25 @@ void QuicSession::Initialize() { connection_->SetDataProducer(this); connection_->SetFromConfig(config_); + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + return; + } + DCHECK_EQ(QuicUtils::GetCryptoStreamId(connection_->transport_version()), GetMutableCryptoStream()->id()); - RegisterStaticStream( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), - GetMutableCryptoStream()); + if (!eliminate_static_stream_map_) { + RegisterStaticStream( + QuicUtils::GetCryptoStreamId(connection_->transport_version()), + GetMutableCryptoStream()); + } else { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 10, 17); + QuicStreamId id = + QuicUtils::GetCryptoStreamId(connection_->transport_version()); + largest_static_stream_id_ = std::max(id, largest_static_stream_id_); + if (connection_->transport_version() == QUIC_VERSION_99) { + v99_streamid_manager_.RegisterStaticStream(id); + } + } } QuicSession::~QuicSession() { @@ -118,6 +142,43 @@ void QuicSession::RegisterStaticStream(QuicStreamId id, QuicStream* stream) { } } +void QuicSession::RegisterStaticStreamNew(std::unique_ptr<QuicStream> stream) { + DCHECK(eliminate_static_stream_map_); + QuicStreamId stream_id = stream->id(); + dynamic_stream_map_[stream_id] = std::move(stream); + if (connection_->transport_version() == QUIC_VERSION_99) { + v99_streamid_manager_.RegisterStaticStream(stream_id); + } + if (IsIncomingStream(stream_id)) { + ++num_incoming_static_streams_; + } else { + ++num_outgoing_static_streams_; + } +} + +void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) { + DCHECK(VersionHasStreamType(connection()->transport_version())); + QuicStreamId stream_id = frame.stream_id; + + PendingStream* pending = GetOrCreatePendingStream(stream_id); + + if (!pending) { + if (frame.fin) { + QuicStreamOffset final_byte_offset = frame.offset + frame.data_length; + OnFinalByteOffsetReceived(stream_id, final_byte_offset); + } + return; + } + + pending->OnStreamFrame(frame); + if (ProcessPendingStream(pending)) { + // The pending stream should now be in the scope of normal streams. + DCHECK(IsClosedStream(stream_id) || IsOpenStream(stream_id)) + << "Stream " << stream_id << " not created"; + pending_stream_map_.erase(stream_id); + } +} + void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) { // TODO(rch) deal with the error case of stream id 0. QuicStreamId stream_id = frame.stream_id; @@ -136,13 +197,19 @@ void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) { return; } - StreamHandler handler = GetOrCreateStreamImpl(stream_id, frame.offset != 0); - if (handler.is_pending) { - handler.pending->OnStreamFrame(frame); + if (VersionHasStreamType(connection()->transport_version()) && + UsesPendingStreams() && + QuicUtils::GetStreamType(stream_id, perspective(), + IsIncomingStream(stream_id)) == + READ_UNIDIRECTIONAL && + dynamic_stream_map_.find(stream_id) == dynamic_stream_map_.end()) { + PendingStreamOnStreamFrame(frame); return; } - if (!handler.stream) { + QuicStream* stream = GetOrCreateStream(stream_id); + + if (!stream) { // The stream no longer exists, but we may still be interested in the // final stream byte offset sent by the peer. A frame with a FIN can give // us this offset. @@ -152,7 +219,14 @@ void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) { } return; } - handler.stream->OnStreamFrame(frame); + if (eliminate_static_stream_map_ && frame.fin && stream->is_static()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 1, 17); + connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Attempt to close a static stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + stream->OnStreamFrame(frame); } void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) { @@ -183,7 +257,9 @@ bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { // TODO(fkastenholz): IETF Quic does not have static streams and does not // make exceptions for them with respect to processing things like // STOP_SENDING. - if (QuicContainsKey(static_stream_map_, stream_id)) { + if (QuicContainsKey(static_stream_map_, stream_id) || + QuicUtils::IsCryptoStreamId(connection_->transport_version(), + stream_id)) { QUIC_DVLOG(1) << ENDPOINT << "Received STOP_SENDING for a static stream, id: " << stream_id << " Closing connection"; @@ -220,16 +296,28 @@ bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { // Get the QuicStream for this stream. Ignore the STOP_SENDING // if the QuicStream pointer is NULL - // QUESTION: IS THIS THE RIGHT THING TO DO? (that is, this would happen IFF - // there was an entry in the map, but the pointer is null. sounds more like a - // deep programming error rather than a simple protocol problem). + // QUESTION(fkastenholz): IS THIS THE RIGHT THING TO DO? (that is, this would + // happen IFF there was an entry in the map, but the pointer is null. sounds + // more like a deep programming error rather than a simple protocol problem). QuicStream* stream = it->second.get(); if (stream == nullptr) { - QUIC_DVLOG(1) << ENDPOINT - << "Received STOP_SENDING for NULL QuicStream, stream_id: " - << stream_id << ". Ignoring."; + QUIC_BUG << ENDPOINT + << "Received STOP_SENDING for NULL QuicStream, stream_id: " + << stream_id << ". Ignoring."; return true; } + + if (eliminate_static_stream_map_ && stream->is_static()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 2, 17); + QUIC_DVLOG(1) << ENDPOINT + << "Received STOP_SENDING for a static stream, id: " + << stream_id << " Closing connection"; + connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } + stream->OnStopSending(frame.application_error_code); stream->set_stream_error( @@ -243,6 +331,21 @@ bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { return true; } +void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) { + DCHECK(VersionHasStreamType(connection()->transport_version())); + QuicStreamId stream_id = frame.stream_id; + + PendingStream* pending = GetOrCreatePendingStream(stream_id); + + if (!pending) { + HandleRstOnValidNonexistentStream(frame); + return; + } + + pending->OnRstStreamFrame(frame); + ClosePendingStream(stream_id); +} + void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { QuicStreamId stream_id = frame.stream_id; if (stream_id == @@ -264,20 +367,30 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { visitor_->OnRstStreamReceived(frame); } - // may_buffer is true here to allow subclasses to buffer streams until the - // first byte of payload arrives which would allow sessions to delay - // creation of the stream until the type is known. - StreamHandler handler = GetOrCreateStreamImpl(stream_id, /*may_buffer=*/true); - if (handler.is_pending) { - handler.pending->OnRstStreamFrame(frame); - ClosePendingStream(stream_id); + if (VersionHasStreamType(connection()->transport_version()) && + UsesPendingStreams() && + QuicUtils::GetStreamType(stream_id, perspective(), + IsIncomingStream(stream_id)) == + READ_UNIDIRECTIONAL && + dynamic_stream_map_.find(stream_id) == dynamic_stream_map_.end()) { + PendingStreamOnRstStream(frame); return; } - if (!handler.stream) { + + QuicStream* stream = GetOrCreateStream(stream_id); + + if (!stream) { HandleRstOnValidNonexistentStream(frame); return; // Errors are handled by GetOrCreateStream. } - handler.stream->OnStreamReset(frame); + if (eliminate_static_stream_map_ && stream->is_static()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 3, 17); + connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + stream->OnStreamReset(frame); } void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) { @@ -317,14 +430,35 @@ void QuicSession::OnConnectionClosed(QuicErrorCode error, error_ = error; } - while (!dynamic_stream_map_.empty()) { - DynamicStreamMap::iterator it = dynamic_stream_map_.begin(); - QuicStreamId id = it->first; - it->second->OnConnectionClosed(error, source); - // The stream should call CloseStream as part of OnConnectionClosed. - if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) { - QUIC_BUG << ENDPOINT << "Stream failed to close under OnConnectionClosed"; - CloseStream(id); + if (!eliminate_static_stream_map_) { + while (!dynamic_stream_map_.empty()) { + DynamicStreamMap::iterator it = dynamic_stream_map_.begin(); + QuicStreamId id = it->first; + it->second->OnConnectionClosed(error, source); + // The stream should call CloseStream as part of OnConnectionClosed. + if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) { + QUIC_BUG << ENDPOINT << "Stream " << id + << " failed to close under OnConnectionClosed"; + CloseStream(id); + } + } + } else { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 4, 17); + // Copy all non static streams in a new map for the ease of deleting. + QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams; + for (const auto& it : dynamic_stream_map_) { + if (!it.second->is_static()) { + non_static_streams[it.first] = it.second.get(); + } + } + for (const auto& it : non_static_streams) { + QuicStreamId id = it.first; + it.second->OnConnectionClosed(error, source); + if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) { + QUIC_BUG << ENDPOINT << "Stream " << id + << " failed to close under OnConnectionClosed"; + CloseStream(id); + } } } @@ -509,6 +643,14 @@ void QuicSession::OnCanWrite() { } } +bool QuicSession::SendProbingData() { + if (connection()->sent_packet_manager().MaybeRetransmitOldestPacket( + PROBING_RETRANSMISSION)) { + return true; + } + return false; +} + bool QuicSession::WillingAndAbleToWrite() const { // Schedule a write when: // 1) control frame manager has pending or new control frames, or @@ -524,6 +666,11 @@ bool QuicSession::WillingAndAbleToWrite() const { } bool QuicSession::HasPendingHandshake() const { + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + // Writing CRYPTO frames is not subject to flow control, so there can't be + // pending data to write, only pending retransmissions. + return GetCryptoStream()->HasPendingCryptoRetransmission(); + } return QuicContainsKey( streams_with_pending_retransmission_, QuicUtils::GetCryptoStreamId(connection_->transport_version())) || @@ -533,7 +680,8 @@ bool QuicSession::HasPendingHandshake() const { uint64_t QuicSession::GetNumOpenDynamicStreams() const { return dynamic_stream_map_.size() - draining_streams_.size() + - locally_closed_streams_highest_offset_.size(); + locally_closed_streams_highest_offset_.size() - + num_incoming_static_streams_ - num_outgoing_static_streams_; } void QuicSession::ProcessUdpPacket(const QuicSocketAddress& self_address, @@ -552,7 +700,7 @@ QuicConsumedData QuicSession::WritevData(QuicStream* stream, // it might end up resulting in unencrypted stream data being sent. // While this is impossible to avoid given sufficient corruption, this // seems like a reasonable mitigation. - if (id == QuicUtils::GetCryptoStreamId(connection_->transport_version()) && + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) && stream != GetMutableCryptoStream()) { QUIC_BUG << "Stream id mismatch"; connection_->CloseConnection( @@ -562,7 +710,7 @@ QuicConsumedData QuicSession::WritevData(QuicStream* stream, return QuicConsumedData(0, false); } if (!IsEncryptionEstablished() && - id != QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + !QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) { // Do not let streams write without encryption. The calling stream will end // up write blocked until OnCanWrite is next called. return QuicConsumedData(0, false); @@ -625,6 +773,16 @@ void QuicSession::SendRstStreamInner(QuicStreamId id, DynamicStreamMap::iterator it = dynamic_stream_map_.find(id); if (it != dynamic_stream_map_.end()) { + if (eliminate_static_stream_map_ && it->second->is_static()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 5, 17); + QUIC_DVLOG(1) << ENDPOINT + << "Try to send rst for a static stream, id: " << id + << " Closing connection"; + connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Sending rst for a static stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } QuicStream* stream = it->second.get(); if (stream) { stream->set_rst_sent(true); @@ -654,12 +812,15 @@ void QuicSession::SendWindowUpdate(QuicStreamId id, control_frame_manager_.WriteOrBufferWindowUpdate(id, byte_offset); } -void QuicSession::SendMaxStreamId(QuicStreamId max_allowed_incoming_id) { - control_frame_manager_.WriteOrBufferMaxStreamId(max_allowed_incoming_id); +void QuicSession::SendMaxStreams(QuicStreamCount stream_count, + bool unidirectional) { + control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional); } -void QuicSession::SendStreamIdBlocked(QuicStreamId max_allowed_outgoing_id) { - control_frame_manager_.WriteOrBufferStreamIdBlocked(max_allowed_outgoing_id); +void QuicSession::SendStreamsBlocked(QuicStreamCount stream_count, + bool unidirectional) { + control_frame_manager_.WriteOrBufferStreamsBlocked(stream_count, + unidirectional); } void QuicSession::CloseStream(QuicStreamId stream_id) { @@ -687,6 +848,16 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) { return; } QuicStream* stream = it->second.get(); + if (eliminate_static_stream_map_ && stream->is_static()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 6, 17); + QUIC_DVLOG(1) << ENDPOINT + << "Try to close a static stream, id: " << stream_id + << " Closing connection"; + connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Try to close a static stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } // Tell the stream that a RST has been sent. if (locally_reset) { @@ -818,16 +989,33 @@ bool QuicSession::IsCryptoHandshakeConfirmed() const { void QuicSession::OnConfigNegotiated() { connection_->SetFromConfig(config_); - uint32_t max_streams = 0; - if (config_.HasReceivedMaxIncomingDynamicStreams()) { - max_streams = config_.ReceivedMaxIncomingDynamicStreams(); - } - QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams; if (connection_->transport_version() == QUIC_VERSION_99) { - v99_streamid_manager_.SetMaxOpenOutgoingStreams(max_streams); + uint32_t max_streams = 0; + if (config_.HasReceivedMaxIncomingBidirectionalStreams()) { + max_streams = config_.ReceivedMaxIncomingBidirectionalStreams(); + } + QUIC_DVLOG(1) << "Setting Bidirectional outgoing_max_streams_ to " + << max_streams; + v99_streamid_manager_.AdjustMaxOpenOutgoingBidirectionalStreams( + max_streams); + + max_streams = 0; + if (config_.HasReceivedMaxIncomingUnidirectionalStreams()) { + max_streams = config_.ReceivedMaxIncomingUnidirectionalStreams(); + } + QUIC_DVLOG(1) << "Setting Unidirectional outgoing_max_streams_ to " + << max_streams; + v99_streamid_manager_.AdjustMaxOpenOutgoingUnidirectionalStreams( + max_streams); } else { + uint32_t max_streams = 0; + if (config_.HasReceivedMaxIncomingBidirectionalStreams()) { + max_streams = config_.ReceivedMaxIncomingBidirectionalStreams(); + } + QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams; stream_id_manager_.set_max_open_outgoing_streams(max_streams); } + if (perspective() == Perspective::IS_SERVER) { if (config_.HasReceivedConnectionOptions()) { // The following variations change the initial receive flow control @@ -852,17 +1040,19 @@ void QuicSession::OnConfigNegotiated() { config_.SetStatelessResetTokenToSend(GetStatelessResetToken()); } - // A small number of additional incoming streams beyond the limit should be - // allowed. This helps avoid early connection termination when FIN/RSTs for - // old streams are lost or arrive out of order. - // Use a minimum number of additional streams, or a percentage increase, - // whichever is larger. - uint32_t max_incoming_streams_to_send = - config_.GetMaxIncomingDynamicStreamsToSend(); if (connection_->transport_version() == QUIC_VERSION_99) { - v99_streamid_manager_.SetMaxOpenIncomingStreams( - max_incoming_streams_to_send); + v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams( + config_.GetMaxIncomingBidirectionalStreamsToSend()); + v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams( + config_.GetMaxIncomingUnidirectionalStreamsToSend()); } else { + // A small number of additional incoming streams beyond the limit should be + // allowed. This helps avoid early connection termination when FIN/RSTs for + // old streams are lost or arrive out of order. + // Use a minimum number of additional streams, or a percentage increase, + // whichever is larger. + uint32_t max_incoming_streams_to_send = + config_.GetMaxIncomingBidirectionalStreamsToSend(); uint32_t max_incoming_streams = std::max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement, static_cast<uint32_t>(max_incoming_streams_to_send * @@ -905,6 +1095,12 @@ void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) { for (auto const& kv : dynamic_stream_map_) { kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window); } + if (eliminate_static_stream_map_ && + !QuicVersionUsesCryptoFrames(connection_->transport_version())) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 11, 17); + GetMutableCryptoStream()->flow_controller()->UpdateReceiveWindowSize( + stream_window); + } } void QuicSession::HandleFrameOnNonexistentOutgoingStream( @@ -930,10 +1126,11 @@ void QuicSession::HandleRstOnValidNonexistentStream( } void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) { - if (new_window < kMinimumFlowControlSendWindow) { + if (new_window < kMinimumFlowControlSendWindow && + !connection_->version().AllowsLowFlowControlLimits()) { QUIC_LOG_FIRST_N(ERROR, 1) << "Peer sent us an invalid stream flow control send window: " - << new_window << ", below default: " << kMinimumFlowControlSendWindow; + << new_window << ", below minimum: " << kMinimumFlowControlSendWindow; if (connection_->connected()) { connection_->CloseConnection( QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low", @@ -949,10 +1146,16 @@ void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) { for (auto const& kv : dynamic_stream_map_) { kv.second->UpdateSendWindowOffset(new_window); } + if (eliminate_static_stream_map_ && + !QuicVersionUsesCryptoFrames(connection_->transport_version())) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 12, 17); + GetMutableCryptoStream()->UpdateSendWindowOffset(new_window); + } } void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) { - if (new_window < kMinimumFlowControlSendWindow) { + if (new_window < kMinimumFlowControlSendWindow && + !connection_->version().AllowsLowFlowControlLimits()) { QUIC_LOG_FIRST_N(ERROR, 1) << "Peer sent us an invalid session flow control send window: " << new_window << ", below default: " << kMinimumFlowControlSendWindow; @@ -1024,6 +1227,7 @@ QuicConfig* QuicSession::config() { } void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) { + DCHECK(!stream->is_static()); QuicStreamId stream_id = stream->id(); QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size() << ". activating " << stream_id; @@ -1066,20 +1270,17 @@ bool QuicSession::CanOpenNextOutgoingUnidirectionalStream() { } QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) { - StreamHandler handler = - GetOrCreateStreamImpl(stream_id, /*may_buffer=*/false); - DCHECK(!handler.is_pending); - return handler.stream; -} - -QuicSession::StreamHandler QuicSession::GetOrCreateStreamImpl( - QuicStreamId stream_id, - bool may_buffer) { + if (eliminate_static_stream_map_ && + QuicUtils::IsCryptoStreamId(connection_->transport_version(), + stream_id)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 13, 17); + return GetMutableCryptoStream(); + } StaticStreamMap::iterator it = static_stream_map_.find(stream_id); if (it != static_stream_map_.end()) { - return StreamHandler(it->second); + return it->second; } - return GetOrCreateDynamicStreamImpl(stream_id, may_buffer); + return GetOrCreateDynamicStream(stream_id); } void QuicSession::StreamDraining(QuicStreamId stream_id) { @@ -1114,47 +1315,40 @@ bool QuicSession::ShouldYield(QuicStreamId stream_id) { return write_blocked_streams()->ShouldYield(stream_id); } -QuicStream* QuicSession::GetOrCreateDynamicStream( - const QuicStreamId stream_id) { - StreamHandler handler = - GetOrCreateDynamicStreamImpl(stream_id, /*may_buffer=*/false); - DCHECK(!handler.is_pending); - return handler.stream; +PendingStream* QuicSession::GetOrCreatePendingStream(QuicStreamId stream_id) { + auto it = pending_stream_map_.find(stream_id); + if (it != pending_stream_map_.end()) { + return it->second.get(); + } + + if (IsClosedStream(stream_id) || + !MaybeIncreaseLargestPeerStreamId(stream_id)) { + return nullptr; + } + + auto pending = QuicMakeUnique<PendingStream>(stream_id, this); + PendingStream* unowned_pending = pending.get(); + pending_stream_map_[stream_id] = std::move(pending); + return unowned_pending; } -QuicSession::StreamHandler QuicSession::GetOrCreateDynamicStreamImpl( - QuicStreamId stream_id, - bool may_buffer) { +QuicStream* QuicSession::GetOrCreateDynamicStream( + const QuicStreamId stream_id) { DCHECK(!QuicContainsKey(static_stream_map_, stream_id)) << "Attempt to call GetOrCreateDynamicStream for a static stream"; DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id); if (it != dynamic_stream_map_.end()) { - return StreamHandler(it->second.get()); + return it->second.get(); } if (IsClosedStream(stream_id)) { - return StreamHandler(); + return nullptr; } if (!IsIncomingStream(stream_id)) { HandleFrameOnNonexistentOutgoingStream(stream_id); - return StreamHandler(); - } - - auto pending_it = pending_stream_map_.find(stream_id); - if (pending_it != pending_stream_map_.end()) { - DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version()); - if (may_buffer) { - return StreamHandler(pending_it->second.get()); - } - // The stream limit accounting has already been taken care of - // when the PendingStream was created, so there is no need to - // do so here. Now we can create the actual stream from the - // PendingStream. - StreamHandler handler(CreateIncomingStream(std::move(*pending_it->second))); - pending_stream_map_.erase(pending_it); - return handler; + return nullptr; } // TODO(fkastenholz): If we are creating a new stream and we have @@ -1163,7 +1357,7 @@ QuicSession::StreamHandler QuicSession::GetOrCreateDynamicStreamImpl( // B) reject stream creation ("return nullptr") if (!MaybeIncreaseLargestPeerStreamId(stream_id)) { - return StreamHandler(); + return nullptr; } if (connection_->transport_version() != QUIC_VERSION_99) { @@ -1173,23 +1367,11 @@ QuicSession::StreamHandler QuicSession::GetOrCreateDynamicStreamImpl( GetNumOpenIncomingStreams())) { // Refuse to open the stream. SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0); - return StreamHandler(); + return nullptr; } } - if (connection_->transport_version() == QUIC_VERSION_99 && may_buffer && - ShouldBufferIncomingStream(stream_id)) { - ++num_dynamic_incoming_streams_; - // Since STREAM frames may arrive out of order, delay creating the - // stream object until the first byte arrives. Buffer the frames and - // handle flow control accounting in the PendingStream. - auto pending = QuicMakeUnique<PendingStream>(stream_id, this); - StreamHandler handler(pending.get()); - pending_stream_map_[stream_id] = std::move(pending); - return handler; - } - - return StreamHandler(CreateIncomingStream(stream_id)); + return CreateIncomingStream(stream_id); } void QuicSession::set_largest_peer_created_stream_id( @@ -1223,13 +1405,26 @@ bool QuicSession::IsOpenStream(QuicStreamId id) { id); if (QuicContainsKey(static_stream_map_, id) || QuicContainsKey(dynamic_stream_map_, id) || - QuicContainsKey(pending_stream_map_, id)) { + QuicContainsKey(pending_stream_map_, id) || + QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) { // Stream is active return true; } return false; } +bool QuicSession::IsStaticStream(QuicStreamId id) const { + if (eliminate_static_stream_map()) { + auto it = dynamic_stream_map_.find(id); + if (it == dynamic_stream_map_.end()) { + return false; + } + return it->second->is_static(); + } + + return QuicContainsKey(static_streams(), id); +} + size_t QuicSession::GetNumOpenIncomingStreams() const { return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ + num_locally_closed_incoming_streams_highest_offset_; @@ -1245,7 +1440,8 @@ size_t QuicSession::GetNumOpenOutgoingStreams() const { } size_t QuicSession::GetNumActiveStreams() const { - return dynamic_stream_map_.size() - draining_streams_.size(); + return dynamic_stream_map_.size() - draining_streams_.size() - + num_incoming_static_streams_ - num_outgoing_static_streams_; } size_t QuicSession::GetNumDrainingStreams() const { @@ -1280,9 +1476,11 @@ void QuicSession::SendPing() { size_t QuicSession::GetNumDynamicOutgoingStreams() const { DCHECK_GE(static_cast<size_t>(dynamic_stream_map_.size() + pending_stream_map_.size()), - num_dynamic_incoming_streams_); + num_dynamic_incoming_streams_ + num_outgoing_static_streams_ + + num_incoming_static_streams_); return dynamic_stream_map_.size() + pending_stream_map_.size() - - num_dynamic_incoming_streams_; + num_dynamic_incoming_streams_ - num_outgoing_static_streams_ - + num_incoming_static_streams_; } size_t QuicSession::GetNumDrainingOutgoingStreams() const { @@ -1312,6 +1510,12 @@ bool QuicSession::IsStreamFlowControlBlocked() { return true; } } + if (eliminate_static_stream_map_ && + !QuicVersionUsesCryptoFrames(connection_->transport_version()) && + GetMutableCryptoStream()->flow_controller()->IsBlocked()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 14, 17); + return true; + } return false; } @@ -1367,6 +1571,13 @@ QuicStream* QuicSession::GetStream(QuicStreamId id) const { if (zombie_stream != zombie_streams_.end()) { return zombie_stream->second.get(); } + + if (eliminate_static_stream_map_ && + QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 15, 17); + return const_cast<QuicCryptoStream*>(GetCryptoStream()); + } + return nullptr; } @@ -1603,7 +1814,8 @@ void QuicSession::NeuterUnencryptedData() { if (connection_->session_decides_what_to_write()) { QuicCryptoStream* crypto_stream = GetMutableCryptoStream(); crypto_stream->NeuterUnencryptedStreamData(); - if (!crypto_stream->HasPendingRetransmission()) { + if (!crypto_stream->HasPendingRetransmission() && + !QuicVersionUsesCryptoFrames(connection_->transport_version())) { streams_with_pending_retransmission_.erase( QuicUtils::GetCryptoStreamId(connection_->transport_version())); } @@ -1672,13 +1884,12 @@ QuicStreamId QuicSession::next_outgoing_unidirectional_stream_id() const { return stream_id_manager_.next_outgoing_stream_id(); } -bool QuicSession::OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) { - return v99_streamid_manager_.OnMaxStreamIdFrame(frame); +bool QuicSession::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) { + return v99_streamid_manager_.OnMaxStreamsFrame(frame); } -bool QuicSession::OnStreamIdBlockedFrame( - const QuicStreamIdBlockedFrame& frame) { - return v99_streamid_manager_.OnStreamIdBlockedFrame(frame); +bool QuicSession::OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) { + return v99_streamid_manager_.OnStreamsBlockedFrame(frame); } size_t QuicSession::max_open_incoming_bidirectional_streams() const { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.h b/chromium/net/third_party/quiche/src/quic/core/quic_session.h index a9fb9923624..513ed9bf60f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.h @@ -52,7 +52,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, virtual ~Visitor() {} // Called when the connection is closed after the streams have been closed. - virtual void OnConnectionClosed(QuicConnectionId connection_id, + virtual void OnConnectionClosed(QuicConnectionId server_connection_id, QuicErrorCode error, const std::string& error_details, ConnectionCloseSource source) = 0; @@ -115,6 +115,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address) override; void OnCanWrite() override; + bool SendProbingData() override; void OnCongestionWindowChange(QuicTime /*now*/) override {} void OnConnectionMigration(AddressChangeType type) override {} // Adds a connection level WINDOW_UPDATE frame. @@ -125,8 +126,8 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, void OnPathDegrading() override; bool AllowSelfAddressChange() const override; void OnForwardProgressConfirmed() override; - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override; - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override; + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override; + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override; bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override; // QuicStreamFrameDataProducer @@ -211,11 +212,11 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // Sends a WINDOW_UPDATE frame. virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset); - // Send a MAX_STREAM_ID frame. - void SendMaxStreamId(QuicStreamId max_allowed_incoming_id); + // Send a MAX_STREAMS frame. + void SendMaxStreams(QuicStreamCount stream_count, bool unidirectional); - // Send a STREAM_ID_BLOCKED frame. - void SendStreamIdBlocked(QuicStreamId max_allowed_outgoing_id); + // Send a STREAMS_BLOCKED frame. + void SendStreamsBlocked(QuicStreamCount stream_count, bool unidirectional); // Create and transmit a STOP_SENDING frame virtual void SendStopSending(uint16_t code, QuicStreamId stream_id); @@ -300,6 +301,16 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // reserved headers and crypto streams. size_t GetNumOpenOutgoingStreams() const; + // Returns the number of open peer initiated static streams. + size_t num_incoming_static_streams() const { + return num_incoming_static_streams_; + } + + // Returns the number of open self initiated static streams. + size_t num_outgoing_static_streams() const { + return num_outgoing_static_streams_; + } + // Add the stream to the session's write-blocked list because it is blocked by // connection-level flow control but not by its own stream-level flow control. // The stream will be given a chance to write when a connection-level @@ -408,6 +419,10 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, static void RecordConnectionCloseAtServer(QuicErrorCode error, ConnectionCloseSource source); + inline QuicTransportVersion transport_version() const { + return connection_->transport_version(); + } + protected: using StaticStreamMap = QuicSmallMap<QuicStreamId, QuicStream*, 2>; @@ -472,15 +487,18 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, virtual void OnFinalByteOffsetReceived(QuicStreamId id, QuicStreamOffset final_byte_offset); - // Returns true if incoming streams should be buffered until the first - // byte of the stream arrives. - virtual bool ShouldBufferIncomingStream(QuicStreamId id) const { - return false; - } + // Returns true if incoming unidirectional streams should be buffered until + // the first byte of the stream arrives. + // If a subclass returns true here, it should make sure to implement + // ProcessPendingStream(). + virtual bool UsesPendingStreams() const { return false; } // Register (|id|, |stream|) with the static stream map. Override previous // registrations with the same id. void RegisterStaticStream(QuicStreamId id, QuicStream* stream); + // TODO(renjietang): Replace the original Register method with the new one + // once flag is deprecated. + void RegisterStaticStreamNew(std::unique_ptr<QuicStream> stream); const StaticStreamMap& static_streams() const { return static_stream_map_; } DynamicStreamMap& dynamic_streams() { return dynamic_stream_map_; } @@ -507,6 +525,9 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // Returns true if the stream is still active. bool IsOpenStream(QuicStreamId id); + // Returns true if the stream is a static stream. + bool IsStaticStream(QuicStreamId id) const; + // Close connection when receive a frame for a locally-created nonexistant // stream. // Prerequisite: IsClosedStream(stream_id) == false @@ -536,30 +557,14 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, return stream_id_manager_; } - // A StreamHandler represents an object which can receive a STREAM or - // or RST_STREAM frame. - struct StreamHandler { - StreamHandler() : is_pending(false), stream(nullptr) {} - - // Creates a StreamHandler wrapping a QuicStream. - explicit StreamHandler(QuicStream* stream) - : is_pending(false), stream(stream) {} - - // Creates a StreamHandler wrapping a PendingStream. - explicit StreamHandler(PendingStream* pending) - : is_pending(true), pending(pending) { - DCHECK(pending != nullptr); - } - - // True if this handler contains a non-null PendingStream, false otherwise. - bool is_pending; - union { - QuicStream* stream; - PendingStream* pending; - }; - }; + // Processes the stream type information of |pending| depending on + // different kinds of sessions' own rules. Returns true if the pending stream + // is converted into a normal stream. + virtual bool ProcessPendingStream(PendingStream* pending) { return false; } - StreamHandler GetOrCreateStreamImpl(QuicStreamId stream_id, bool may_buffer); + bool eliminate_static_stream_map() const { + return eliminate_static_stream_map_; + } private: friend class test::QuicSessionPeer; @@ -591,8 +596,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // closed. QuicStream* GetStream(QuicStreamId id) const; - StreamHandler GetOrCreateDynamicStreamImpl(QuicStreamId stream_id, - bool may_buffer); + PendingStream* GetOrCreatePendingStream(QuicStreamId stream_id); // Let streams and control frame managers retransmit lost data, returns true // if all lost data is retransmitted. Returns false otherwise. @@ -601,6 +605,14 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // Closes the pending stream |stream_id| before it has been created. void ClosePendingStream(QuicStreamId stream_id); + // Creates or gets pending stream, feeds it with |frame|, and processes the + // pending stream. + void PendingStreamOnStreamFrame(const QuicStreamFrame& frame); + + // Creates or gets pending strea, feed it with |frame|, and closes the pending + // stream. + void PendingStreamOnRstStream(const QuicRstStreamFrame& frame); + // Keep track of highest received byte offset of locally closed streams, while // waiting for a definitive final highest offset from the peer. std::map<QuicStreamId, QuicStreamOffset> @@ -653,6 +665,14 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // A counter for peer initiated streams which are in the draining_streams_. size_t num_draining_incoming_streams_; + // A counter for self initiated static streams which are in + // dynamic_stream_map_. + size_t num_outgoing_static_streams_; + + // A counter for peer initiated static streams which are in + // dynamic_stream_map_. + size_t num_incoming_static_streams_; + // A counter for peer initiated streams which are in the // locally_closed_streams_highest_offset_. size_t num_locally_closed_incoming_streams_highest_offset_; @@ -695,6 +715,9 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // Supported version list used by the crypto handshake only. Please note, this // list may be a superset of the connection framer's supported versions. ParsedQuicVersionVector supported_versions_; + + // Latched value of quic_eliminate_static_stream_map. + const bool eliminate_static_stream_map_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc index a517d4703da..e2996db731c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc @@ -9,7 +9,6 @@ #include <string> #include <utility> -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h" @@ -70,7 +69,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { kInitialStreamFlowControlWindowForTest); session()->config()->SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); - session()->config()->ToHandshakeMessage(&msg); + session()->config()->ToHandshakeMessage( + &msg, session()->connection()->transport_version()); const QuicErrorCode error = session()->config()->ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); @@ -94,7 +94,7 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { } MOCK_METHOD0(OnCanWrite, void()); - bool HasPendingCryptoRetransmission() override { return false; } + bool HasPendingCryptoRetransmission() const override { return false; } MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); @@ -109,10 +109,16 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { class TestStream : public QuicStream { public: TestStream(QuicStreamId id, QuicSession* session, StreamType type) - : QuicStream(id, session, /*is_static=*/false, type) {} + : TestStream(id, session, /*is_static=*/false, type) {} + + TestStream(QuicStreamId id, + QuicSession* session, + bool is_static, + StreamType type) + : QuicStream(id, session, is_static, type) {} TestStream(PendingStream pending, StreamType type) - : QuicStream(std::move(pending), type) {} + : QuicStream(std::move(pending), type, /*is_static=*/false) {} using QuicStream::CloseReadSide; using QuicStream::CloseWriteSide; @@ -139,7 +145,7 @@ class TestSession : public QuicSession { CurrentSupportedVersions()), crypto_stream_(this), writev_consumes_all_data_(false), - should_buffer_incoming_streams_(false), + uses_pending_streams_(false), num_incoming_streams_created_(0) { Initialize(); this->connection()->SetEncrypter( @@ -210,6 +216,19 @@ class TestSession : public QuicSession { return stream; } + // QuicSession doesn't do anything in this method. So it's overridden here to + // test that the session handles pending streams correctly in terms of + // receiving stream frames. + bool ProcessPendingStream(PendingStream* pending) override { + struct iovec iov; + if (pending->sequencer()->GetReadableRegion(&iov)) { + // Create TestStream once the first byte is received. + CreateIncomingStream(std::move(*pending)); + return true; + } + return false; + } + bool IsClosedStream(QuicStreamId id) { return QuicSession::IsClosedStream(id); } @@ -249,8 +268,8 @@ class TestSession : public QuicSession { QuicConsumedData SendStreamData(QuicStream* stream) { struct iovec iov; - if (stream->id() != - QuicUtils::GetCryptoStreamId(connection()->transport_version()) && + if (!QuicUtils::IsCryptoStreamId(connection()->transport_version(), + stream->id()) && this->connection()->encryption_level() != ENCRYPTION_FORWARD_SECURE) { this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); } @@ -280,12 +299,10 @@ class TestSession : public QuicSession { return WritevData(stream, stream->id(), bytes, 0, FIN); } - bool ShouldBufferIncomingStream(QuicStreamId id) const override { - return should_buffer_incoming_streams_; - } + bool UsesPendingStreams() const override { return uses_pending_streams_; } - void set_should_buffer_incoming_streams(bool should_buffer_incoming_streams) { - should_buffer_incoming_streams_ = should_buffer_incoming_streams; + void set_uses_pending_streams(bool uses_pending_streams) { + uses_pending_streams_ = uses_pending_streams; } int num_incoming_streams_created() const { @@ -300,7 +317,7 @@ class TestSession : public QuicSession { StrictMock<TestCryptoStream> crypto_stream_; bool writev_consumes_all_data_; - bool should_buffer_incoming_streams_; + bool uses_pending_streams_; QuicFrame save_frame_; int num_incoming_streams_created_; }; @@ -393,6 +410,24 @@ class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { QuicUtils::StreamIdDelta(connection_->transport_version()) * n; } + QuicStreamId StreamCountToId(QuicStreamCount stream_count, + Perspective perspective, + bool bidirectional) { + // Calculate and build up stream ID rather than use + // GetFirst... because tests that rely on this method + // needs to do the stream count where #1 is 0/1/2/3, and not + // take into account that stream 0 is special. + QuicStreamId id = + ((stream_count - 1) * QuicUtils::StreamIdDelta(QUIC_VERSION_99)); + if (!bidirectional) { + id |= 0x2; + } + if (perspective == Perspective::IS_SERVER) { + id |= 0x1; + } + return id; + } + MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; NiceMock<MockQuicSessionVisitor> session_visitor_; @@ -681,31 +716,89 @@ TEST_P(QuicSessionTestServer, TooManyAvailableUnidirectionalStreams) { TEST_P(QuicSessionTestServer, ManyAvailableBidirectionalStreams) { // When max_open_streams_ is 200, should be able to create 200 streams // out-of-order, that is, creating the one with the largest stream ID first. - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + if (transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, 200); + // Smaller limit on unidirectional streams to help detect crossed wires. + QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams(&session_, 50); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + } + // Create a stream at the start of the range. QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); - // Create one stream. EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); - EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); // Create the largest stream ID of a threatened total of 200 streams. // GetNth... starts at 0, so for 200 streams, get the 199th. + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream( GetNthClientInitiatedBidirectionalId(199))); + + if (transport_version() == QUIC_VERSION_99) { + // If IETF QUIC, check to make sure that creating bidirectional + // streams does not mess up the unidirectional streams. + stream_id = GetNthClientInitiatedUnidirectionalId(0); + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); + // Now try to get the last possible unidirectional stream. + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream( + GetNthClientInitiatedUnidirectionalId(49))); + // and this should fail because it exceeds the unidirectional limit + // (but not the bi-) + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_STREAM_ID, + "Stream id 798 would exceed stream count limit 50", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET + + )) + .Times(1); + EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream( + GetNthClientInitiatedUnidirectionalId(199))); + } } TEST_P(QuicSessionTestServer, ManyAvailableUnidirectionalStreams) { // When max_open_streams_ is 200, should be able to create 200 streams // out-of-order, that is, creating the one with the largest stream ID first. - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); - QuicStreamId stream_id = GetNthClientInitiatedUnidirectionalId(0); + if (transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams(&session_, 200); + // Smaller limit on unidirectional streams to help detect crossed wires. + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, 50); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + } // Create one stream. + QuicStreamId stream_id = GetNthClientInitiatedUnidirectionalId(0); EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); - EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); // Create the largest stream ID of a threatened total of 200 streams. // GetNth... starts at 0, so for 200 streams, get the 199th. + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream( GetNthClientInitiatedUnidirectionalId(199))); + if (transport_version() == QUIC_VERSION_99) { + // If IETF QUIC, check to make sure that creating unidirectional + // streams does not mess up the bidirectional streams. + stream_id = GetNthClientInitiatedBidirectionalId(0); + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); + // Now try to get the last possible bidirectional stream. + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream( + GetNthClientInitiatedBidirectionalId(49))); + // and this should fail because it exceeds the bnidirectional limit + // (but not the uni-) + std::string error_detail; + if (QuicVersionUsesCryptoFrames(transport_version())) { + error_detail = "Stream id 796 would exceed stream count limit 50"; + } else { + error_detail = "Stream id 800 would exceed stream count limit 50"; + } + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_STREAM_ID, error_detail, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)) + .Times(1); + EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream( + GetNthClientInitiatedBidirectionalId(199))); + } } TEST_P(QuicSessionTestServer, DebugDFatalIfMarkingClosedStreamWriteBlocked) { @@ -935,6 +1028,11 @@ TEST_P(QuicSessionTestServer, OnCanWriteWriterBlocks) { } TEST_P(QuicSessionTestServer, BufferedHandshake) { + // This test is testing behavior of crypto stream flow control, but when + // CRYPTO frames are used, there is no flow control for the crypto handshake. + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + return; + } session_.set_writev_consumes_all_data(true); EXPECT_FALSE(session_.HasPendingHandshake()); // Default value. @@ -1021,8 +1119,10 @@ TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { // Mark the crypto and headers streams as write blocked, we expect them to be // allowed to write later. - session_.MarkConnectionLevelWriteBlocked( - QuicUtils::GetCryptoStreamId(connection_->transport_version())); + if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + session_.MarkConnectionLevelWriteBlocked( + QuicUtils::GetCryptoStreamId(connection_->transport_version())); + } // Create a data stream, and although it is write blocked we never expect it // to be allowed to write as we are connection level flow control blocked. @@ -1032,8 +1132,10 @@ TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { // The crypto and headers streams should be called even though we are // connection flow control blocked. - TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); - EXPECT_CALL(*crypto_stream, OnCanWrite()); + if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); + EXPECT_CALL(*crypto_stream, OnCanWrite()); + } // After the crypto and header streams perform a write, the connection will be // blocked by the flow control, hence it should become application-limited. @@ -1164,10 +1266,19 @@ TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) { } TEST_P(QuicSessionTestServer, OnStreamFrameFinStaticStreamId) { + QuicStreamId headers_stream_id = + QuicUtils::GetHeadersStreamId(connection_->transport_version()); + std::unique_ptr<TestStream> fake_headers_stream = QuicMakeUnique<TestStream>( + headers_stream_id, &session_, /*is_static*/ true, BIDIRECTIONAL); + if (GetQuicReloadableFlag(quic_eliminate_static_stream_map_3)) { + QuicSessionPeer::RegisterStaticStreamNew(&session_, + std::move(fake_headers_stream)); + } else { + QuicSessionPeer::RegisterStaticStream(&session_, headers_stream_id, + fake_headers_stream.get()); + } // Send two bytes of payload. - QuicStreamFrame data1( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), true, 0, - QuicStringPiece("HT")); + QuicStreamFrame data1(headers_stream_id, true, 0, QuicStringPiece("HT")); EXPECT_CALL(*connection_, CloseConnection( QUIC_INVALID_STREAM_ID, "Attempt to close a static stream", @@ -1176,11 +1287,20 @@ TEST_P(QuicSessionTestServer, OnStreamFrameFinStaticStreamId) { } TEST_P(QuicSessionTestServer, OnRstStreamStaticStreamId) { + QuicStreamId headers_stream_id = + QuicUtils::GetHeadersStreamId(connection_->transport_version()); + std::unique_ptr<TestStream> fake_headers_stream = QuicMakeUnique<TestStream>( + headers_stream_id, &session_, /*is_static*/ true, BIDIRECTIONAL); + if (GetQuicReloadableFlag(quic_eliminate_static_stream_map_3)) { + QuicSessionPeer::RegisterStaticStreamNew(&session_, + std::move(fake_headers_stream)); + } else { + QuicSessionPeer::RegisterStaticStream(&session_, headers_stream_id, + fake_headers_stream.get()); + } // Send two bytes of payload. - QuicRstStreamFrame rst1( - kInvalidControlFrameId, - QuicUtils::GetCryptoStreamId(connection_->transport_version()), - QUIC_ERROR_PROCESSING_STREAM, 0); + QuicRstStreamFrame rst1(kInvalidControlFrameId, headers_stream_id, + QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(*connection_, CloseConnection( QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream", @@ -1269,7 +1389,7 @@ TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { QuicStreamOffset offset = crypto_stream->stream_bytes_written(); QuicConfig config; CryptoHandshakeMessage crypto_message; - config.ToHandshakeMessage(&crypto_message); + config.ToHandshakeMessage(&crypto_message, transport_version()); crypto_stream->SendHandshakeMessage(crypto_message); char buf[1000]; QuicDataWriter writer(1000, buf, NETWORK_BYTE_ORDER); @@ -1431,8 +1551,12 @@ TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) { QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(session_.config(), kInvalidWindow); - EXPECT_CALL(*connection_, - CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); + if (!connection_->version().AllowsLowFlowControlLimits()) { + EXPECT_CALL(*connection_, + CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); + } else { + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); + } session_.OnConfigNegotiated(); } @@ -1442,9 +1566,12 @@ TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) { const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(), kInvalidWindow); - - EXPECT_CALL(*connection_, - CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); + if (!connection_->version().AllowsLowFlowControlLimits()) { + EXPECT_CALL(*connection_, + CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); + } else { + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); + } session_.OnConfigNegotiated(); } @@ -1486,7 +1613,12 @@ TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) { // with a FIN or RST then we send an RST to refuse streams. For V99 the // connection is closed. const QuicStreamId kMaxStreams = 5; - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + if (transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, + kMaxStreams); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + } const QuicStreamId kFirstStreamId = GetNthClientInitiatedBidirectionalId(0); const QuicStreamId kFinalStreamId = GetNthClientInitiatedBidirectionalId(kMaxStreams); @@ -1514,8 +1646,10 @@ TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) { } if (transport_version() == QUIC_VERSION_99) { - EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, - "Stream id 24 above 20", _)); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_STREAM_ID, + "Stream id 20 would exceed stream count limit 5", _)); } else { EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); EXPECT_CALL(*connection_, @@ -1540,7 +1674,7 @@ TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpenedOutgoing) { } TEST_P(QuicSessionTestServer, NoPendingStreams) { - session_.set_should_buffer_incoming_streams(false); + session_.set_uses_pending_streams(false); QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId( transport_version(), Perspective::IS_CLIENT); @@ -1557,7 +1691,7 @@ TEST_P(QuicSessionTestServer, PendingStreams) { if (connection_->transport_version() != QUIC_VERSION_99) { return; } - session_.set_should_buffer_incoming_streams(true); + session_.set_uses_pending_streams(true); QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId( transport_version(), Perspective::IS_CLIENT); @@ -1574,7 +1708,7 @@ TEST_P(QuicSessionTestServer, RstPendingStreams) { if (connection_->transport_version() != QUIC_VERSION_99) { return; } - session_.set_should_buffer_incoming_streams(true); + session_.set_uses_pending_streams(true); QuicStreamId stream_id = QuicUtils::GetFirstUnidirectionalStreamId( transport_version(), Perspective::IS_CLIENT); @@ -1601,7 +1735,7 @@ TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { // it) does not count against the open quota (because it is closed from the // protocol point of view). if (transport_version() == QUIC_VERSION_99) { - // On v99, we will expect to see a MAX_STREAM_ID go out when there are not + // On v99, we will expect to see a MAX_STREAMS go out when there are not // enough streams to create the next one. EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); } else { @@ -1609,7 +1743,12 @@ TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { } EXPECT_CALL(*connection_, OnStreamReset(_, QUIC_REFUSED_STREAM)).Times(0); const QuicStreamId kMaxStreams = 5; - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + if (transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, + kMaxStreams); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + } // Create kMaxStreams + 1 data streams, and mark them draining. const QuicStreamId kFirstStreamId = GetNthClientInitiatedBidirectionalId(0); @@ -1806,9 +1945,12 @@ TEST_P(QuicSessionTestServer, OnStreamFrameLost) { TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); TestStream* stream4 = session_.CreateOutgoingBidirectionalStream(); - QuicStreamFrame frame1( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), false, 0, - 1300); + QuicStreamFrame frame1; + if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + frame1 = QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_->transport_version()), false, + 0, 1300); + } QuicStreamFrame frame2(stream2->id(), false, 0, 9); QuicStreamFrame frame3(stream4->id(), false, 0, 9); @@ -2179,19 +2321,24 @@ TEST_P(QuicSessionTestServer, NewStreamIdBelowLimit) { // Applicable only to V99 return; } - QuicStreamId bidirectional_stream_id = + QuicStreamId bidirectional_stream_id = StreamCountToId( QuicSessionPeer::v99_streamid_manager(&session_) - ->advertised_max_allowed_incoming_bidirectional_stream_id() - - kV99StreamIdIncrement; + ->advertised_max_allowed_incoming_bidirectional_streams() - + 1, + Perspective::IS_CLIENT, + /*bidirectional=*/true); + QuicStreamFrame bidirectional_stream_frame(bidirectional_stream_id, false, 0, "Random String"); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); session_.OnStreamFrame(bidirectional_stream_frame); - QuicStreamId unidirectional_stream_id = + QuicStreamId unidirectional_stream_id = StreamCountToId( QuicSessionPeer::v99_streamid_manager(&session_) - ->advertised_max_allowed_incoming_unidirectional_stream_id() - - kV99StreamIdIncrement; + ->advertised_max_allowed_incoming_unidirectional_streams() - + 1, + Perspective::IS_CLIENT, + /*bidirectional=*/false); QuicStreamFrame unidirectional_stream_frame(unidirectional_stream_id, false, 0, "Random String"); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); @@ -2204,17 +2351,19 @@ TEST_P(QuicSessionTestServer, NewStreamIdAtLimit) { // Applicable only to V99 return; } - QuicStreamId bidirectional_stream_id = + QuicStreamId bidirectional_stream_id = StreamCountToId( QuicSessionPeer::v99_streamid_manager(&session_) - ->advertised_max_allowed_incoming_bidirectional_stream_id(); + ->advertised_max_allowed_incoming_bidirectional_streams(), + Perspective::IS_CLIENT, /*bidirectional=*/true); QuicStreamFrame bidirectional_stream_frame(bidirectional_stream_id, false, 0, "Random String"); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); session_.OnStreamFrame(bidirectional_stream_frame); - QuicStreamId unidirectional_stream_id = + QuicStreamId unidirectional_stream_id = StreamCountToId( QuicSessionPeer::v99_streamid_manager(&session_) - ->advertised_max_allowed_incoming_unidirectional_stream_id(); + ->advertised_max_allowed_incoming_unidirectional_streams(), + Perspective::IS_CLIENT, /*bidirectional=*/false); QuicStreamFrame unidirectional_stream_frame(unidirectional_stream_id, false, 0, "Random String"); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); @@ -2227,24 +2376,30 @@ TEST_P(QuicSessionTestServer, NewStreamIdAboveLimit) { // Applicable only to V99 return; } - QuicStreamId bidirectional_stream_id = + QuicStreamId bidirectional_stream_id = StreamCountToId( QuicSessionPeer::v99_streamid_manager(&session_) - ->advertised_max_allowed_incoming_bidirectional_stream_id() + - kV99StreamIdIncrement; + ->advertised_max_allowed_incoming_bidirectional_streams() + + 1, + Perspective::IS_CLIENT, /*bidirectional=*/true); QuicStreamFrame bidirectional_stream_frame(bidirectional_stream_id, false, 0, "Random String"); - EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, - "Stream id 404 above 400", _)); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_STREAM_ID, + "Stream id 400 would exceed stream count limit 100", _)); session_.OnStreamFrame(bidirectional_stream_frame); - QuicStreamId unidirectional_stream_id = + QuicStreamId unidirectional_stream_id = StreamCountToId( QuicSessionPeer::v99_streamid_manager(&session_) - ->advertised_max_allowed_incoming_unidirectional_stream_id() + - kV99StreamIdIncrement; + ->advertised_max_allowed_incoming_unidirectional_streams() + + 1, + Perspective::IS_CLIENT, /*bidirectional=*/false); QuicStreamFrame unidirectional_stream_frame(unidirectional_stream_id, false, 0, "Random String"); - EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, - "Stream id 402 above 398", _)); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_STREAM_ID, + "Stream id 402 would exceed stream count limit 100", _)); session_.OnStreamFrame(unidirectional_stream_frame); } @@ -2272,9 +2427,19 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputStaticStreams) { // Applicable only to V99 return; } + QuicStreamId stream_id = 0; + std::unique_ptr<TestStream> fake_static_stream = QuicMakeUnique<TestStream>( + stream_id, &session_, /*is_static*/ true, BIDIRECTIONAL); + if (GetQuicReloadableFlag(quic_eliminate_static_stream_map_3)) { + QuicSessionPeer::RegisterStaticStreamNew(&session_, + std::move(fake_static_stream)); + } else { + QuicSessionPeer::RegisterStaticStream(&session_, stream_id, + fake_static_stream.get()); + } // Check that a stream id in the static stream map is ignored. // Note that the notion of a static stream is Google-specific. - QuicStopSendingFrame frame(1, 0, 123); + QuicStopSendingFrame frame(1, stream_id, 123); EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream", _)); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc index 4fba898377a..94cffd4030c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc @@ -33,7 +33,7 @@ size_t GetReceivedFlowControlWindow(QuicSession* session) { return session->config()->ReceivedInitialStreamFlowControlWindowBytes(); } - return kMinimumFlowControlSendWindow; + return kDefaultFlowControlSendWindow; } } // namespace @@ -58,8 +58,8 @@ PendingStream::PendingStream(QuicStreamId id, QuicSession* session) sequencer_(this) {} void PendingStream::OnDataAvailable() { - QUIC_BUG << "OnDataAvailable should not be called."; - CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "Unexpected data available"); + // It will be called when pending stream receives its first byte. But this + // call should simply be ignored so that data remains in sequencer. } void PendingStream::OnFinRead() { @@ -68,8 +68,9 @@ void PendingStream::OnFinRead() { } void PendingStream::AddBytesConsumed(QuicByteCount bytes) { - QUIC_BUG << "AddBytesConsumed should not be called."; - CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "Unexpected bytes consumed"); + // It will be called when the metadata of the stream is consumed. + flow_controller_.AddBytesConsumed(bytes); + connection_flow_controller_->AddBytesConsumed(bytes); } void PendingStream::Reset(QuicRstStreamErrorCode error) { @@ -92,7 +93,6 @@ const QuicSocketAddress& PendingStream::PeerAddressOfLatestPacket() const { void PendingStream::OnStreamFrame(const QuicStreamFrame& frame) { DCHECK_EQ(frame.stream_id, id_); - DCHECK_NE(0u, frame.offset); bool is_stream_too_long = (frame.offset > kMaxStreamLength) || @@ -169,11 +169,15 @@ bool PendingStream::MaybeIncreaseHighestReceivedOffset( return true; } -QuicStream::QuicStream(PendingStream pending, StreamType type) +void PendingStream::MarkConsumed(size_t num_bytes) { + sequencer_.MarkConsumed(num_bytes); +} + +QuicStream::QuicStream(PendingStream pending, StreamType type, bool is_static) : QuicStream(pending.id_, pending.session_, std::move(pending.sequencer_), - /*is_static=*/false, + is_static, type, pending.stream_bytes_read_, pending.fin_received_, @@ -182,6 +186,30 @@ QuicStream::QuicStream(PendingStream pending, StreamType type) sequencer_.set_stream(this); } +namespace { + +QuicOptional<QuicFlowController> FlowController(QuicStreamId id, + QuicSession* session, + StreamType type) { + if (type == CRYPTO) { + // The only QuicStream with a StreamType of CRYPTO is QuicCryptoStream, when + // it is using crypto frames instead of stream frames. The QuicCryptoStream + // doesn't have any flow control in that case, so we don't create a + // QuicFlowController for it. + return QuicOptional<QuicFlowController>(); + } + return QuicFlowController( + session, id, + /*is_connection_flow_controller*/ false, + GetReceivedFlowControlWindow(session), + GetInitialStreamFlowControlWindowToSend(session), + kStreamReceiveWindowLimit, + session->flow_controller()->auto_tune_receive_window(), + session->flow_controller()); +} + +} // namespace + QuicStream::QuicStream(QuicStreamId id, QuicSession* session, bool is_static, @@ -193,15 +221,7 @@ QuicStream::QuicStream(QuicStreamId id, type, 0, false, - QuicFlowController( - session, - id, - /*is_connection_flow_controller*/ false, - GetReceivedFlowControlWindow(session), - GetInitialStreamFlowControlWindowToSend(session), - kStreamReceiveWindowLimit, - session->flow_controller()->auto_tune_receive_window(), - session->flow_controller()), + FlowController(id, session, type), session->flow_controller()) {} QuicStream::QuicStream(QuicStreamId id, @@ -211,7 +231,7 @@ QuicStream::QuicStream(QuicStreamId id, StreamType type, uint64_t stream_bytes_read, bool fin_received, - QuicFlowController flow_controller, + QuicOptional<QuicFlowController> flow_controller, QuicFlowController* connection_flow_controller) : sequencer_(std::move(sequencer)), id_(id), @@ -240,7 +260,8 @@ QuicStream::QuicStream(QuicStreamId id, buffered_data_threshold_(GetQuicFlag(FLAGS_quic_buffered_data_threshold)), is_static_(is_static), deadline_(QuicTime::Zero()), - type_(session->connection()->transport_version() == QUIC_VERSION_99 + type_(session->connection()->transport_version() == QUIC_VERSION_99 && + type != CRYPTO ? QuicUtils::GetStreamType(id_, perspective_, session->IsIncomingStream(id_)) @@ -253,7 +274,9 @@ QuicStream::QuicStream(QuicStreamId id, CloseWriteSide(); } SetFromConfig(); - session_->RegisterStreamPriority(id, is_static_, priority_); + if (type_ != CRYPTO) { + session_->RegisterStreamPriority(id, is_static_, priority_); + } } QuicStream::~QuicStream() { @@ -264,7 +287,7 @@ QuicStream::~QuicStream() { << send_buffer_.stream_bytes_outstanding() << ", fin_outstanding: " << fin_outstanding_; } - if (session_ != nullptr) { + if (session_ != nullptr && type_ != CRYPTO) { session_->UnregisterStreamPriority(id(), is_static_); } } @@ -324,7 +347,7 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size)) { // As the highest received offset has changed, check to see if this is a // violation of flow control. - if (flow_controller_.FlowControlViolation() || + if (flow_controller_->FlowControlViolation() || connection_flow_controller_->FlowControlViolation()) { CloseConnectionWithDetails( QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, @@ -353,7 +376,7 @@ void QuicStream::OnStreamReset(const QuicRstStreamFrame& frame) { return; } MaybeIncreaseHighestReceivedOffset(frame.byte_offset); - if (flow_controller_.FlowControlViolation() || + if (flow_controller_->FlowControlViolation() || connection_flow_controller_->FlowControlViolation()) { CloseConnectionWithDetails( QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, @@ -494,7 +517,7 @@ void QuicStream::OnCanWrite() { } void QuicStream::MaybeSendBlocked() { - if (flow_controller_.ShouldSendBlocked()) { + if (flow_controller_->ShouldSendBlocked()) { session_->SendBlocked(id_); } if (!stream_contributes_to_connection_flow_control_) { @@ -508,7 +531,7 @@ void QuicStream::MaybeSendBlocked() { // the stream will be given a chance to write when a connection-level // WINDOW_UPDATE arrives. if (connection_flow_controller_->IsBlocked() && - !flow_controller_.IsBlocked()) { + !flow_controller_->IsBlocked()) { session_->MarkConnectionLevelWriteBlocked(id()); } } @@ -708,7 +731,7 @@ void QuicStream::OnClose() { rst_sent_ = true; } - if (flow_controller_.FlowControlViolation() || + if (flow_controller_->FlowControlViolation() || connection_flow_controller_->FlowControlViolation()) { return; } @@ -717,13 +740,13 @@ void QuicStream::OnClose() { // the same connection level flow control state, mark all unreceived or // buffered bytes as consumed. QuicByteCount bytes_to_consume = - flow_controller_.highest_received_byte_offset() - - flow_controller_.bytes_consumed(); + flow_controller_->highest_received_byte_offset() - + flow_controller_->bytes_consumed(); AddBytesConsumed(bytes_to_consume); } void QuicStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { - if (flow_controller_.UpdateSendWindowOffset(frame.byte_offset)) { + if (flow_controller_->UpdateSendWindowOffset(frame.byte_offset)) { // Let session unblock this stream. session_->MarkConnectionLevelWriteBlocked(id_); } @@ -732,8 +755,8 @@ void QuicStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { bool QuicStream::MaybeIncreaseHighestReceivedOffset( QuicStreamOffset new_offset) { uint64_t increment = - new_offset - flow_controller_.highest_received_byte_offset(); - if (!flow_controller_.UpdateHighestReceivedOffset(new_offset)) { + new_offset - flow_controller_->highest_received_byte_offset(); + if (!flow_controller_->UpdateHighestReceivedOffset(new_offset)) { return false; } @@ -749,16 +772,22 @@ bool QuicStream::MaybeIncreaseHighestReceivedOffset( } void QuicStream::AddBytesSent(QuicByteCount bytes) { - flow_controller_.AddBytesSent(bytes); + flow_controller_->AddBytesSent(bytes); if (stream_contributes_to_connection_flow_control_) { connection_flow_controller_->AddBytesSent(bytes); } } void QuicStream::AddBytesConsumed(QuicByteCount bytes) { + if (type_ == CRYPTO) { + // A stream with type CRYPTO has no flow control, so there's nothing this + // function needs to do. This function still gets called by the + // QuicStreamSequencers used by QuicCryptoStream. + return; + } // Only adjust stream level flow controller if still reading. if (!read_side_closed_) { - flow_controller_.AddBytesConsumed(bytes); + flow_controller_->AddBytesConsumed(bytes); } if (stream_contributes_to_connection_flow_control_) { @@ -767,7 +796,7 @@ void QuicStream::AddBytesConsumed(QuicByteCount bytes) { } void QuicStream::UpdateSendWindowOffset(QuicStreamOffset new_window) { - if (flow_controller_.UpdateSendWindowOffset(new_window)) { + if (flow_controller_->UpdateSendWindowOffset(new_window)) { // Let session unblock this stream. session_->MarkConnectionLevelWriteBlocked(id_); } @@ -920,7 +949,7 @@ void QuicStream::WriteBufferedData() { bool fin = fin_buffered_; // How much data flow control permits to be written. - QuicByteCount send_window = flow_controller_.SendWindowSize(); + QuicByteCount send_window = flow_controller_->SendWindowSize(); if (stream_contributes_to_connection_flow_control_) { send_window = std::min(send_window, connection_flow_controller_->SendWindowSize()); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h index 40bed1c19c9..80ee4e4a24a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h @@ -30,6 +30,7 @@ #include "net/third_party/quiche/src/quic/core/session_notifier_interface.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_optional.h" #include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" @@ -73,6 +74,10 @@ class QUIC_EXPORT_PRIVATE PendingStream // Returns the number of bytes read on this stream. uint64_t stream_bytes_read() { return stream_bytes_read_; } + const QuicStreamSequencer* sequencer() const { return &sequencer_; } + + void MarkConsumed(size_t num_bytes); + private: friend class QuicStream; @@ -121,7 +126,7 @@ class QUIC_EXPORT_PRIVATE QuicStream QuicSession* session, bool is_static, StreamType type); - QuicStream(PendingStream pending, StreamType type); + QuicStream(PendingStream pending, StreamType type, bool is_static); QuicStream(const QuicStream&) = delete; QuicStream& operator=(const QuicStream&) = delete; @@ -222,7 +227,7 @@ class QUIC_EXPORT_PRIVATE QuicStream int num_frames_received() const; int num_duplicate_frames_received() const; - QuicFlowController* flow_controller() { return &flow_controller_; } + QuicFlowController* flow_controller() { return &*flow_controller_; } // Called when endpoint receives a frame which could increase the highest // offset. @@ -343,6 +348,9 @@ class QUIC_EXPORT_PRIVATE QuicStream // Does not send a FIN. May cause the stream to be closed. virtual void CloseWriteSide(); + // Returns true if the stream is static. + bool is_static() const { return is_static_; } + protected: // Sends as many bytes in the first |count| buffers of |iov| to the connection // as the connection will consume. If FIN is consumed, the write side is @@ -428,7 +436,7 @@ class QUIC_EXPORT_PRIVATE QuicStream StreamType type, uint64_t stream_bytes_read, bool fin_received, - QuicFlowController flow_controller, + QuicOptional<QuicFlowController> flow_controller, QuicFlowController* connection_flow_controller); // Subclasses and consumers should use reading_stopped. @@ -499,7 +507,7 @@ class QUIC_EXPORT_PRIVATE QuicStream // server or a client. Perspective perspective_; - QuicFlowController flow_controller_; + QuicOptional<QuicFlowController> flow_controller_; // The connection level flow controller. Not owned. QuicFlowController* connection_flow_controller_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc index fb6e14b8957..2921268b5a2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc @@ -22,312 +22,341 @@ namespace quic { QuicStreamIdManager::QuicStreamIdManager( QuicSession* session, - QuicStreamId next_outgoing_stream_id, - QuicStreamId largest_peer_created_stream_id, - QuicStreamId first_incoming_dynamic_stream_id, - size_t max_allowed_outgoing_streams, - size_t max_allowed_incoming_streams) + bool unidirectional, + QuicStreamCount max_allowed_outgoing_streams, + QuicStreamCount max_allowed_incoming_streams) : session_(session), - next_outgoing_stream_id_(next_outgoing_stream_id), - largest_peer_created_stream_id_(largest_peer_created_stream_id), - max_allowed_outgoing_stream_id_(0), - actual_max_allowed_incoming_stream_id_(0), - advertised_max_allowed_incoming_stream_id_(0), - max_stream_id_window_(max_allowed_incoming_streams / - kMaxStreamIdWindowDivisor), - max_allowed_incoming_streams_(max_allowed_incoming_streams), - first_incoming_dynamic_stream_id_(first_incoming_dynamic_stream_id), - first_outgoing_dynamic_stream_id_(next_outgoing_stream_id) { - available_incoming_streams_ = max_allowed_incoming_streams_; - SetMaxOpenOutgoingStreams(max_allowed_outgoing_streams); - SetMaxOpenIncomingStreams(max_allowed_incoming_streams); + unidirectional_(unidirectional), + outgoing_max_streams_(max_allowed_outgoing_streams), + next_outgoing_stream_id_(GetFirstOutgoingStreamId()), + outgoing_stream_count_(0), + outgoing_static_stream_count_(0), + using_default_max_streams_(true), + incoming_actual_max_streams_(max_allowed_incoming_streams), + // Advertised max starts at actual because it's communicated in the + // handshake. + incoming_advertised_max_streams_(max_allowed_incoming_streams), + incoming_initial_max_open_streams_(max_allowed_incoming_streams), + incoming_static_stream_count_(0), + incoming_stream_count_(0), + largest_peer_created_stream_id_( + QuicUtils::GetInvalidStreamId(transport_version())), + max_streams_window_(0) { + CalculateIncomingMaxStreamsWindow(); } QuicStreamIdManager::~QuicStreamIdManager() { - QUIC_LOG_IF(WARNING, - session_->num_locally_closed_incoming_streams_highest_offset() > - max_allowed_incoming_streams_) - << "Surprisingly high number of locally closed peer initiated streams" - "still waiting for final byte offset: " - << session_->num_locally_closed_incoming_streams_highest_offset(); - QUIC_LOG_IF(WARNING, - session_->GetNumLocallyClosedOutgoingStreamsHighestOffset() > - max_allowed_outgoing_streams_) - << "Surprisingly high number of locally closed self initiated streams" - "still waiting for final byte offset: " - << session_->GetNumLocallyClosedOutgoingStreamsHighestOffset(); } -bool QuicStreamIdManager::OnMaxStreamIdFrame( - const QuicMaxStreamIdFrame& frame) { - DCHECK_EQ(QuicUtils::IsBidirectionalStreamId(frame.max_stream_id), - QuicUtils::IsBidirectionalStreamId(next_outgoing_stream_id_)); - // Need to determine whether the stream id matches our client/server - // perspective or not. If not, it's an error. If so, update appropriate - // maxima. - QUIC_CODE_COUNT_N(max_stream_id_received, 2, 2); - // TODO(fkastenholz): this test needs to be broader to handle uni- and bi- - // directional stream ids when that functionality is supported. - if (IsIncomingStream(frame.max_stream_id)) { - // TODO(fkastenholz): This, and following, closeConnection may - // need modification when proper support for IETF CONNECTION - // CLOSE is done. - QUIC_CODE_COUNT(max_stream_id_bad_direction); - session_->connection()->CloseConnection( - QUIC_MAX_STREAM_ID_ERROR, - "Received max stream ID with wrong initiator bit setting", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); +bool QuicStreamIdManager::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) { + // Ensure that the frame has the correct directionality. + DCHECK_EQ(frame.unidirectional, unidirectional_); + QUIC_CODE_COUNT_N(quic_max_streams_received, 2, 2); + const QuicStreamCount current_outgoing_max_streams = outgoing_max_streams_; + + // Set the limit to be exactly the stream count in the frame. + if (!ConfigureMaxOpenOutgoingStreams(frame.stream_count)) { return false; } - - // If a MAX_STREAM_ID advertises a stream ID that is smaller than previously - // advertised, it is to be ignored. - if (frame.max_stream_id < max_allowed_outgoing_stream_id_) { - QUIC_CODE_COUNT(max_stream_id_ignored); - return true; + // If we were at the previous limit and this MAX_STREAMS frame + // increased the limit, inform the application that new streams are + // available. + if (outgoing_stream_count_ == current_outgoing_max_streams && + current_outgoing_max_streams < outgoing_max_streams_) { + session_->OnCanCreateNewOutgoingStream(); } - max_allowed_outgoing_stream_id_ = frame.max_stream_id; - - // Outgoing stream limit has increased, tell the applications - session_->OnCanCreateNewOutgoingStream(); - return true; } -bool QuicStreamIdManager::OnStreamIdBlockedFrame( - const QuicStreamIdBlockedFrame& frame) { - DCHECK_EQ(QuicUtils::IsBidirectionalStreamId(frame.stream_id), - QuicUtils::IsBidirectionalStreamId(next_outgoing_stream_id_)); - QUIC_CODE_COUNT_N(stream_id_blocked_received, 2, 2); - QuicStreamId id = frame.stream_id; - if (!IsIncomingStream(frame.stream_id)) { - // Client/server mismatch, close the connection - // TODO(fkastenholz): revise when proper IETF Connection Close support is - // done. - QUIC_CODE_COUNT(stream_id_blocked_bad_direction); - session_->connection()->CloseConnection( - QUIC_STREAM_ID_BLOCKED_ERROR, - "Invalid stream ID directionality specified", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; - } +// The peer sends a streams blocked frame when it can not open any more +// streams because it has runs into the limit. +bool QuicStreamIdManager::OnStreamsBlockedFrame( + const QuicStreamsBlockedFrame& frame) { + // Ensure that the frame has the correct directionality. + DCHECK_EQ(frame.unidirectional, unidirectional_); + QUIC_CODE_COUNT_N(quic_streams_blocked_received, 2, 2); - if (id > advertised_max_allowed_incoming_stream_id_) { + if (frame.stream_count > incoming_advertised_max_streams_) { // Peer thinks it can send more streams that we've told it. // This is a protocol error. // TODO(fkastenholz): revise when proper IETF Connection Close support is // done. - QUIC_CODE_COUNT(stream_id_blocked_id_too_big); + QUIC_CODE_COUNT(quic_streams_blocked_too_big); session_->connection()->CloseConnection( - QUIC_STREAM_ID_BLOCKED_ERROR, "Invalid stream ID specified", + QUIC_STREAMS_BLOCKED_ERROR, "Invalid stream count specified", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return false; } - if (id < actual_max_allowed_incoming_stream_id_) { - // Peer thinks it's blocked on an ID that is less than our current - // max. Inform the peer of the correct stream ID. - SendMaxStreamIdFrame(); + if (frame.stream_count < incoming_actual_max_streams_) { + // Peer thinks it's blocked on a stream count that is less than our current + // max. Inform the peer of the correct stream count. Sending a MAX_STREAMS + // frame in this case is not controlled by the window. + SendMaxStreamsFrame(); + } + QUIC_CODE_COUNT(quic_streams_blocked_id_correct); + return true; +} + +// Used when configuration has been done and we have an initial +// maximum stream count from the peer. +bool QuicStreamIdManager::ConfigureMaxOpenOutgoingStreams( + size_t max_open_streams) { + if (using_default_max_streams_) { + // This is the first MAX_STREAMS/transport negotiation we've received. Treat + // this a bit differently than later ones. The difference is that + // outgoing_max_streams_ is currently an estimate. The MAX_STREAMS frame or + // transport negotiation is authoritative and can reduce + // outgoing_max_streams_ -- so long as outgoing_max_streams_ is not set to + // be less than the number of existing outgoing streams. If that happens, + // close the connection. + if (max_open_streams < outgoing_stream_count_) { + session_->connection()->CloseConnection( + QUIC_MAX_STREAMS_ERROR, + "Stream limit less than existing stream count", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } + using_default_max_streams_ = false; + } else if (max_open_streams <= outgoing_max_streams_) { + // Is not the 1st MAX_STREAMS or negotiation. + // Only update the stream count if it would increase the limit. + // If it decreases the limit, or doesn't change it, then do not update. + // Note that this handles the case of receiving a count of 0 in the frame return true; } - // The peer's notion of the maximum ID is correct, - // there is nothing to do. - QUIC_CODE_COUNT(stream_id_blocked_id_correct); + + // This implementation only supports 32 bit Stream IDs, so limit max streams + // if it would exceed the max 32 bits can express. + outgoing_max_streams_ = std::min<size_t>( + max_open_streams, + QuicUtils::GetMaxStreamCount(unidirectional_, session_->perspective())); return true; } -// TODO(fkastenholz): Many changes will be needed here: -// -- Use IETF QUIC server/client-initiation sense -// -- Support both BIDI and UNI streams. -// -- can not change the max number of streams after config negotiation has -// been done. -void QuicStreamIdManager::SetMaxOpenOutgoingStreams(size_t max_streams) { - max_allowed_outgoing_streams_ = max_streams; - max_allowed_outgoing_stream_id_ = - next_outgoing_stream_id_ + (max_streams - 1) * kV99StreamIdIncrement; +void QuicStreamIdManager::SetMaxOpenOutgoingStreams(size_t max_open_streams) { + QUIC_BUG_IF(!using_default_max_streams_); + // TODO(fkastenholz): when static streams are removed from I-Quic, this + // should be revised to invoke ConfigureMaxOpen... + AdjustMaxOpenOutgoingStreams(max_open_streams); } -// TODO(fkastenholz): Many changes will be needed here: -// -- can not change the max number of streams after config negotiation has -// been done. -// -- Currently uses the Google Client/server-initiation sense, needs to -// be IETF. -// -- Support both BIDI and UNI streams. -// -- Convert calculation of the maximum ID from Google-QUIC semantics to IETF -// QUIC semantics. -void QuicStreamIdManager::SetMaxOpenIncomingStreams(size_t max_streams) { - max_allowed_incoming_streams_ = max_streams; - // The peer should always believe that it has the negotiated - // number of stream ids available for use. - available_incoming_streams_ = max_allowed_incoming_streams_; - - // the window is a fraction of the peer's notion of its stream-id space. - max_stream_id_window_ = - available_incoming_streams_ / kMaxStreamIdWindowDivisor; - if (max_stream_id_window_ == 0) { - max_stream_id_window_ = 1; +// Adjust the outgoing stream limit - max_open_streams is the limit, not +// including static streams. If the new stream limit wraps, will peg +// the limit at the implementation max. +// TODO(fkastenholz): AdjustMax is cognizant of the number of static streams and +// sets the maximum to be max_streams + number_of_statics. This should be +// removed from IETF QUIC when static streams are gone. +void QuicStreamIdManager::AdjustMaxOpenOutgoingStreams( + size_t max_open_streams) { + if ((outgoing_static_stream_count_ + max_open_streams) < max_open_streams) { + // New limit causes us to wrap, set limit to be the implementation maximum. + ConfigureMaxOpenOutgoingStreams( + QuicUtils::GetMaxStreamCount(unidirectional_, perspective())); + return; } + // Does not wrap, set limit to what is requested. + ConfigureMaxOpenOutgoingStreams(outgoing_static_stream_count_ + + max_open_streams); +} - actual_max_allowed_incoming_stream_id_ = - first_incoming_dynamic_stream_id_ + - (max_allowed_incoming_streams_ - 1) * kV99StreamIdIncrement; - // To start, we can assume advertised and actual are the same. - advertised_max_allowed_incoming_stream_id_ = - actual_max_allowed_incoming_stream_id_; +void QuicStreamIdManager::SetMaxOpenIncomingStreams(size_t max_open_streams) { + QuicStreamCount implementation_max = + QuicUtils::GetMaxStreamCount(unidirectional_, perspective()); + QuicStreamCount new_max = + std::min(implementation_max, + static_cast<QuicStreamCount>(max_open_streams + + incoming_static_stream_count_)); + if (new_max < max_open_streams) { + // wrapped around ... + new_max = implementation_max; + } + if (new_max < incoming_stream_count_) { + session_->connection()->CloseConnection( + QUIC_MAX_STREAMS_ERROR, "Stream limit less than existing stream count", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + incoming_actual_max_streams_ = new_max; + incoming_advertised_max_streams_ = new_max; + incoming_initial_max_open_streams_ = + std::min(max_open_streams, static_cast<size_t>(implementation_max)); + CalculateIncomingMaxStreamsWindow(); } -void QuicStreamIdManager::MaybeSendMaxStreamIdFrame() { - if (available_incoming_streams_ > max_stream_id_window_) { +void QuicStreamIdManager::MaybeSendMaxStreamsFrame() { + if ((incoming_advertised_max_streams_ - incoming_stream_count_) > + max_streams_window_) { // window too large, no advertisement return; } - // Calculate the number of streams that the peer will believe - // it has. The "/kV99StreamIdIncrement" converts from stream-id- - // values to number-of-stream-ids. - available_incoming_streams_ += (actual_max_allowed_incoming_stream_id_ - - advertised_max_allowed_incoming_stream_id_) / - kV99StreamIdIncrement; - SendMaxStreamIdFrame(); + SendMaxStreamsFrame(); } -void QuicStreamIdManager::SendMaxStreamIdFrame() { - advertised_max_allowed_incoming_stream_id_ = - actual_max_allowed_incoming_stream_id_; - // And Advertise it. - session_->SendMaxStreamId(advertised_max_allowed_incoming_stream_id_); +void QuicStreamIdManager::SendMaxStreamsFrame() { + incoming_advertised_max_streams_ = incoming_actual_max_streams_; + session_->SendMaxStreams(incoming_advertised_max_streams_, unidirectional_); } void QuicStreamIdManager::OnStreamClosed(QuicStreamId stream_id) { - DCHECK_EQ(QuicUtils::IsBidirectionalStreamId(stream_id), - QuicUtils::IsBidirectionalStreamId(next_outgoing_stream_id_)); + DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_); if (!IsIncomingStream(stream_id)) { - // Nothing to do for outbound streams with respect to the - // stream ID space management. + // Nothing to do for outgoing streams. return; } - // If the stream is inbound, we can increase the stream ID limit and maybe - // advertise the new limit to the peer. - if (actual_max_allowed_incoming_stream_id_ >= - (kMaxQuicStreamId - kV99StreamIdIncrement)) { + // If the stream is inbound, we can increase the actual stream limit and maybe + // advertise the new limit to the peer. Have to check to make sure that we do + // not exceed the maximum. + if (incoming_actual_max_streams_ == + QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) { // Reached the maximum stream id value that the implementation // supports. Nothing can be done here. return; } - actual_max_allowed_incoming_stream_id_ += kV99StreamIdIncrement; - MaybeSendMaxStreamIdFrame(); + // One stream closed ... another can be opened. + incoming_actual_max_streams_++; + MaybeSendMaxStreamsFrame(); } QuicStreamId QuicStreamIdManager::GetNextOutgoingStreamId() { - QUIC_BUG_IF(next_outgoing_stream_id_ > max_allowed_outgoing_stream_id_) - << "Attempt allocate a new outgoing stream ID would exceed the limit"; + // TODO(fkastenholz): Should we close the connection? + QUIC_BUG_IF(outgoing_stream_count_ >= outgoing_max_streams_) + << "Attempt to allocate a new outgoing stream that would exceed the " + "limit"; QuicStreamId id = next_outgoing_stream_id_; - next_outgoing_stream_id_ += kV99StreamIdIncrement; + next_outgoing_stream_id_ += QuicUtils::StreamIdDelta(transport_version()); + outgoing_stream_count_++; return id; } bool QuicStreamIdManager::CanOpenNextOutgoingStream() { - DCHECK_EQ(QUIC_VERSION_99, session_->connection()->transport_version()); - if (next_outgoing_stream_id_ > max_allowed_outgoing_stream_id_) { - // Next stream ID would exceed the limit, need to inform the peer. - session_->SendStreamIdBlocked(max_allowed_outgoing_stream_id_); - QUIC_CODE_COUNT(reached_outgoing_stream_id_limit); - return false; + DCHECK_EQ(QUIC_VERSION_99, transport_version()); + if (outgoing_stream_count_ < outgoing_max_streams_) { + return true; } - return true; + // Next stream ID would exceed the limit, need to inform the peer. + session_->SendStreamsBlocked(outgoing_max_streams_, unidirectional_); + QUIC_CODE_COUNT(quic_reached_outgoing_stream_id_limit); + return false; } -void QuicStreamIdManager::RegisterStaticStream(QuicStreamId stream_id) { - DCHECK_EQ(QuicUtils::IsBidirectionalStreamId(stream_id), - QuicUtils::IsBidirectionalStreamId(next_outgoing_stream_id_)); - QuicStreamId first_dynamic_stream_id = stream_id + kV99StreamIdIncrement; - - if (IsIncomingStream(first_dynamic_stream_id)) { +bool QuicStreamIdManager::RegisterStaticStream(QuicStreamId stream_id) { + DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_); + if (IsIncomingStream(stream_id)) { // This code is predicated on static stream ids being allocated densely, in // order, and starting with the first stream allowed. QUIC_BUG if this is // not so. - QUIC_BUG_IF(stream_id > first_incoming_dynamic_stream_id_) - << "Error in incoming static stream allocation, expected to allocate " - << first_incoming_dynamic_stream_id_ << " got " << stream_id; - // This is a stream id for a stream that is started by the peer, deal with // the incoming stream ids. Increase the floor and adjust everything // accordingly. - if (stream_id == first_incoming_dynamic_stream_id_) { - actual_max_allowed_incoming_stream_id_ += kV99StreamIdIncrement; - first_incoming_dynamic_stream_id_ = first_dynamic_stream_id; + + QUIC_BUG_IF(incoming_actual_max_streams_ > + QuicUtils::GetMaxStreamCount(unidirectional_, perspective())); + + // If we have reached the limit on stream creation, do not create + // the static stream; return false. + if (incoming_stream_count_ >= + QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) { + return false; } - return; + + if (incoming_actual_max_streams_ < + QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) { + incoming_actual_max_streams_++; + } + if (incoming_advertised_max_streams_ < + QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) { + incoming_advertised_max_streams_++; + } + incoming_stream_count_++; + incoming_static_stream_count_++; + return true; } - // This code is predicated on static stream ids being allocated densely, in - // order, and starting with the first stream allowed. QUIC_BUG if this is - // not so. - QUIC_BUG_IF(stream_id > first_outgoing_dynamic_stream_id_) - << "Error in outgoing static stream allocation, expected to allocate " - << first_outgoing_dynamic_stream_id_ << " got " << stream_id; - // This is a stream id for a stream that is started by this node; deal with - // the outgoing stream ids. Increase the floor and adjust everything - // accordingly. - if (stream_id == first_outgoing_dynamic_stream_id_) { - max_allowed_outgoing_stream_id_ += kV99StreamIdIncrement; - first_outgoing_dynamic_stream_id_ = first_dynamic_stream_id; + QUIC_BUG_IF(!using_default_max_streams_) + << "Attempted to allocate static stream (id " << stream_id + << ") after receiving a MAX_STREAMS frame"; + + // If we have reached the limit on stream creation, do not create + // the static stream; return false. + if (outgoing_max_streams_ >= + QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) { + return false; } + + // Increase the outgoing_max_streams_ limit to reflect the semantic that + // outgoing_max_streams_ was inialized to a "maximum request/response" count + // and only becomes a maximum stream count when we receive the first + // MAX_STREAMS. + outgoing_max_streams_++; + outgoing_static_stream_count_++; + return true; } +// Stream_id is the id of a new incoming stream. Check if it can be +// created (doesn't violate limits, etc). bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId( const QuicStreamId stream_id) { - DCHECK_EQ(QuicUtils::IsBidirectionalStreamId(stream_id), - QuicUtils::IsBidirectionalStreamId(next_outgoing_stream_id_)); + DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_); + available_streams_.erase(stream_id); if (largest_peer_created_stream_id_ != - QuicUtils::GetInvalidStreamId( - session_->connection()->transport_version()) && + QuicUtils::GetInvalidStreamId(transport_version()) && stream_id <= largest_peer_created_stream_id_) { return true; } - if (stream_id > actual_max_allowed_incoming_stream_id_) { - // Desired stream ID is larger than the limit, do not increase. + QuicStreamCount stream_count_increment; + if (largest_peer_created_stream_id_ != + QuicUtils::GetInvalidStreamId(transport_version())) { + stream_count_increment = (stream_id - largest_peer_created_stream_id_) / + QuicUtils::StreamIdDelta(transport_version()); + } else { + // Largest_peer_created_stream_id is the invalid ID, + // which means that the peer has not created any stream IDs. + // The "+1" is because the first stream ID has not yet + // been used. For example, if the FirstIncoming ID is 1 + // and stream_id is 1, then we want the increment to be 1. + stream_count_increment = ((stream_id - GetFirstIncomingStreamId()) / + QuicUtils::StreamIdDelta(transport_version())) + + 1; + } + + // If already at, or over, the limit, close the connection/etc. + if (((incoming_stream_count_ + stream_count_increment) > + incoming_advertised_max_streams_) || + ((incoming_stream_count_ + stream_count_increment) < + incoming_stream_count_)) { + // This stream would exceed the limit. do not increase. QUIC_DLOG(INFO) << ENDPOINT << "Failed to create a new incoming stream with id:" - << stream_id << ". Maximum allowed stream id is " - << actual_max_allowed_incoming_stream_id_ << "."; + << stream_id << ", reaching MAX_STREAMS limit: " + << incoming_advertised_max_streams_ << "."; session_->connection()->CloseConnection( QUIC_INVALID_STREAM_ID, - QuicStrCat("Stream id ", stream_id, " above ", - actual_max_allowed_incoming_stream_id_), + QuicStrCat("Stream id ", stream_id, " would exceed stream count limit ", + incoming_advertised_max_streams_), ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return false; } - available_incoming_streams_--; - - QuicStreamId id = largest_peer_created_stream_id_ + kV99StreamIdIncrement; - if (largest_peer_created_stream_id_ == - QuicUtils::GetInvalidStreamId( - session_->connection()->transport_version())) { - // Adjust id based on perspective and whether stream_id is bidirectional or - // unidirectional. - if (QuicUtils::IsBidirectionalStreamId(stream_id)) { - // This should only happen on client side because server bidirectional - // stream ID manager's largest_peer_created_stream_id_ is initialized to - // the crypto stream ID. - DCHECK_EQ(Perspective::IS_CLIENT, session_->perspective()); - id = 1; - } else { - id = session_->perspective() == Perspective::IS_SERVER ? 2 : 3; - } + QuicStreamId id = GetFirstIncomingStreamId(); + if (largest_peer_created_stream_id_ != + QuicUtils::GetInvalidStreamId(transport_version())) { + id = largest_peer_created_stream_id_ + + QuicUtils::StreamIdDelta(transport_version()); } - for (; id < stream_id; id += kV99StreamIdIncrement) { + + for (; id < stream_id; id += QuicUtils::StreamIdDelta(transport_version())) { available_streams_.insert(id); } + incoming_stream_count_ += stream_count_increment; largest_peer_created_stream_id_ = stream_id; return true; } bool QuicStreamIdManager::IsAvailableStream(QuicStreamId id) const { - DCHECK_EQ(QuicUtils::IsBidirectionalStreamId(id), - QuicUtils::IsBidirectionalStreamId(next_outgoing_stream_id_)); + DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_); if (!IsIncomingStream(id)) { // Stream IDs under next_ougoing_stream_id_ are either open or previously // open but now closed. @@ -335,17 +364,57 @@ bool QuicStreamIdManager::IsAvailableStream(QuicStreamId id) const { } // For peer created streams, we also need to consider available streams. return largest_peer_created_stream_id_ == - QuicUtils::GetInvalidStreamId( - session_->connection()->transport_version()) || + QuicUtils::GetInvalidStreamId(transport_version()) || id > largest_peer_created_stream_id_ || QuicContainsKey(available_streams_, id); } bool QuicStreamIdManager::IsIncomingStream(QuicStreamId id) const { - DCHECK_EQ(QuicUtils::IsBidirectionalStreamId(id), - QuicUtils::IsBidirectionalStreamId(next_outgoing_stream_id_)); - return id % kV99StreamIdIncrement != - next_outgoing_stream_id_ % kV99StreamIdIncrement; + DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_); + // The 0x1 bit in the stream id indicates whether the stream id is + // server- or client- initiated. Next_OUTGOING_stream_id_ has that bit + // set based on whether this node is a server or client. Thus, if the stream + // id in question has the 0x1 bit set opposite of next_OUTGOING_stream_id_, + // then that stream id is incoming -- it is for streams initiated by the peer. + return (id & 0x1) != (next_outgoing_stream_id_ & 0x1); +} + +QuicStreamId QuicStreamIdManager::GetFirstOutgoingStreamId() const { + return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId( + transport_version(), perspective()) + : QuicUtils::GetFirstBidirectionalStreamId( + transport_version(), perspective()); +} + +QuicStreamId QuicStreamIdManager::GetFirstIncomingStreamId() const { + return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId( + transport_version(), peer_perspective()) + : QuicUtils::GetFirstBidirectionalStreamId( + transport_version(), peer_perspective()); +} + +Perspective QuicStreamIdManager::perspective() const { + return session_->perspective(); +} + +Perspective QuicStreamIdManager::peer_perspective() const { + return (perspective() == Perspective::IS_SERVER) ? Perspective::IS_CLIENT + : Perspective::IS_SERVER; +} + +QuicTransportVersion QuicStreamIdManager::transport_version() const { + return session_->connection()->transport_version(); +} + +size_t QuicStreamIdManager::available_incoming_streams() { + return incoming_advertised_max_streams_ - incoming_stream_count_; +} + +void QuicStreamIdManager::CalculateIncomingMaxStreamsWindow() { + max_streams_window_ = incoming_actual_max_streams_ / kMaxStreamsWindowDivisor; + if (max_streams_window_ == 0) { + max_streams_window_ = 1; + } } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h index 6fd75fb4168..42c7d1a260d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.h @@ -6,6 +6,7 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_frame.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" @@ -23,21 +24,17 @@ class QuicSession; const QuicStreamId kV99StreamIdIncrement = 4; // This constant controls the size of the window when deciding whether -// to generate a MAX STREAM ID frame or not. See the discussion of the +// to generate a MAX_STREAMS frame or not. See the discussion of the // window, below, for more details. -const int kMaxStreamIdWindowDivisor = 2; +const int kMaxStreamsWindowDivisor = 2; // This class manages the stream ids for Version 99/IETF QUIC. -// TODO(fkastenholz): Expand to support bi- and uni-directional stream ids -// TODO(fkastenholz): Roll in pre-version-99 management class QUIC_EXPORT_PRIVATE QuicStreamIdManager { public: QuicStreamIdManager(QuicSession* session, - QuicStreamId next_outgoing_stream_id, - QuicStreamId largest_peer_created_stream_id, - QuicStreamId first_incoming_dynamic_stream_id, - size_t max_allowed_outgoing_streams, - size_t max_allowed_incoming_streams); + bool unidirectional, + QuicStreamCount max_allowed_outgoing_streams, + QuicStreamCount max_allowed_incoming_streams); ~QuicStreamIdManager(); @@ -45,68 +42,85 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { // of the stream ID manager. std::string DebugString() const { return QuicStrCat( - " { max_allowed_outgoing_stream_id: ", max_allowed_outgoing_stream_id_, - ", actual_max_allowed_incoming_stream_id_: ", - actual_max_allowed_incoming_stream_id_, - ", advertised_max_allowed_incoming_stream_id_: ", - advertised_max_allowed_incoming_stream_id_, - ", max_stream_id_window_: ", max_stream_id_window_, - ", max_allowed_outgoing_streams_: ", max_allowed_outgoing_streams_, - ", max_allowed_incoming_streams_: ", max_allowed_incoming_streams_, - ", available_incoming_streams_: ", available_incoming_streams_, - ", first_incoming_dynamic_stream_id_: ", - first_incoming_dynamic_stream_id_, - ", first_outgoing_dynamic_stream_id_: ", - first_outgoing_dynamic_stream_id_, " }"); + " { unidirectional_: ", unidirectional_, + ", perspective: ", perspective(), + ", outgoing_max_streams_: ", outgoing_max_streams_, + ", next_outgoing_stream_id_: ", next_outgoing_stream_id_, + ", outgoing_stream_count_: ", outgoing_stream_count_, + ", outgoing_static_stream_count_: ", outgoing_static_stream_count_, + ", using_default_max_streams_: ", using_default_max_streams_, + ", incoming_actual_max_streams_: ", incoming_actual_max_streams_, + ", incoming_advertised_max_streams_: ", + incoming_advertised_max_streams_, + ", incoming_static_stream_count_: ", incoming_static_stream_count_, + ", incoming_stream_count_: ", incoming_stream_count_, + ", available_streams_.size(): ", available_streams_.size(), + ", largest_peer_created_stream_id_: ", largest_peer_created_stream_id_, + ", max_streams_window_: ", max_streams_window_, " }"); } - // Processes the MAX STREAM ID frame, invoked from - // QuicSession::OnMaxStreamIdFrame. It has the same semantics as the + // Processes the MAX_STREAMS frame, invoked from + // QuicSession::OnMaxStreamsFrame. It has the same semantics as the // QuicFramerVisitorInterface, returning true if the framer should continue // processing the packet, false if not. - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame); + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame); - // Processes the STREAM ID BLOCKED frame, invoked from - // QuicSession::OnStreamIdBlockedFrame. It has the same semantics as the + // Processes the STREAMS_BLOCKED frame, invoked from + // QuicSession::OnStreamsBlockedFrame. It has the same semantics as the // QuicFramerVisitorInterface, returning true if the framer should continue // processing the packet, false if not. - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame); + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame); - // Indicates whether the next outgoing stream ID can be allocated or not. The - // test is whether it will exceed the maximum-stream-id or not. + // Indicates whether the next outgoing stream ID can be allocated or not. bool CanOpenNextOutgoingStream(); - // Generate and send a MAX_STREAM_ID frame. - void SendMaxStreamIdFrame(); + // Generate and send a MAX_STREAMS frame. + void SendMaxStreamsFrame(); - // Invoked to deal with releasing a stream ID. + // Invoked to deal with releasing a stream. Does nothing if the stream is + // outgoing. If the stream is incoming, the number of streams that the peer + // can open will be updated and a MAX_STREAMS frame, informing the peer of + // the additional streams, may be sent. void OnStreamClosed(QuicStreamId stream_id); - // Returns the next outgoing stream id. If it fails (due to running into the - // max_allowed_outgoing_stream_id limit) then it returns an invalid stream id. + // Returns the next outgoing stream id. Applications must call + // CanOpenNextOutgoingStream() first. A QUIC_BUG is logged if this method + // allocates a stream ID past the peer specified limit. QuicStreamId GetNextOutgoingStreamId(); - // Initialize the maximum allowed incoming stream id and number of streams. - void SetMaxOpenIncomingStreams(size_t max_streams); - - // Initialize the maximum allowed outgoing stream id, number of streams, and - // MAX_STREAM_ID advertisement window. - void SetMaxOpenOutgoingStreams(size_t max_streams); + // Set the outgoing stream limits to be |max_open_streams| plus the number + // of static streams that have been opened. For outgoing and incoming, + // respectively. + // SetMaxOpenOutgoingStreams will QUIC_BUG if it is called after + // a MAX_STREAMS frame has been received. + // TODO(fkastenholz): When static streams disappear, these should be removed. + void SetMaxOpenOutgoingStreams(size_t max_open_streams); + void SetMaxOpenIncomingStreams(size_t max_open_streams); + + // Adjust the outgoing stream limit - max_open_streams is the limit, not + // including static streams. Does not QUIC_BUG if it is called _after_ + // receiving a MAX_STREAMS. + void AdjustMaxOpenOutgoingStreams(size_t max_open_streams); + + // Sets the maximum number of outgoing streams to max_open_streams. + // Used when configuration has been done and we have an initial + // maximum stream count from the peer. Note that if the stream count is such + // that it would result in stream ID values that are greater than the + // implementation limit, it pegs the count at the implementation limit. + bool ConfigureMaxOpenOutgoingStreams(size_t max_open_streams); // Register a new stream as a static stream. This is used so that the - // advertised maximum stream ID can be calculated based on the start of the + // advertised MAX STREAMS can be calculated based on the start of the // dynamic stream space. This method will take any stream ID, one that either // this node or the peer will initiate. - void RegisterStaticStream(QuicStreamId stream_id); - - // Check that an incoming stream id is valid -- is below the maximum allowed - // stream ID. Note that this method uses the actual maximum, not the most - // recently advertised maximum this helps preserve the Google-QUIC semantic - // that we actually care about the number of open streams, not the maximum - // stream ID. Returns true if the stream ID is valid. If the stream ID fails - // the test, will close the connection (per the protocol specification) and - // return false. This method also maintains state with regard to the number of - // streams that the peer can open (used for generating MAX_STREAM_ID frames). + // Returns false if this fails because the new static stream would cause the + // stream limit to be exceeded. + bool RegisterStaticStream(QuicStreamId stream_id); + + // Checks if the incoming stream ID exceeds the MAX_STREAMS limit. If the + // limit is exceeded, closes the connection and returns false. Uses the + // actual maximium, not the most recently advertised value, in order to + // enforce the Google-QUIC number of open streams behavior. // This method should be called exactly once for each incoming stream // creation. bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id); @@ -117,122 +131,145 @@ class QUIC_EXPORT_PRIVATE QuicStreamIdManager { // Return true if given stream is peer initiated. bool IsIncomingStream(QuicStreamId id) const; - size_t max_allowed_outgoing_streams() const { - return max_allowed_outgoing_streams_; - } - size_t max_allowed_incoming_streams() const { - return max_allowed_incoming_streams_; - } - QuicStreamId max_allowed_outgoing_stream_id() const { - return max_allowed_outgoing_stream_id_; + size_t outgoing_static_stream_count() const { + return outgoing_static_stream_count_; } - QuicStreamId advertised_max_allowed_incoming_stream_id() const { - return advertised_max_allowed_incoming_stream_id_; - } - QuicStreamId actual_max_allowed_incoming_stream_id() const { - return actual_max_allowed_incoming_stream_id_; + + size_t incoming_initial_max_open_streams() const { + return incoming_initial_max_open_streams_; } - QuicStreamId max_stream_id_window() const { return max_stream_id_window_; } + + QuicStreamCount max_streams_window() const { return max_streams_window_; } QuicStreamId next_outgoing_stream_id() const { return next_outgoing_stream_id_; } - QuicStreamId first_incoming_dynamic_stream_id() { - return first_incoming_dynamic_stream_id_; - } - QuicStreamId first_outgoing_dynamic_stream_id() { - return first_outgoing_dynamic_stream_id_; - } - size_t available_incoming_streams() { return available_incoming_streams_; } - - void set_max_allowed_incoming_streams(size_t stream_count) { - max_allowed_incoming_streams_ = stream_count; - } + // Number of streams that the peer believes that it can still create. + size_t available_incoming_streams(); void set_largest_peer_created_stream_id( QuicStreamId largest_peer_created_stream_id) { largest_peer_created_stream_id_ = largest_peer_created_stream_id; } + // These are the limits for outgoing and incoming streams, + // respectively. For incoming there are two limits, what has + // been advertised to the peer and what is actually available. + // The advertised incoming amount should never be more than the actual + // incoming one. + QuicStreamCount outgoing_max_streams() const { return outgoing_max_streams_; } + QuicStreamCount incoming_actual_max_streams() const { + return incoming_actual_max_streams_; + } + QuicStreamCount incoming_advertised_max_streams() const { + return incoming_advertised_max_streams_; + } + // Number of streams that have been opened (including those that have been + // opened and then closed. Must never exceed outgoing_max_streams + QuicStreamCount outgoing_stream_count() { return outgoing_stream_count_; } + + // Perspective (CLIENT/SERVER) of this node and the peer, respectively. + Perspective perspective() const; + Perspective peer_perspective() const; + + QuicTransportVersion transport_version() const; + private: friend class test::QuicSessionPeer; friend class test::QuicStreamIdManagerPeer; - // Check whether the MAX_STREAM_ID window has opened up enough and, if so, - // generate and send a MAX_STREAM_ID frame. - void MaybeSendMaxStreamIdFrame(); + // Check whether the MAX_STREAMS window has opened up enough and, if so, + // generate and send a MAX_STREAMS frame. + void MaybeSendMaxStreamsFrame(); + + // Get what should be the first incoming/outgoing stream ID that + // this stream id manager will manage, taking into account directionality and + // client/server perspective. + QuicStreamId GetFirstOutgoingStreamId() const; + QuicStreamId GetFirstIncomingStreamId() const; + + void CalculateIncomingMaxStreamsWindow(); // Back reference to the session containing this Stream ID Manager. // needed to access various session methods, such as perspective() QuicSession* session_; + // Whether this stream id manager is for unidrectional (true) or bidirectional + // (false) streams. + bool unidirectional_; + + // This is the number of streams that this node can initiate. + // This limit applies to both static and dynamic streams - the total + // of the two can not exceed this count. + // This limit is: + // - Initiated to a value specified in the constructor + // - May be updated when the config is received. + // - Is updated whenever a MAX STREAMS frame is received. + QuicStreamCount outgoing_max_streams_; + // The ID to use for the next outgoing stream. QuicStreamId next_outgoing_stream_id_; + // The number of outgoing streams that have ever been opened, including those + // that have been closed. This number must never be larger than + // outgoing_max_streams_. + QuicStreamCount outgoing_stream_count_; + + // Number of outgoing static streams created. + // TODO(fkastenholz): Remove when static streams no longer supported for IETF + // QUIC. + QuicStreamCount outgoing_static_stream_count_; + + // Set to true while the default (from the constructor) outgoing stream limit + // is in use. It is set to false when either a MAX STREAMS frame is received + // or the transport negotiation completes and sets the stream limit (this is + // equivalent to a MAX_STREAMS frame). + // Necessary because outgoing_max_streams_ is a "best guess" + // until we receive an authoritative value from the peer. + // outgoing_max_streams_ is initialized in the constructor + // to some hard-coded value, which may or may not be consistent + // with what the peer wants. Furthermore, as we create outgoing + // static streams, the cap raises as static streams get inserted + // "beneath" the dynamic streams because, prior to receiving + // a MAX_STREAMS, the values setting the limit are interpreted + // as "number of request/responses" that can be created. Once + // a MAX_STREAMS is received, it becomes a hard limit. + bool using_default_max_streams_; + + // FOR INCOMING STREAMS + + // The maximum number of streams that can be opened by the peer. + QuicStreamCount incoming_actual_max_streams_; + QuicStreamCount incoming_advertised_max_streams_; + + // Initial maximum on the number of open streams allowed. + QuicStreamCount incoming_initial_max_open_streams_; + + // Number of outgoing static streams created. + // TODO(fkastenholz): Remove when static streams no longer supported for IETF + // QUIC. + QuicStreamCount incoming_static_stream_count_; + + // This is the number of streams that have been created -- some are still + // open, the others have been closed. It is the number that is compared + // against MAX_STREAMS when deciding whether to accept a new stream or not. + QuicStreamCount incoming_stream_count_; + // Set of stream ids that are less than the largest stream id that has been // received, but are nonetheless available to be created. QuicUnorderedSet<QuicStreamId> available_streams_; QuicStreamId largest_peer_created_stream_id_; - // The maximum stream ID value that we can use. This is initialized based on, - // first, the default number of open streams we can do, updated per the number - // of streams we receive in the transport parameters, and then finally is - // modified whenever a MAX_STREAM_ID frame is received from the peer. - QuicStreamId max_allowed_outgoing_stream_id_; - - // Unlike for streams this node initiates, for incoming streams, there are two - // maxima; the actual maximum which is the limit the peer must obey and the - // maximum that was most recently advertised to the peer in a MAX_STREAM_ID - // frame. - // - // The advertised maximum is never larger than the actual maximum. The actual - // maximum increases whenever an incoming stream is closed. The advertised - // maximum increases (to the actual maximum) whenever a MAX_STREAM_ID is sent. - // - // The peer is granted some leeway, incoming streams are accepted as long as - // their stream id is not greater than the actual maximum. The protocol - // specifies that the advertised maximum is the limit. This implmentation uses - // the actual maximum in order to support Google-QUIC semantics, where it's - // the number of open streams, not their ID number, that is the real limit. - QuicStreamId actual_max_allowed_incoming_stream_id_; - QuicStreamId advertised_max_allowed_incoming_stream_id_; - - // max_stream_id_window_ is set to max_allowed_outgoing_streams_ / 2 - // (half of the number of streams that are allowed). The local node - // does not send a MAX_STREAM_ID frame to the peer until the local node - // believes that the peer can open fewer than |max_stream_id_window_| - // streams. When that is so, the local node sends a MAX_STREAM_ID every time - // an inbound stream is closed. - QuicStreamId max_stream_id_window_; - - // Maximum number of outgoing and incoming streams that are allowed to be - // concurrently opened. Initialized as part of configuration. - size_t max_allowed_outgoing_streams_; - size_t max_allowed_incoming_streams_; - - // Keep track of the first dynamic stream id (which is the largest static - // stream id plus one id). For Google QUIC, static streams are not counted - // against the stream count limit. When the number of static streams - // increases, the maximum stream id has to increase by a corresponding amount. - // These are used as floors from which the relevant maximum is - // calculated. Keeping the "first dynamic" rather than the "last static" has - // some implementation advantages. - QuicStreamId first_incoming_dynamic_stream_id_; - QuicStreamId first_outgoing_dynamic_stream_id_; - - // Number of streams that that this node believes that the - // peer can open. It is initialized to the same value as - // max_allowed_incoming_streams_. It is decremented every - // time a new incoming stream is detected. A MAX_STREAM_ID - // is sent whenver a stream closes and this counter is less - // than the window. When that happens, it is incremented by - // the number of streams we make available (the actual max - // stream ID - the most recently advertised one) - size_t available_incoming_streams_; + // When incoming streams close the local node sends MAX_STREAMS frames. It + // does so only when the peer can open fewer than |max_stream_id_window_| + // streams. That is, when |incoming_actual_max_streams_| - + // |incoming_advertised_max_streams_| is less than the window. + // max_streams_window_ is set to 1/2 of the initial number of incoming streams + // that are allowed (as set in the constructor). + QuicStreamId max_streams_window_; }; - } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc index 3d0c06c2eb1..79c484525d3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc @@ -118,10 +118,10 @@ class QuicStreamIdManagerTestBase : public QuicTestWithParam<bool> { connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); session_ = QuicMakeUnique<TestQuicSession>(connection_); stream_id_manager_ = - GetParam() ? QuicSessionPeer::v99_bidirectional_stream_id_manager( - session_.get()) - : QuicSessionPeer::v99_unidirectional_stream_id_manager( - session_.get()); + IsBidi() ? QuicSessionPeer::v99_bidirectional_stream_id_manager( + session_.get()) + : QuicSessionPeer::v99_unidirectional_stream_id_manager( + session_.get()); } QuicTransportVersion transport_version() const { @@ -154,6 +154,27 @@ class QuicStreamIdManagerTestBase : public QuicTestWithParam<bool> { kV99StreamIdIncrement * n; } + QuicStreamId StreamCountToId(QuicStreamCount stream_count, + Perspective perspective) { + // Calculate and build up stream ID rather than use + // GetFirst... because the tests that rely on this method + // needs to do the stream count where #1 is 0/1/2/3, and not + // take into account that stream 0 is special. + QuicStreamId id = + ((stream_count - 1) * QuicUtils::StreamIdDelta(QUIC_VERSION_99)); + if (IsUnidi()) { + id |= 0x2; + } + if (perspective == Perspective::IS_SERVER) { + id |= 0x1; + } + return id; + } + + // GetParam returns true if the test is for bidirectional streams + bool IsUnidi() { return GetParam() ? false : true; } + bool IsBidi() { return GetParam(); } + MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; StrictMock<MockQuicConnection>* connection_; @@ -178,128 +199,154 @@ INSTANTIATE_TEST_SUITE_P(Tests, QuicStreamIdManagerTestClient, testing::Bool()); TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerClientInitialization) { // These fields are inited via the QuicSession constructor to default // values defined as a constant. + // If bidi, Crypto stream default created at start up, it is one + // more stream to account for since initialization is "number of + // request/responses" & crypto is added in to that, not streams. + size_t extra_stream_count = 0; + if (GetParam() && !QuicVersionUsesCryptoFrames(transport_version())) { + extra_stream_count = 1; + } + EXPECT_EQ(kDefaultMaxStreamsPerConnection + extra_stream_count, + stream_id_manager_->outgoing_max_streams()); + // Test is predicated on having 1 static stream going if bidi, 0 if not...) + EXPECT_EQ(extra_stream_count, + stream_id_manager_->outgoing_static_stream_count()); + + EXPECT_EQ(kDefaultMaxStreamsPerConnection, + stream_id_manager_->incoming_actual_max_streams()); EXPECT_EQ(kDefaultMaxStreamsPerConnection, - stream_id_manager_->max_allowed_incoming_streams()); + stream_id_manager_->incoming_advertised_max_streams()); EXPECT_EQ(kDefaultMaxStreamsPerConnection, - stream_id_manager_->max_allowed_outgoing_streams()); + stream_id_manager_->incoming_initial_max_open_streams()); // The window for advertising updates to the MAX STREAM ID is half the number // of streams allowed. - EXPECT_EQ(kDefaultMaxStreamsPerConnection / kMaxStreamIdWindowDivisor, - stream_id_manager_->max_stream_id_window()); - - // This test runs as a client, so it initiates (that is to say, outgoing) - // even-numbered stream IDs. Also, our implementation starts allocating - // stream IDs at 0 (for clients) 1 (for servers) -- before taking statically - // allocated streams into account. The -1 in the calculation is - // because the value being tested is the maximum allowed stream ID, not the - // first unallowed stream id. - const QuicStreamId kExpectedMaxOutgoingStreamId = - (GetParam() ? session_->next_outgoing_bidirectional_stream_id() - : session_->next_outgoing_unidirectional_stream_id()) + - ((kDefaultMaxStreamsPerConnection - 1) * kV99StreamIdIncrement); - EXPECT_EQ(kExpectedMaxOutgoingStreamId, - stream_id_manager_->max_allowed_outgoing_stream_id()); - - // Same for IDs of incoming streams... - const QuicStreamId kExpectedMaxIncomingStreamId = - stream_id_manager_->first_incoming_dynamic_stream_id() + - (kDefaultMaxStreamsPerConnection - 1) * kV99StreamIdIncrement; - EXPECT_EQ(kExpectedMaxIncomingStreamId, - stream_id_manager_->actual_max_allowed_incoming_stream_id()); - EXPECT_EQ(kExpectedMaxIncomingStreamId, - stream_id_manager_->advertised_max_allowed_incoming_stream_id()); -} - -// This test checks that the initialization for the maximum allowed outgoing -// stream id is correct. -TEST_P(QuicStreamIdManagerTestClient, CheckMaxAllowedOutgoing) { - const size_t kNumOutgoingStreams = 124; - stream_id_manager_->SetMaxOpenOutgoingStreams(kNumOutgoingStreams); - EXPECT_EQ(kNumOutgoingStreams, - stream_id_manager_->max_allowed_outgoing_streams()); - - // Check that the maximum available stream is properly set. - size_t expected_max_outgoing_id = - (GetParam() ? session_->next_outgoing_bidirectional_stream_id() - : session_->next_outgoing_unidirectional_stream_id()) + - ((kNumOutgoingStreams - 1) * kV99StreamIdIncrement); - EXPECT_EQ(expected_max_outgoing_id, - stream_id_manager_->max_allowed_outgoing_stream_id()); -} - -// This test checks that the initialization for the maximum allowed incoming -// stream id is correct. -TEST_P(QuicStreamIdManagerTestClient, CheckMaxAllowedIncoming) { - const size_t kStreamCount = 245; - stream_id_manager_->SetMaxOpenIncomingStreams(kStreamCount); - EXPECT_EQ(kStreamCount, stream_id_manager_->max_allowed_incoming_streams()); - // Check that the window is 1/2 (integer math) of the stream count. - EXPECT_EQ(kStreamCount / 2, stream_id_manager_->max_stream_id_window()); - - // Actual- and advertised- maxima start out equal. - EXPECT_EQ(stream_id_manager_->actual_max_allowed_incoming_stream_id(), - stream_id_manager_->advertised_max_allowed_incoming_stream_id()); - - // Check that the maximum stream ID is properly calculated. - EXPECT_EQ(stream_id_manager_->first_incoming_dynamic_stream_id() + - ((kStreamCount - 1) * kV99StreamIdIncrement), - stream_id_manager_->actual_max_allowed_incoming_stream_id()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection / kMaxStreamsWindowDivisor, + stream_id_manager_->max_streams_window()); } // This test checks that the stream advertisement window is set to 1 // if the number of stream ids is 1. This is a special case in the code. -TEST_P(QuicStreamIdManagerTestClient, CheckMaxStreamIdWindow1) { +TEST_P(QuicStreamIdManagerTestClient, CheckMaxStreamsWindow1) { stream_id_manager_->SetMaxOpenIncomingStreams(1); - EXPECT_EQ(1u, stream_id_manager_->max_allowed_incoming_streams()); + EXPECT_EQ(1u, stream_id_manager_->incoming_initial_max_open_streams()); + EXPECT_EQ(1u, stream_id_manager_->incoming_actual_max_streams()); // If streamid_count/2==0 (integer math) force it to 1. - EXPECT_EQ(1u, stream_id_manager_->max_stream_id_window()); + EXPECT_EQ(1u, stream_id_manager_->max_streams_window()); +} + +// Test that stream counts that would exceed the implementation maximum are +// safely handled. +// First, check that setting up to and including the implementation maximum +// is OK. +TEST_P(QuicStreamIdManagerTestClient, CheckMaxStreamsBadValuesToMaxOkOutgoing) { + QuicStreamCount implementation_max = + QuicUtils::GetMaxStreamCount(!GetParam(), /* GetParam==true for bidi */ + Perspective::IS_CLIENT); + stream_id_manager_->AdjustMaxOpenOutgoingStreams(implementation_max - 1u); + // If bidi, Crypto stream default created at start up, it is one + // more stream to account for since initialization is "number of + // request/responses" & crypto is added in to that, not streams. + size_t extra_stream_count = 0; + if (GetParam() && !QuicVersionUsesCryptoFrames(transport_version())) { + extra_stream_count = 1; + } + EXPECT_EQ(implementation_max - 1u + extra_stream_count, + stream_id_manager_->outgoing_max_streams()); + + stream_id_manager_->AdjustMaxOpenOutgoingStreams(implementation_max); + EXPECT_EQ(implementation_max, stream_id_manager_->outgoing_max_streams()); +} + +// Now check that setting to a value larger than the maximum fails. +TEST_P(QuicStreamIdManagerTestClient, + CheckMaxStreamsBadValuesOverMaxFailsOutgoing) { + QuicStreamCount implementation_max = + QuicUtils::GetMaxStreamCount(!GetParam(), /* GetParam==true for bidi */ + Perspective::IS_CLIENT); + // Ensure that the limit is less than the implementation maximum. + EXPECT_LT(stream_id_manager_->outgoing_max_streams(), implementation_max); + + // Try to go over. + stream_id_manager_->AdjustMaxOpenOutgoingStreams(implementation_max + 1); + // Should be pegged at the max. + EXPECT_EQ(implementation_max, stream_id_manager_->outgoing_max_streams()); } -// Check the case of the stream ID in a STREAM_ID_BLOCKED frame is less than the -// stream ID most recently advertised in a MAX_STREAM_ID frame. This should -// cause a MAX_STREAM_ID frame with the most recently advertised stream id to be -// sent. -TEST_P(QuicStreamIdManagerTestClient, ProcessStreamIdBlockedOk) { +// Now do the same for the incoming streams +TEST_P(QuicStreamIdManagerTestClient, CheckMaxStreamsBadValuesIncoming) { + QuicStreamCount implementation_max = + QuicUtils::GetMaxStreamCount(!GetParam(), /* GetParam==true for bidi */ + Perspective::IS_CLIENT); + stream_id_manager_->SetMaxOpenIncomingStreams(implementation_max - 1u); + EXPECT_EQ(implementation_max - 1u, + stream_id_manager_->incoming_initial_max_open_streams()); + EXPECT_EQ(implementation_max - 1u, + stream_id_manager_->incoming_actual_max_streams()); + EXPECT_EQ((implementation_max - 1u) / 2u, + stream_id_manager_->max_streams_window()); + + stream_id_manager_->SetMaxOpenIncomingStreams(implementation_max); + EXPECT_EQ(implementation_max, + stream_id_manager_->incoming_initial_max_open_streams()); + EXPECT_EQ(implementation_max, + stream_id_manager_->incoming_actual_max_streams()); + EXPECT_EQ(implementation_max / 2, stream_id_manager_->max_streams_window()); + + // Reset to 1 so that we can detect the change. + stream_id_manager_->SetMaxOpenIncomingStreams(1u); + EXPECT_EQ(1u, stream_id_manager_->incoming_initial_max_open_streams()); + EXPECT_EQ(1u, stream_id_manager_->incoming_actual_max_streams()); + EXPECT_EQ(1u, stream_id_manager_->max_streams_window()); + // Now try to exceed the max, without wrapping. + stream_id_manager_->SetMaxOpenIncomingStreams(implementation_max + 1); + EXPECT_EQ(implementation_max, + stream_id_manager_->incoming_initial_max_open_streams()); + EXPECT_EQ(implementation_max, + stream_id_manager_->incoming_actual_max_streams()); + EXPECT_EQ(implementation_max / 2u, stream_id_manager_->max_streams_window()); +} + +// Check the case of the stream count in a STREAMS_BLOCKED frame is less than +// the count most recently advertised in a MAX_STREAMS frame. This should cause +// a MAX_STREAMS frame with the most recently advertised count to be sent. +TEST_P(QuicStreamIdManagerTestClient, ProcessStreamsBlockedOk) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillRepeatedly(Invoke(session_.get(), &TestQuicSession::SaveFrame)); - QuicStreamId stream_id = - stream_id_manager_->advertised_max_allowed_incoming_stream_id() - - kV99StreamIdIncrement; - QuicStreamIdBlockedFrame frame(0, stream_id); - session_->OnStreamIdBlockedFrame(frame); + QuicStreamCount stream_count = + stream_id_manager_->incoming_initial_max_open_streams() - 1; + QuicStreamsBlockedFrame frame(0, stream_count, /*unidirectional=*/false); + session_->OnStreamsBlockedFrame(frame); - // We should see a MAX_STREAM_ID frame. - EXPECT_EQ(MAX_STREAM_ID_FRAME, session_->save_frame().type); + // We should see a MAX_STREAMS frame. + EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type); // and it should advertise the current max-allowed value. - EXPECT_EQ(stream_id_manager_->actual_max_allowed_incoming_stream_id(), - session_->save_frame().max_stream_id_frame.max_stream_id); + EXPECT_EQ(stream_id_manager_->incoming_initial_max_open_streams(), + session_->save_frame().max_streams_frame.stream_count); } -// Check the case of the stream ID in a STREAM_ID_BLOCKED frame is equal to -// stream ID most recently advertised in a MAX_STREAM_ID frame. No -// MAX_STREAM_ID should be generated. -TEST_P(QuicStreamIdManagerTestClient, ProcessStreamIdBlockedNoOp) { +// Check the case of the stream count in a STREAMS_BLOCKED frame is equal to the +// count most recently advertised in a MAX_STREAMS frame. No MAX_STREAMS +// should be generated. +TEST_P(QuicStreamIdManagerTestClient, ProcessStreamsBlockedNoOp) { EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); - QuicStreamId stream_id = - stream_id_manager_->advertised_max_allowed_incoming_stream_id(); - QuicStreamIdBlockedFrame frame(0, stream_id); - session_->OnStreamIdBlockedFrame(frame); + QuicStreamCount stream_count = + stream_id_manager_->incoming_initial_max_open_streams(); + QuicStreamsBlockedFrame frame(0, stream_count, /*unidirectional=*/false); + session_->OnStreamsBlockedFrame(frame); } -// Check the case of the stream ID in a STREAM_ID_BLOCKED frame is greater than -// the stream ID most recently advertised in a MAX_STREAM_ID frame. Expect a +// Check the case of the stream count in a STREAMS_BLOCKED frame is greater than +// the count most recently advertised in a MAX_STREAMS frame. Expect a // connection close with an error. -TEST_P(QuicStreamIdManagerTestClient, ProcessStreamIdBlockedTooBig) { - EXPECT_CALL(*connection_, - CloseConnection(QUIC_STREAM_ID_BLOCKED_ERROR, _, _)); +TEST_P(QuicStreamIdManagerTestClient, ProcessStreamsBlockedTooBig) { + EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAMS_BLOCKED_ERROR, _, _)); EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); - QuicStreamId stream_id = - stream_id_manager_->advertised_max_allowed_incoming_stream_id() + - kV99StreamIdIncrement; - QuicStreamIdBlockedFrame frame(0, stream_id); - session_->OnStreamIdBlockedFrame(frame); + QuicStreamCount stream_count = + stream_id_manager_->incoming_initial_max_open_streams() + 1; + QuicStreamsBlockedFrame frame(0, stream_count, /*unidirectional=*/false); + session_->OnStreamsBlockedFrame(frame); } // Same basic tests as above, but calls @@ -310,8 +357,8 @@ TEST_P(QuicStreamIdManagerTestClient, ProcessStreamIdBlockedTooBig) { // First test make sure that streams with ids below the limit are accepted. TEST_P(QuicStreamIdManagerTestClient, IsIncomingStreamIdValidBelowLimit) { QuicStreamId stream_id = - stream_id_manager_->actual_max_allowed_incoming_stream_id() - - kV99StreamIdIncrement; + StreamCountToId(stream_id_manager_->incoming_actual_max_streams() - 1, + Perspective::IS_CLIENT); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); EXPECT_TRUE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId(stream_id)); } @@ -319,227 +366,223 @@ TEST_P(QuicStreamIdManagerTestClient, IsIncomingStreamIdValidBelowLimit) { // Accept a stream with an ID that equals the limit. TEST_P(QuicStreamIdManagerTestClient, IsIncomingStreamIdValidAtLimit) { QuicStreamId stream_id = - stream_id_manager_->actual_max_allowed_incoming_stream_id(); + StreamCountToId(stream_id_manager_->incoming_actual_max_streams(), + Perspective::IS_CLIENT); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); EXPECT_TRUE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId(stream_id)); } // Close the connection if the id exceeds the limit. TEST_P(QuicStreamIdManagerTestClient, IsIncomingStreamIdInValidAboveLimit) { - QuicStreamId stream_id = - stream_id_manager_->actual_max_allowed_incoming_stream_id() + - kV99StreamIdIncrement; + QuicStreamId stream_id = StreamCountToId( + stream_id_manager_->incoming_actual_max_streams() + 1, + Perspective::IS_SERVER); // This node is a client, incoming + // stream ids must be server-originated. std::string error_details = - GetParam() ? "Stream id 401 above 397" : "Stream id 403 above 399"; + GetParam() ? "Stream id 401 would exceed stream count limit 100" + : "Stream id 403 would exceed stream count limit 100"; EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, error_details, _)); EXPECT_FALSE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId(stream_id)); } -// Test that a client will reject a MAX_STREAM_ID that specifies a -// server-initiated stream ID. -TEST_P(QuicStreamIdManagerTestClient, RejectServerMaxStreamId) { - QuicStreamId id = stream_id_manager_->max_allowed_outgoing_stream_id(); - - // Ensure that the ID that will be in the MAX_STREAM_ID is larger than the - // current MAX. - id += (kV99StreamIdIncrement * 2); - - // Make it an odd (server-initiated) ID. - id |= 0x1; - EXPECT_FALSE(QuicUtils::IsClientInitiatedStreamId(QUIC_VERSION_99, id)); - - // Make the frame and process it; should result in the connection being - // closed. - QuicMaxStreamIdFrame frame(0, id); - EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAM_ID_ERROR, _, _)); - session_->OnMaxStreamIdFrame(frame); -} - -// Test that a client will reject a STREAM_ID_BLOCKED that specifies a -// client-initiated stream ID. STREAM_ID_BLOCKED from a server should specify an -// odd (server-initiated_ ID). Generate one with an odd ID and check that the -// connection is closed. -TEST_P(QuicStreamIdManagerTestClient, RejectServerStreamIdBlocked) { - QuicStreamId id = stream_id_manager_->max_allowed_outgoing_stream_id(); - - // Ensure that the ID that will be in the MAX_STREAM_ID is larger than the - // current MAX. - id += (kV99StreamIdIncrement * 2); - // Make sure it's odd, like a client-initiated ID. - id &= ~0x01; - EXPECT_TRUE(QuicUtils::IsClientInitiatedStreamId(QUIC_VERSION_99, id)); - - // Generate and process the frame; connection should be closed. - QuicStreamIdBlockedFrame frame(0, id); - EXPECT_CALL(*connection_, - CloseConnection(QUIC_STREAM_ID_BLOCKED_ERROR, _, _)); - session_->OnStreamIdBlockedFrame(frame); -} - -// Test functionality for reception of a MAX STREAM ID frame. This code is +// Test functionality for reception of a MAX_STREAMS frame. This code is // client/server-agnostic. -TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerClientOnMaxStreamIdFrame) { - // Get the current maximum allowed outgoing stream ID. - QuicStreamId initial_stream_id = - stream_id_manager_->max_allowed_outgoing_stream_id(); - QuicMaxStreamIdFrame frame; - - // If the stream ID in the frame is < the current maximum then - // the frame should be ignored. - frame.max_stream_id = initial_stream_id - kV99StreamIdIncrement; - EXPECT_TRUE(stream_id_manager_->OnMaxStreamIdFrame(frame)); - EXPECT_EQ(initial_stream_id, - stream_id_manager_->max_allowed_outgoing_stream_id()); - - // A stream ID greater than the current limit should increase the limit. - frame.max_stream_id = initial_stream_id + kV99StreamIdIncrement; - EXPECT_TRUE(stream_id_manager_->OnMaxStreamIdFrame(frame)); - EXPECT_EQ(initial_stream_id + kV99StreamIdIncrement, - stream_id_manager_->max_allowed_outgoing_stream_id()); +TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerClientOnMaxStreamsFrame) { + // Get the current maximum allowed outgoing stream count. + QuicStreamCount initial_stream_count = + // need to know the number of request/response streams. + // This is the total number of outgoing streams (which includes both + // req/resp and statics) minus just the statics... + stream_id_manager_->outgoing_max_streams() - + stream_id_manager_->outgoing_static_stream_count(); + + QuicMaxStreamsFrame frame; + + // Even though the stream count in the frame is < the initial maximum, + // it is should be ignored since the initial max was set via + // the constructor (an educated guess) and the MAX STREAMS frame + // is authoritative. + frame.stream_count = initial_stream_count - 1; + + frame.unidirectional = IsUnidi(); + EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame)); + EXPECT_EQ(initial_stream_count - 1u, + stream_id_manager_->outgoing_max_streams()); + + QuicStreamCount save_outgoing_max_streams = + stream_id_manager_->outgoing_max_streams(); + // Now that there has been one MAX STREAMS frame, we should not + // accept a MAX_STREAMS that reduces the limit... + frame.stream_count = initial_stream_count - 2; + frame.unidirectional = IsUnidi(); + EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame)); + // should not change from previous setting. + EXPECT_EQ(save_outgoing_max_streams, + stream_id_manager_->outgoing_max_streams()); + + // A stream count greater than the current limit should increase the limit. + frame.stream_count = initial_stream_count + 1; + EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame)); + + EXPECT_EQ(initial_stream_count + 1u, + stream_id_manager_->outgoing_max_streams()); } -// Test functionality for reception of a STREAM ID BLOCKED frame. +// Test functionality for reception of a STREAMS_BLOCKED frame. // This code is client/server-agnostic. -TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerOnStreamIdBlockedFrame) { - // Get the current maximum allowed incoming stream ID. - QuicStreamId advertised_stream_id = - stream_id_manager_->advertised_max_allowed_incoming_stream_id(); - QuicStreamIdBlockedFrame frame; +TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerOnStreamsBlockedFrame) { + // Get the current maximum allowed incoming stream count. + QuicStreamCount advertised_stream_count = + stream_id_manager_->incoming_advertised_max_streams(); + QuicStreamsBlockedFrame frame; + + frame.unidirectional = IsUnidi(); - // If the peer is saying it's blocked on the stream ID that + // If the peer is saying it's blocked on the stream count that // we've advertised, it's a noop since the peer has the correct information. - frame.stream_id = advertised_stream_id; - EXPECT_TRUE(stream_id_manager_->OnStreamIdBlockedFrame(frame)); + frame.stream_count = advertised_stream_count; + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); + EXPECT_TRUE(stream_id_manager_->OnStreamsBlockedFrame(frame)); - // If the peer is saying it's blocked on a stream ID that is larger + // If the peer is saying it's blocked on a stream count that is larger // than what we've advertised, the connection should get closed. - frame.stream_id = advertised_stream_id + kV99StreamIdIncrement; - EXPECT_CALL(*connection_, - CloseConnection(QUIC_STREAM_ID_BLOCKED_ERROR, _, _)); - EXPECT_FALSE(stream_id_manager_->OnStreamIdBlockedFrame(frame)); + frame.stream_count = advertised_stream_count + 1; + EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAMS_BLOCKED_ERROR, _, _)); + EXPECT_FALSE(stream_id_manager_->OnStreamsBlockedFrame(frame)); - // If the peer is saying it's blocked on a stream ID that is less than - // what we've advertised, we send a MAX STREAM ID frame and update + // If the peer is saying it's blocked on a count that is less than + // our actual count, we send a MAX_STREAMS frame and update // the advertised value. // First, need to bump up the actual max so there is room for the MAX - // STREAM_ID frame to send a larger ID. - QuicStreamId actual_stream_id = - stream_id_manager_->actual_max_allowed_incoming_stream_id(); + // STREAMS frame to send a larger ID. + QuicStreamCount actual_stream_count = + stream_id_manager_->incoming_actual_max_streams(); + + // Closing a stream will result in the ability to initiate one more + // stream stream_id_manager_->OnStreamClosed( - stream_id_manager_->first_incoming_dynamic_stream_id()); - EXPECT_EQ(actual_stream_id + kV99StreamIdIncrement, - stream_id_manager_->actual_max_allowed_incoming_stream_id()); - EXPECT_GT(stream_id_manager_->actual_max_allowed_incoming_stream_id(), - stream_id_manager_->advertised_max_allowed_incoming_stream_id()); - - // Now simulate receiving a STTREAM_ID_BLOCKED frame... - // Changing the actual maximum, above, forces a MAX STREAM ID frame to be - // sent, so the logic for that (SendMaxStreamIdFrame(), etc) is tested. - frame.stream_id = advertised_stream_id; + QuicStreamIdManagerPeer::GetFirstIncomingStreamId(stream_id_manager_)); + EXPECT_EQ(actual_stream_count + 1u, + stream_id_manager_->incoming_actual_max_streams()); + EXPECT_EQ(stream_id_manager_->incoming_actual_max_streams(), + stream_id_manager_->incoming_advertised_max_streams() + 1u); + + // Now simulate receiving a STREAMS_BLOCKED frame... + // Changing the actual maximum, above, forces a MAX_STREAMS frame to be + // sent, so the logic for that (SendMaxStreamsFrame(), etc) is tested. + + // The STREAMS_BLOCKED frame contains the previous advertised count, + // not the one that the peer would have received as a result of the + // MAX_STREAMS sent earler. + frame.stream_count = advertised_stream_count; + EXPECT_CALL(*connection_, SendControlFrame(_)) .Times(1) .WillRepeatedly(Invoke(session_.get(), &TestQuicSession::SaveFrame)); - EXPECT_TRUE(stream_id_manager_->OnStreamIdBlockedFrame(frame)); - EXPECT_EQ(stream_id_manager_->actual_max_allowed_incoming_stream_id(), - stream_id_manager_->advertised_max_allowed_incoming_stream_id()); - EXPECT_EQ(MAX_STREAM_ID_FRAME, session_->save_frame().type); - EXPECT_EQ(stream_id_manager_->advertised_max_allowed_incoming_stream_id(), - session_->save_frame().max_stream_id_frame.max_stream_id); - - // Ensure a client initiated stream ID is rejected. - frame.stream_id = GetParam() ? GetNthClientInitiatedBidirectionalId(1) - : GetNthClientInitiatedUnidirectionalId(1); - EXPECT_CALL(*connection_, - CloseConnection(QUIC_STREAM_ID_BLOCKED_ERROR, _, _)); - EXPECT_FALSE(stream_id_manager_->OnStreamIdBlockedFrame(frame)); + + EXPECT_TRUE(stream_id_manager_->OnStreamsBlockedFrame(frame)); + // Check that the saved frame is correct. + EXPECT_EQ(stream_id_manager_->incoming_actual_max_streams(), + stream_id_manager_->incoming_advertised_max_streams()); + EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type); + EXPECT_EQ(stream_id_manager_->incoming_advertised_max_streams(), + session_->save_frame().max_streams_frame.stream_count); + // Make sure that this is the only MAX_STREAMS + EXPECT_EQ(1u, GetControlFrameId(session_->save_frame())); } // Test GetNextOutgoingStream. This is client/server agnostic. -TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerGetNextOutgoingFrame) { +TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerGetNextOutgoingStream) { // Number of streams we can open and the first one we should get when // opening... int number_of_streams = kDefaultMaxStreamsPerConnection; QuicStreamId stream_id = - GetParam() ? session_->next_outgoing_bidirectional_stream_id() - : session_->next_outgoing_unidirectional_stream_id(); - + IsUnidi() ? session_->next_outgoing_unidirectional_stream_id() + : session_->next_outgoing_bidirectional_stream_id(); + + // If bidi, Crypto stream default created at start up, it is one + // more stream to account for since initialization is "number of + // request/responses" & crypto is added in to that, not streams. + size_t extra_stream_count = 0; + if (IsBidi() && !QuicVersionUsesCryptoFrames(transport_version())) { + extra_stream_count = 1; + } + EXPECT_EQ(number_of_streams + extra_stream_count, + stream_id_manager_->outgoing_max_streams()); while (number_of_streams) { EXPECT_TRUE(stream_id_manager_->CanOpenNextOutgoingStream()); EXPECT_EQ(stream_id, stream_id_manager_->GetNextOutgoingStreamId()); stream_id += kV99StreamIdIncrement; number_of_streams--; } - EXPECT_EQ(stream_id - kV99StreamIdIncrement, - stream_id_manager_->max_allowed_outgoing_stream_id()); // If we try to check that the next outgoing stream id is available it should - // A) fail and B) generate a STREAM_ID_BLOCKED frame. + // A) fail and B) generate a STREAMS_BLOCKED frame. EXPECT_CALL(*connection_, SendControlFrame(_)) .Times(1) .WillRepeatedly(Invoke(session_.get(), &TestQuicSession::SaveFrame)); EXPECT_FALSE(stream_id_manager_->CanOpenNextOutgoingStream()); - EXPECT_EQ(STREAM_ID_BLOCKED_FRAME, session_->save_frame().type); - EXPECT_EQ(stream_id_manager_->max_allowed_outgoing_stream_id(), - session_->save_frame().max_stream_id_frame.max_stream_id); + EXPECT_EQ(STREAMS_BLOCKED_FRAME, session_->save_frame().type); + // If bidi, Crypto stream default created at start up, it is one + // more stream to account for since initialization is "number of + // request/responses" & crypto is added in to that, not streams. + EXPECT_EQ(kDefaultMaxStreamsPerConnection + extra_stream_count, + session_->save_frame().max_streams_frame.stream_count); // If we try to get the next id (above the limit), it should cause a quic-bug. EXPECT_QUIC_BUG( stream_id_manager_->GetNextOutgoingStreamId(), - "Attempt allocate a new outgoing stream ID would exceed the limit"); + "Attempt to allocate a new outgoing stream that would exceed the limit"); } // Ensure that MaybeIncreaseLargestPeerStreamId works properly. This is // server/client agnostic. TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerServerMaybeIncreaseLargestPeerStreamId) { - EXPECT_TRUE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId( - stream_id_manager_->actual_max_allowed_incoming_stream_id())); + QuicStreamId max_stream_id = + StreamCountToId(stream_id_manager_->incoming_actual_max_streams(), + Perspective::IS_SERVER); + EXPECT_TRUE( + stream_id_manager_->MaybeIncreaseLargestPeerStreamId(max_stream_id)); + QuicStreamId server_initiated_stream_id = - GetParam() ? GetNthServerInitiatedBidirectionalId(0) - : GetNthServerInitiatedUnidirectionalId(0); + StreamCountToId(1u, // get 1st id + Perspective::IS_SERVER); EXPECT_TRUE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId( server_initiated_stream_id)); // A bad stream ID results in a closed connection. EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _)); EXPECT_FALSE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId( - stream_id_manager_->actual_max_allowed_incoming_stream_id() + - kV99StreamIdIncrement)); + max_stream_id + kV99StreamIdIncrement)); } -// Test the MAX STREAM ID Window functionality. -// Free up Stream ID space. Do not expect to see a MAX_STREAM_ID -// until |window| stream ids are available. -TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerServerMaxStreamId) { - // Test that a MAX_STREAM_ID frame is generated when the peer has less than - // |max_stream_id_window_| streams left that it can initiate. +// Test the MAX STREAMS Window functionality. +TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerServerMaxStreams) { + // Test that a MAX_STREAMS frame is generated when the peer has less than + // |max_streams_window_| streams left that it can initiate. - // First, open, and then close, max_stream_id_window_ streams. This will - // max_stream_id_window_ streams available for the peer -- no MAX_STREAM_ID + // First, open, and then close, max_streams_window_ streams. This will + // max_streams_window_ streams available for the peer -- no MAX_STREAMS // should be sent. The -1 is because the check in - // QuicStreamIdManager::MaybeSendMaxStreamIdFrame sends a MAX_STREAM_ID if the - // number of available streams at the peer is <= |max_stream_id_window_| - int stream_count = stream_id_manager_->max_stream_id_window() - 1; - - QuicStreamId advertised_max = - stream_id_manager_->advertised_max_allowed_incoming_stream_id(); - QuicStreamId expected_actual_max_id = - stream_id_manager_->actual_max_allowed_incoming_stream_id(); + // QuicStreamIdManager::MaybeSendMaxStreamsFrame sends a MAX_STREAMS if the + // number of available streams at the peer is <= |max_streams_window_| + int stream_count = stream_id_manager_->max_streams_window() - 1; // Should not get a control-frame transmission since the peer should have // "plenty" of stream IDs to use. EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); - // This test runs as a client, so the first stream to release is 2, a - // server-initiated stream. - QuicStreamId stream_id = GetParam() - ? GetNthServerInitiatedBidirectionalId(0) - : GetNthServerInitiatedUnidirectionalId(0); + + // Get the first incoming stream ID to try and allocate. + QuicStreamId stream_id = IsBidi() ? GetNthServerInitiatedBidirectionalId(0) + : GetNthServerInitiatedUnidirectionalId(0); size_t old_available_incoming_streams = stream_id_manager_->available_incoming_streams(); - while (stream_count) { EXPECT_TRUE( stream_id_manager_->MaybeIncreaseLargestPeerStreamId(stream_id)); + // This node should think that the peer believes it has one fewer + // stream it can create. old_available_incoming_streams--; EXPECT_EQ(old_available_incoming_streams, stream_id_manager_->available_incoming_streams()); @@ -548,27 +591,31 @@ TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerServerMaxStreamId) { stream_id += kV99StreamIdIncrement; } - // Now close them, still should get no MAX_STREAM_ID - stream_count = stream_id_manager_->max_stream_id_window(); - stream_id = GetParam() ? GetNthServerInitiatedBidirectionalId(0) - : GetNthServerInitiatedUnidirectionalId(0); + // Now close them, still should get no MAX_STREAMS + stream_count = stream_id_manager_->max_streams_window(); + stream_id = IsBidi() ? GetNthServerInitiatedBidirectionalId(0) + : GetNthServerInitiatedUnidirectionalId(0); + QuicStreamCount expected_actual_max = + stream_id_manager_->incoming_actual_max_streams(); + QuicStreamCount expected_advertised_max_streams = + stream_id_manager_->incoming_advertised_max_streams(); while (stream_count) { stream_id_manager_->OnStreamClosed(stream_id); stream_count--; stream_id += kV99StreamIdIncrement; - expected_actual_max_id += kV99StreamIdIncrement; - EXPECT_EQ(expected_actual_max_id, - stream_id_manager_->actual_max_allowed_incoming_stream_id()); + expected_actual_max++; + EXPECT_EQ(expected_actual_max, + stream_id_manager_->incoming_actual_max_streams()); // Advertised maximum should remain the same. - EXPECT_EQ(advertised_max, - stream_id_manager_->advertised_max_allowed_incoming_stream_id()); + EXPECT_EQ(expected_advertised_max_streams, + stream_id_manager_->incoming_advertised_max_streams()); } // This should not change. EXPECT_EQ(old_available_incoming_streams, stream_id_manager_->available_incoming_streams()); - // Now whenever we close a stream we should get a MAX_STREAM_ID frame. + // Now whenever we close a stream we should get a MAX_STREAMS frame. // Above code closed all the open streams, so we have to open/close EXPECT_CALL(*connection_, SendControlFrame(_)) .Times(1) @@ -577,37 +624,74 @@ TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerServerMaxStreamId) { stream_id_manager_->OnStreamClosed(stream_id); stream_id += kV99StreamIdIncrement; - // Check that the MAX STREAM ID was sent and has the correct values. - EXPECT_EQ(MAX_STREAM_ID_FRAME, session_->save_frame().type); - EXPECT_EQ(stream_id_manager_->advertised_max_allowed_incoming_stream_id(), - session_->save_frame().max_stream_id_frame.max_stream_id); + // Check that the MAX STREAMS was sent and has the correct values. + EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type); + EXPECT_EQ(stream_id_manager_->incoming_advertised_max_streams(), + session_->save_frame().max_streams_frame.stream_count); } -// Test that registering static stream IDs causes the stream ID limit to rise +// Test that registering static stream IDs causes the stream limit to rise // accordingly. This is server/client agnostic. TEST_P(QuicStreamIdManagerTestClient, TestStaticStreamAdjustment) { QuicStreamId first_dynamic = - stream_id_manager_->first_incoming_dynamic_stream_id(); - QuicStreamId expected_max_incoming = - stream_id_manager_->actual_max_allowed_incoming_stream_id(); + QuicStreamIdManagerPeer::GetFirstIncomingStreamId(stream_id_manager_); + QuicStreamCount actual_max = + stream_id_manager_->incoming_actual_max_streams(); // First test will register the first dynamic stream id as being for a static - // stream. This takes one stream ID out of the low-end of the dynamic range - // so therefore the high end should go up by 1 ID. - expected_max_incoming += kV99StreamIdIncrement; + // stream. stream_id_manager_->RegisterStaticStream(first_dynamic); - EXPECT_EQ(expected_max_incoming, - stream_id_manager_->actual_max_allowed_incoming_stream_id()); - - // Now be extreme, increase static by 100 stream ids. A discontinuous - // jump is not allowed; make sure. - first_dynamic += kV99StreamIdIncrement * 100; - expected_max_incoming += kV99StreamIdIncrement * 100; - std::string bug_detail = - GetParam() ? "allocate 5 got 401" : "allocate 7 got 403"; - EXPECT_QUIC_BUG( - stream_id_manager_->RegisterStaticStream(first_dynamic), - "Error in incoming static stream allocation, expected to " + bug_detail); + // Should go up by 1 stream/stream id. + EXPECT_EQ(actual_max + 1u, stream_id_manager_->incoming_actual_max_streams()); +} + +// Check that the OnMaxStreamFrame logic properly handles all the +// cases of offered max streams and outgoing_static_stream_count_, +// checking for the wrap conditions. Tests in client perspective, necessary +// because internally, some calculations depend on the client/server +// perspective. +TEST_P(QuicStreamIdManagerTestClient, TestMaxStreamsWrapChecks) { + QuicStreamCount max_stream_count = + QuicUtils::GetMaxStreamCount(IsUnidi(), Perspective::IS_CLIENT); + QuicMaxStreamsFrame frame; + frame.unidirectional = IsUnidi(); + + // Check the case where the offered stream count is less than the + // maximum + frame.stream_count = max_stream_count - 10; + EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame)); + EXPECT_EQ(max_stream_count - 10u, stream_id_manager_->outgoing_max_streams()); + + // Now check if the offered count is larger than the max. + // The count should be pegged at the max. + frame.stream_count = max_stream_count + 10; + EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame)); + EXPECT_EQ(max_stream_count, stream_id_manager_->outgoing_max_streams()); +} + +// Check that edge conditions of the stream count in a STREAMS_BLOCKED frame +// are. properly handled. +TEST_P(QuicStreamIdManagerTestClient, StreamsBlockedEdgeConditions) { + QuicStreamsBlockedFrame frame; + frame.unidirectional = IsUnidi(); + + // Check that receipt of a STREAMS BLOCKED with stream-count = 0 does nothing + // when max_allowed_incoming_streams is 0. + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); + stream_id_manager_->SetMaxOpenIncomingStreams(0); + frame.stream_count = 0; + stream_id_manager_->OnStreamsBlockedFrame(frame); + + // Check that receipt of a STREAMS BLOCKED with stream-count = 0 invokes a + // MAX STREAMS, count = 123, when the MaxOpen... is set to 123. + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(1) + .WillOnce(Invoke(session_.get(), &TestQuicSession::SaveFrame)); + stream_id_manager_->SetMaxOpenIncomingStreams(123); + frame.stream_count = 0; + stream_id_manager_->OnStreamsBlockedFrame(frame); + EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type); + EXPECT_EQ(123u, session_->save_frame().max_streams_frame.stream_count); } // Following tests all are server-specific. They depend, in some way, on @@ -626,42 +710,13 @@ INSTANTIATE_TEST_SUITE_P(Tests, QuicStreamIdManagerTestServer, testing::Bool()); TEST_P(QuicStreamIdManagerTestServer, CheckMaxAllowedOutgoing) { const size_t kIncomingStreamCount = 123; stream_id_manager_->SetMaxOpenOutgoingStreams(kIncomingStreamCount); - EXPECT_EQ(kIncomingStreamCount, - stream_id_manager_->max_allowed_outgoing_streams()); - - // Check that the max outgoing stream id is properly calculated - EXPECT_EQ(stream_id_manager_->GetNextOutgoingStreamId() + - ((kIncomingStreamCount - 1) * kV99StreamIdIncrement), - stream_id_manager_->max_allowed_outgoing_stream_id()); + EXPECT_EQ(kIncomingStreamCount, stream_id_manager_->outgoing_max_streams()); } -// This test checks that the initialization for the maximum allowed incoming -// stream id is correct. -TEST_P(QuicStreamIdManagerTestServer, CheckMaxAllowedIncoming) { - const size_t kIncomingStreamCount = 245; - stream_id_manager_->SetMaxOpenIncomingStreams(kIncomingStreamCount); - EXPECT_EQ(kIncomingStreamCount, - stream_id_manager_->max_allowed_incoming_streams()); - - // Check that the window is 1/2 (integer math) of the stream count. - EXPECT_EQ((kIncomingStreamCount / 2), - stream_id_manager_->max_stream_id_window()); - - // Actual- and advertised- maxima start out equal. - EXPECT_EQ(stream_id_manager_->actual_max_allowed_incoming_stream_id(), - stream_id_manager_->advertised_max_allowed_incoming_stream_id()); - - // First stream ID the client should use should be 3, this means that the max - // stream id is 491 -- ((number of stream ids-1) * 2) + first available id. - EXPECT_EQ(stream_id_manager_->first_incoming_dynamic_stream_id() + - ((kIncomingStreamCount - 1) * kV99StreamIdIncrement), - stream_id_manager_->actual_max_allowed_incoming_stream_id()); -} - -// Test that a MAX_STREAM_ID frame is generated when half the stream ids become +// Test that a MAX_STREAMS frame is generated when half the stream ids become // available. This has a useful side effect of testing that when streams are // closed, the number of available stream ids increases. -TEST_P(QuicStreamIdManagerTestServer, MaxStreamIdSlidingWindow) { +TEST_P(QuicStreamIdManagerTestServer, MaxStreamsSlidingWindow) { // Ignore OnStreamReset calls. EXPECT_CALL(*connection_, OnStreamReset(_, _)).WillRepeatedly(Return()); // Capture control frames for analysis. @@ -669,16 +724,17 @@ TEST_P(QuicStreamIdManagerTestServer, MaxStreamIdSlidingWindow) { .WillRepeatedly(Invoke(session_.get(), &TestQuicSession::SaveFrame)); // Simulate config being negotiated, causing the limits all to be initialized. session_->OnConfigNegotiated(); - QuicStreamId first_advert = - stream_id_manager_->advertised_max_allowed_incoming_stream_id(); + QuicStreamCount first_advert = + stream_id_manager_->incoming_advertised_max_streams(); - // Open/close enough streams to shrink the window without causing a MAX STREAM - // ID to be generated. The window will open (and a MAX STREAM ID generated) - // when max_stream_id_window() stream IDs have been made available. The loop + // Open/close enough streams to shrink the window without causing a MAX + // STREAMS to be generated. The window will open (and a MAX STREAMS generated) + // when max_streams_window() stream IDs have been made available. The loop // will make that many stream IDs available, so the last CloseStream should - // cause a MAX STREAM ID frame to be generated. - int i = static_cast<int>(stream_id_manager_->max_stream_id_window()); - QuicStreamId id = stream_id_manager_->first_incoming_dynamic_stream_id(); + // cause a MAX STREAMS frame to be generated. + int i = static_cast<int>(stream_id_manager_->max_streams_window()); + QuicStreamId id = + QuicStreamIdManagerPeer::GetFirstIncomingStreamId(stream_id_manager_); while (i) { QuicStream* stream = session_->GetOrCreateStream(id); EXPECT_NE(nullptr, stream); @@ -687,10 +743,10 @@ TEST_P(QuicStreamIdManagerTestServer, MaxStreamIdSlidingWindow) { // to the stream being added to the locally_closed_streams_highest_offset_ // map, and therefore not counting as truly being closed. The test requires // that the stream truly close, so that new streams become available, - // causing the MAX_STREAM_ID to be sent. + // causing the MAX_STREAMS to be sent. stream->set_fin_received(true); EXPECT_EQ(id, stream->id()); - if (GetParam()) { + if (IsBidi()) { // Only send reset for incoming bidirectional streams. EXPECT_CALL(*session_, SendRstStream(_, _, _)); } @@ -698,147 +754,123 @@ TEST_P(QuicStreamIdManagerTestServer, MaxStreamIdSlidingWindow) { i--; id += kV99StreamIdIncrement; } - EXPECT_EQ(MAX_STREAM_ID_FRAME, session_->save_frame().type); - QuicStreamId second_advert = - session_->save_frame().max_stream_id_frame.max_stream_id; - EXPECT_EQ(first_advert + (stream_id_manager_->max_stream_id_window() * - kV99StreamIdIncrement), + EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type); + QuicStreamCount second_advert = + session_->save_frame().max_streams_frame.stream_count; + EXPECT_EQ(first_advert + stream_id_manager_->max_streams_window(), second_advert); } // Tast that an attempt to create an outgoing stream does not exceed the limit -// and that it generates an appropriate STREAM_ID_BLOCKED frame. +// and that it generates an appropriate STREAMS_BLOCKED frame. TEST_P(QuicStreamIdManagerTestServer, NewStreamDoesNotExceedLimit) { - size_t stream_count = stream_id_manager_->max_allowed_outgoing_streams(); + size_t stream_count = stream_id_manager_->outgoing_max_streams(); EXPECT_NE(0u, stream_count); TestQuicStream* stream; while (stream_count) { - stream = GetParam() ? session_->CreateOutgoingBidirectionalStream() - : session_->CreateOutgoingUnidirectionalStream(); + stream = IsBidi() ? session_->CreateOutgoingBidirectionalStream() + : session_->CreateOutgoingUnidirectionalStream(); EXPECT_NE(stream, nullptr); stream_count--; } - // Quis Custodiet Ipsos Custodes. - EXPECT_EQ(stream->id(), stream_id_manager_->max_allowed_outgoing_stream_id()); - // Create another, it should fail. Should also send a STREAM_ID_BLOCKED + + EXPECT_EQ(stream_id_manager_->outgoing_stream_count(), + stream_id_manager_->outgoing_max_streams()); + // Create another, it should fail. Should also send a STREAMS_BLOCKED // control frame. EXPECT_CALL(*connection_, SendControlFrame(_)); - stream = GetParam() ? session_->CreateOutgoingBidirectionalStream() - : session_->CreateOutgoingUnidirectionalStream(); + stream = IsBidi() ? session_->CreateOutgoingBidirectionalStream() + : session_->CreateOutgoingUnidirectionalStream(); EXPECT_EQ(nullptr, stream); } -// Test that a server will reject a MAX_STREAM_ID that specifies a -// client-initiated stream ID. -TEST_P(QuicStreamIdManagerTestServer, RejectClientMaxStreamId) { - QuicStreamId id = stream_id_manager_->max_allowed_outgoing_stream_id(); - - // Ensure that the ID that will be in the MAX_STREAM_ID is larger than the - // current MAX. - id += (kV99StreamIdIncrement * 2); - - // Turn it into a client-initiated ID (even). - id &= ~0x1; - EXPECT_TRUE(QuicUtils::IsClientInitiatedStreamId(QUIC_VERSION_99, id)); - - // Generate a MAX_STREAM_ID frame and process it; the connection should close. - QuicMaxStreamIdFrame frame(0, id); - EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAM_ID_ERROR, _, _)); - session_->OnMaxStreamIdFrame(frame); -} - -// Test that a server will reject a STREAM_ID_BLOCKED that specifies a -// server-initiated stream ID. STREAM_ID_BLOCKED from a client should specify an -// even (client-initiated_ ID) generate one with an odd ID and check that the -// connection is closed. -TEST_P(QuicStreamIdManagerTestServer, RejectClientStreamIdBlocked) { - QuicStreamId id = stream_id_manager_->max_allowed_outgoing_stream_id(); - - // Ensure that the ID that will be in the MAX_STREAM_ID is larger than the - // current MAX. - id += (kV99StreamIdIncrement * 2); - - // Make the ID odd, so it looks like the client is trying to specify a - // server-initiated ID. - id |= 0x1; - EXPECT_FALSE(QuicUtils::IsClientInitiatedStreamId(QUIC_VERSION_99, id)); - - // Generate a STREAM_ID_BLOCKED frame and process it; the connection should - // close. - QuicStreamIdBlockedFrame frame(0, id); - EXPECT_CALL(*connection_, - CloseConnection(QUIC_STREAM_ID_BLOCKED_ERROR, _, _)); - session_->OnStreamIdBlockedFrame(frame); -} - // Check that the parameters used by the stream ID manager are properly // initialized TEST_P(QuicStreamIdManagerTestServer, StreamIdManagerServerInitialization) { // These fields are inited via the QuicSession constructor to default // values defined as a constant. EXPECT_EQ(kDefaultMaxStreamsPerConnection, - stream_id_manager_->max_allowed_incoming_streams()); + stream_id_manager_->incoming_initial_max_open_streams()); + // If bidi, Crypto stream default created at start up, it is one + // more stream to account for since initialization is "number of + // request/responses" & crypto is added in to that, not streams. + // Since this is the server, the stream is incoming. + size_t extra_stream_count = 0; + if (IsBidi() && !QuicVersionUsesCryptoFrames(transport_version())) { + extra_stream_count = 1; + } + EXPECT_EQ(kDefaultMaxStreamsPerConnection + extra_stream_count, + stream_id_manager_->incoming_actual_max_streams()); EXPECT_EQ(kDefaultMaxStreamsPerConnection, - stream_id_manager_->max_allowed_outgoing_streams()); + stream_id_manager_->outgoing_max_streams()); // The window for advertising updates to the MAX STREAM ID is half the number // of stream allowed. - EXPECT_EQ(kDefaultMaxStreamsPerConnection / kMaxStreamIdWindowDivisor, - stream_id_manager_->max_stream_id_window()); - - // This test runs as a server, so it initiates (that is to say, outgoing) - // even-numbered stream IDs. The -1 in the calculation is because the value - // being tested is the maximum allowed stream ID, not the first unallowed - // stream id. - const QuicStreamId kExpectedMaxOutgoingStreamId = - (GetParam() ? session_->next_outgoing_bidirectional_stream_id() - : session_->next_outgoing_unidirectional_stream_id()) + - ((kDefaultMaxStreamsPerConnection - 1) * kV99StreamIdIncrement); - EXPECT_EQ(kExpectedMaxOutgoingStreamId, - stream_id_manager_->max_allowed_outgoing_stream_id()); - - // Same for IDs of incoming streams... But they are client initiated, so are - // even. - const QuicStreamId kExpectedMaxIncomingStreamId = - GetParam() ? GetNthClientInitiatedBidirectionalId( - kDefaultMaxStreamsPerConnection - 1) - : GetNthClientInitiatedUnidirectionalId( - kDefaultMaxStreamsPerConnection - 1); - EXPECT_EQ(kExpectedMaxIncomingStreamId, - stream_id_manager_->actual_max_allowed_incoming_stream_id()); - EXPECT_EQ(kExpectedMaxIncomingStreamId, - stream_id_manager_->advertised_max_allowed_incoming_stream_id()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection / kMaxStreamsWindowDivisor, + stream_id_manager_->max_streams_window()); } TEST_P(QuicStreamIdManagerTestServer, AvailableStreams) { stream_id_manager_->MaybeIncreaseLargestPeerStreamId( - GetParam() ? GetNthClientInitiatedBidirectionalId(3) - : GetNthClientInitiatedUnidirectionalId(3)); + IsBidi() ? GetNthClientInitiatedBidirectionalId(3) + : GetNthClientInitiatedUnidirectionalId(3)); EXPECT_TRUE(stream_id_manager_->IsAvailableStream( - GetParam() ? GetNthClientInitiatedBidirectionalId(1) - : GetNthClientInitiatedUnidirectionalId(1))); + IsBidi() ? GetNthClientInitiatedBidirectionalId(1) + : GetNthClientInitiatedUnidirectionalId(1))); EXPECT_TRUE(stream_id_manager_->IsAvailableStream( - GetParam() ? GetNthClientInitiatedBidirectionalId(2) - : GetNthClientInitiatedUnidirectionalId(2))); + IsBidi() ? GetNthClientInitiatedBidirectionalId(2) + : GetNthClientInitiatedUnidirectionalId(2))); } // Tests that if MaybeIncreaseLargestPeerStreamId is given an extremely // large stream ID (larger than the limit) it is rejected. // This is a regression for Chromium bugs 909987 and 910040 TEST_P(QuicStreamIdManagerTestServer, ExtremeMaybeIncreaseLargestPeerStreamId) { - QuicStreamId too_big_stream_id = - stream_id_manager_->actual_max_allowed_incoming_stream_id() + - kV99StreamIdIncrement * 20; + QuicStreamId too_big_stream_id = StreamCountToId( + stream_id_manager_->incoming_actual_max_streams() + 20, + Perspective::IS_CLIENT); // This node is a server, incoming stream + // ids must be client-originated. + std::string error_details; + if (IsBidi()) { + if (QuicVersionUsesCryptoFrames(transport_version())) { + error_details = "Stream id 476 would exceed stream count limit 100"; + } else { + error_details = "Stream id 480 would exceed stream count limit 101"; + } + } else { + error_details = "Stream id 478 would exceed stream count limit 100"; + } - std::string error_details = - GetParam() ? "Stream id 480 above 400" : "Stream id 478 above 398"; EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, error_details, _)); - EXPECT_FALSE( stream_id_manager_->MaybeIncreaseLargestPeerStreamId(too_big_stream_id)); } +// Check that the OnMaxStreamFrame logic properly handles all the +// cases of offered max streams and outgoing_static_stream_count_, +// checking for the wrap conditions. Tests in server perspective, necessary +// because internally, some calculations depend on the client/server +// perspective. +TEST_P(QuicStreamIdManagerTestServer, TestMaxStreamsWrapChecks) { + QuicStreamCount max_stream_count = + QuicUtils::GetMaxStreamCount(IsUnidi(), Perspective::IS_SERVER); + QuicMaxStreamsFrame frame; + frame.unidirectional = IsUnidi(); + + // Check the case where the offered stream count is less than the + // implementation maximum, + frame.stream_count = max_stream_count - 10; + EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame)); + EXPECT_EQ(max_stream_count - 10u, stream_id_manager_->outgoing_max_streams()); + + // Check the case where the offered stream count is greater than the + // implementation maximum. The count should peg at the maximum. + frame.stream_count = max_stream_count + 10; + EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame)); + EXPECT_EQ(max_stream_count, stream_id_manager_->outgoing_max_streams()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc index 57e2bd1802a..3a5efb50e7f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_send_buffer_test.cc @@ -48,7 +48,7 @@ class QuicStreamSendBufferTest : public QuicTest { QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer_)); // Save all data. - SetQuicFlag(&FLAGS_quic_send_buffer_max_data_slice_size, 1024); + SetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size, 1024); send_buffer_.SaveStreamData(iov, 2, 0, 2048); send_buffer_.SaveMemSlice(std::move(slice1)); EXPECT_TRUE(slice1.empty()); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc index d42ee20de5d..7f0f2cbf22d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.cc @@ -34,9 +34,7 @@ QuicStreamSequencerBuffer::QuicStreamSequencerBuffer(size_t max_capacity_bytes) blocks_count_(CalculateBlockCount(max_capacity_bytes)), total_bytes_read_(0), blocks_(nullptr), - total_bytes_prefetched_(0), - faster_interval_add_in_sequence_buffer_( - GetQuicReloadableFlag(quic_faster_interval_add_in_sequence_buffer)) { + total_bytes_prefetched_(0) { Clear(); } @@ -90,35 +88,15 @@ QuicErrorCode QuicStreamSequencerBuffer::OnStreamData( bytes_received_.IsDisjoint(QuicInterval<QuicStreamOffset>( starting_offset, starting_offset + size))) { // Optimization for the typical case, when all data is newly received. - if (faster_interval_add_in_sequence_buffer_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_faster_interval_add_in_sequence_buffer); - bytes_received_.AddOptimizedForAppend(starting_offset, - starting_offset + size); - if (bytes_received_.Size() >= kMaxNumDataIntervalsAllowed) { - // This frame is going to create more intervals than allowed. Stop - // processing. - *error_details = "Too many data intervals received for this stream."; - return QUIC_TOO_MANY_STREAM_DATA_INTERVALS; - } - } else { - if (!bytes_received_.Empty() && - starting_offset == bytes_received_.rbegin()->max()) { - // Extend the right edge of last interval. - // TODO(fayang): Encapsulate this into a future version of - // QuicIntervalSet if this is more efficient than Add. - const_cast<QuicInterval<QuicStreamOffset>*>( - &(*bytes_received_.rbegin())) - ->SetMax(starting_offset + size); - } else { - bytes_received_.Add(starting_offset, starting_offset + size); - if (bytes_received_.Size() >= kMaxNumDataIntervalsAllowed) { - // This frame is going to create more intervals than allowed. Stop - // processing. - *error_details = "Too many data intervals received for this stream."; - return QUIC_TOO_MANY_STREAM_DATA_INTERVALS; - } - } + bytes_received_.AddOptimizedForAppend(starting_offset, + starting_offset + size); + if (bytes_received_.Size() >= kMaxNumDataIntervalsAllowed) { + // This frame is going to create more intervals than allowed. Stop + // processing. + *error_details = "Too many data intervals received for this stream."; + return QUIC_TOO_MANY_STREAM_DATA_INTERVALS; } + size_t bytes_copy = 0; if (!CopyStreamData(starting_offset, data, &bytes_copy, error_details)) { return QUIC_STREAM_SEQUENCER_INVALID_STATE; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h index 6f4717d8ca6..08a1ab4a640 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h @@ -239,9 +239,6 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { // Total number of bytes that have been prefetched. QuicStreamOffset total_bytes_prefetched_; - - // Latched value of --quic_faster_interval_add_in_sequence_buffer. - const bool faster_interval_add_in_sequence_buffer_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc index aa30b5107ef..335aa2dd3d8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer_test.cc @@ -11,7 +11,6 @@ #include <string> #include <utility> -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" @@ -36,10 +35,10 @@ char GetCharFromIOVecs(size_t offset, iovec iov[], size_t count) { } start_offset += iov[i].iov_len; } - LOG(ERROR) << "Could not locate char at offset " << offset << " in " << count - << " iovecs"; + QUIC_LOG(ERROR) << "Could not locate char at offset " << offset << " in " + << count << " iovecs"; for (size_t i = 0; i < count; ++i) { - LOG(ERROR) << " iov[" << i << "].iov_len = " << iov[i].iov_len; + QUIC_LOG(ERROR) << " iov[" << i << "].iov_len = " << iov[i].iov_len; } return '\0'; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc index d1b442ed888..9b32012e319 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc @@ -49,8 +49,8 @@ class TestStream : public QuicStream { TestStream(QuicStreamId id, QuicSession* session, StreamType type) : QuicStream(id, session, /*is_static=*/false, type) {} - TestStream(PendingStream pending, StreamType type) - : QuicStream(std::move(pending), type) {} + TestStream(PendingStream pending, StreamType type, bool is_static) + : QuicStream(std::move(pending), type, is_static) {} void OnDataAvailable() override {} @@ -171,6 +171,18 @@ INSTANTIATE_TEST_SUITE_P(QuicParameterizedStreamTests, QuicParameterizedStreamTest, ::testing::ValuesIn(AllSupportedVersions())); +TEST_P(QuicStreamTest, PendingStreamStaticness) { + Initialize(); + + PendingStream pending(kTestStreamId + 2, session_.get()); + TestStream stream(std::move(pending), StreamType::BIDIRECTIONAL, false); + EXPECT_FALSE(stream.is_static()); + + PendingStream pending2(kTestStreamId + 3, session_.get()); + TestStream stream2(std::move(pending2), StreamType::BIDIRECTIONAL, true); + EXPECT_TRUE(stream2.is_static()); +} + TEST_P(QuicStreamTest, PendingStreamTooMuchData) { Initialize(); @@ -228,7 +240,7 @@ TEST_P(QuicStreamTest, FromPendingStream) { QuicStreamFrame frame2(kTestStreamId + 2, true, 3, QuicStringPiece(".")); pending.OnStreamFrame(frame2); - TestStream stream(std::move(pending), StreamType::READ_UNIDIRECTIONAL); + TestStream stream(std::move(pending), StreamType::READ_UNIDIRECTIONAL, false); EXPECT_EQ(3, stream.num_frames_received()); EXPECT_EQ(3u, stream.stream_bytes_read()); EXPECT_EQ(1, stream.num_duplicate_frames_received()); @@ -247,8 +259,8 @@ TEST_P(QuicStreamTest, FromPendingStreamThenData) { QuicStreamFrame frame(kTestStreamId + 2, false, 2, QuicStringPiece(".")); pending.OnStreamFrame(frame); - auto stream = - new TestStream(std::move(pending), StreamType::READ_UNIDIRECTIONAL); + auto stream = new TestStream(std::move(pending), + StreamType::READ_UNIDIRECTIONAL, false); session_->ActivateStream(QuicWrapUnique(stream)); QuicStreamFrame frame2(kTestStreamId + 2, true, 3, QuicStringPiece(".")); @@ -956,7 +968,7 @@ TEST_P(QuicStreamTest, ConnectionClosed) { } TEST_P(QuicStreamTest, CanWriteNewDataAfterData) { - SetQuicFlag(&FLAGS_quic_buffered_data_threshold, 100); + SetQuicFlag(FLAGS_quic_buffered_data_threshold, 100); Initialize(); EXPECT_TRUE(stream_->CanWriteNewDataAfterData(99)); EXPECT_FALSE(stream_->CanWriteNewDataAfterData(100)); @@ -964,7 +976,7 @@ TEST_P(QuicStreamTest, CanWriteNewDataAfterData) { TEST_P(QuicStreamTest, WriteBufferedData) { // Set buffered data low water mark to be 100. - SetQuicFlag(&FLAGS_quic_buffered_data_threshold, 100); + SetQuicFlag(FLAGS_quic_buffered_data_threshold, 100); // Do not stream level flow control block this stream. set_initial_flow_control_window_bytes(500000); @@ -1006,7 +1018,8 @@ TEST_P(QuicStreamTest, WriteBufferedData) { // Buffered data size < threshold, ask upper layer for more data. EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); stream_->OnCanWrite(); - EXPECT_EQ(GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1, + EXPECT_EQ(static_cast<uint64_t>( + GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1), stream_->BufferedDataBytes()); EXPECT_TRUE(stream_->CanWriteNewData()); @@ -1055,7 +1068,8 @@ TEST_P(QuicStreamTest, WriteBufferedData) { EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); stream_->OnCanWrite(); - EXPECT_EQ(GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1, + EXPECT_EQ(static_cast<uint64_t>( + GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1), stream_->BufferedDataBytes()); EXPECT_TRUE(stream_->CanWriteNewData()); @@ -1096,7 +1110,7 @@ TEST_P(QuicStreamTest, WritevDataReachStreamLimit) { TEST_P(QuicStreamTest, WriteMemSlices) { // Set buffered data low water mark to be 100. - SetQuicFlag(&FLAGS_quic_buffered_data_threshold, 100); + SetQuicFlag(FLAGS_quic_buffered_data_threshold, 100); // Do not flow control block this stream. set_initial_flow_control_window_bytes(500000); @@ -1139,7 +1153,8 @@ TEST_P(QuicStreamTest, WriteMemSlices) { })); EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); stream_->OnCanWrite(); - EXPECT_EQ(GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1, + EXPECT_EQ(static_cast<uint64_t>( + GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1), stream_->BufferedDataBytes()); // Try to write slices2 again. EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(0); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time.cc index 25cd56092e3..ffc59dadf9b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time.cc @@ -13,7 +13,7 @@ namespace quic { -std::string QuicTime::Delta::ToDebugValue() const { +std::string QuicTime::Delta::ToDebuggingValue() const { const int64_t one_ms = 1000; const int64_t one_s = 1000 * one_ms; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time.h b/chromium/net/third_party/quiche/src/quic/core/quic_time.h index cd33649be5c..9a5ae7dd5b2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time.h @@ -75,7 +75,7 @@ class QUIC_EXPORT_PRIVATE QuicTime { return time_offset_ == kQuicInfiniteTimeUs; } - std::string ToDebugValue() const; + std::string ToDebuggingValue() const; private: friend inline bool operator==(QuicTime::Delta lhs, QuicTime::Delta rhs); @@ -275,7 +275,7 @@ inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs) { // Override stream output operator for gtest. inline std::ostream& operator<<(std::ostream& output, const QuicTime::Delta delta) { - output << delta.ToDebugValue(); + output << delta.ToDebuggingValue(); return output; } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_test.cc index 97205325a95..2e2838a4b51 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_test.cc @@ -82,18 +82,18 @@ TEST_F(QuicTimeDeltaTest, NotEqual) { QuicTime::Delta::FromSeconds(0)); } -TEST_F(QuicTimeDeltaTest, DebugValue) { +TEST_F(QuicTimeDeltaTest, DebuggingValue) { const QuicTime::Delta one_us = QuicTime::Delta::FromMicroseconds(1); const QuicTime::Delta one_ms = QuicTime::Delta::FromMilliseconds(1); const QuicTime::Delta one_s = QuicTime::Delta::FromSeconds(1); - EXPECT_EQ("3s", (3 * one_s).ToDebugValue()); - EXPECT_EQ("3ms", (3 * one_ms).ToDebugValue()); - EXPECT_EQ("3us", (3 * one_us).ToDebugValue()); + EXPECT_EQ("3s", (3 * one_s).ToDebuggingValue()); + EXPECT_EQ("3ms", (3 * one_ms).ToDebuggingValue()); + EXPECT_EQ("3us", (3 * one_us).ToDebuggingValue()); - EXPECT_EQ("3001us", (3 * one_ms + one_us).ToDebugValue()); - EXPECT_EQ("3001ms", (3 * one_s + one_ms).ToDebugValue()); - EXPECT_EQ("3000001us", (3 * one_s + one_us).ToDebugValue()); + EXPECT_EQ("3001us", (3 * one_ms + one_us).ToDebuggingValue()); + EXPECT_EQ("3001ms", (3 * one_s + one_ms).ToDebuggingValue()); + EXPECT_EQ("3000001us", (3 * one_s + one_us).ToDebuggingValue()); } class QuicTimeTest : public QuicTest { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc index 6fba2ebe5e0..f1f6dcf2678 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.cc @@ -22,6 +22,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" namespace quic { @@ -161,18 +162,15 @@ void QuicTimeWaitListManager::ProcessPacket( if (connection_data->encryption_level == ENCRYPTION_INITIAL) { QUIC_CODE_COUNT( quic_encryption_none_termination_packets_for_short_header); - if (GetQuicReloadableFlag(quic_always_reset_short_header_packets)) { - QUIC_RELOADABLE_FLAG_COUNT( - quic_always_reset_short_header_packets); - // Send stateless reset in response to short header packets, - // because ENCRYPTION_INITIAL termination packets will not be - // processed by clients. - SendPublicReset(self_address, peer_address, connection_id, - connection_data->ietf_quic, - std::move(packet_context)); - return; - } - } else if (connection_data->encryption_level == ENCRYPTION_ZERO_RTT) { + // Send stateless reset in response to short header packets, + // because ENCRYPTION_INITIAL termination packets will not be + // processed by clients. + SendPublicReset(self_address, peer_address, connection_id, + connection_data->ietf_quic, + std::move(packet_context)); + return; + } + if (connection_data->encryption_level == ENCRYPTION_ZERO_RTT) { QUIC_CODE_COUNT(quic_zero_rtt_termination_packets_for_short_header); } break; @@ -203,16 +201,24 @@ void QuicTimeWaitListManager::ProcessPacket( } void QuicTimeWaitListManager::SendVersionNegotiationPacket( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, + QuicConnectionId client_connection_id, bool ietf_quic, const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, std::unique_ptr<QuicPerPacketContext> packet_context) { - SendOrQueuePacket(QuicMakeUnique<QueuedPacket>( - self_address, peer_address, - QuicFramer::BuildVersionNegotiationPacket( - connection_id, ietf_quic, supported_versions)), + std::unique_ptr<QuicEncryptedPacket> version_packet = + QuicFramer::BuildVersionNegotiationPacket(server_connection_id, + client_connection_id, ietf_quic, + supported_versions); + QUIC_DVLOG(2) << "Dispatcher sending version negotiation packet: {" + << ParsedQuicVersionVectorToString(supported_versions) << "}, " + << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl + << QuicTextUtils::HexDump(QuicStringPiece( + version_packet->data(), version_packet->length())); + SendOrQueuePacket(QuicMakeUnique<QueuedPacket>(self_address, peer_address, + std::move(version_packet)), packet_context.get()); } @@ -229,10 +235,17 @@ void QuicTimeWaitListManager::SendPublicReset( bool ietf_quic, std::unique_ptr<QuicPerPacketContext> packet_context) { if (ietf_quic) { - SendOrQueuePacket(QuicMakeUnique<QueuedPacket>( - self_address, peer_address, - BuildIetfStatelessResetPacket(connection_id)), - packet_context.get()); + std::unique_ptr<QuicEncryptedPacket> ietf_reset_packet = + BuildIetfStatelessResetPacket(connection_id); + QUIC_DVLOG(2) << "Dispatcher sending IETF reset packet for " + << connection_id << std::endl + << QuicTextUtils::HexDump( + QuicStringPiece(ietf_reset_packet->data(), + ietf_reset_packet->length())); + SendOrQueuePacket( + QuicMakeUnique<QueuedPacket>(self_address, peer_address, + std::move(ietf_reset_packet)), + packet_context.get()); return; } QuicPublicResetPacket packet; @@ -243,8 +256,13 @@ void QuicTimeWaitListManager::SendPublicReset( packet.client_address = peer_address; GetEndpointId(&packet.endpoint_id); // Takes ownership of the packet. + std::unique_ptr<QuicEncryptedPacket> reset_packet = BuildPublicReset(packet); + QUIC_DVLOG(2) << "Dispatcher sending reset packet for " << connection_id + << std::endl + << QuicTextUtils::HexDump(QuicStringPiece( + reset_packet->data(), reset_packet->length())); SendOrQueuePacket(QuicMakeUnique<QueuedPacket>(self_address, peer_address, - BuildPublicReset(packet)), + std::move(reset_packet)), packet_context.get()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h index dee5d11de43..ba0c76336aa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h @@ -118,10 +118,12 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { // The number of connections on the time-wait list. size_t num_connections() const { return connection_id_map_.size(); } - // Sends a version negotiation packet for |connection_id| announcing support - // for |supported_versions| to |peer_address| from |self_address|. + // Sends a version negotiation packet for |server_connection_id| and + // |client_connection_id| announcing support for |supported_versions| to + // |peer_address| from |self_address|. virtual void SendVersionNegotiationPacket( - QuicConnectionId connection_id, + QuicConnectionId server_connection_id, + QuicConnectionId client_connection_id, bool ietf_quic, const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& self_address, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc index aa0c911ee9b..4624a236503 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time_wait_list_manager_test.cc @@ -251,15 +251,50 @@ TEST_F(QuicTimeWaitListManagerTest, CheckStatelessConnectionIdInTimeWait) { TEST_F(QuicTimeWaitListManagerTest, SendVersionNegotiationPacket) { std::unique_ptr<QuicEncryptedPacket> packet( - QuicFramer::BuildVersionNegotiationPacket(connection_id_, false, + QuicFramer::BuildVersionNegotiationPacket(connection_id_, + EmptyQuicConnectionId(), false, AllSupportedVersions())); EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), peer_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); time_wait_list_manager_.SendVersionNegotiationPacket( - connection_id_, false, AllSupportedVersions(), self_address_, - peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + connection_id_, EmptyQuicConnectionId(), false, AllSupportedVersions(), + self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); +} + +TEST_F(QuicTimeWaitListManagerTest, SendIetfVersionNegotiationPacket) { + std::unique_ptr<QuicEncryptedPacket> packet( + QuicFramer::BuildVersionNegotiationPacket(connection_id_, + EmptyQuicConnectionId(), true, + AllSupportedVersions())); + EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), + peer_address_, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); + + time_wait_list_manager_.SendVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), true, AllSupportedVersions(), + self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); +} + +TEST_F(QuicTimeWaitListManagerTest, + SendIetfVersionNegotiationPacketWithClientConnectionId) { + // Client connection IDs cannot be used unless this flag is true. + SetQuicRestartFlag(quic_do_not_override_connection_id, true); + + std::unique_ptr<QuicEncryptedPacket> packet( + QuicFramer::BuildVersionNegotiationPacket(connection_id_, + TestConnectionId(0x33), true, + AllSupportedVersions())); + EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), + peer_address_, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); + + time_wait_list_manager_.SendVersionNegotiationPacket( + connection_id_, TestConnectionId(0x33), true, AllSupportedVersions(), + self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>()); EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); } @@ -560,18 +595,11 @@ TEST_F(QuicTimeWaitListManagerTest, QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, ENCRYPTION_INITIAL, &termination_packets); - if (GetQuicReloadableFlag(quic_always_reset_short_header_packets)) { - // Termination packet is not encrypted, instead, send stateless reset. - EXPECT_CALL(writer_, - WritePacket(_, _, self_address_.host(), peer_address_, _)) - .With(Args<0, 1>(PublicResetPacketEq(connection_id_))) - .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); - } else { - // An unprocessable connection close is sent to peer. - EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength, - self_address_.host(), peer_address_, _)) - .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); - } + // Termination packet is not encrypted, instead, send stateless reset. + EXPECT_CALL(writer_, + WritePacket(_, _, self_address_.host(), peer_address_, _)) + .With(Args<0, 1>(PublicResetPacketEq(connection_id_))) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); // Processes IETF short header packet. time_wait_list_manager_.ProcessPacket( self_address_, peer_address_, connection_id_, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc index 5fdab2d6f37..8b1b62a6278 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc @@ -78,8 +78,8 @@ void QuicTraceVisitor::OnPacketSent(const SerializedPacket& serialized_packet, // New IETF frames, not used in current gQUIC version. case NEW_CONNECTION_ID_FRAME: case RETIRE_CONNECTION_ID_FRAME: - case MAX_STREAM_ID_FRAME: - case STREAM_ID_BLOCKED_FRAME: + case MAX_STREAMS_FRAME: + case STREAMS_BLOCKED_FRAME: case PATH_RESPONSE_FRAME: case PATH_CHALLENGE_FRAME: case STOP_SENDING_FRAME: @@ -208,8 +208,8 @@ void QuicTraceVisitor::PopulateFrameInfo(const QuicFrame& frame, // New IETF frames, not used in current gQUIC version. case NEW_CONNECTION_ID_FRAME: case RETIRE_CONNECTION_ID_FRAME: - case MAX_STREAM_ID_FRAME: - case STREAM_ID_BLOCKED_FRAME: + case MAX_STREAMS_FRAME: + case STREAMS_BLOCKED_FRAME: case PATH_RESPONSE_FRAME: case PATH_CHALLENGE_FRAME: case STOP_SENDING_FRAME: @@ -278,7 +278,9 @@ void QuicTraceVisitor::OnApplicationLimited() { } void QuicTraceVisitor::OnAdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) { + QuicTime::Delta rtt, + QuicByteCount old_cwnd, + QuicByteCount new_cwnd) { quic_trace::Event* event = trace_.add_events(); event->set_time_us( ConvertTimestampToRecordedFormat(connection_->clock()->ApproximateNow())); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h index a70b150d653..8021865f852 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h @@ -42,7 +42,9 @@ class QuicTraceVisitor : public QuicConnectionDebugVisitor { void OnApplicationLimited() override; void OnAdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) override; + QuicTime::Delta rtt, + QuicByteCount old_cwnd, + QuicByteCount new_cwnd) override; // Returns a mutable pointer to the trace. The trace is owned by the // visitor, but can be moved using Swap() method after the connection is diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor_test.cc index 1a581534a9c..5e771336d9c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor_test.cc @@ -4,8 +4,6 @@ #include "net/third_party/quiche/src/quic/core/quic_trace_visitor.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc index c9e21d6190f..102b60ecf63 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc @@ -31,6 +31,12 @@ std::ostream& operator<<(std::ostream& os, const AckedPacket& acked_packet) { return os; } +std::ostream& operator<<(std::ostream& os, const LostPacket& lost_packet) { + os << "{ packet_number: " << lost_packet.packet_number + << ", bytes_lost: " << lost_packet.bytes_lost << "} "; + return os; +} + std::string HistogramEnumString(WriteStatus enum_value) { switch (enum_value) { case WRITE_STATUS_OK: diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.h b/chromium/net/third_party/quiche/src/quic/core/quic_types.h index 6f4cbe615c2..66a90c16562 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.h @@ -27,6 +27,10 @@ typedef uint32_t QuicMessageId; // TODO(fkastenholz): Should update this to 64 bits for V99. typedef uint32_t QuicStreamId; +// Count of stream IDs. Used in MAX_STREAMS and STREAMS_BLOCKED +// frames. +typedef uint32_t QuicStreamCount; + typedef uint64_t QuicByteCount; typedef uint64_t QuicPacketCount; typedef uint64_t QuicPublicResetNonceProof; @@ -169,8 +173,7 @@ enum class ConnectionCloseSource { FROM_PEER, FROM_SELF }; // Should a connection be closed silently or not. enum class ConnectionCloseBehavior { SILENT_CLOSE, - SEND_CONNECTION_CLOSE_PACKET, - SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK + SEND_CONNECTION_CLOSE_PACKET }; enum QuicFrameType : uint8_t { @@ -198,8 +201,8 @@ enum QuicFrameType : uint8_t { // QUIC has been negotiated. Values are not important, they are not // the values that are in the packets (see QuicIetfFrameType, below). NEW_CONNECTION_ID_FRAME, - MAX_STREAM_ID_FRAME, - STREAM_ID_BLOCKED_FRAME, + MAX_STREAMS_FRAME, + STREAMS_BLOCKED_FRAME, PATH_RESPONSE_FRAME, PATH_CHALLENGE_FRAME, STOP_SENDING_FRAME, @@ -296,6 +299,7 @@ enum QuicPacketNumberLength : uint8_t { PACKET_2BYTE_PACKET_NUMBER = 2, PACKET_3BYTE_PACKET_NUMBER = 3, // Used in version > QUIC_VERSION_44. PACKET_4BYTE_PACKET_NUMBER = 4, + IETF_MAX_PACKET_NUMBER_LENGTH = 4, // TODO(rch): Remove this when we remove QUIC_VERSION_39. PACKET_6BYTE_PACKET_NUMBER = 6, PACKET_8BYTE_PACKET_NUMBER = 8 @@ -386,6 +390,10 @@ enum EncryptionLevel : int8_t { NUM_ENCRYPTION_LEVELS, }; +inline bool EncryptionLevelIsValid(EncryptionLevel level) { + return ENCRYPTION_INITIAL <= level && level < NUM_ENCRYPTION_LEVELS; +} + enum AddressChangeType : uint8_t { // IP address and port remain unchanged. NO_CHANGE, @@ -476,6 +484,10 @@ struct LostPacket { LostPacket(QuicPacketNumber packet_number, QuicPacketLength bytes_lost) : packet_number(packet_number), bytes_lost(bytes_lost) {} + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const LostPacket& lost_packet); + QuicPacketNumber packet_number; // Number of bytes sent in the packet that was lost. QuicPacketLength bytes_lost; @@ -572,6 +584,9 @@ enum StreamType { // Unidirectional streams carry data in one direction only. WRITE_UNIDIRECTIONAL, READ_UNIDIRECTIONAL, + // Not actually a stream type. Used only by QuicCryptoStream when it uses + // CRYPTO frames and isn't actually a QuicStream. + CRYPTO, }; // A packet number space is the context in which a packet can be processed and diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc index 413a2446642..a7fe40f6730 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_prefetch.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" @@ -382,14 +383,23 @@ QuicStreamId QuicUtils::GetInvalidStreamId(QuicTransportVersion version) { // static QuicStreamId QuicUtils::GetCryptoStreamId(QuicTransportVersion version) { - // TODO(nharper): Change this to return GetInvalidStreamId for version 47 or - // greater. Currently, too many things break with that change. - return version == QUIC_VERSION_99 ? 0 : 1; + QUIC_BUG_IF(QuicVersionUsesCryptoFrames(version)) + << "CRYPTO data aren't in stream frames; they have no stream ID."; + return QuicVersionUsesCryptoFrames(version) ? GetInvalidStreamId(version) : 1; +} + +// static +bool QuicUtils::IsCryptoStreamId(QuicTransportVersion version, + QuicStreamId stream_id) { + if (QuicVersionUsesCryptoFrames(version)) { + return false; + } + return stream_id == GetCryptoStreamId(version); } // static QuicStreamId QuicUtils::GetHeadersStreamId(QuicTransportVersion version) { - return version == QUIC_VERSION_99 ? 4 : 3; + return GetFirstBidirectionalStreamId(version, Perspective::IS_CLIENT); } // static @@ -451,18 +461,26 @@ QuicStreamId QuicUtils::StreamIdDelta(QuicTransportVersion version) { QuicStreamId QuicUtils::GetFirstBidirectionalStreamId( QuicTransportVersion version, Perspective perspective) { - if (perspective == Perspective::IS_CLIENT) { - return version == QUIC_VERSION_99 ? 4 : 3; + if (version == QUIC_VERSION_99) { + return perspective == Perspective::IS_CLIENT ? 0 : 1; + } else if (QuicVersionUsesCryptoFrames(version)) { + return perspective == Perspective::IS_CLIENT ? 1 : 2; } - return version == QUIC_VERSION_99 ? 1 : 2; + return perspective == Perspective::IS_CLIENT ? 3 : 2; } // static QuicStreamId QuicUtils::GetFirstUnidirectionalStreamId( QuicTransportVersion version, Perspective perspective) { + if (version == QUIC_VERSION_99) { + return perspective == Perspective::IS_CLIENT ? 2 : 3; + } else if (QuicVersionUsesCryptoFrames(version)) { + return perspective == Perspective::IS_CLIENT ? 1 : 2; + } + return perspective == Perspective::IS_CLIENT ? 3 : 2; if (perspective == Perspective::IS_CLIENT) { - return version == QUIC_VERSION_99 ? 2 : 3; + return version == QUIC_VERSION_99 ? 2 : 1; } return version == QUIC_VERSION_99 ? 3 : 2; } @@ -505,7 +523,16 @@ QuicConnectionId QuicUtils::CreateRandomConnectionId( // static bool QuicUtils::VariableLengthConnectionIdAllowedForVersion( QuicTransportVersion version) { - return version >= QUIC_VERSION_47; + if (!GetQuicRestartFlag( + quic_allow_variable_length_connection_id_for_negotiation)) { + return version >= QUIC_VERSION_47; + } + QUIC_RESTART_FLAG_COUNT( + quic_allow_variable_length_connection_id_for_negotiation); + // We allow variable length connection IDs for unsupported versions to + // ensure that IETF version negotiation works when other implementations + // trigger version negotiation with custom connection ID lengths. + return version >= QUIC_VERSION_47 || version == QUIC_VERSION_UNSUPPORTED; } // static @@ -543,6 +570,24 @@ QuicUint128 QuicUtils::GenerateStatelessResetToken( QuicEndian::NetToHost64(data_bytes[0])); } +// Returns the maximum value that a stream count may have, taking into account +// the fact that bidirectional, client initiated, streams have one fewer stream +// available than the others. This is because the old crypto streams, with ID == +// 0 are not included in the count. +// The version is not included in the call, nor does the method take the version +// into account, because this is called only from code used for IETF QUIC. +// TODO(fkastenholz): Remove this method and replace calls to it with direct +// references to kMaxQuicStreamIdCount when streamid 0 becomes a normal stream +// id. +// static +QuicStreamCount QuicUtils::GetMaxStreamCount(bool unidirectional, + Perspective perspective) { + if (!unidirectional && perspective == Perspective::IS_CLIENT) { + return kMaxQuicStreamCount >> 2; + } + return (kMaxQuicStreamCount >> 2) + 1; +} + // static PacketNumberSpace QuicUtils::GetPacketNumberSpace( EncryptionLevel encryption_level) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h index cacbc60219a..bac025e79a0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h @@ -116,6 +116,11 @@ class QUIC_EXPORT_PRIVATE QuicUtils { // Returns crypto stream ID of |version|. static QuicStreamId GetCryptoStreamId(QuicTransportVersion version); + // Returns whether |id| is the stream ID for the crypto stream. If |version| + // is a version where crypto data doesn't go over stream frames, this function + // will always return false. + static bool IsCryptoStreamId(QuicTransportVersion version, QuicStreamId id); + // Returns headers stream ID of |version|. static QuicStreamId GetHeadersStreamId(QuicTransportVersion version); @@ -190,6 +195,12 @@ class QUIC_EXPORT_PRIVATE QuicUtils { // Determines encryption level to send packets in |packet_number_space|. static EncryptionLevel GetEncryptionLevel( PacketNumberSpace packet_number_space); + + // Get the maximum value for a V99/IETF QUIC stream count. If a count + // exceeds this value, it will result in a stream ID that exceeds the + // implementation limit on stream ID size. + static QuicStreamCount GetMaxStreamCount(bool unidirectional, + Perspective perspective); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc index 62b2e44dd7a..5874f92abb7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc @@ -18,7 +18,6 @@ QuicVersionManager::QuicVersionManager( enable_version_47_(GetQuicReloadableFlag(quic_enable_version_47)), enable_version_46_(GetQuicReloadableFlag(quic_enable_version_46)), enable_version_44_(GetQuicReloadableFlag(quic_enable_version_44)), - enable_version_43_(GetQuicReloadableFlag(quic_enable_version_43)), disable_version_39_(GetQuicReloadableFlag(quic_disable_version_39)), allowed_supported_versions_(std::move(supported_versions)) { RefilterSupportedVersions(); @@ -42,13 +41,11 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() { enable_version_47_ != GetQuicReloadableFlag(quic_enable_version_47) || enable_version_46_ != GetQuicReloadableFlag(quic_enable_version_46) || enable_version_44_ != GetQuicReloadableFlag(quic_enable_version_44) || - enable_version_43_ != GetQuicReloadableFlag(quic_enable_version_43) || disable_version_39_ != GetQuicReloadableFlag(quic_disable_version_39)) { enable_version_99_ = GetQuicReloadableFlag(quic_enable_version_99); enable_version_47_ = GetQuicReloadableFlag(quic_enable_version_47); enable_version_46_ = GetQuicReloadableFlag(quic_enable_version_46); enable_version_44_ = GetQuicReloadableFlag(quic_enable_version_44); - enable_version_43_ = GetQuicReloadableFlag(quic_enable_version_43); disable_version_39_ = GetQuicReloadableFlag(quic_disable_version_39); RefilterSupportedVersions(); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h index 4fedae35baa..db9f2c5880e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h @@ -46,8 +46,6 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager { bool enable_version_46_; // quic_enable_version_44 flag bool enable_version_44_; - // quic_enable_version_43 flag - bool enable_version_43_; // quic_disable_version_39 flag bool disable_version_39_; // The list of versions that may be supported. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc index 7c7a08d655c..9a7b2a328be 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc @@ -22,20 +22,16 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) { SetQuicReloadableFlag(quic_enable_version_47, false); SetQuicReloadableFlag(quic_enable_version_46, false); SetQuicReloadableFlag(quic_enable_version_44, false); - SetQuicReloadableFlag(quic_enable_version_43, false); SetQuicReloadableFlag(quic_disable_version_39, true); QuicVersionManager manager(AllSupportedVersions()); EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()), manager.GetSupportedTransportVersions()); - EXPECT_TRUE(manager.GetSupportedTransportVersions().empty()); - - SetQuicReloadableFlag(quic_disable_version_39, false); - EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_39}), + EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_43}), manager.GetSupportedTransportVersions()); - SetQuicReloadableFlag(quic_enable_version_43, true); + SetQuicReloadableFlag(quic_disable_version_39, false); EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_43, QUIC_VERSION_39}), manager.GetSupportedTransportVersions()); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc index a37f3a7b433..6873eddfe12 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc @@ -32,16 +32,35 @@ ParsedQuicVersion::ParsedQuicVersion(HandshakeProtocol handshake_protocol, : handshake_protocol(handshake_protocol), transport_version(transport_version) { if (handshake_protocol == PROTOCOL_TLS1_3 && - !FLAGS_quic_supports_tls_handshake) { + !GetQuicFlag(FLAGS_quic_supports_tls_handshake)) { QUIC_BUG << "TLS use attempted when not enabled"; } } bool ParsedQuicVersion::KnowsWhichDecrypterToUse() const { - return transport_version == QUIC_VERSION_99 || + return transport_version >= QUIC_VERSION_47 || handshake_protocol == PROTOCOL_TLS1_3; } +bool ParsedQuicVersion::AllowsLowFlowControlLimits() const { + return transport_version == QUIC_VERSION_99 && + handshake_protocol == PROTOCOL_TLS1_3; +} + +bool ParsedQuicVersion::HasHeaderProtection() const { + return transport_version == QUIC_VERSION_99; +} + +bool ParsedQuicVersion::SupportsRetry() const { + return transport_version > QUIC_VERSION_46; +} + +bool ParsedQuicVersion::SupportsClientConnectionIds() const { + // This will be enabled in v99 after the rest of the client connection ID + // code lands. + return false; +} + std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) { os << ParsedQuicVersionToString(version); return os; @@ -75,9 +94,12 @@ QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { case QUIC_VERSION_99: if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3 && GetQuicFlag(FLAGS_quic_ietf_draft_version) != 0) { - return 0xff000000 + GetQuicFlag(FLAGS_quic_ietf_draft_version); + return MakeVersionLabel(0xff, 0x00, 0x00, + GetQuicFlag(FLAGS_quic_ietf_draft_version)); } return MakeVersionLabel(proto, '0', '9', '9'); + case QUIC_VERSION_RESERVED_FOR_NEGOTIATION: + return MakeVersionLabel(0xda, 0x5a, 0x3a, 0x3a); default: // This shold be an ERROR because we should never attempt to convert an // invalid QuicTransportVersion to be written to the wire. @@ -99,7 +121,7 @@ QuicVersionLabelVector CreateQuicVersionLabelVector( ParsedQuicVersion ParseQuicVersionLabel(QuicVersionLabel version_label) { std::vector<HandshakeProtocol> protocols = {PROTOCOL_QUIC_CRYPTO}; - if (FLAGS_quic_supports_tls_handshake) { + if (GetQuicFlag(FLAGS_quic_supports_tls_handshake)) { protocols.push_back(PROTOCOL_TLS1_3); } for (QuicTransportVersion version : kSupportedTransportVersions) { @@ -129,7 +151,7 @@ ParsedQuicVersion ParseQuicVersionString(std::string version_string) { } std::vector<HandshakeProtocol> protocols = {PROTOCOL_QUIC_CRYPTO}; - if (FLAGS_quic_supports_tls_handshake) { + if (GetQuicFlag(FLAGS_quic_supports_tls_handshake)) { protocols.push_back(PROTOCOL_TLS1_3); } for (QuicTransportVersion version : kSupportedTransportVersions) { @@ -142,7 +164,8 @@ ParsedQuicVersion ParseQuicVersionString(std::string version_string) { } } // Still recognize T099 even if flag quic_ietf_draft_version has been changed. - if (FLAGS_quic_supports_tls_handshake && version_string == "T099") { + if (GetQuicFlag(FLAGS_quic_supports_tls_handshake) && + version_string == "T099") { return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); } // Reading from the client so this should not be considered an ERROR. @@ -162,7 +185,8 @@ QuicTransportVersionVector AllSupportedTransportVersions() { ParsedQuicVersionVector AllSupportedVersions() { ParsedQuicVersionVector supported_versions; for (HandshakeProtocol protocol : kSupportedHandshakeProtocols) { - if (protocol == PROTOCOL_TLS1_3 && !FLAGS_quic_supports_tls_handshake) { + if (protocol == PROTOCOL_TLS1_3 && + !GetQuicFlag(FLAGS_quic_supports_tls_handshake)) { continue; } for (QuicTransportVersion version : kSupportedTransportVersions) { @@ -212,30 +236,22 @@ ParsedQuicVersionVector FilterSupportedVersions( if (GetQuicReloadableFlag(quic_enable_version_99) && GetQuicReloadableFlag(quic_enable_version_47) && GetQuicReloadableFlag(quic_enable_version_46) && - GetQuicReloadableFlag(quic_enable_version_44) && - GetQuicReloadableFlag(quic_enable_version_43)) { + GetQuicReloadableFlag(quic_enable_version_44)) { filtered_versions.push_back(version); } } else if (version.transport_version == QUIC_VERSION_47) { if (GetQuicReloadableFlag(quic_enable_version_47) && GetQuicReloadableFlag(quic_enable_version_46) && - GetQuicReloadableFlag(quic_enable_version_44) && - GetQuicReloadableFlag(quic_enable_version_43)) { + GetQuicReloadableFlag(quic_enable_version_44)) { filtered_versions.push_back(version); } } else if (version.transport_version == QUIC_VERSION_46) { if (GetQuicReloadableFlag(quic_enable_version_46) && - GetQuicReloadableFlag(quic_enable_version_44) && - GetQuicReloadableFlag(quic_enable_version_43)) { + GetQuicReloadableFlag(quic_enable_version_44)) { filtered_versions.push_back(version); } } else if (version.transport_version == QUIC_VERSION_44) { - if (GetQuicReloadableFlag(quic_enable_version_44) && - GetQuicReloadableFlag(quic_enable_version_43)) { - filtered_versions.push_back(version); - } - } else if (version.transport_version == QUIC_VERSION_43) { - if (GetQuicReloadableFlag(quic_enable_version_43)) { + if (GetQuicReloadableFlag(quic_enable_version_44)) { filtered_versions.push_back(version); } } else if (version.transport_version == QUIC_VERSION_39) { @@ -379,6 +395,11 @@ ParsedQuicVersion UnsupportedQuicVersion() { return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED); } +ParsedQuicVersion QuicVersionReservedForNegotiation() { + return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, + QUIC_VERSION_RESERVED_FOR_NEGOTIATION); +} + std::string AlpnForVersion(ParsedQuicVersion parsed_version) { if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3 && parsed_version.transport_version == QUIC_VERSION_99 && @@ -395,26 +416,37 @@ void QuicVersionInitializeSupportForIetfDraft(int32_t draft_version) { return; } - SetQuicFlag(&FLAGS_quic_ietf_draft_version, draft_version); + SetQuicFlag(FLAGS_quic_ietf_draft_version, draft_version); if (draft_version == 0) { return; } // Enable necessary flags. - SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); SetQuicReloadableFlag(quic_deprecate_ack_bundling_mode, true); SetQuicReloadableFlag(quic_rpm_decides_when_to_send_acks, true); SetQuicReloadableFlag(quic_use_uber_loss_algorithm, true); SetQuicReloadableFlag(quic_use_uber_received_packet_manager, true); SetQuicReloadableFlag(quic_validate_packet_number_post_decryption, true); SetQuicReloadableFlag(quic_print_tag_hex, true); + SetQuicReloadableFlag(quic_send_version_negotiation_fixed_bit, true); + SetQuicReloadableFlag(quic_no_client_conn_ver_negotiation, true); + SetQuicReloadableFlag(quic_eliminate_static_stream_map_3, true); + SetQuicReloadableFlag(quic_tolerate_reneging, true); + SetQuicReloadableFlag(quic_simplify_stop_waiting, true); + SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, true); + SetQuicRestartFlag(quic_server_drop_version_negotiation, true); SetQuicRestartFlag(quic_enable_accept_random_ipn, true); + SetQuicRestartFlag(quic_allow_variable_length_connection_id_for_negotiation, + true); + SetQuicRestartFlag(quic_do_not_override_connection_id, true); + SetQuicRestartFlag(quic_no_framer_object_in_dispatcher, true); } void QuicEnableVersion(ParsedQuicVersion parsed_version) { if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) { - SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); } static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); @@ -430,9 +462,6 @@ void QuicEnableVersion(ParsedQuicVersion parsed_version) { if (parsed_version.transport_version >= QUIC_VERSION_44) { SetQuicReloadableFlag(quic_enable_version_44, true); } - if (parsed_version.transport_version >= QUIC_VERSION_43) { - SetQuicReloadableFlag(quic_enable_version_43, true); - } } #undef RETURN_STRING_LITERAL // undef for jumbo builds diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h index 160adeb7f59..0a368dfc0bb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h @@ -106,6 +106,11 @@ enum QuicTransportVersion { QUIC_VERSION_47 = 47, // Allow variable-length QUIC connection IDs. QUIC_VERSION_99 = 99, // Dumping ground for IETF QUIC changes which are not // yet ready for production. + // QUIC_VERSION_RESERVED_FOR_NEGOTIATION is sent over the wire as da5a3a3a + // which is part of a range reserved by the IETF for version negotiation + // testing. It is intentionally meant to never be supported by servers to + // trigger version negotiation when proposed by clients. + QUIC_VERSION_RESERVED_FOR_NEGOTIATION = 999, }; // The crypto handshake protocols that can be used with QUIC. @@ -147,10 +152,25 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion { } bool KnowsWhichDecrypterToUse() const; + + // Indicates that this QUIC version does not have an enforced minimum value + // for flow control values negotiated during the handshake. + bool AllowsLowFlowControlLimits() const; + + // Returns whether header protection is used in this version of QUIC. + bool HasHeaderProtection() const; + + // Returns whether this version supports IETF RETRY packets. + bool SupportsRetry() const; + + // Returns whether this version supports client connection ID. + bool SupportsClientConnectionIds() const; }; QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion(); +QUIC_EXPORT_PRIVATE ParsedQuicVersion QuicVersionReservedForNegotiation(); + QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version); @@ -323,13 +343,23 @@ QUIC_EXPORT_PRIVATE inline bool VersionHasDataFrameHeader( return transport_version == QUIC_VERSION_99; } -// Returns true if QuicSpdySession instantiates a QPACK encoder and decoder. +// If true: +// * QuicSpdySession instantiates a QPACK encoder and decoder; +// * HEADERS frames (containing headers or trailers) are sent on +// request/response streams, compressed with QPACK; +// * trailers must not contain :final-offset key. +// If false: +// * HEADERS frames (containing headers or trailers) are sent on the headers +// stream, compressed with HPACK; +// * trailers must contain :final-offset key. +// // TODO(123528590): Implement the following features and gate them on this -// function as well, optionally renaming this function as appropriate. -// Send HEADERS on the request/response stream instead of the headers stream. -// Send PUSH_PROMISE on the request/response stream instead of headers stream. -// Send PRIORITY on the request/response stream instead of the headers stream. -// Do not instantiate the headers stream object. +// function as well, optionally renaming this function as appropriate: +// * send PUSH_PROMISE frames on the request/response stream instead of the +// headers stream; +// * send PRIORITY frames on the request/response stream instead of the headers +// stream; +// * do not instantiate the headers stream object. QUIC_EXPORT_PRIVATE inline bool VersionUsesQpack( QuicTransportVersion transport_version) { const bool uses_qpack = (transport_version == QUIC_VERSION_99); @@ -355,8 +385,8 @@ QUIC_EXPORT_PRIVATE inline bool QuicVersionUsesCryptoFrames( return transport_version == QUIC_VERSION_99; } -// Returns whether |transport_version| has HTTP/3 Control stream. -QUIC_EXPORT_PRIVATE inline bool VersionHasControlStreams( +// Returns whether |transport_version| has HTTP/3 stream type. +QUIC_EXPORT_PRIVATE inline bool VersionHasStreamType( QuicTransportVersion transport_version) { return transport_version == QUIC_VERSION_99; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc index b04db0caff1..c19e621fd0a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc @@ -116,11 +116,11 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToHandshakeProtocol) { } // Test a TLS version: - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); QuicTag tls_tag = MakeQuicTag('3', '4', '0', 'T'); EXPECT_EQ(PROTOCOL_TLS1_3, QuicVersionLabelToHandshakeProtocol(tls_tag)); - FLAGS_quic_supports_tls_handshake = false; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, false); if (QUIC_DLOG_INFO_IS_ON()) { EXPECT_QUIC_LOG_CALL_CONTAINS(log, INFO, "Unsupported QuicVersionLabel version: T043") @@ -142,7 +142,7 @@ TEST_F(QuicVersionsTest, ParseQuicVersionLabel) { ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '7'))); // Test a TLS version: - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '9'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43), @@ -154,7 +154,7 @@ TEST_F(QuicVersionsTest, ParseQuicVersionLabel) { EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7'))); - FLAGS_quic_supports_tls_handshake = false; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, false); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '5'))); EXPECT_EQ(UnsupportedQuicVersion(), @@ -188,7 +188,7 @@ TEST_F(QuicVersionsTest, ParseQuicVersionString) { EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q047 ")); // Test a TLS version: - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39), ParseQuicVersionString("T039")); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43), @@ -200,7 +200,7 @@ TEST_F(QuicVersionsTest, ParseQuicVersionString) { EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47), ParseQuicVersionString("T047")); - FLAGS_quic_supports_tls_handshake = false; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, false); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T035")); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T039")); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T043")); @@ -228,7 +228,7 @@ TEST_F(QuicVersionsTest, CreateQuicVersionLabel) { ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47))); // Test a TLS version: - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); EXPECT_EQ(MakeVersionLabel('T', '0', '3', '9'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39))); @@ -245,7 +245,7 @@ TEST_F(QuicVersionsTest, CreateQuicVersionLabel) { CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47))); - FLAGS_quic_supports_tls_handshake = false; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, false); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '5'))); EXPECT_EQ(UnsupportedQuicVersion(), @@ -323,7 +323,7 @@ TEST_F(QuicVersionsTest, ParsedQuicVersionToString) { // Make sure that all supported versions are present in // ParsedQuicVersionToString. - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); for (QuicTransportVersion transport_version : kSupportedTransportVersions) { for (HandshakeProtocol protocol : kSupportedHandshakeProtocols) { EXPECT_NE("0", ParsedQuicVersionToString( @@ -342,7 +342,6 @@ TEST_F(QuicVersionsTest, AllSupportedTransportVersions) { TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); SetQuicReloadableFlag(quic_enable_version_46, true); SetQuicReloadableFlag(quic_enable_version_47, true); @@ -367,7 +366,6 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) { TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); SetQuicReloadableFlag(quic_enable_version_46, true); SetQuicReloadableFlag(quic_enable_version_47, true); @@ -392,7 +390,6 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) { TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); SetQuicReloadableFlag(quic_enable_version_46, true); SetQuicReloadableFlag(quic_enable_version_47, false); @@ -416,7 +413,6 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) { TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo46) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); SetQuicReloadableFlag(quic_enable_version_46, false); SetQuicReloadableFlag(quic_enable_version_47, false); @@ -440,7 +436,6 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo46) { TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo44) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, false); SetQuicReloadableFlag(quic_enable_version_46, false); SetQuicReloadableFlag(quic_enable_version_47, false); @@ -461,33 +456,9 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo44) { ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); } -TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo43) { - QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_43, false); - SetQuicReloadableFlag(quic_enable_version_44, false); - SetQuicReloadableFlag(quic_enable_version_46, false); - SetQuicReloadableFlag(quic_enable_version_47, false); - SetQuicReloadableFlag(quic_enable_version_99, false); - ParsedQuicVersionVector parsed_versions; - for (QuicTransportVersion version : all_versions) { - parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - QuicTransportVersionVector expected_versions = {QUIC_VERSION_39}; - ParsedQuicVersionVector expected_parsed_versions; - for (QuicTransportVersion version : expected_versions) { - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - - ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions)); - ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); -} - TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo39) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); SetQuicReloadableFlag(quic_disable_version_39, true); - SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, false); SetQuicReloadableFlag(quic_enable_version_46, false); SetQuicReloadableFlag(quic_enable_version_47, false); @@ -557,14 +528,14 @@ TEST_F(QuicVersionsTest, CheckVersionNumbersForTypos) { } TEST_F(QuicVersionsTest, AlpnForVersion) { - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); ParsedQuicVersion parsed_version_q047 = ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47); ParsedQuicVersion parsed_version_t047 = ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47); ParsedQuicVersion parsed_version_t099 = ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); - FLAGS_quic_supports_tls_handshake = false; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, false); EXPECT_EQ("h3-google-Q047", AlpnForVersion(parsed_version_q047)); EXPECT_EQ("h3-google-T047", AlpnForVersion(parsed_version_t047)); @@ -572,10 +543,10 @@ TEST_F(QuicVersionsTest, AlpnForVersion) { } TEST_F(QuicVersionsTest, InitializeSupportForIetfDraft) { - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); ParsedQuicVersion parsed_version_t099 = ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); - FLAGS_quic_supports_tls_handshake = false; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, false); EXPECT_EQ(MakeVersionLabel('T', '0', '9', '9'), CreateQuicVersionLabel(parsed_version_t099)); EXPECT_EQ("h3-google-T099", AlpnForVersion(parsed_version_t099)); @@ -584,10 +555,10 @@ TEST_F(QuicVersionsTest, InitializeSupportForIetfDraft) { EXPECT_EQ(MakeVersionLabel('T', '0', '9', '9'), CreateQuicVersionLabel(parsed_version_t099)); EXPECT_EQ("h3-google-T099", AlpnForVersion(parsed_version_t099)); - EXPECT_FALSE(FLAGS_quic_supports_tls_handshake); + EXPECT_FALSE(GetQuicFlag(FLAGS_quic_supports_tls_handshake)); QuicVersionInitializeSupportForIetfDraft(18); - EXPECT_TRUE(FLAGS_quic_supports_tls_handshake); + EXPECT_TRUE(GetQuicFlag(FLAGS_quic_supports_tls_handshake)); EXPECT_EQ(MakeVersionLabel(0xff, 0, 0, 18), CreateQuicVersionLabel(parsed_version_t099)); EXPECT_EQ("h3-18", AlpnForVersion(parsed_version_t099)); @@ -599,37 +570,47 @@ TEST_F(QuicVersionsTest, InitializeSupportForIetfDraft) { } TEST_F(QuicVersionsTest, QuicEnableVersion) { - FLAGS_quic_supports_tls_handshake = true; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); ParsedQuicVersion parsed_version_q047 = ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47); ParsedQuicVersion parsed_version_t047 = ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47); ParsedQuicVersion parsed_version_t099 = ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); - FLAGS_quic_supports_tls_handshake = false; + SetQuicFlag(FLAGS_quic_supports_tls_handshake, false); SetQuicReloadableFlag(quic_disable_version_39, false); - SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); SetQuicReloadableFlag(quic_enable_version_46, true); SetQuicReloadableFlag(quic_enable_version_47, false); SetQuicReloadableFlag(quic_enable_version_99, false); QuicEnableVersion(parsed_version_q047); - EXPECT_FALSE(FLAGS_quic_supports_tls_handshake); + EXPECT_FALSE(GetQuicFlag(FLAGS_quic_supports_tls_handshake)); EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47)); EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); QuicEnableVersion(parsed_version_t047); - EXPECT_TRUE(FLAGS_quic_supports_tls_handshake); + EXPECT_TRUE(GetQuicFlag(FLAGS_quic_supports_tls_handshake)); EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47)); EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); QuicEnableVersion(parsed_version_t099); - EXPECT_TRUE(FLAGS_quic_supports_tls_handshake); + EXPECT_TRUE(GetQuicFlag(FLAGS_quic_supports_tls_handshake)); EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47)); EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_99)); } +TEST_F(QuicVersionsTest, ReservedForNegotiation) { + EXPECT_EQ(QUIC_VERSION_RESERVED_FOR_NEGOTIATION, + QuicVersionReservedForNegotiation().transport_version); + // QUIC_VERSION_RESERVED_FOR_NEGOTIATION MUST NOT be added to + // kSupportedTransportVersions. + for (size_t i = 0; i < QUIC_ARRAYSIZE(kSupportedTransportVersions); ++i) { + EXPECT_NE(QUIC_VERSION_RESERVED_FOR_NEGOTIATION, + kSupportedTransportVersions[i]); + } +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc index e3929557caf..d7fe3c0e554 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc @@ -9,7 +9,11 @@ namespace quic { -QuicWriteBlockedList::QuicWriteBlockedList() : last_priority_popped_(0) { +QuicWriteBlockedList::QuicWriteBlockedList(QuicTransportVersion version) + : priority_write_scheduler_(QuicVersionUsesCryptoFrames(version) + ? std::numeric_limits<QuicStreamId>::max() + : 0), + last_priority_popped_(0) { memset(batch_write_stream_id_, 0, sizeof(batch_write_stream_id_)); memset(bytes_left_for_batch_write_, 0, sizeof(bytes_left_for_batch_write_)); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h index 83c2e2069be..eca7c1a29ab 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h @@ -24,7 +24,7 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { typedef spdy::PriorityWriteScheduler<QuicStreamId> QuicPriorityWriteScheduler; public: - explicit QuicWriteBlockedList(); + explicit QuicWriteBlockedList(QuicTransportVersion version); QuicWriteBlockedList(const QuicWriteBlockedList&) = delete; QuicWriteBlockedList& operator=(const QuicWriteBlockedList&) = delete; ~QuicWriteBlockedList(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list_test.cc index a9319e333e6..30bb08ef010 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list_test.cc @@ -14,218 +14,214 @@ namespace quic { namespace test { namespace { -class QuicWriteBlockedListTest : public QuicTest {}; +class QuicWriteBlockedListTest : public QuicTest { + public: + QuicWriteBlockedListTest() + : write_blocked_list_(AllSupportedVersions()[0].transport_version) {} -TEST_F(QuicWriteBlockedListTest, PriorityOrder) { - QuicWriteBlockedList write_blocked_list; + protected: + QuicWriteBlockedList write_blocked_list_; +}; +TEST_F(QuicWriteBlockedListTest, PriorityOrder) { // Mark streams blocked in roughly reverse priority order, and // verify that streams are sorted. - write_blocked_list.RegisterStream(40, false, kV3LowestPriority); - write_blocked_list.RegisterStream(23, false, kV3HighestPriority); - write_blocked_list.RegisterStream(17, false, kV3HighestPriority); - write_blocked_list.RegisterStream(1, true, kV3HighestPriority); - write_blocked_list.RegisterStream(3, true, kV3HighestPriority); - - write_blocked_list.AddStream(40); - EXPECT_TRUE(write_blocked_list.IsStreamBlocked(40)); - write_blocked_list.AddStream(23); - EXPECT_TRUE(write_blocked_list.IsStreamBlocked(23)); - write_blocked_list.AddStream(17); - EXPECT_TRUE(write_blocked_list.IsStreamBlocked(17)); - write_blocked_list.AddStream(3); - EXPECT_TRUE(write_blocked_list.IsStreamBlocked(3)); - write_blocked_list.AddStream(1); - EXPECT_TRUE(write_blocked_list.IsStreamBlocked(1)); - - EXPECT_EQ(5u, write_blocked_list.NumBlockedStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedSpecialStream()); - EXPECT_EQ(2u, write_blocked_list.NumBlockedSpecialStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams()); + write_blocked_list_.RegisterStream(40, false, kV3LowestPriority); + write_blocked_list_.RegisterStream(23, false, kV3HighestPriority); + write_blocked_list_.RegisterStream(17, false, kV3HighestPriority); + write_blocked_list_.RegisterStream(1, true, kV3HighestPriority); + write_blocked_list_.RegisterStream(3, true, kV3HighestPriority); + + write_blocked_list_.AddStream(40); + EXPECT_TRUE(write_blocked_list_.IsStreamBlocked(40)); + write_blocked_list_.AddStream(23); + EXPECT_TRUE(write_blocked_list_.IsStreamBlocked(23)); + write_blocked_list_.AddStream(17); + EXPECT_TRUE(write_blocked_list_.IsStreamBlocked(17)); + write_blocked_list_.AddStream(3); + EXPECT_TRUE(write_blocked_list_.IsStreamBlocked(3)); + write_blocked_list_.AddStream(1); + EXPECT_TRUE(write_blocked_list_.IsStreamBlocked(1)); + + EXPECT_EQ(5u, write_blocked_list_.NumBlockedStreams()); + EXPECT_TRUE(write_blocked_list_.HasWriteBlockedSpecialStream()); + EXPECT_EQ(2u, write_blocked_list_.NumBlockedSpecialStreams()); + EXPECT_TRUE(write_blocked_list_.HasWriteBlockedDataStreams()); // The Crypto stream is highest priority. - EXPECT_EQ(1u, write_blocked_list.PopFront()); - EXPECT_EQ(1u, write_blocked_list.NumBlockedSpecialStreams()); - EXPECT_FALSE(write_blocked_list.IsStreamBlocked(1)); + EXPECT_EQ(1u, write_blocked_list_.PopFront()); + EXPECT_EQ(1u, write_blocked_list_.NumBlockedSpecialStreams()); + EXPECT_FALSE(write_blocked_list_.IsStreamBlocked(1)); // Followed by the Headers stream. - EXPECT_EQ(3u, write_blocked_list.PopFront()); - EXPECT_EQ(0u, write_blocked_list.NumBlockedSpecialStreams()); - EXPECT_FALSE(write_blocked_list.IsStreamBlocked(3)); + EXPECT_EQ(3u, write_blocked_list_.PopFront()); + EXPECT_EQ(0u, write_blocked_list_.NumBlockedSpecialStreams()); + EXPECT_FALSE(write_blocked_list_.IsStreamBlocked(3)); // Streams with same priority are popped in the order they were inserted. - EXPECT_EQ(23u, write_blocked_list.PopFront()); - EXPECT_FALSE(write_blocked_list.IsStreamBlocked(23)); - EXPECT_EQ(17u, write_blocked_list.PopFront()); - EXPECT_FALSE(write_blocked_list.IsStreamBlocked(17)); + EXPECT_EQ(23u, write_blocked_list_.PopFront()); + EXPECT_FALSE(write_blocked_list_.IsStreamBlocked(23)); + EXPECT_EQ(17u, write_blocked_list_.PopFront()); + EXPECT_FALSE(write_blocked_list_.IsStreamBlocked(17)); // Low priority stream appears last. - EXPECT_EQ(40u, write_blocked_list.PopFront()); - EXPECT_FALSE(write_blocked_list.IsStreamBlocked(40)); + EXPECT_EQ(40u, write_blocked_list_.PopFront()); + EXPECT_FALSE(write_blocked_list_.IsStreamBlocked(40)); - EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedSpecialStream()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams()); + EXPECT_EQ(0u, write_blocked_list_.NumBlockedStreams()); + EXPECT_FALSE(write_blocked_list_.HasWriteBlockedSpecialStream()); + EXPECT_FALSE(write_blocked_list_.HasWriteBlockedDataStreams()); } TEST_F(QuicWriteBlockedListTest, CryptoStream) { - QuicWriteBlockedList write_blocked_list; - write_blocked_list.RegisterStream(1, true, kV3HighestPriority); - write_blocked_list.AddStream(1); - - EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedSpecialStream()); - EXPECT_EQ(1u, write_blocked_list.PopFront()); - EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedSpecialStream()); + write_blocked_list_.RegisterStream(1, true, kV3HighestPriority); + write_blocked_list_.AddStream(1); + + EXPECT_EQ(1u, write_blocked_list_.NumBlockedStreams()); + EXPECT_TRUE(write_blocked_list_.HasWriteBlockedSpecialStream()); + EXPECT_EQ(1u, write_blocked_list_.PopFront()); + EXPECT_EQ(0u, write_blocked_list_.NumBlockedStreams()); + EXPECT_FALSE(write_blocked_list_.HasWriteBlockedSpecialStream()); } TEST_F(QuicWriteBlockedListTest, HeadersStream) { - QuicWriteBlockedList write_blocked_list; - write_blocked_list.RegisterStream(3, true, kV3HighestPriority); - write_blocked_list.AddStream(3); - - EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedSpecialStream()); - EXPECT_EQ(3u, write_blocked_list.PopFront()); - EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedSpecialStream()); + write_blocked_list_.RegisterStream(3, true, kV3HighestPriority); + write_blocked_list_.AddStream(3); + + EXPECT_EQ(1u, write_blocked_list_.NumBlockedStreams()); + EXPECT_TRUE(write_blocked_list_.HasWriteBlockedSpecialStream()); + EXPECT_EQ(3u, write_blocked_list_.PopFront()); + EXPECT_EQ(0u, write_blocked_list_.NumBlockedStreams()); + EXPECT_FALSE(write_blocked_list_.HasWriteBlockedSpecialStream()); } TEST_F(QuicWriteBlockedListTest, VerifyHeadersStream) { - QuicWriteBlockedList write_blocked_list; - write_blocked_list.RegisterStream(5, false, kV3HighestPriority); - write_blocked_list.RegisterStream(3, true, kV3HighestPriority); - write_blocked_list.AddStream(5); - write_blocked_list.AddStream(3); - - EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedSpecialStream()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams()); + write_blocked_list_.RegisterStream(5, false, kV3HighestPriority); + write_blocked_list_.RegisterStream(3, true, kV3HighestPriority); + write_blocked_list_.AddStream(5); + write_blocked_list_.AddStream(3); + + EXPECT_EQ(2u, write_blocked_list_.NumBlockedStreams()); + EXPECT_TRUE(write_blocked_list_.HasWriteBlockedSpecialStream()); + EXPECT_TRUE(write_blocked_list_.HasWriteBlockedDataStreams()); // In newer QUIC versions, there is a headers stream which is // higher priority than data streams. - EXPECT_EQ(3u, write_blocked_list.PopFront()); - EXPECT_EQ(5u, write_blocked_list.PopFront()); - EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedSpecialStream()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams()); + EXPECT_EQ(3u, write_blocked_list_.PopFront()); + EXPECT_EQ(5u, write_blocked_list_.PopFront()); + EXPECT_EQ(0u, write_blocked_list_.NumBlockedStreams()); + EXPECT_FALSE(write_blocked_list_.HasWriteBlockedSpecialStream()); + EXPECT_FALSE(write_blocked_list_.HasWriteBlockedDataStreams()); } TEST_F(QuicWriteBlockedListTest, NoDuplicateEntries) { // Test that QuicWriteBlockedList doesn't allow duplicate entries. - QuicWriteBlockedList write_blocked_list; - // Try to add a stream to the write blocked list multiple times at the same // priority. const QuicStreamId kBlockedId = 3 + 2; - write_blocked_list.RegisterStream(kBlockedId, false, kV3HighestPriority); - write_blocked_list.AddStream(kBlockedId); - write_blocked_list.AddStream(kBlockedId); - write_blocked_list.AddStream(kBlockedId); + write_blocked_list_.RegisterStream(kBlockedId, false, kV3HighestPriority); + write_blocked_list_.AddStream(kBlockedId); + write_blocked_list_.AddStream(kBlockedId); + write_blocked_list_.AddStream(kBlockedId); // This should only result in one blocked stream being added. - EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams()); + EXPECT_EQ(1u, write_blocked_list_.NumBlockedStreams()); + EXPECT_TRUE(write_blocked_list_.HasWriteBlockedDataStreams()); // There should only be one stream to pop off the front. - EXPECT_EQ(kBlockedId, write_blocked_list.PopFront()); - EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams()); + EXPECT_EQ(kBlockedId, write_blocked_list_.PopFront()); + EXPECT_EQ(0u, write_blocked_list_.NumBlockedStreams()); + EXPECT_FALSE(write_blocked_list_.HasWriteBlockedDataStreams()); } TEST_F(QuicWriteBlockedListTest, BatchingWrites) { - QuicWriteBlockedList write_blocked_list; - const QuicStreamId id1 = 3 + 2; const QuicStreamId id2 = id1 + 2; const QuicStreamId id3 = id2 + 2; - write_blocked_list.RegisterStream(id1, false, kV3LowestPriority); - write_blocked_list.RegisterStream(id2, false, kV3LowestPriority); - write_blocked_list.RegisterStream(id3, false, kV3HighestPriority); + write_blocked_list_.RegisterStream(id1, false, kV3LowestPriority); + write_blocked_list_.RegisterStream(id2, false, kV3LowestPriority); + write_blocked_list_.RegisterStream(id3, false, kV3HighestPriority); - write_blocked_list.AddStream(id1); - write_blocked_list.AddStream(id2); - EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams()); + write_blocked_list_.AddStream(id1); + write_blocked_list_.AddStream(id2); + EXPECT_EQ(2u, write_blocked_list_.NumBlockedStreams()); // The first stream we push back should stay at the front until 16k is // written. - EXPECT_EQ(id1, write_blocked_list.PopFront()); - write_blocked_list.UpdateBytesForStream(id1, 15999); - write_blocked_list.AddStream(id1); - EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams()); - EXPECT_EQ(id1, write_blocked_list.PopFront()); + EXPECT_EQ(id1, write_blocked_list_.PopFront()); + write_blocked_list_.UpdateBytesForStream(id1, 15999); + write_blocked_list_.AddStream(id1); + EXPECT_EQ(2u, write_blocked_list_.NumBlockedStreams()); + EXPECT_EQ(id1, write_blocked_list_.PopFront()); // Once 16k is written the first stream will yield to the next. - write_blocked_list.UpdateBytesForStream(id1, 1); - write_blocked_list.AddStream(id1); - EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams()); - EXPECT_EQ(id2, write_blocked_list.PopFront()); + write_blocked_list_.UpdateBytesForStream(id1, 1); + write_blocked_list_.AddStream(id1); + EXPECT_EQ(2u, write_blocked_list_.NumBlockedStreams()); + EXPECT_EQ(id2, write_blocked_list_.PopFront()); // Set the new stream to have written all but one byte. - write_blocked_list.UpdateBytesForStream(id2, 15999); - write_blocked_list.AddStream(id2); - EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams()); + write_blocked_list_.UpdateBytesForStream(id2, 15999); + write_blocked_list_.AddStream(id2); + EXPECT_EQ(2u, write_blocked_list_.NumBlockedStreams()); // Ensure higher priority streams are popped first. - write_blocked_list.AddStream(id3); - EXPECT_EQ(id3, write_blocked_list.PopFront()); + write_blocked_list_.AddStream(id3); + EXPECT_EQ(id3, write_blocked_list_.PopFront()); // Higher priority streams will always be popped first, even if using their // byte quota - write_blocked_list.UpdateBytesForStream(id3, 20000); - write_blocked_list.AddStream(id3); - EXPECT_EQ(id3, write_blocked_list.PopFront()); + write_blocked_list_.UpdateBytesForStream(id3, 20000); + write_blocked_list_.AddStream(id3); + EXPECT_EQ(id3, write_blocked_list_.PopFront()); // Once the higher priority stream is out of the way, id2 will resume its 16k // write, with only 1 byte remaining of its guaranteed write allocation. - EXPECT_EQ(id2, write_blocked_list.PopFront()); - write_blocked_list.UpdateBytesForStream(id2, 1); - write_blocked_list.AddStream(id2); - EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams()); - EXPECT_EQ(id1, write_blocked_list.PopFront()); + EXPECT_EQ(id2, write_blocked_list_.PopFront()); + write_blocked_list_.UpdateBytesForStream(id2, 1); + write_blocked_list_.AddStream(id2); + EXPECT_EQ(2u, write_blocked_list_.NumBlockedStreams()); + EXPECT_EQ(id1, write_blocked_list_.PopFront()); } TEST_F(QuicWriteBlockedListTest, Ceding) { - QuicWriteBlockedList write_blocked_list; - - write_blocked_list.RegisterStream(15, false, kV3HighestPriority); - write_blocked_list.RegisterStream(16, false, kV3HighestPriority); - write_blocked_list.RegisterStream(5, false, 5); - write_blocked_list.RegisterStream(4, false, 5); - write_blocked_list.RegisterStream(7, false, 7); - write_blocked_list.RegisterStream(1, true, kV3HighestPriority); - write_blocked_list.RegisterStream(3, true, kV3HighestPriority); + write_blocked_list_.RegisterStream(15, false, kV3HighestPriority); + write_blocked_list_.RegisterStream(16, false, kV3HighestPriority); + write_blocked_list_.RegisterStream(5, false, 5); + write_blocked_list_.RegisterStream(4, false, 5); + write_blocked_list_.RegisterStream(7, false, 7); + write_blocked_list_.RegisterStream(1, true, kV3HighestPriority); + write_blocked_list_.RegisterStream(3, true, kV3HighestPriority); // When nothing is on the list, nothing yields. - EXPECT_FALSE(write_blocked_list.ShouldYield(5)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(5)); - write_blocked_list.AddStream(5); + write_blocked_list_.AddStream(5); // 5 should not yield to itself. - EXPECT_FALSE(write_blocked_list.ShouldYield(5)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(5)); // 4 and 7 are equal or lower priority and should yield to 5. - EXPECT_TRUE(write_blocked_list.ShouldYield(4)); - EXPECT_TRUE(write_blocked_list.ShouldYield(7)); + EXPECT_TRUE(write_blocked_list_.ShouldYield(4)); + EXPECT_TRUE(write_blocked_list_.ShouldYield(7)); // 15, headers and crypto should preempt 5. - EXPECT_FALSE(write_blocked_list.ShouldYield(15)); - EXPECT_FALSE(write_blocked_list.ShouldYield(3)); - EXPECT_FALSE(write_blocked_list.ShouldYield(1)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(15)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(3)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(1)); // Block a high priority stream. - write_blocked_list.AddStream(15); + write_blocked_list_.AddStream(15); // 16 should yield (same priority) but headers and crypto will still not. - EXPECT_TRUE(write_blocked_list.ShouldYield(16)); - EXPECT_FALSE(write_blocked_list.ShouldYield(3)); - EXPECT_FALSE(write_blocked_list.ShouldYield(1)); + EXPECT_TRUE(write_blocked_list_.ShouldYield(16)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(3)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(1)); // Block the headers stream. All streams but crypto and headers should yield. - write_blocked_list.AddStream(3); - EXPECT_TRUE(write_blocked_list.ShouldYield(16)); - EXPECT_TRUE(write_blocked_list.ShouldYield(15)); - EXPECT_FALSE(write_blocked_list.ShouldYield(3)); - EXPECT_FALSE(write_blocked_list.ShouldYield(1)); + write_blocked_list_.AddStream(3); + EXPECT_TRUE(write_blocked_list_.ShouldYield(16)); + EXPECT_TRUE(write_blocked_list_.ShouldYield(15)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(3)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(1)); // Block the crypto stream. All streams but crypto should yield. - write_blocked_list.AddStream(1); - EXPECT_TRUE(write_blocked_list.ShouldYield(16)); - EXPECT_TRUE(write_blocked_list.ShouldYield(15)); - EXPECT_TRUE(write_blocked_list.ShouldYield(3)); - EXPECT_FALSE(write_blocked_list.ShouldYield(1)); + write_blocked_list_.AddStream(1); + EXPECT_TRUE(write_blocked_list_.ShouldYield(16)); + EXPECT_TRUE(write_blocked_list_.ShouldYield(15)); + EXPECT_TRUE(write_blocked_list_.ShouldYield(3)); + EXPECT_FALSE(write_blocked_list_.ShouldYield(1)); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/stateless_rejector.cc b/chromium/net/third_party/quiche/src/quic/core/stateless_rejector.cc deleted file mode 100644 index e2ef51cb845..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/stateless_rejector.cc +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/core/stateless_rejector.h" - -#include <string> - -#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" - -namespace quic { - -class StatelessRejector::ValidateCallback - : public ValidateClientHelloResultCallback { - public: - explicit ValidateCallback( - std::unique_ptr<StatelessRejector> rejector, - std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb) - : rejector_(std::move(rejector)), cb_(std::move(cb)) {} - - ~ValidateCallback() override = default; - - void Run(QuicReferenceCountedPointer<Result> result, - std::unique_ptr<ProofSource::Details> /* proof_source_details */) - override { - StatelessRejector* rejector_ptr = rejector_.get(); - rejector_ptr->ProcessClientHello(std::move(result), std::move(rejector_), - std::move(cb_)); - } - - private: - std::unique_ptr<StatelessRejector> rejector_; - std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb_; -}; - -StatelessRejector::StatelessRejector( - ParsedQuicVersion version, - const ParsedQuicVersionVector& versions, - const QuicCryptoServerConfig* crypto_config, - QuicCompressedCertsCache* compressed_certs_cache, - const QuicClock* clock, - QuicRandom* random, - QuicByteCount chlo_packet_size, - const QuicSocketAddress& client_address, - const QuicSocketAddress& server_address) - : state_(UNKNOWN), - error_(QUIC_INTERNAL_ERROR), - version_(version), - versions_(versions), - connection_id_(EmptyQuicConnectionId()), - chlo_packet_size_(chlo_packet_size), - client_address_(client_address), - server_address_(server_address), - clock_(clock), - random_(random), - crypto_config_(crypto_config), - compressed_certs_cache_(compressed_certs_cache), - signed_config_(new QuicSignedServerConfig), - params_(new QuicCryptoNegotiatedParameters) {} - -StatelessRejector::~StatelessRejector() = default; - -void StatelessRejector::OnChlo(QuicTransportVersion version, - QuicConnectionId connection_id, - QuicConnectionId server_designated_connection_id, - const CryptoHandshakeMessage& message) { - DCHECK_EQ(kCHLO, message.tag()); - DCHECK_NE(connection_id, server_designated_connection_id); - DCHECK_EQ(state_, UNKNOWN); - - if (!GetQuicReloadableFlag(enable_quic_stateless_reject_support) || - !GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) || - !QuicCryptoServerStream::DoesPeerSupportStatelessRejects(message)) { - state_ = UNSUPPORTED; - return; - } - - connection_id_ = connection_id; - server_designated_connection_id_ = server_designated_connection_id; - chlo_ = message; // Note: copies the message -} - -void StatelessRejector::Process(std::unique_ptr<StatelessRejector> rejector, - std::unique_ptr<ProcessDoneCallback> done_cb) { - QUIC_BUG_IF(rejector->state() != UNKNOWN) << "StatelessRejector::Process " - "called for a rejector which " - "has already made a decision"; - StatelessRejector* rejector_ptr = rejector.get(); - rejector_ptr->crypto_config_->ValidateClientHello( - rejector_ptr->chlo_, rejector_ptr->client_address_.host(), - rejector_ptr->server_address_, rejector_ptr->version_.transport_version, - rejector_ptr->clock_, rejector_ptr->signed_config_, - std::unique_ptr<ValidateCallback>( - new ValidateCallback(std::move(rejector), std::move(done_cb)))); -} - -class StatelessRejector::ProcessClientHelloCallback - : public ProcessClientHelloResultCallback { - public: - ProcessClientHelloCallback( - std::unique_ptr<StatelessRejector> rejector, - std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) - : rejector_(std::move(rejector)), done_cb_(std::move(done_cb)) {} - - void Run(QuicErrorCode error, - const std::string& error_details, - std::unique_ptr<CryptoHandshakeMessage> message, - std::unique_ptr<DiversificationNonce> diversification_nonce, - std::unique_ptr<ProofSource::Details> /* proof_source_details */) - override { - StatelessRejector* rejector_ptr = rejector_.get(); - rejector_ptr->ProcessClientHelloDone( - error, error_details, std::move(message), std::move(rejector_), - std::move(done_cb_)); - } - - private: - std::unique_ptr<StatelessRejector> rejector_; - std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb_; -}; - -void StatelessRejector::ProcessClientHello( - QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> - result, - std::unique_ptr<StatelessRejector> rejector, - std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) { - std::unique_ptr<ProcessClientHelloCallback> cb( - new ProcessClientHelloCallback(std::move(rejector), std::move(done_cb))); - crypto_config_->ProcessClientHello( - result, - /*reject_only=*/true, connection_id_, server_address_, client_address_, - version_, versions_, - /*use_stateless_rejects=*/true, server_designated_connection_id_, clock_, - random_, compressed_certs_cache_, params_, signed_config_, - QuicCryptoStream::CryptoMessageFramingOverhead(version_.transport_version, - connection_id_), - chlo_packet_size_, std::move(cb)); -} - -void StatelessRejector::ProcessClientHelloDone( - QuicErrorCode error, - const std::string& error_details, - std::unique_ptr<CryptoHandshakeMessage> message, - std::unique_ptr<StatelessRejector> rejector, - std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) { - reply_ = std::move(message); - - if (error != QUIC_NO_ERROR) { - error_ = error; - error_details_ = error_details; - state_ = FAILED; - } else if (reply_->tag() == kSREJ) { - state_ = REJECTED; - } else { - state_ = ACCEPTED; - } - done_cb->Run(std::move(rejector)); -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/stateless_rejector.h b/chromium/net/third_party/quiche/src/quic/core/stateless_rejector.h deleted file mode 100644 index 18dbdcb45c0..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/stateless_rejector.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_CORE_STATELESS_REJECTOR_H_ -#define QUICHE_QUIC_CORE_STATELESS_REJECTOR_H_ - -#include <string> - -#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" -#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" -#include "net/third_party/quiche/src/quic/core/quic_packets.h" - -namespace quic { - -// The StatelessRejector receives CHLO messages and generates an SREJ -// message in response, if the CHLO can be statelessly rejected. -class StatelessRejector { - public: - enum State { - UNKNOWN, // State has not yet been determined - UNSUPPORTED, // Stateless rejects are not supported - FAILED, // There was an error processing the CHLO. - ACCEPTED, // The CHLO was accepted - REJECTED, // The CHLO was rejected. - }; - - StatelessRejector(ParsedQuicVersion version, - const ParsedQuicVersionVector& versions, - const QuicCryptoServerConfig* crypto_config, - QuicCompressedCertsCache* compressed_certs_cache, - const QuicClock* clock, - QuicRandom* random, - QuicByteCount chlo_packet_size, - const QuicSocketAddress& client_address, - const QuicSocketAddress& server_address); - StatelessRejector(const StatelessRejector&) = delete; - StatelessRejector& operator=(const StatelessRejector&) = delete; - - ~StatelessRejector(); - - // Called when |chlo| is received for |connection_id|. - void OnChlo(QuicTransportVersion version, - QuicConnectionId connection_id, - QuicConnectionId server_designated_connection_id, - const CryptoHandshakeMessage& chlo); - - class ProcessDoneCallback { - public: - virtual ~ProcessDoneCallback() = default; - virtual void Run(std::unique_ptr<StatelessRejector> rejector) = 0; - }; - - // Perform processing to determine whether the CHLO received in OnChlo should - // be statelessly rejected, and invoke the callback once a decision has been - // made. - static void Process(std::unique_ptr<StatelessRejector> rejector, - std::unique_ptr<ProcessDoneCallback> done_cb); - - // Return the version of the CHLO. - ParsedQuicVersion version() const { return version_; } - - // Returns the state of the rejector after OnChlo() has been called. - State state() const { return state_; } - - // Returns the error code when state() returns FAILED. - QuicErrorCode error() const { return error_; } - - // Returns the error details when state() returns FAILED. - std::string error_details() const { return error_details_; } - - // Returns the connection ID. - QuicConnectionId connection_id() const { return connection_id_; } - - // Returns the SREJ message when state() returns REJECTED. - const CryptoHandshakeMessage& reply() const { return *reply_; } - - private: - // Helper class which is passed in to - // QuicCryptoServerConfig::ValidateClientHello. - class ValidateCallback; - friend class ValidateCallback; - - class ProcessClientHelloCallback; - friend class ProcessClientHelloCallback; - - void ProcessClientHello( - QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> - result, - std::unique_ptr<StatelessRejector> rejector, - std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb); - - void ProcessClientHelloDone( - QuicErrorCode error, - const std::string& error_details, - std::unique_ptr<CryptoHandshakeMessage> message, - std::unique_ptr<StatelessRejector> rejector, - std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb); - - State state_; - QuicErrorCode error_; - std::string error_details_; - ParsedQuicVersion version_; - ParsedQuicVersionVector versions_; - QuicConnectionId connection_id_; - QuicConnectionId server_designated_connection_id_; - QuicByteCount chlo_packet_size_; - QuicSocketAddress client_address_; - QuicSocketAddress server_address_; - const QuicClock* clock_; - QuicRandom* random_; - const QuicCryptoServerConfig* crypto_config_; - QuicCompressedCertsCache* compressed_certs_cache_; - CryptoHandshakeMessage chlo_; - std::unique_ptr<CryptoHandshakeMessage> reply_; - CryptoFramer crypto_framer_; - QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_; - QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_CORE_STATELESS_REJECTOR_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/stateless_rejector_test.cc b/chromium/net/third_party/quiche/src/quic/core/stateless_rejector_test.cc deleted file mode 100644 index f8757e10b11..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/stateless_rejector_test.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/core/stateless_rejector.h" - -#include <memory> -#include <string> -#include <vector> - -#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" -#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" -#include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" - -namespace quic { -namespace test { -namespace { - -QuicConnectionId TestServerDesignatedConnectionId() { - return TestConnectionId(24); -} - -// All four combinations of the two flags involved. -enum FlagsMode { ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED }; - -const char* FlagsModeToString(FlagsMode mode) { - switch (mode) { - case ENABLED: - return "ENABLED"; - case STATELESS_DISABLED: - return "STATELESS_DISABLED"; - case CHEAP_DISABLED: - return "CHEAP_DISABLED"; - case BOTH_DISABLED: - return "BOTH_DISABLED"; - default: - QUIC_DLOG(FATAL) << "Unexpected FlagsMode"; - return nullptr; - } -} - -// Test various combinations of QUIC version and flag state. -struct TestParams { - ParsedQuicVersion version = UnsupportedQuicVersion(); - FlagsMode flags; -}; - -std::string TestParamToString( - const testing::TestParamInfo<TestParams>& params) { - return QuicStrCat("v", ParsedQuicVersionToString(params.param.version), "_", - FlagsModeToString(params.param.flags)); -} - -std::vector<TestParams> GetTestParams() { - std::vector<TestParams> params; - for (FlagsMode flags : - {ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED}) { - for (ParsedQuicVersion version : AllSupportedVersions()) { - TestParams param; - param.version = version; - param.flags = flags; - params.push_back(param); - } - } - return params; -} - -class StatelessRejectorTest : public QuicTestWithParam<TestParams> { - public: - StatelessRejectorTest() - : proof_source_(crypto_test_utils::ProofSourceForTesting()), - config_(QuicCryptoServerConfig::TESTING, - QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting(), - KeyExchangeSource::Default(), - TlsServerHandshaker::CreateSslCtx()), - config_peer_(&config_), - compressed_certs_cache_( - QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), - rejector_(QuicMakeUnique<StatelessRejector>( - GetParam().version, - AllSupportedVersions(), - &config_, - &compressed_certs_cache_, - &clock_, - QuicRandom::GetInstance(), - kDefaultMaxPacketSize, - QuicSocketAddress(QuicIpAddress::Loopback4(), 12345), - QuicSocketAddress(QuicIpAddress::Loopback4(), 443))) { - SetQuicReloadableFlag( - enable_quic_stateless_reject_support, - GetParam().flags == ENABLED || GetParam().flags == CHEAP_DISABLED); - SetQuicReloadableFlag( - quic_use_cheap_stateless_rejects, - GetParam().flags == ENABLED || GetParam().flags == STATELESS_DISABLED); - - // Add a new primary config. - std::unique_ptr<CryptoHandshakeMessage> msg(config_.AddDefaultConfig( - QuicRandom::GetInstance(), &clock_, config_options_)); - - // Save the server config. - scid_hex_ = - "#" + QuicTextUtils::HexEncode(config_peer_.GetPrimaryConfig()->id); - - // Encode the QUIC version. - ver_hex_ = ParsedQuicVersionToString(GetParam().version); - - // Generate a public value. - char public_value[32]; - memset(public_value, 42, sizeof(public_value)); - pubs_hex_ = - "#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value)); - - // Generate a client nonce. - std::string nonce; - CryptoUtils::GenerateNonce( - clock_.WallNow(), QuicRandom::GetInstance(), - QuicStringPiece( - reinterpret_cast<char*>(config_peer_.GetPrimaryConfig()->orbit), - kOrbitSize), - &nonce); - nonc_hex_ = "#" + QuicTextUtils::HexEncode(nonce); - - // Generate a source address token. - SourceAddressTokens previous_tokens; - QuicIpAddress ip = QuicIpAddress::Loopback4(); - MockRandom rand; - std::string stk = config_peer_.NewSourceAddressToken( - config_peer_.GetPrimaryConfig()->id, previous_tokens, ip, &rand, - clock_.WallNow(), nullptr); - stk_hex_ = "#" + QuicTextUtils::HexEncode(stk); - } - - protected: - class ProcessDoneCallback : public StatelessRejector::ProcessDoneCallback { - public: - explicit ProcessDoneCallback(StatelessRejectorTest* test) : test_(test) {} - void Run(std::unique_ptr<StatelessRejector> rejector) override { - test_->rejector_ = std::move(rejector); - } - - private: - StatelessRejectorTest* test_; - }; - - std::unique_ptr<ProofSource> proof_source_; - MockClock clock_; - QuicCryptoServerConfig config_; - QuicCryptoServerConfigPeer config_peer_; - QuicCompressedCertsCache compressed_certs_cache_; - QuicCryptoServerConfig::ConfigOptions config_options_; - std::unique_ptr<StatelessRejector> rejector_; - - // Values used in CHLO messages - std::string scid_hex_; - std::string nonc_hex_; - std::string pubs_hex_; - std::string ver_hex_; - std::string stk_hex_; -}; - -INSTANTIATE_TEST_SUITE_P(Flags, - StatelessRejectorTest, - ::testing::ValuesIn(GetTestParams()), - TestParamToString); - -TEST_P(StatelessRejectorTest, InvalidChlo) { - // clang-format off - const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO( - {{"PDMD", "X509"}, - {"COPT", "SREJ"}}); - // clang-format on - rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(), - TestServerDesignatedConnectionId(), client_hello); - - if (GetParam().flags != ENABLED) { - EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state()); - return; - } - - // The StatelessRejector is undecided - proceed with async processing - ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state()); - StatelessRejector::Process(std::move(rejector_), - QuicMakeUnique<ProcessDoneCallback>(this)); - - EXPECT_EQ(StatelessRejector::FAILED, rejector_->state()); - EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, rejector_->error()); -} - -TEST_P(StatelessRejectorTest, ValidChloWithoutSrejSupport) { - // clang-format off - const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO( - {{"PDMD", "X509"}, - {"AEAD", "AESG"}, - {"KEXS", "C255"}, - {"PUBS", pubs_hex_}, - {"NONC", nonc_hex_}, - {"VER\0", ver_hex_}}, - kClientHelloMinimumSize); - // clang-format on - - rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(), - TestServerDesignatedConnectionId(), client_hello); - EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state()); -} - -TEST_P(StatelessRejectorTest, RejectChlo) { - // clang-format off - const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO( - {{"PDMD", "X509"}, - {"AEAD", "AESG"}, - {"KEXS", "C255"}, - {"COPT", "SREJ"}, - {"SCID", scid_hex_}, - {"PUBS", pubs_hex_}, - {"NONC", nonc_hex_}, - {"#004b5453", stk_hex_}, - {"VER\0", ver_hex_}}, - kClientHelloMinimumSize); - // clang-format on - - rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(), - TestServerDesignatedConnectionId(), client_hello); - if (GetParam().flags != ENABLED) { - EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state()); - return; - } - - // The StatelessRejector is undecided - proceed with async processing - ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state()); - StatelessRejector::Process(std::move(rejector_), - QuicMakeUnique<ProcessDoneCallback>(this)); - - ASSERT_EQ(StatelessRejector::REJECTED, rejector_->state()); - const CryptoHandshakeMessage& reply = rejector_->reply(); - EXPECT_EQ(kSREJ, reply.tag()); - QuicTagVector reject_reasons; - EXPECT_EQ(QUIC_NO_ERROR, reply.GetTaglist(kRREJ, &reject_reasons)); - EXPECT_EQ(1u, reject_reasons.size()); - EXPECT_EQ(INVALID_EXPECTED_LEAF_CERTIFICATE, - static_cast<HandshakeFailureReason>(reject_reasons[0])); -} - -TEST_P(StatelessRejectorTest, AcceptChlo) { - const uint64_t xlct = crypto_test_utils::LeafCertHashForTesting(); - const std::string xlct_hex = - "#" + QuicTextUtils::HexEncode(reinterpret_cast<const char*>(&xlct), - sizeof(xlct)); - // clang-format off - const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO( - {{"PDMD", "X509"}, - {"AEAD", "AESG"}, - {"KEXS", "C255"}, - {"COPT", "SREJ"}, - {"SCID", scid_hex_}, - {"PUBS", pubs_hex_}, - {"NONC", nonc_hex_}, - {"#004b5453", stk_hex_}, - {"VER\0", ver_hex_}, - {"XLCT", xlct_hex}}, - kClientHelloMinimumSize); - // clang-format on - - rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(), - TestServerDesignatedConnectionId(), client_hello); - if (GetParam().flags != ENABLED) { - EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state()); - return; - } - - // The StatelessRejector is undecided - proceed with async processing - ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state()); - StatelessRejector::Process(std::move(rejector_), - QuicMakeUnique<ProcessDoneCallback>(this)); - - EXPECT_EQ(StatelessRejector::ACCEPTED, rejector_->state()); -} - -} // namespace -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc index 932d537b16d..db1f6b480d6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc @@ -152,6 +152,15 @@ bool TlsClientHandshaker::ProcessTransportParameters( return false; } + // When interoperating with non-Google implementations that do not send + // the version extension, set it to what we expect. + if (params.version == 0) { + params.version = CreateQuicVersionLabel(session()->connection()->version()); + } + if (params.supported_versions.empty()) { + params.supported_versions.push_back(params.version); + } + if (params.version != CreateQuicVersionLabel(session()->connection()->version())) { *error_details = "Version mismatch detected"; @@ -181,16 +190,6 @@ int TlsClientHandshaker::num_scup_messages_received() const { return 0; } -bool TlsClientHandshaker::WasChannelIDSent() const { - // Channel ID is not used with TLS in QUIC. - return false; -} - -bool TlsClientHandshaker::WasChannelIDSourceCallbackRun() const { - // Channel ID is not used with TLS in QUIC. - return false; -} - std::string TlsClientHandshaker::chlo_hash() const { return ""; } @@ -331,12 +330,22 @@ enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) { std::string(reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)), CRYPTO_BUFFER_len(cert))); } + const uint8_t* ocsp_response_raw; + size_t ocsp_response_len; + SSL_get0_ocsp_response(ssl(), &ocsp_response_raw, &ocsp_response_len); + std::string ocsp_response(reinterpret_cast<const char*>(ocsp_response_raw), + ocsp_response_len); + const uint8_t* sct_list_raw; + size_t sct_list_len; + SSL_get0_signed_cert_timestamp_list(ssl(), &sct_list_raw, &sct_list_len); + std::string sct_list(reinterpret_cast<const char*>(sct_list_raw), + sct_list_len); ProofVerifierCallbackImpl* proof_verify_callback = new ProofVerifierCallbackImpl(this); QuicAsyncStatus verify_result = proof_verifier_->VerifyCertChain( - server_id_.host(), certs, verify_context_.get(), + server_id_.host(), certs, ocsp_response, sct_list, verify_context_.get(), &cert_verify_error_details_, &verify_details_, std::unique_ptr<ProofVerifierCallback>(proof_verify_callback)); switch (verify_result) { diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h index c2243b3efb5..3647e10f084 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h @@ -42,8 +42,6 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker bool CryptoConnect() override; int num_sent_client_hellos() const override; int num_scup_messages_received() const override; - bool WasChannelIDSent() const override; - bool WasChannelIDSourceCallbackRun() const override; std::string chlo_hash() const override; // From QuicCryptoClientStream::HandshakerDelegate and TlsHandshaker diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc index 3a45f36379f..51602b42daa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc @@ -105,8 +105,9 @@ EncryptionLevel TlsHandshaker::QuicEncryptionLevel( case ssl_encryption_initial: return ENCRYPTION_INITIAL; case ssl_encryption_early_data: - case ssl_encryption_handshake: return ENCRYPTION_ZERO_RTT; + case ssl_encryption_handshake: + return ENCRYPTION_HANDSHAKE; case ssl_encryption_application: return ENCRYPTION_FORWARD_SECURE; } @@ -119,8 +120,9 @@ enum ssl_encryption_level_t TlsHandshaker::BoringEncryptionLevel( case ENCRYPTION_INITIAL: return ssl_encryption_initial; case ENCRYPTION_HANDSHAKE: - case ENCRYPTION_ZERO_RTT: return ssl_encryption_handshake; + case ENCRYPTION_ZERO_RTT: + return ssl_encryption_early_data; case ENCRYPTION_FORWARD_SECURE: return ssl_encryption_application; default: diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc index a7b2aa8b410..e710d7b166b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc @@ -47,17 +47,20 @@ class FakeProofVerifier : public ProofVerifier { QuicAsyncStatus VerifyCertChain( const std::string& hostname, const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, const ProofVerifyContext* context, std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, std::unique_ptr<ProofVerifierCallback> callback) override { if (!active_) { - return verifier_->VerifyCertChain(hostname, certs, context, error_details, + return verifier_->VerifyCertChain(hostname, certs, ocsp_response, + cert_sct, context, error_details, details, std::move(callback)); } pending_ops_.push_back(QuicMakeUnique<VerifyChainPendingOp>( - hostname, certs, context, error_details, details, std::move(callback), - verifier_.get())); + hostname, certs, ocsp_response, cert_sct, context, error_details, + details, std::move(callback), verifier_.get())); return QUIC_PENDING; } @@ -92,6 +95,8 @@ class FakeProofVerifier : public ProofVerifier { public: VerifyChainPendingOp(const std::string& hostname, const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, const ProofVerifyContext* context, std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, @@ -99,6 +104,8 @@ class FakeProofVerifier : public ProofVerifier { ProofVerifier* delegate) : hostname_(hostname), certs_(certs), + ocsp_response_(ocsp_response), + cert_sct_(cert_sct), context_(context), error_details_(error_details), details_(details), @@ -111,7 +118,8 @@ class FakeProofVerifier : public ProofVerifier { // runs the original callback after asserting that the verification ran // synchronously. QuicAsyncStatus status = delegate_->VerifyCertChain( - hostname_, certs_, context_, error_details_, details_, + hostname_, certs_, ocsp_response_, cert_sct_, context_, + error_details_, details_, QuicMakeUnique<FailingProofVerifierCallback>()); ASSERT_NE(status, QUIC_PENDING); callback_->Run(status == QUIC_SUCCESS, *error_details_, details_); @@ -120,6 +128,8 @@ class FakeProofVerifier : public ProofVerifier { private: std::string hostname_; std::vector<std::string> certs_; + std::string ocsp_response_; + std::string cert_sct_; const ProofVerifyContext* context_; std::string* error_details_; std::unique_ptr<ProofVerifyDetails>* details_; @@ -265,7 +275,7 @@ void ExchangeHandshakeMessages(TestQuicCryptoStream* client, ParsedQuicVersionVector AllTlsSupportedVersions() { SetQuicReloadableFlag(quic_enable_version_99, true); - SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); ParsedQuicVersionVector supported_versions; for (QuicTransportVersion version : kSupportedTransportVersions) { if (!QuicVersionUsesCryptoFrames(version)) { diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc index ec254b53550..ca56e4dd3d2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc @@ -211,6 +211,14 @@ bool TlsServerHandshaker::ProcessTransportParameters( *error_details = "Unable to parse Transport Parameters"; return false; } + + // When interoperating with non-Google implementations that do not send + // the version extension, set it to what we expect. + if (client_params.version == 0) { + client_params.version = + CreateQuicVersionLabel(session()->connection()->version()); + } + if (CryptoUtils::ValidateClientHelloVersion( client_params.version, session()->connection()->version(), session()->supported_versions(), error_details) != QUIC_NO_ERROR || diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc index 51ea994fe95..75f7c6ac71a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc @@ -8,47 +8,22 @@ #include "net/third_party/quiche/src/quic/core/quic_utils.h" namespace quic { -namespace { - -Perspective Reverse(Perspective perspective) { - return perspective == Perspective::IS_SERVER ? Perspective::IS_CLIENT - : Perspective::IS_SERVER; -} - -} // namespace UberQuicStreamIdManager::UberQuicStreamIdManager( QuicSession* session, - size_t max_open_outgoing_streams, - size_t max_open_incoming_streams) - : bidirectional_stream_id_manager_( - session, - QuicUtils::GetFirstBidirectionalStreamId( - session->connection()->transport_version(), - session->perspective()), - session->perspective() == Perspective::IS_SERVER - ? QuicUtils::GetCryptoStreamId( - session->connection()->transport_version()) - : QuicUtils::GetInvalidStreamId( - session->connection()->transport_version()), - QuicUtils::GetFirstBidirectionalStreamId( - session->connection()->transport_version(), - Reverse(session->perspective())), - max_open_outgoing_streams, - max_open_incoming_streams), + QuicStreamCount max_open_outgoing_bidirectional_streams, + QuicStreamCount max_open_outgoing_unidirectional_streams, + QuicStreamCount max_open_incoming_bidirectional_streams, + QuicStreamCount max_open_incoming_unidirectional_streams) + : bidirectional_stream_id_manager_(session, + /*unidirectional=*/false, + max_open_outgoing_bidirectional_streams, + max_open_incoming_bidirectional_streams), unidirectional_stream_id_manager_( session, - QuicUtils::GetFirstUnidirectionalStreamId( - session->connection()->transport_version(), - session->perspective()), - QuicUtils::GetInvalidStreamId( - session->connection()->transport_version()), - QuicUtils::GetFirstUnidirectionalStreamId( - session->connection()->transport_version(), - Reverse(session->perspective())), - max_open_outgoing_streams, - max_open_incoming_streams) {} - + /*unidirectional=*/true, + max_open_outgoing_unidirectional_streams, + max_open_incoming_unidirectional_streams) {} void UberQuicStreamIdManager::RegisterStaticStream(QuicStreamId id) { if (QuicUtils::IsBidirectionalStreamId(id)) { bidirectional_stream_id_manager_.RegisterStaticStream(id); @@ -57,14 +32,43 @@ void UberQuicStreamIdManager::RegisterStaticStream(QuicStreamId id) { unidirectional_stream_id_manager_.RegisterStaticStream(id); } -void UberQuicStreamIdManager::SetMaxOpenOutgoingStreams(size_t max_streams) { - bidirectional_stream_id_manager_.SetMaxOpenOutgoingStreams(max_streams); - unidirectional_stream_id_manager_.SetMaxOpenOutgoingStreams(max_streams); +void UberQuicStreamIdManager::AdjustMaxOpenOutgoingUnidirectionalStreams( + size_t max_streams) { + unidirectional_stream_id_manager_.AdjustMaxOpenOutgoingStreams(max_streams); +} +void UberQuicStreamIdManager::AdjustMaxOpenOutgoingBidirectionalStreams( + size_t max_streams) { + bidirectional_stream_id_manager_.AdjustMaxOpenOutgoingStreams(max_streams); } -void UberQuicStreamIdManager::SetMaxOpenIncomingStreams(size_t max_streams) { - bidirectional_stream_id_manager_.SetMaxOpenIncomingStreams(max_streams); - unidirectional_stream_id_manager_.SetMaxOpenIncomingStreams(max_streams); +void UberQuicStreamIdManager::ConfigureMaxOpenOutgoingBidirectionalStreams( + size_t max_streams) { + bidirectional_stream_id_manager_.ConfigureMaxOpenOutgoingStreams(max_streams); +} +void UberQuicStreamIdManager::ConfigureMaxOpenOutgoingUnidirectionalStreams( + size_t max_streams) { + unidirectional_stream_id_manager_.ConfigureMaxOpenOutgoingStreams( + max_streams); +} + +// TODO(fkastenholz): SetMax is cognizant of the number of static streams and +// sets the maximum to be max_streams + number_of_statics. This should +// eventually be removed from IETF QUIC. +void UberQuicStreamIdManager::SetMaxOpenOutgoingBidirectionalStreams( + size_t max_open_streams) { + bidirectional_stream_id_manager_.SetMaxOpenOutgoingStreams(max_open_streams); +} +void UberQuicStreamIdManager::SetMaxOpenOutgoingUnidirectionalStreams( + size_t max_open_streams) { + unidirectional_stream_id_manager_.SetMaxOpenOutgoingStreams(max_open_streams); +} +void UberQuicStreamIdManager::SetMaxOpenIncomingBidirectionalStreams( + size_t max_open_streams) { + bidirectional_stream_id_manager_.SetMaxOpenIncomingStreams(max_open_streams); +} +void UberQuicStreamIdManager::SetMaxOpenIncomingUnidirectionalStreams( + size_t max_open_streams) { + unidirectional_stream_id_manager_.SetMaxOpenIncomingStreams(max_open_streams); } bool UberQuicStreamIdManager::CanOpenNextOutgoingBidirectionalStream() { @@ -100,20 +104,20 @@ void UberQuicStreamIdManager::OnStreamClosed(QuicStreamId id) { unidirectional_stream_id_manager_.OnStreamClosed(id); } -bool UberQuicStreamIdManager::OnMaxStreamIdFrame( - const QuicMaxStreamIdFrame& frame) { - if (QuicUtils::IsBidirectionalStreamId(frame.max_stream_id)) { - return bidirectional_stream_id_manager_.OnMaxStreamIdFrame(frame); +bool UberQuicStreamIdManager::OnMaxStreamsFrame( + const QuicMaxStreamsFrame& frame) { + if (frame.unidirectional) { + return unidirectional_stream_id_manager_.OnMaxStreamsFrame(frame); } - return unidirectional_stream_id_manager_.OnMaxStreamIdFrame(frame); + return bidirectional_stream_id_manager_.OnMaxStreamsFrame(frame); } -bool UberQuicStreamIdManager::OnStreamIdBlockedFrame( - const QuicStreamIdBlockedFrame& frame) { - if (QuicUtils::IsBidirectionalStreamId(frame.stream_id)) { - return bidirectional_stream_id_manager_.OnStreamIdBlockedFrame(frame); +bool UberQuicStreamIdManager::OnStreamsBlockedFrame( + const QuicStreamsBlockedFrame& frame) { + if (frame.unidirectional) { + return unidirectional_stream_id_manager_.OnStreamsBlockedFrame(frame); } - return unidirectional_stream_id_manager_.OnStreamIdBlockedFrame(frame); + return bidirectional_stream_id_manager_.OnStreamsBlockedFrame(frame); } bool UberQuicStreamIdManager::IsIncomingStream(QuicStreamId id) const { @@ -132,12 +136,12 @@ bool UberQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const { size_t UberQuicStreamIdManager::GetMaxAllowdIncomingBidirectionalStreams() const { - return bidirectional_stream_id_manager_.max_allowed_incoming_streams(); + return bidirectional_stream_id_manager_.incoming_initial_max_open_streams(); } size_t UberQuicStreamIdManager::GetMaxAllowdIncomingUnidirectionalStreams() const { - return unidirectional_stream_id_manager_.max_allowed_incoming_streams(); + return unidirectional_stream_id_manager_.incoming_initial_max_open_streams(); } void UberQuicStreamIdManager::SetLargestPeerCreatedStreamId( @@ -161,50 +165,37 @@ QuicStreamId UberQuicStreamIdManager::next_outgoing_unidirectional_stream_id() return unidirectional_stream_id_manager_.next_outgoing_stream_id(); } -QuicStreamId -UberQuicStreamIdManager::max_allowed_outgoing_bidirectional_stream_id() const { - return bidirectional_stream_id_manager_.max_allowed_outgoing_stream_id(); -} - -QuicStreamId -UberQuicStreamIdManager::max_allowed_outgoing_unidirectional_stream_id() const { - return unidirectional_stream_id_manager_.max_allowed_outgoing_stream_id(); -} - size_t UberQuicStreamIdManager::max_allowed_outgoing_bidirectional_streams() const { - return bidirectional_stream_id_manager_.max_allowed_outgoing_streams(); + return bidirectional_stream_id_manager_.outgoing_max_streams(); } size_t UberQuicStreamIdManager::max_allowed_outgoing_unidirectional_streams() const { - return unidirectional_stream_id_manager_.max_allowed_outgoing_streams(); + return unidirectional_stream_id_manager_.outgoing_max_streams(); } -QuicStreamId -UberQuicStreamIdManager::actual_max_allowed_incoming_bidirectional_stream_id() +QuicStreamCount +UberQuicStreamIdManager::actual_max_allowed_incoming_bidirectional_streams() const { - return bidirectional_stream_id_manager_ - .actual_max_allowed_incoming_stream_id(); + return bidirectional_stream_id_manager_.incoming_actual_max_streams(); } -QuicStreamId -UberQuicStreamIdManager::actual_max_allowed_incoming_unidirectional_stream_id() +QuicStreamCount +UberQuicStreamIdManager::actual_max_allowed_incoming_unidirectional_streams() const { - return unidirectional_stream_id_manager_ - .actual_max_allowed_incoming_stream_id(); + return unidirectional_stream_id_manager_.incoming_actual_max_streams(); } -QuicStreamId UberQuicStreamIdManager:: - advertised_max_allowed_incoming_bidirectional_stream_id() const { - return bidirectional_stream_id_manager_ - .advertised_max_allowed_incoming_stream_id(); +QuicStreamCount +UberQuicStreamIdManager::advertised_max_allowed_incoming_bidirectional_streams() + const { + return bidirectional_stream_id_manager_.incoming_advertised_max_streams(); } -QuicStreamId UberQuicStreamIdManager:: - advertised_max_allowed_incoming_unidirectional_stream_id() const { - return unidirectional_stream_id_manager_ - .advertised_max_allowed_incoming_stream_id(); +QuicStreamCount UberQuicStreamIdManager:: + advertised_max_allowed_incoming_unidirectional_streams() const { + return unidirectional_stream_id_manager_.incoming_advertised_max_streams(); } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h index bf5a5882ba4..288f0c0a092 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h @@ -11,6 +11,7 @@ namespace quic { namespace test { class QuicSessionPeer; +class UberQuicStreamIdManagerPeer; } // namespace test class QuicSession; @@ -19,19 +20,39 @@ class QuicSession; // unidirectional stream IDs, respectively. class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager { public: - UberQuicStreamIdManager(QuicSession* session, - size_t max_open_outgoing_streams, - size_t max_open_incoming_streams); + UberQuicStreamIdManager( + QuicSession* session, + QuicStreamCount max_open_outgoing_bidirectional_streams, + QuicStreamCount max_open_outgoing_unidirectional_streams, + QuicStreamCount max_open_incoming_bidirectional_streams, + QuicStreamCount max_open_incoming_unidirectional_streams); // Called when a stream with |stream_id| is registered as a static stream. void RegisterStaticStream(QuicStreamId id); - // Initialize the maximum allowed outgoing stream id, number of streams, and - // MAX_STREAM_ID advertisement window. - void SetMaxOpenOutgoingStreams(size_t max_streams); - - // Initialize the maximum allowed incoming stream id and number of streams. - void SetMaxOpenIncomingStreams(size_t max_streams); + // Sets the maximum outgoing stream count as a result of doing the transport + // configuration negotiation. Forces the limit to max_streams, regardless of + // static streams. + void ConfigureMaxOpenOutgoingBidirectionalStreams(size_t max_streams); + void ConfigureMaxOpenOutgoingUnidirectionalStreams(size_t max_streams); + + // Sets the limits to max_open_streams + number of static streams + // in existence. SetMaxOpenOutgoingStreams will QUIC_BUG if it is called + // after getting the first MAX_STREAMS frame or the transport configuration + // was done. + // TODO(fkastenholz): SetMax is cognizant of the number of static streams and + // sets the maximum to be max_streams + number_of_statics. This should + // eventually be removed from IETF QUIC. + void SetMaxOpenOutgoingBidirectionalStreams(size_t max_open_streams); + void SetMaxOpenOutgoingUnidirectionalStreams(size_t max_open_streams); + void SetMaxOpenIncomingBidirectionalStreams(size_t max_open_streams); + void SetMaxOpenIncomingUnidirectionalStreams(size_t max_open_streams); + + // Sets the outgoing stream count to the number of static streams + max + // outgoing streams. Unlike SetMaxOpenOutgoingStreams, this method will + // not QUIC_BUG if called after getting the first MAX_STREAMS frame. + void AdjustMaxOpenOutgoingBidirectionalStreams(size_t max_streams); + void AdjustMaxOpenOutgoingUnidirectionalStreams(size_t max_streams); // Returns true if next outgoing bidirectional stream ID can be allocated. bool CanOpenNextOutgoingBidirectionalStream(); @@ -45,17 +66,17 @@ class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager { // Returns the next outgoing unidirectional stream id. QuicStreamId GetNextOutgoingUnidirectionalStreamId(); - // Returns true if allow to open the incoming |id|. + // Returns true if the incoming |id| is within the limit. bool MaybeIncreaseLargestPeerStreamId(QuicStreamId id); // Called when |id| is released. void OnStreamClosed(QuicStreamId id); - // Called when a MAX_STREAM_ID frame is received. - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame); + // Called when a MAX_STREAMS frame is received. + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame); - // Called when a STREAM_ID_BLOCKED frame is received. - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame); + // Called when a STREAMS_BLOCKED frame is received. + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame); // Return true if |id| is peer initiated. bool IsIncomingStream(QuicStreamId id) const; @@ -73,20 +94,19 @@ class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager { QuicStreamId next_outgoing_bidirectional_stream_id() const; QuicStreamId next_outgoing_unidirectional_stream_id() const; - QuicStreamId max_allowed_outgoing_bidirectional_stream_id() const; - QuicStreamId max_allowed_outgoing_unidirectional_stream_id() const; - size_t max_allowed_outgoing_bidirectional_streams() const; size_t max_allowed_outgoing_unidirectional_streams() const; - QuicStreamId actual_max_allowed_incoming_bidirectional_stream_id() const; - QuicStreamId actual_max_allowed_incoming_unidirectional_stream_id() const; + QuicStreamCount actual_max_allowed_incoming_bidirectional_streams() const; + QuicStreamCount actual_max_allowed_incoming_unidirectional_streams() const; - QuicStreamId advertised_max_allowed_incoming_bidirectional_stream_id() const; - QuicStreamId advertised_max_allowed_incoming_unidirectional_stream_id() const; + QuicStreamCount advertised_max_allowed_incoming_bidirectional_streams() const; + QuicStreamCount advertised_max_allowed_incoming_unidirectional_streams() + const; private: friend class test::QuicSessionPeer; + friend class test::UberQuicStreamIdManagerPeer; // Manages stream IDs of bidirectional streams. QuicStreamIdManager bidirectional_stream_id_manager_; diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc index 929d0a1cc8f..8b1bacea54f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc @@ -7,6 +7,7 @@ #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" using testing::_; @@ -59,6 +60,38 @@ class UberQuicStreamIdManagerTest : public QuicTestWithParam<Perspective> { kV99StreamIdIncrement * n; } + // TODO(fkastenholz): Existing tests can use these helper functions. + QuicStreamId GetNthPeerInitiatedBidirectionalStreamId(int n) { + return ((GetParam() == Perspective::IS_SERVER) + ? GetNthClientInitiatedBidirectionalId(n) + : GetNthServerInitiatedBidirectionalId(n)); + } + QuicStreamId GetNthPeerInitiatedUnidirectionalStreamId(int n) { + return ((GetParam() == Perspective::IS_SERVER) + ? GetNthClientInitiatedUnidirectionalId(n) + : GetNthServerInitiatedUnidirectionalId(n)); + } + QuicStreamId GetNthSelfInitiatedBidirectionalStreamId(int n) { + return ((GetParam() == Perspective::IS_CLIENT) + ? GetNthClientInitiatedBidirectionalId(n) + : GetNthServerInitiatedBidirectionalId(n)); + } + QuicStreamId GetNthSelfInitiatedUnidirectionalStreamId(int n) { + return ((GetParam() == Perspective::IS_CLIENT) + ? GetNthClientInitiatedUnidirectionalId(n) + : GetNthServerInitiatedUnidirectionalId(n)); + } + + QuicStreamId StreamCountToId(QuicStreamCount stream_count, + Perspective perspective, + bool bidirectional) { + return ((bidirectional) ? QuicUtils::GetFirstBidirectionalStreamId( + QUIC_VERSION_99, perspective) + : QuicUtils::GetFirstUnidirectionalStreamId( + QUIC_VERSION_99, perspective)) + + ((stream_count - 1) * QuicUtils::StreamIdDelta(QUIC_VERSION_99)); + } + MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; MockQuicConnection* connection_; @@ -96,66 +129,86 @@ TEST_P(UberQuicStreamIdManagerTest, RegisterStaticStream) { ? GetNthClientInitiatedUnidirectionalId(0) : GetNthServerInitiatedUnidirectionalId(0); - QuicStreamId actual_max_allowed_incoming_bidirectional_stream_id = - manager_->actual_max_allowed_incoming_bidirectional_stream_id(); - QuicStreamId actual_max_allowed_incoming_unidirectional_stream_id = - manager_->actual_max_allowed_incoming_unidirectional_stream_id(); + QuicStreamCount actual_max_allowed_incoming_bidirectional_streams = + manager_->actual_max_allowed_incoming_bidirectional_streams(); + QuicStreamCount actual_max_allowed_incoming_unidirectional_streams = + manager_->actual_max_allowed_incoming_unidirectional_streams(); manager_->RegisterStaticStream(first_incoming_bidirectional_stream_id); - // Verify actual_max_allowed_incoming_bidirectional_stream_id increases. - EXPECT_EQ(actual_max_allowed_incoming_bidirectional_stream_id + - kV99StreamIdIncrement, - manager_->actual_max_allowed_incoming_bidirectional_stream_id()); - // Verify actual_max_allowed_incoming_unidirectional_stream_id does not + // Verify actual_max_allowed_incoming_bidirectional_streams increases. + EXPECT_EQ(actual_max_allowed_incoming_bidirectional_streams + 1u, + manager_->actual_max_allowed_incoming_bidirectional_streams()); + // Verify actual_max_allowed_incoming_unidirectional_streams does not // change. - EXPECT_EQ(actual_max_allowed_incoming_unidirectional_stream_id, - manager_->actual_max_allowed_incoming_unidirectional_stream_id()); + EXPECT_EQ(actual_max_allowed_incoming_unidirectional_streams, + manager_->actual_max_allowed_incoming_unidirectional_streams()); manager_->RegisterStaticStream(first_incoming_unidirectional_stream_id); - EXPECT_EQ(actual_max_allowed_incoming_bidirectional_stream_id + - kV99StreamIdIncrement, - manager_->actual_max_allowed_incoming_bidirectional_stream_id()); - EXPECT_EQ(actual_max_allowed_incoming_unidirectional_stream_id + - kV99StreamIdIncrement, - manager_->actual_max_allowed_incoming_unidirectional_stream_id()); + EXPECT_EQ(actual_max_allowed_incoming_bidirectional_streams + 1u, + manager_->actual_max_allowed_incoming_bidirectional_streams()); + EXPECT_EQ(actual_max_allowed_incoming_unidirectional_streams + 1u, + manager_->actual_max_allowed_incoming_unidirectional_streams()); } TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenOutgoingStreams) { const size_t kNumMaxOutgoingStream = 123; - manager_->SetMaxOpenOutgoingStreams(kNumMaxOutgoingStream); + // Set the uni- and bi- directional limits to different values to ensure + // that they are managed separately. + manager_->SetMaxOpenOutgoingBidirectionalStreams(kNumMaxOutgoingStream); + manager_->SetMaxOpenOutgoingUnidirectionalStreams(kNumMaxOutgoingStream + 1); EXPECT_EQ(kNumMaxOutgoingStream, manager_->max_allowed_outgoing_bidirectional_streams()); - EXPECT_EQ(kNumMaxOutgoingStream, + EXPECT_EQ(kNumMaxOutgoingStream + 1, manager_->max_allowed_outgoing_unidirectional_streams()); + // Check that, for each directionality, we can open the correct number of + // streams. + int i = kNumMaxOutgoingStream; + while (i) { + EXPECT_TRUE(manager_->CanOpenNextOutgoingBidirectionalStream()); + manager_->GetNextOutgoingBidirectionalStreamId(); + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + manager_->GetNextOutgoingUnidirectionalStreamId(); + i--; + } + // One more unidirectional + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + manager_->GetNextOutgoingUnidirectionalStreamId(); + + // Both should be exhausted... + EXPECT_FALSE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + EXPECT_FALSE(manager_->CanOpenNextOutgoingBidirectionalStream()); } TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenIncomingStreams) { const size_t kNumMaxIncomingStreams = 456; - manager_->SetMaxOpenIncomingStreams(kNumMaxIncomingStreams); - EXPECT_EQ(kNumMaxIncomingStreams, + manager_->SetMaxOpenIncomingUnidirectionalStreams(kNumMaxIncomingStreams); + // Do +1 for bidirectional to ensure that uni- and bi- get properly set. + manager_->SetMaxOpenIncomingBidirectionalStreams(kNumMaxIncomingStreams + 1); + EXPECT_EQ(kNumMaxIncomingStreams + 1, manager_->GetMaxAllowdIncomingBidirectionalStreams()); EXPECT_EQ(kNumMaxIncomingStreams, manager_->GetMaxAllowdIncomingUnidirectionalStreams()); - EXPECT_EQ( - manager_->actual_max_allowed_incoming_bidirectional_stream_id(), - manager_->advertised_max_allowed_incoming_bidirectional_stream_id()); - EXPECT_EQ( - manager_->actual_max_allowed_incoming_unidirectional_stream_id(), - manager_->advertised_max_allowed_incoming_unidirectional_stream_id()); + EXPECT_EQ(manager_->actual_max_allowed_incoming_bidirectional_streams(), + manager_->advertised_max_allowed_incoming_bidirectional_streams()); + EXPECT_EQ(manager_->actual_max_allowed_incoming_unidirectional_streams(), + manager_->advertised_max_allowed_incoming_unidirectional_streams()); + // Make sure that we can create kNumMaxIncomingStreams incoming unidirectional + // streams and kNumMaxIncomingStreams+1 incoming bidirectional streams. + size_t i; + for (i = 0; i < kNumMaxIncomingStreams; i++) { + EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedUnidirectionalStreamId(i))); + EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedBidirectionalStreamId(i))); + } + // Should be able to open the next bidirectional stream + EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedBidirectionalStreamId(i))); - QuicStreamId first_incoming_bidirectional_stream_id = - GetParam() == Perspective::IS_SERVER - ? GetNthClientInitiatedBidirectionalId(0) - : GetNthServerInitiatedBidirectionalId(0); - QuicStreamId first_incoming_unidirectional_stream_id = - GetParam() == Perspective::IS_SERVER - ? GetNthClientInitiatedUnidirectionalId(0) - : GetNthServerInitiatedUnidirectionalId(0); - EXPECT_EQ(first_incoming_bidirectional_stream_id + - (kNumMaxIncomingStreams - 1) * kV99StreamIdIncrement, - manager_->actual_max_allowed_incoming_bidirectional_stream_id()); - EXPECT_EQ(first_incoming_unidirectional_stream_id + - (kNumMaxIncomingStreams - 1) * kV99StreamIdIncrement, - manager_->actual_max_allowed_incoming_unidirectional_stream_id()); + // We should have exhausted the counts, the next streams should fail + EXPECT_FALSE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedUnidirectionalStreamId(i))); + EXPECT_FALSE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedBidirectionalStreamId(i + 1))); } TEST_P(UberQuicStreamIdManagerTest, GetNextOutgoingStreamId) { @@ -214,86 +267,116 @@ TEST_P(UberQuicStreamIdManagerTest, AvailableStreams) { TEST_P(UberQuicStreamIdManagerTest, MaybeIncreaseLargestPeerStreamId) { EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); - EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId( - manager_->actual_max_allowed_incoming_bidirectional_stream_id())); - EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId( - manager_->actual_max_allowed_incoming_unidirectional_stream_id())); + EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId(StreamCountToId( + manager_->actual_max_allowed_incoming_bidirectional_streams(), + /* Perspective=*/GetParam() == Perspective::IS_SERVER + ? Perspective::IS_CLIENT + : Perspective::IS_SERVER, + /* bidirectional=*/true))); + EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId(StreamCountToId( + manager_->actual_max_allowed_incoming_bidirectional_streams(), + /* Perspective=*/GetParam() == Perspective::IS_SERVER + ? Perspective::IS_CLIENT + : Perspective::IS_SERVER, + /* bidirectional=*/false))); + + std::string error_details = + GetParam() == Perspective::IS_SERVER + ? "Stream id 400 would exceed stream count limit 100" + : "Stream id 401 would exceed stream count limit 100"; - std::string error_details = GetParam() == Perspective::IS_SERVER - ? "Stream id 404 above 400" - : "Stream id 401 above 397"; EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, error_details, _)); - EXPECT_FALSE(manager_->MaybeIncreaseLargestPeerStreamId( - manager_->actual_max_allowed_incoming_bidirectional_stream_id() + - kV99StreamIdIncrement)); + EXPECT_FALSE(manager_->MaybeIncreaseLargestPeerStreamId(StreamCountToId( + manager_->actual_max_allowed_incoming_bidirectional_streams() + 1, + /* Perspective=*/GetParam() == Perspective::IS_SERVER + ? Perspective::IS_CLIENT + : Perspective::IS_SERVER, + /* bidirectional=*/true))); error_details = GetParam() == Perspective::IS_SERVER - ? "Stream id 402 above 398" - : "Stream id 403 above 399"; + ? "Stream id 402 would exceed stream count limit 100" + : "Stream id 403 would exceed stream count limit 100"; EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, error_details, _)); - EXPECT_FALSE(manager_->MaybeIncreaseLargestPeerStreamId( - manager_->actual_max_allowed_incoming_unidirectional_stream_id() + - kV99StreamIdIncrement)); + EXPECT_FALSE(manager_->MaybeIncreaseLargestPeerStreamId(StreamCountToId( + manager_->actual_max_allowed_incoming_bidirectional_streams() + 1, + /* Perspective=*/GetParam() == Perspective::IS_SERVER + ? Perspective::IS_CLIENT + : Perspective::IS_SERVER, + /* bidirectional=*/false))); } -TEST_P(UberQuicStreamIdManagerTest, OnMaxStreamIdFrame) { - QuicStreamId max_allowed_outgoing_bidirectional_stream_id = - manager_->max_allowed_outgoing_bidirectional_stream_id(); - QuicStreamId max_allowed_outgoing_unidirectional_stream_id = - manager_->max_allowed_outgoing_unidirectional_stream_id(); - - QuicMaxStreamIdFrame frame(kInvalidControlFrameId, - max_allowed_outgoing_bidirectional_stream_id); - EXPECT_TRUE(manager_->OnMaxStreamIdFrame(frame)); - EXPECT_EQ(max_allowed_outgoing_bidirectional_stream_id, - manager_->max_allowed_outgoing_bidirectional_stream_id()); - frame.max_stream_id = max_allowed_outgoing_unidirectional_stream_id; - EXPECT_TRUE(manager_->OnMaxStreamIdFrame(frame)); - EXPECT_EQ(max_allowed_outgoing_unidirectional_stream_id, - manager_->max_allowed_outgoing_unidirectional_stream_id()); - - frame.max_stream_id = - max_allowed_outgoing_bidirectional_stream_id + kV99StreamIdIncrement; - EXPECT_TRUE(manager_->OnMaxStreamIdFrame(frame)); - EXPECT_EQ( - max_allowed_outgoing_bidirectional_stream_id + kV99StreamIdIncrement, - manager_->max_allowed_outgoing_bidirectional_stream_id()); - EXPECT_EQ(max_allowed_outgoing_unidirectional_stream_id, - manager_->max_allowed_outgoing_unidirectional_stream_id()); - - frame.max_stream_id = - max_allowed_outgoing_unidirectional_stream_id + kV99StreamIdIncrement; - EXPECT_TRUE(manager_->OnMaxStreamIdFrame(frame)); - EXPECT_EQ( - max_allowed_outgoing_bidirectional_stream_id + kV99StreamIdIncrement, - manager_->max_allowed_outgoing_bidirectional_stream_id()); - EXPECT_EQ( - max_allowed_outgoing_unidirectional_stream_id + kV99StreamIdIncrement, - manager_->max_allowed_outgoing_unidirectional_stream_id()); +TEST_P(UberQuicStreamIdManagerTest, OnMaxStreamsFrame) { + QuicStreamCount max_allowed_outgoing_bidirectional_stream_count = + manager_->max_allowed_outgoing_bidirectional_streams(); + + QuicStreamCount max_allowed_outgoing_unidirectional_stream_count = + manager_->max_allowed_outgoing_unidirectional_streams(); + + // Inject a MAX_STREAMS frame that does not increase the limit and then + // check that there are no changes. First try the bidirectional manager. + QuicMaxStreamsFrame frame(kInvalidControlFrameId, + max_allowed_outgoing_bidirectional_stream_count, + /*unidirectional=*/false); + EXPECT_TRUE(manager_->OnMaxStreamsFrame(frame)); + EXPECT_EQ(max_allowed_outgoing_bidirectional_stream_count, + manager_->max_allowed_outgoing_bidirectional_streams()); + + // Now try the unidirectioanl manager + frame.stream_count = max_allowed_outgoing_unidirectional_stream_count; + frame.unidirectional = true; + EXPECT_TRUE(manager_->OnMaxStreamsFrame(frame)); + EXPECT_EQ(max_allowed_outgoing_unidirectional_stream_count, + manager_->max_allowed_outgoing_unidirectional_streams()); + + // Now try to increase the bidirectional stream count. + frame.stream_count = max_allowed_outgoing_bidirectional_stream_count + 1; + frame.unidirectional = false; + EXPECT_TRUE(manager_->OnMaxStreamsFrame(frame)); + EXPECT_EQ(max_allowed_outgoing_bidirectional_stream_count + 1, + manager_->max_allowed_outgoing_bidirectional_streams()); + // Make sure that the unidirectional state does not change. + EXPECT_EQ(max_allowed_outgoing_unidirectional_stream_count, + manager_->max_allowed_outgoing_unidirectional_streams()); + + // Now check that a MAX_STREAMS for the unidirectional manager increases + // just the unidirectiomal manager's state. + frame.stream_count = max_allowed_outgoing_unidirectional_stream_count + 1; + frame.unidirectional = true; + EXPECT_TRUE(manager_->OnMaxStreamsFrame(frame)); + EXPECT_EQ(max_allowed_outgoing_bidirectional_stream_count + 1, + manager_->max_allowed_outgoing_bidirectional_streams()); + EXPECT_EQ(max_allowed_outgoing_unidirectional_stream_count + 1, + manager_->max_allowed_outgoing_unidirectional_streams()); } -TEST_P(UberQuicStreamIdManagerTest, OnStreamIdBlockedFrame) { +TEST_P(UberQuicStreamIdManagerTest, OnStreamsBlockedFrame) { + // Set up to capture calls to SendControlFrame - when a STREAMS_BLOCKED + // frame is received, it will result in a a new MAX_STREAMS frame being + // sent (if new streams can be made available). EXPECT_CALL(*connection_, SendControlFrame(_)) .WillRepeatedly( Invoke(this, &UberQuicStreamIdManagerTest::SaveControlFrame)); - QuicStreamId stream_id = - manager_->advertised_max_allowed_incoming_bidirectional_stream_id() - - kV99StreamIdIncrement; - QuicStreamIdBlockedFrame frame(kInvalidControlFrameId, stream_id); - session_->OnStreamIdBlockedFrame(frame); - EXPECT_EQ(MAX_STREAM_ID_FRAME, frame_.type); - EXPECT_EQ(manager_->actual_max_allowed_incoming_bidirectional_stream_id(), - frame_.max_stream_id_frame.max_stream_id); - - frame.stream_id = - manager_->advertised_max_allowed_incoming_unidirectional_stream_id() - - kV99StreamIdIncrement; - session_->OnStreamIdBlockedFrame(frame); - EXPECT_EQ(MAX_STREAM_ID_FRAME, frame_.type); - EXPECT_EQ(manager_->actual_max_allowed_incoming_unidirectional_stream_id(), - frame_.max_stream_id_frame.max_stream_id); + QuicStreamCount stream_count = + manager_->advertised_max_allowed_incoming_bidirectional_streams() - 1; + + QuicStreamsBlockedFrame frame(kInvalidControlFrameId, stream_count, + /*unidirectional=*/false); + session_->OnStreamsBlockedFrame(frame); + EXPECT_EQ(MAX_STREAMS_FRAME, frame_.type); + EXPECT_EQ(manager_->actual_max_allowed_incoming_bidirectional_streams(), + frame_.max_streams_frame.stream_count); + + stream_count = + manager_->advertised_max_allowed_incoming_unidirectional_streams() - 1; + frame.stream_count = stream_count; + frame.unidirectional = true; + + session_->OnStreamsBlockedFrame(frame); + EXPECT_EQ(MAX_STREAMS_FRAME, frame_.type); + EXPECT_EQ(manager_->actual_max_allowed_incoming_unidirectional_streams(), + frame_.max_streams_frame.stream_count); } TEST_P(UberQuicStreamIdManagerTest, IsIncomingStream) { @@ -318,6 +401,44 @@ TEST_P(UberQuicStreamIdManagerTest, IsIncomingStream) { } } +TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenOutgoingStreamsPlusFrame) { + const size_t kNumMaxOutgoingStream = 123; + // Set the uni- and bi- directional limits to different values to ensure + // that they are managed separately. + manager_->SetMaxOpenOutgoingBidirectionalStreams(kNumMaxOutgoingStream); + manager_->SetMaxOpenOutgoingUnidirectionalStreams(kNumMaxOutgoingStream + 1); + EXPECT_EQ(kNumMaxOutgoingStream, + manager_->max_allowed_outgoing_bidirectional_streams()); + EXPECT_EQ(kNumMaxOutgoingStream + 1, + manager_->max_allowed_outgoing_unidirectional_streams()); + // Check that, for each directionality, we can open the correct number of + // streams. + int i = kNumMaxOutgoingStream; + while (i) { + EXPECT_TRUE(manager_->CanOpenNextOutgoingBidirectionalStream()); + manager_->GetNextOutgoingBidirectionalStreamId(); + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + manager_->GetNextOutgoingUnidirectionalStreamId(); + i--; + } + // One more unidirectional + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + manager_->GetNextOutgoingUnidirectionalStreamId(); + + // Both should be exhausted... + EXPECT_FALSE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + EXPECT_FALSE(manager_->CanOpenNextOutgoingBidirectionalStream()); + + // Now cons a MAX STREAMS frame for unidirectional streams to raise + // the limit. + QuicMaxStreamsFrame frame(1, kNumMaxOutgoingStream + 10, + /*unidirectional=*/true); + manager_->OnMaxStreamsFrame(frame); + // We now should be able to get another uni- stream, but not a bi. + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + EXPECT_FALSE(manager_->CanOpenNextOutgoingBidirectionalStream()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc index e8876369c8b..a3c79d34428 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc @@ -195,6 +195,12 @@ const QuicAckFrame& UberReceivedPacketManager::ack_frame() const { return received_packet_managers_[0].ack_frame(); } +const QuicAckFrame& UberReceivedPacketManager::GetAckFrame( + PacketNumberSpace packet_number_space) const { + DCHECK(supports_multiple_packet_number_spaces_); + return received_packet_managers_[packet_number_space].ack_frame(); +} + void UberReceivedPacketManager::set_max_ack_ranges(size_t max_ack_ranges) { for (auto& received_packet_manager : received_packet_managers_) { received_packet_manager.set_max_ack_ranges(max_ack_ranges); diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h index 5c813e21f6d..21c2c0c7240 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h @@ -85,6 +85,7 @@ class QUIC_EXPORT_PRIVATE UberReceivedPacketManager { // For logging purposes. const QuicAckFrame& ack_frame() const; + const QuicAckFrame& GetAckFrame(PacketNumberSpace packet_number_space) const; void set_max_ack_ranges(size_t max_ack_ranges); diff --git a/chromium/net/third_party/quiche/src/quic/platform/README.md b/chromium/net/third_party/quiche/src/quic/platform/README.md new file mode 100644 index 00000000000..6538de108cf --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/platform/README.md @@ -0,0 +1,12 @@ +# QUIC platform + +This platform/ directory exists in order to allow QUIC code to be built on +numerous platforms. It contains two subdirectories: + +- api/ contains platform independent class definitions for fundamental data + structures (e.g., IPAddress, SocketAddress, etc.). +- impl/ contains platform specific implementations of these data structures. + The content of files in impl/ will vary depending on the platform. + +Code in the parent quic/ directory should not depend on any platform specific +code, other than that found in impl/. diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/README.md b/chromium/net/third_party/quiche/src/quic/platform/api/README.md new file mode 100644 index 00000000000..d3de2e14073 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/platform/api/README.md @@ -0,0 +1,67 @@ +# QUIC platform API + +This directory contains the infrastructure blocks needed to support QUIC in +certain platform. These APIs act as interaction layers between QUIC core and +either the upper layer application (i.e. Chrome, Envoy) or the platform's own +infrastructure (i.e. logging, test framework and system IO). QUIC core needs the +implementations of these APIs to build and function appropriately. There is +unidirectional dependency from QUIC core to most of the APIs here, such as +QUIC_LOG and QuicMutex, but a few APIs also depend back on QUIC core's basic +QUIC data types, such as QuicClock and QuicSleep. + +- APIs used by QUIC core: + + Most APIs are used by QUIC core to interact with platform infrastructure + (i.e. QUIC_LOG) or to wrap around platform dependent data types (i.e. + QuicIntervalSet), the dependency is: + + ```dot + digraph { + application -> quic_core -> quic_platform_api -> quic_platform_impl -> platform_infrastructure + application -> platform_infrastructure + } + ``` + +- APIs used by applications: + + Some APIs are used by applications to interact with QUIC core (i.e. + QuicMemSlice). For such APIs, their dependency model is: + + ```dot + digraph { + application -> quic_platform_impl -> platform_infrastructure + application -> quic_core -> quic_platform_api + quic_platform_impl -> quic_platform_api + application -> platform_infrastructure + } + ``` + + An example for such dependency is QuicClock. + + Or + + ```dot + digraph { + application -> quic_platform_impl -> platform_infrastructure + application -> quic_core -> quic_platform_api -> quic_platform_impl + quic_platform_impl -> quic_platform_api + application -> platform_infrastructure + } + ``` + + An example for such dependency is QuicMemSlice. + +# Documentation of each API and its usage. + +QuicMemSlice +: QuicMemSlice is used to wrap application data and pass to QUIC stream's + write interface. It refers to a memory block of data which should be around + till QuicMemSlice::Reset() is called. It's upto each platform, to implement + it as reference counted or not. + +QuicClock +: QuicClock is used by QUIC core to get current time. Its instance is created + by applications and passed into QuicDispatcher and + QuicConnectionHelperInterface. + +TODO(b/131224336) add document for other APIs diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_clock.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_clock.h index afd82dc5906..80000177780 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_clock.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_clock.h @@ -8,6 +8,11 @@ #include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +/* API_DESCRIPTION + QuicClock is used by QUIC core to get current time. Its instance is created by + applications and passed into QuicDispatcher and QuicConnectionHelperInterface. + API-DESCRIPTION */ + namespace quic { // Interface for retrieving the current time. diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_flags.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_flags.h index 302036fd3d8..bf6fc3c306a 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_flags.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_flags.h @@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/impl/quic_flags_impl.h" // Define a command-line flag that can be automatically set via diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address.cc index 2b86cadc3fa..3b48c475f67 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address.cc +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address.cc @@ -85,7 +85,15 @@ bool QuicIpAddress::IsIPv6() const { bool QuicIpAddress::InSameSubnet(const QuicIpAddress& other, int subnet_length) { - return impl_.InSameSubnet(other.impl(), subnet_length); + return impl_.InSameSubnet(other.impl_, subnet_length); +} + +in_addr QuicIpAddress::GetIPv4() const { + return impl_.GetIPv4(); +} + +in6_addr QuicIpAddress::GetIPv6() const { + return impl_.GetIPv6(); } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address.h index f6013af4d4b..6d507b4d843 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address.h @@ -73,7 +73,8 @@ class QUIC_EXPORT_PRIVATE QuicIpAddress { bool IsIPv6() const; bool InSameSubnet(const QuicIpAddress& other, int subnet_length); - const QuicIpAddressImpl& impl() const { return impl_; } + in_addr GetIPv4() const; + in6_addr GetIPv6() const; private: QuicIpAddressImpl impl_; diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address_test.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address_test.cc new file mode 100644 index 00000000000..69424272146 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_ip_address_test.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2019 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/third_party/quiche/src/quic/platform/api/quic_ip_address.h" + +#include <cstdint> + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { +namespace { + +TEST(QuicIpAddressTest, IPv4) { + QuicIpAddress ip_address; + EXPECT_FALSE(ip_address.IsInitialized()); + + EXPECT_TRUE(ip_address.FromString("127.0.52.223")); + EXPECT_TRUE(ip_address.IsInitialized()); + + EXPECT_EQ(IpAddressFamily::IP_V4, ip_address.address_family()); + EXPECT_TRUE(ip_address.IsIPv4()); + EXPECT_FALSE(ip_address.IsIPv6()); + + EXPECT_EQ("127.0.52.223", ip_address.ToString()); + const in_addr v4_address = ip_address.GetIPv4(); + const uint8_t* const v4_address_ptr = + reinterpret_cast<const uint8_t*>(&v4_address); + EXPECT_EQ(127u, *(v4_address_ptr + 0)); + EXPECT_EQ(0u, *(v4_address_ptr + 1)); + EXPECT_EQ(52u, *(v4_address_ptr + 2)); + EXPECT_EQ(223u, *(v4_address_ptr + 3)); +} + +TEST(QuicIpAddressTest, IPv6) { + QuicIpAddress ip_address; + EXPECT_FALSE(ip_address.IsInitialized()); + + EXPECT_TRUE(ip_address.FromString("fe80::1ff:fe23:4567")); + EXPECT_TRUE(ip_address.IsInitialized()); + + EXPECT_EQ(IpAddressFamily::IP_V6, ip_address.address_family()); + EXPECT_FALSE(ip_address.IsIPv4()); + EXPECT_TRUE(ip_address.IsIPv6()); + + EXPECT_EQ("fe80::1ff:fe23:4567", ip_address.ToString()); + const in6_addr v6_address = ip_address.GetIPv6(); + const uint16_t* const v6_address_ptr = + reinterpret_cast<const uint16_t*>(&v6_address); + EXPECT_EQ(0x80feu, *(v6_address_ptr + 0)); + EXPECT_EQ(0x0000u, *(v6_address_ptr + 1)); + EXPECT_EQ(0x0000u, *(v6_address_ptr + 2)); + EXPECT_EQ(0x0000u, *(v6_address_ptr + 3)); + EXPECT_EQ(0x0000u, *(v6_address_ptr + 4)); + EXPECT_EQ(0xff01u, *(v6_address_ptr + 5)); + EXPECT_EQ(0x23feu, *(v6_address_ptr + 6)); + EXPECT_EQ(0x6745u, *(v6_address_ptr + 7)); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h index a4318ad8bcc..a40d6384df9 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h @@ -8,6 +8,13 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/quic/platform/impl/quic_mem_slice_impl.h" +/* API_DESCRIPTION + QuicMemSlice is used to wrap application data and pass to QUIC stream's write + interface. It refers to a memory block of data which should be around till + QuicMemSlice::Reset() is called. It's upto each platform, to implement it as + reference counted or not. + API-DESCRIPTION */ + namespace quic { // QuicMemSlice is an internally reference counted data buffer used as the @@ -53,6 +60,8 @@ class QUIC_EXPORT_PRIVATE QuicMemSlice { bool empty() const { return impl_.empty(); } + QuicMemSliceImpl* impl() { return &impl_; } + private: QuicMemSliceImpl impl_; }; diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h index 4fdf059434b..62cec4871c9 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h @@ -22,6 +22,9 @@ class QUIC_EXPORT_PRIVATE QuicMemSliceSpan { public: explicit QuicMemSliceSpan(QuicMemSliceSpanImpl impl) : impl_(impl) {} + // Constructs a span with a single QuicMemSlice. + explicit QuicMemSliceSpan(QuicMemSlice* slice) : impl_(slice->impl()) {} + QuicMemSliceSpan(const QuicMemSliceSpan& other) = default; QuicMemSliceSpan& operator=(const QuicMemSliceSpan& other) = default; QuicMemSliceSpan(QuicMemSliceSpan&& other) = default; diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_optional.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_optional.h new file mode 100644 index 00000000000..921c3a874a3 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_optional.h @@ -0,0 +1,17 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_OPTIONAL_H_ +#define QUICHE_QUIC_PLATFORM_API_QUIC_OPTIONAL_H_ + +#include "net/quic/platform/impl/quic_optional_impl.h" + +namespace quic { + +template <typename T> +using QuicOptional = QuicOptionalImpl<T>; + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_API_QUIC_OPTIONAL_H_ diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc index dacd6ac3505..e0bb35c4f7d 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.cc @@ -9,7 +9,7 @@ namespace quic { QuicSocketAddress::QuicSocketAddress(QuicIpAddress address, uint16_t port) - : impl_(address.impl(), port) {} + : impl_(address, port) {} QuicSocketAddress::QuicSocketAddress(const struct sockaddr_storage& saddr) : impl_(saddr) {} diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.h index 57689a77828..85e61d5a235 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_socket_address.h @@ -39,7 +39,6 @@ class QUIC_EXPORT_PRIVATE QuicSocketAddress { QuicIpAddress host() const; uint16_t port() const; sockaddr_storage generic_address() const; - const QuicSocketAddressImpl& impl() const { return impl_; } private: QuicSocketAddressImpl impl_; diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_string_utils_test.cc b/chromium/net/third_party/quiche/src/quic/platform/api/quic_string_utils_test.cc index e2f13005846..39f675f8bd3 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_string_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_string_utils_test.cc @@ -6,9 +6,9 @@ #include <cstdint> -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h index f4d255ab0b8..2f3286541a9 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_test.h @@ -5,6 +5,7 @@ #ifndef QUICHE_QUIC_PLATFORM_API_QUIC_TEST_H_ #define QUICHE_QUIC_PLATFORM_API_QUIC_TEST_H_ +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/quic/platform/impl/quic_test_impl.h" using QuicFlagSaver = QuicFlagSaverImpl; diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc index 6c6ee97c29f..da74858d69b 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc @@ -6,15 +6,16 @@ namespace quic { -QuartcConnectionHelper::QuartcConnectionHelper(const QuicClock* clock) - : clock_(clock) {} +QuartcConnectionHelper::QuartcConnectionHelper(const QuicClock* clock, + QuicRandom* random) + : clock_(clock), random_(random) {} const QuicClock* QuartcConnectionHelper::GetClock() const { return clock_; } QuicRandom* QuartcConnectionHelper::GetRandomGenerator() { - return QuicRandom::GetInstance(); + return random_; } QuicBufferAllocator* QuartcConnectionHelper::GetStreamSendBufferAllocator() { diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h index 2b1d62f9a53..184dacc1aaf 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h @@ -16,7 +16,7 @@ namespace quic { // Simple implementation of QuicConnectionHelperInterface for Quartc. class QuartcConnectionHelper : public QuicConnectionHelperInterface { public: - explicit QuartcConnectionHelper(const QuicClock* clock); + QuartcConnectionHelper(const QuicClock* clock, QuicRandom* random); // QuicConnectionHelperInterface overrides. const QuicClock* GetClock() const override; @@ -25,6 +25,7 @@ class QuartcConnectionHelper : public QuicConnectionHelperInterface { private: const QuicClock* clock_; + QuicRandom* random_; SimpleBufferAllocator buffer_allocator_; }; diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc index 93023e72d3f..4653000138b 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc @@ -60,6 +60,8 @@ QuicAsyncStatus InsecureProofVerifier::VerifyProof( QuicAsyncStatus InsecureProofVerifier::VerifyCertChain( const std::string& hostname, const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, const ProofVerifyContext* context, std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h index 2dba7ac7d06..1436aeb41f0 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h @@ -88,6 +88,8 @@ class InsecureProofVerifier : public ProofVerifier { QuicAsyncStatus VerifyCertChain( const std::string& hostname, const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, const ProofVerifyContext* context, std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc index fd4f289f3a6..e6e9c2b0a89 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc @@ -37,9 +37,9 @@ QuartcDispatcher::QuartcDispatcher( delegate_(delegate), packet_writer_(packet_writer.get()) { // Allow incoming packets to set our expected connection ID length. - SetShouldUpdateExpectedConnectionIdLength(true); + SetShouldUpdateExpectedServerConnectionIdLength(true); // Allow incoming packets with connection ID lengths shorter than allowed. - SetAllowShortInitialConnectionIds(true); + SetAllowShortInitialServerConnectionIds(true); // QuicDispatcher takes ownership of the writer. QuicDispatcher::InitializeWithWriter(packet_writer.release()); // NB: This must happen *after* InitializeWithWriter. It can call us back @@ -58,7 +58,7 @@ QuartcSession* QuartcDispatcher::CreateQuicSession( QuicStringPiece alpn, const ParsedQuicVersion& version) { // Make our expected connection ID non-mutable since we have a connection. - SetShouldUpdateExpectedConnectionIdLength(false); + SetShouldUpdateExpectedServerConnectionIdLength(false); std::unique_ptr<QuicConnection> connection = CreateQuicConnection( connection_id, client_address, helper(), alarm_factory(), writer(), Perspective::IS_SERVER, ParsedQuicVersionVector{version}); diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h index 26b52ac4f0c..239b6ef0c22 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h @@ -41,7 +41,7 @@ class QuartcDispatcher : public QuicDispatcher, Delegate* delegate); ~QuartcDispatcher() override; - QuartcSession* CreateQuicSession(QuicConnectionId connection_id, + QuartcSession* CreateQuicSession(QuicConnectionId server_connection_id, const QuicSocketAddress& client_address, QuicStringPiece alpn, const ParsedQuicVersion& version) override; diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc index 459ceba0618..7676c591062 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc @@ -47,6 +47,7 @@ QuicArenaScopedPtr<QuicAlarm> QuartcAlarmFactoryWrapper::CreateAlarm( QuartcClientEndpoint::QuartcClientEndpoint( QuicAlarmFactory* alarm_factory, const QuicClock* clock, + QuicRandom* random, QuartcEndpoint::Delegate* delegate, const QuartcSessionConfig& config, QuicStringPiece serialized_server_config, @@ -60,25 +61,82 @@ QuartcClientEndpoint::QuartcClientEndpoint( AllSupportedVersions())), create_session_alarm_(QuicWrapUnique( alarm_factory_->CreateAlarm(new CreateSessionDelegate(this)))), - connection_helper_(QuicMakeUnique<QuartcConnectionHelper>(clock)), + connection_helper_( + QuicMakeUnique<QuartcConnectionHelper>(clock_, random)), config_(config) {} void QuartcClientEndpoint::Connect(QuartcPacketTransport* packet_transport) { packet_transport_ = packet_transport; + // For the first attempt to connect, use any version that the client supports. + current_versions_ = version_manager_->GetSupportedVersions(); create_session_alarm_->Set(clock_->Now()); } void QuartcClientEndpoint::OnCreateSessionAlarm() { session_ = CreateQuartcClientSession( config_, clock_, alarm_factory_, connection_helper_.get(), - version_manager_->GetSupportedVersions(), serialized_server_config_, - packet_transport_); + current_versions_, serialized_server_config_, packet_transport_); + session_->SetDelegate(this); delegate_->OnSessionCreated(session_.get()); } +void QuartcClientEndpoint::OnCryptoHandshakeComplete() { + delegate_->OnCryptoHandshakeComplete(); +} + +void QuartcClientEndpoint::OnConnectionWritable() { + delegate_->OnConnectionWritable(); +} + +void QuartcClientEndpoint::OnIncomingStream(QuartcStream* stream) { + delegate_->OnIncomingStream(stream); +} + +void QuartcClientEndpoint::OnCongestionControlChange( + QuicBandwidth bandwidth_estimate, + QuicBandwidth pacing_rate, + QuicTime::Delta latest_rtt) { + delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate, + latest_rtt); +} + +void QuartcClientEndpoint::OnConnectionClosed(QuicErrorCode error_code, + const std::string& error_details, + ConnectionCloseSource source) { + // First, see if we can restart the session with a mutually-supported version. + if (error_code == QUIC_INVALID_VERSION && session_ && + session_->connection() && + !session_->connection()->server_supported_versions().empty()) { + for (const auto& client_version : + version_manager_->GetSupportedVersions()) { + if (QuicContainsValue(session_->connection()->server_supported_versions(), + client_version)) { + // Found a mutually-supported version. Reconnect using that version. + current_versions_.clear(); + current_versions_.push_back(client_version); + create_session_alarm_->Set(clock_->Now()); + return; + } + } + } + + // Permanent version negotiation errors are forwarded to the |delegate_|, + // along with all other errors. + delegate_->OnConnectionClosed(error_code, error_details, source); +} + +void QuartcClientEndpoint::OnMessageReceived(QuicStringPiece message) { + delegate_->OnMessageReceived(message); +} + +void QuartcClientEndpoint::OnMessageSent(int64_t datagram_id) { + delegate_->OnMessageSent(datagram_id); +} + QuartcServerEndpoint::QuartcServerEndpoint( QuicAlarmFactory* alarm_factory, const QuicClock* clock, + QuicRandom* random, QuartcEndpoint::Delegate* delegate, const QuartcSessionConfig& config, std::unique_ptr<QuicVersionManager> version_manager) @@ -88,7 +146,8 @@ QuartcServerEndpoint::QuartcServerEndpoint( version_manager_(version_manager ? std::move(version_manager) : QuicMakeUnique<QuicVersionManager>( AllSupportedVersions())), - pre_connection_helper_(QuicMakeUnique<QuartcConnectionHelper>(clock)), + pre_connection_helper_( + QuicMakeUnique<QuartcConnectionHelper>(clock, random)), crypto_config_( CreateCryptoServerConfig(pre_connection_helper_->GetRandomGenerator(), clock, @@ -111,6 +170,7 @@ void QuartcServerEndpoint::Connect(QuartcPacketTransport* packet_transport) { } void QuartcServerEndpoint::OnSessionCreated(QuartcSession* session) { + session->SetDelegate(delegate_); delegate_->OnSessionCreated(session); } diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h index 97f30609ec0..6c7644c9519 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h @@ -10,6 +10,7 @@ #include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/platform/api/quic_clock.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h" #include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" #include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h" @@ -29,22 +30,23 @@ class QuartcEndpointImpl { // Endpoint (client or server) in a peer-to-peer Quartc connection. class QuartcEndpoint { public: - class Delegate { + class Delegate : public QuartcSession::Delegate { public: virtual ~Delegate() = default; // Called when an endpoint creates a new session, before any packets are // processed or sent. The callee should perform any additional - // configuration required, such as setting a session delegate, before + // configuration required, such as setting up congestion control, before // returning. |session| is owned by the endpoint, but remains safe to use - // until another call to |OnSessionCreated| occurs, at which point previous - // session is destroyed. + // until another call to |OnSessionCreated| or |OnConnectionClosed| occurs, + // at which point previous session may be destroyed. + // + // Callees must not change the |session|'s delegate. The Endpoint itself + // manages the delegate and will forward calls. + // + // New calls to |OnSessionCreated| will only occur prior to + // |OnConnectionWritable|, during initial connection negotiation. virtual void OnSessionCreated(QuartcSession* session) = 0; - - // Called if the endpoint fails to establish a session after a call to - // Connect. (The most likely cause is a network idle timeout.) - virtual void OnConnectError(QuicErrorCode error, - const std::string& error_details) = 0; }; virtual ~QuartcEndpoint() = default; @@ -58,20 +60,35 @@ class QuartcEndpoint { // Implementation of QuartcEndpoint which immediately (but asynchronously) // creates a session by scheduling a QuicAlarm. Only suitable for use with the // client perspective. -class QuartcClientEndpoint : public QuartcEndpoint { +class QuartcClientEndpoint : public QuartcEndpoint, + public QuartcSession::Delegate { public: // |alarm_factory|, |clock|, and |delegate| are owned by the caller and must // outlive the endpoint. QuartcClientEndpoint( QuicAlarmFactory* alarm_factory, const QuicClock* clock, - Delegate* delegate, + QuicRandom* random, + QuartcEndpoint::Delegate* delegate, const QuartcSessionConfig& config, QuicStringPiece serialized_server_config, std::unique_ptr<QuicVersionManager> version_manager = nullptr); void Connect(QuartcPacketTransport* packet_transport) override; + // QuartcSession::Delegate overrides. + void OnCryptoHandshakeComplete() override; + void OnConnectionWritable() override; + void OnIncomingStream(QuartcStream* stream) override; + void OnCongestionControlChange(QuicBandwidth bandwidth_estimate, + QuicBandwidth pacing_rate, + QuicTime::Delta latest_rtt) override; + void OnConnectionClosed(QuicErrorCode error_code, + const std::string& error_details, + ConnectionCloseSource source) override; + void OnMessageReceived(QuicStringPiece message) override; + void OnMessageSent(int64_t datagram_id) override; + private: friend class CreateSessionDelegate; class CreateSessionDelegate : public QuicAlarm::Delegate { @@ -103,6 +120,18 @@ class QuartcClientEndpoint : public QuartcEndpoint { // Version manager. May be injected to control version negotiation in tests. std::unique_ptr<QuicVersionManager> version_manager_; + // Versions to be used when the next session is created. The session will + // choose one of these versions for its connection attempt. + // + // If the connection does not succeed, the client session MAY try again using + // another version from this list, or it MAY simply fail with a + // QUIC_INVALID_VERSION error. The latter occurs when it is not possible to + // upgrade a connection in-place (for example, if the way stream ids are + // allocated changes between versions). This failure mode is handled by + // narrowing |current_versions_| to one of that is mutually-supported and + // reconnecting (with a new session). + ParsedQuicVersionVector current_versions_; + // Alarm for creating sessions asynchronously. The alarm is set when // Connect() is called. When it fires, the endpoint creates a session and // calls the delegate. @@ -130,6 +159,7 @@ class QuartcServerEndpoint : public QuartcEndpoint, QuartcServerEndpoint( QuicAlarmFactory* alarm_factory, const QuicClock* clock, + QuicRandom* random, QuartcEndpoint::Delegate* delegate, const QuartcSessionConfig& config, std::unique_ptr<QuicVersionManager> version_manager = nullptr); diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc index 3d7d85e8ed8..5f8c25d6416 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc @@ -30,20 +30,20 @@ class QuartcEndpointTest : public QuicTest { &server_transport_, QuicBandwidth::FromKBitsPerSecond(10000), QuicTime::Delta::FromMilliseconds(1)), - server_session_delegate_(&server_stream_delegate_, - simulator_.GetClock()), - server_endpoint_delegate_(&server_session_delegate_), - server_endpoint_( - QuicMakeUnique<QuartcServerEndpoint>(simulator_.GetAlarmFactory(), - simulator_.GetClock(), - &server_endpoint_delegate_, - QuartcSessionConfig())), - client_session_delegate_(&client_stream_delegate_, - simulator_.GetClock()), - client_endpoint_delegate_(&client_session_delegate_), + server_endpoint_delegate_(&server_stream_delegate_, + simulator_.GetClock()), + server_endpoint_(QuicMakeUnique<QuartcServerEndpoint>( + simulator_.GetAlarmFactory(), + simulator_.GetClock(), + simulator_.GetRandomGenerator(), + &server_endpoint_delegate_, + QuartcSessionConfig())), + client_endpoint_delegate_(&client_stream_delegate_, + simulator_.GetClock()), client_endpoint_(QuicMakeUnique<QuartcClientEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), + simulator_.GetRandomGenerator(), &client_endpoint_delegate_, QuartcSessionConfig(), /*serialized_server_config=*/"")) {} @@ -55,13 +55,11 @@ class QuartcEndpointTest : public QuicTest { simulator::SymmetricLink client_server_link_; FakeQuartcStreamDelegate server_stream_delegate_; - FakeQuartcSessionDelegate server_session_delegate_; FakeQuartcEndpointDelegate server_endpoint_delegate_; std::unique_ptr<QuartcServerEndpoint> server_endpoint_; FakeQuartcStreamDelegate client_stream_delegate_; - FakeQuartcSessionDelegate client_session_delegate_; FakeQuartcEndpointDelegate client_endpoint_delegate_; std::unique_ptr<QuartcClientEndpoint> client_endpoint_; @@ -86,7 +84,6 @@ TEST_F(QuartcEndpointTest, // matter, but they must be enabled so that the version manager doesn't filter // them out. SetQuicReloadableFlag(quic_enable_version_46, true); - SetQuicReloadableFlag(quic_enable_version_43, true); // Reset the client endpoint to prefer version 46 but also be capable of // speaking version 43. @@ -95,7 +92,8 @@ TEST_F(QuartcEndpointTest, client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), - &client_endpoint_delegate_, QuartcSessionConfig(), + simulator_.GetRandomGenerator(), &client_endpoint_delegate_, + QuartcSessionConfig(), /*serialized_server_config=*/"", QuicMakeUnique<QuicVersionManager>(client_versions)); @@ -104,7 +102,8 @@ TEST_F(QuartcEndpointTest, server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); server_endpoint_ = QuicMakeUnique<QuartcServerEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), - &server_endpoint_delegate_, QuartcSessionConfig(), + simulator_.GetRandomGenerator(), &server_endpoint_delegate_, + QuartcSessionConfig(), QuicMakeUnique<QuicVersionManager>(server_versions)); // The endpoints should be able to establish a connection using version 46. @@ -131,14 +130,14 @@ TEST_F(QuartcEndpointTest, // matter, but they must be enabled so that the version manager doesn't filter // them out. SetQuicReloadableFlag(quic_enable_version_46, true); - SetQuicReloadableFlag(quic_enable_version_43, true); // Reset the client endpoint to only speak version 43. ParsedQuicVersionVector client_versions; client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), - &client_endpoint_delegate_, QuartcSessionConfig(), + simulator_.GetRandomGenerator(), &client_endpoint_delegate_, + QuartcSessionConfig(), /*serialized_server_config=*/"", QuicMakeUnique<QuicVersionManager>(client_versions)); @@ -149,7 +148,8 @@ TEST_F(QuartcEndpointTest, server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); server_endpoint_ = QuicMakeUnique<QuartcServerEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), - &server_endpoint_delegate_, QuartcSessionConfig(), + simulator_.GetRandomGenerator(), &server_endpoint_delegate_, + QuartcSessionConfig(), QuicMakeUnique<QuicVersionManager>(server_versions)); // The endpoints should be able to establish a connection using version 46. @@ -176,14 +176,14 @@ TEST_F(QuartcEndpointTest, // matter, but they must be enabled so that the version manager doesn't filter // them out. SetQuicReloadableFlag(quic_enable_version_46, true); - SetQuicReloadableFlag(quic_enable_version_43, true); // Reset the client endpoint to only speak version 43. ParsedQuicVersionVector client_versions; client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), - &client_endpoint_delegate_, QuartcSessionConfig(), + simulator_.GetRandomGenerator(), &client_endpoint_delegate_, + QuartcSessionConfig(), /*serialized_server_config=*/"", QuicMakeUnique<QuicVersionManager>(client_versions)); @@ -192,7 +192,8 @@ TEST_F(QuartcEndpointTest, server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46}); server_endpoint_ = QuicMakeUnique<QuartcServerEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), - &server_endpoint_delegate_, QuartcSessionConfig(), + simulator_.GetRandomGenerator(), &server_endpoint_delegate_, + QuartcSessionConfig(), QuicMakeUnique<QuicVersionManager>(server_versions)); // The endpoints should be unable to establish a connection. @@ -210,5 +211,57 @@ TEST_F(QuartcEndpointTest, EXPECT_EQ(client_endpoint_delegate_.session()->error(), QUIC_INVALID_VERSION); } +// Tests that the client endpoint can create a new session in order to continue +// version negotiation. +TEST_F(QuartcEndpointTest, + QUIC_TEST_DISABLED_IN_CHROME(CreatesNewSessionWhenRequired)) { + // Setting this flag to true requires the client to create a new session when + // version negotiation fails. + SetQuicReloadableFlag(quic_no_client_conn_ver_negotiation, true); + + // Note: for this test, we need support for two versions. Which two shouldn't + // matter, but they must be enabled so that the version manager doesn't filter + // them out. + SetQuicReloadableFlag(quic_enable_version_46, true); + + // Reset the client endpoint to prefer version 46 but also be capable of + // speaking version 43. + ParsedQuicVersionVector client_versions; + client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46}); + client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); + client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>( + simulator_.GetAlarmFactory(), simulator_.GetClock(), + simulator_.GetRandomGenerator(), &client_endpoint_delegate_, + QuartcSessionConfig(), + /*serialized_server_config=*/"", + QuicMakeUnique<QuicVersionManager>(client_versions)); + + // Reset the server endpoint to only speak version 43. + ParsedQuicVersionVector server_versions; + server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); + server_endpoint_ = QuicMakeUnique<QuartcServerEndpoint>( + simulator_.GetAlarmFactory(), simulator_.GetClock(), + simulator_.GetRandomGenerator(), &server_endpoint_delegate_, + QuartcSessionConfig(), + QuicMakeUnique<QuicVersionManager>(server_versions)); + + // The endpoints should be able to establish a connection using version 46. + server_endpoint_->Connect(&server_transport_); + client_endpoint_->Connect(&client_transport_); + + ASSERT_TRUE(simulator_.RunUntil([this] { + return client_endpoint_delegate_.session() != nullptr && + client_endpoint_delegate_.session()->IsEncryptionEstablished() && + server_endpoint_delegate_.session() != nullptr && + server_endpoint_delegate_.session()->IsEncryptionEstablished(); + })); + EXPECT_EQ(client_endpoint_delegate_.session()->connection()->version(), + server_versions[0]); + EXPECT_EQ(server_endpoint_delegate_.session()->connection()->version(), + server_versions[0]); + + EXPECT_EQ(2, client_endpoint_delegate_.num_sessions_created()); +} + } // namespace } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc index 436212fd7a1..06871a2fe97 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc @@ -68,19 +68,9 @@ void ConfigureGlobalQuicSettings() { // Ensure that we don't drop data because QUIC streams refuse to buffer it. // TODO(b/120099046): Replace this with correct handling of WriteMemSlices(). - SetQuicFlag(&FLAGS_quic_buffered_data_threshold, + SetQuicFlag(FLAGS_quic_buffered_data_threshold, std::numeric_limits<int>::max()); - // TODO(b/117157454): Perform version negotiation for Quartc outside of - // QuicSession/QuicConnection. Currently default of - // quic_restart_flag_quic_no_server_conn_ver_negotiation2 is false, - // but we fail blueprint test that sets all QUIC flags to true. - // - // Forcing flag to false to pass blueprint tests, but eventually we'll have - // to implement negotiation outside of QuicConnection. - SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, false); - SetQuicReloadableFlag(quic_no_client_conn_ver_negotiation, false); - // Enable and request QUIC to include receive timestamps in ACK frames. SetQuicReloadableFlag(quic_send_timestamps, true); @@ -133,7 +123,6 @@ QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) { copt.push_back(kBBR9); // Ignore app-limited if enough data is in flight. copt.push_back(kBBQ1); // 2.773 pacing gain in STARTUP. copt.push_back(kBBQ2); // 2.0 CWND gain in STARTUP. - copt.push_back(kBBQ4); // 0.75 pacing gain in DRAIN. copt.push_back(k1RTT); // Exit STARTUP after 1 RTT with no gains. copt.push_back(kIW10); // 10-packet (14600 byte) initial cwnd. @@ -191,7 +180,7 @@ QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) { // incomplete streams, but targets 1 second for recovery. Increasing the // number of open streams gives sufficient headroom to recover before QUIC // refuses new streams. - quic_config.SetMaxIncomingDynamicStreamsToSend(1000); + quic_config.SetMaxIncomingBidirectionalStreamsToSend(1000); return quic_config; } diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h index 17e3874051c..13b65b1b532 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h @@ -18,38 +18,19 @@ namespace quic { class FakeQuartcEndpointDelegate : public QuartcEndpoint::Delegate { public: - explicit FakeQuartcEndpointDelegate(QuartcSession::Delegate* session_delegate) - : session_delegate_(session_delegate) {} + explicit FakeQuartcEndpointDelegate(QuartcStream::Delegate* stream_delegate, + const QuicClock* clock) + : stream_delegate_(stream_delegate), clock_(clock) {} void OnSessionCreated(QuartcSession* session) override { - CHECK_EQ(session_, nullptr); CHECK_NE(session, nullptr); session_ = session; - session_->SetDelegate(session_delegate_); session_->StartCryptoHandshake(); + ++num_sessions_created_; } - void OnConnectError(QuicErrorCode error, - const std::string& error_details) override { - LOG(FATAL) << "Unexpected error during QuartcEndpoint::Connect(); error=" - << error << ", error_details=" << error_details; - } - - QuartcSession* session() { return session_; } - - private: - QuartcSession::Delegate* session_delegate_; - QuartcSession* session_ = nullptr; -}; - -class FakeQuartcSessionDelegate : public QuartcSession::Delegate { - public: - explicit FakeQuartcSessionDelegate(QuartcStream::Delegate* stream_delegate, - const QuicClock* clock) - : stream_delegate_(stream_delegate), clock_(clock) {} - void OnConnectionWritable() override { - LOG(INFO) << "Connection writable!"; + QUIC_LOG(INFO) << "Connection writable!"; if (!writable_time_.IsInitialized()) { writable_time_ = clock_->Now(); } @@ -57,7 +38,7 @@ class FakeQuartcSessionDelegate : public QuartcSession::Delegate { // Called when peers have established forward-secure encryption void OnCryptoHandshakeComplete() override { - LOG(INFO) << "Crypto handshake complete!"; + QUIC_LOG(INFO) << "Crypto handshake complete!"; crypto_handshake_time_ = clock_->Now(); } @@ -78,24 +59,44 @@ class FakeQuartcSessionDelegate : public QuartcSession::Delegate { incoming_messages_.emplace_back(message); } + void OnMessageSent(int64_t datagram_id) override { + sent_datagram_ids_.push_back(datagram_id); + } + void OnCongestionControlChange(QuicBandwidth bandwidth_estimate, QuicBandwidth pacing_rate, QuicTime::Delta latest_rtt) override {} - QuartcStream* last_incoming_stream() { return last_incoming_stream_; } + QuartcSession* session() { return session_; } + + int num_sessions_created() const { return num_sessions_created_; } + + QuartcStream* last_incoming_stream() const { return last_incoming_stream_; } // Returns all received messages. - const std::vector<std::string>& incoming_messages() { + const std::vector<std::string>& incoming_messages() const { return incoming_messages_; } - bool connected() { return connected_; } + // Returns all sent datagram ids in the order sent. + const std::vector<int64_t>& sent_datagram_ids() const { + return sent_datagram_ids_; + } + + bool connected() const { return connected_; } QuicTime writable_time() const { return writable_time_; } QuicTime crypto_handshake_time() const { return crypto_handshake_time_; } private: + // Current session. + QuartcSession* session_ = nullptr; + + // Number of new sessions created by the endpoint. + int num_sessions_created_ = 0; + QuartcStream* last_incoming_stream_; std::vector<std::string> incoming_messages_; + std::vector<int64_t> sent_datagram_ids_; bool connected_ = true; QuartcStream::Delegate* stream_delegate_; QuicTime writable_time_ = QuicTime::Zero(); diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc index 9bc9af5e55b..028aaf2dab6 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc @@ -4,8 +4,6 @@ #include "net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/quic_interval.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc index 80031dd0f2c..96156896af6 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc @@ -41,14 +41,16 @@ QuartcStream* QuartcSession::CreateOutgoingBidirectionalStream() { GetNextOutgoingBidirectionalStreamId(), QuicStream::kDefaultPriority)); } -bool QuartcSession::SendOrQueueMessage(std::string message) { +bool QuartcSession::SendOrQueueMessage(QuicMemSliceSpan message, + int64_t datagram_id) { if (!CanSendMessage()) { QUIC_LOG(ERROR) << "Quic session does not support SendMessage"; return false; } - if (message.size() > GetCurrentLargestMessagePayload()) { - QUIC_LOG(ERROR) << "Message is too big, message_size=" << message.size() + if (message.total_length() > GetCurrentLargestMessagePayload()) { + QUIC_LOG(ERROR) << "Message is too big, message_size=" + << message.total_length() << ", GetCurrentLargestMessagePayload=" << GetCurrentLargestMessagePayload(); return false; @@ -56,7 +58,9 @@ bool QuartcSession::SendOrQueueMessage(std::string message) { // There may be other messages in send queue, so we have to add message // to the queue and call queue processing helper. - send_message_queue_.emplace_back(std::move(message)); + message.ConsumeAll([this, datagram_id](QuicMemSlice slice) { + send_message_queue_.emplace_back(std::move(slice), datagram_id); + }); ProcessSendMessageQueue(); @@ -64,21 +68,22 @@ bool QuartcSession::SendOrQueueMessage(std::string message) { } void QuartcSession::ProcessSendMessageQueue() { + QuicConnection::ScopedPacketFlusher flusher( + connection(), QuicConnection::AckBundling::NO_ACK); while (!send_message_queue_.empty()) { - struct iovec iov = {const_cast<char*>(send_message_queue_.front().data()), - send_message_queue_.front().length()}; - QuicMemSliceStorage storage( - &iov, 1, connection()->helper()->GetStreamSendBufferAllocator(), - send_message_queue_.front().length()); - MessageResult result = SendMessage(storage.ToSpan()); - - const size_t message_size = send_message_queue_.front().size(); + QueuedMessage& it = send_message_queue_.front(); + const size_t message_size = it.message.length(); + MessageResult result = SendMessage(QuicMemSliceSpan(&it.message)); // Handle errors. switch (result.status) { case MESSAGE_STATUS_SUCCESS: QUIC_VLOG(1) << "Quartc message sent, message_id=" << result.message_id << ", message_size=" << message_size; + + // Notify that datagram was sent. + session_delegate_->OnMessageSent(it.datagram_id); + break; // If connection is congestion controlled or not writable yet, stop @@ -120,6 +125,20 @@ void QuartcSession::OnCanWrite() { QuicSession::OnCanWrite(); } +bool QuartcSession::SendProbingData() { + if (QuicSession::SendProbingData()) { + return true; + } + + // Set transmission type to PROBING_RETRANSMISSION such that the packets will + // be padded to full. + SetTransmissionType(PROBING_RETRANSMISSION); + // TODO(mellem): this sent PING will be retransmitted if it is lost which is + // not ideal. Consider to send stream data as probing data instead. + SendPing(); + return true; +} + void QuartcSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { QuicSession::OnCryptoHandshakeEvent(event); switch (event) { @@ -192,12 +211,12 @@ void QuartcSession::OnConnectionClosed(QuicErrorCode error, void QuartcSession::CloseConnection(const std::string& details) { connection_->CloseConnection( QuicErrorCode::QUIC_CONNECTION_CANCELLED, details, - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK); + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); } void QuartcSession::SetDelegate(Delegate* session_delegate) { if (session_delegate_) { - LOG(WARNING) << "The delegate for the session has already been set."; + QUIC_LOG(WARNING) << "The delegate for the session has already been set."; } session_delegate_ = session_delegate; DCHECK(session_delegate_); @@ -337,7 +356,7 @@ void QuartcClientSession::StartCryptoHandshake() { std::vector<std::string>{kDummyCertName}, /*cert_sct=*/"", /*chlo_hash=*/"", /*signature=*/"anything"); } else { - LOG(DFATAL) << "Unable to set server config, error=" << error; + QUIC_LOG(DFATAL) << "Unable to set server config, error=" << error; } } @@ -389,8 +408,7 @@ QuicCryptoStream* QuartcServerSession::GetMutableCryptoStream() { void QuartcServerSession::StartCryptoHandshake() { crypto_stream_ = QuicMakeUnique<QuicCryptoServerStream>( - server_crypto_config_, compressed_certs_cache_, - /*use_stateless_rejects_if_peer_supported=*/false, this, stream_helper_); + server_crypto_config_, compressed_certs_cache_, this, stream_helper_); Initialize(); } diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h index 29e63066efe..840f69d084b 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h @@ -48,7 +48,18 @@ class QuartcSession : public QuicSession, // support SendMessage API. Other unexpected errors during send will not be // returned, because messages can be sent later if connection is congestion // controlled. - bool SendOrQueueMessage(std::string message); + // + // |datagram_id| is used to notify when message was sent in + // Delegate::OnMessageSent. + // + // TODO(sukhanov): We can not use QUIC message ID for notifications, because + // QUIC does not take ownership of messages and if connection is congestion + // controlled, message is not sent and does not get message id until it is + // sent successfully. It also creates problem of flow control between + // messages and streams if they are used together. We discussed it with QUIC + // team and there are multiple solutions, but for now we have to use our + // own datagram identification. + bool SendOrQueueMessage(QuicMemSliceSpan message, int64_t datagram_id); // Returns largest message payload acceptable in SendQuartcMessage. QuicPacketLength GetCurrentLargestMessagePayload() const { @@ -67,6 +78,7 @@ class QuartcSession : public QuicSession, bool ShouldKeepConnectionAlive() const override; void OnCanWrite() override; + bool SendProbingData() override; void OnConnectionClosed(QuicErrorCode error, const std::string& error_details, @@ -128,6 +140,22 @@ class QuartcSession : public QuicSession, // Called when message (sent as SendMessage) is received. virtual void OnMessageReceived(QuicStringPiece message) = 0; + // Called when message is sent to QUIC. + // + // Takes into account delay due to congestion control, but does not take + // into account any additional socket delays. + // + // Passed |datagram_id| is the same used in SendOrQueueMessage. + // + // TODO(sukhanov): We can take into account socket delay, but it's not clear + // if it's worth doing if we eventually plan to move congestion control to + // QUIC in QRTP model. If we need to do it, mellem@ thinks it's fairly + // strtaightforward: QUIC does not know about socket delay, but ICE does. We + // can tell ICE the QUIC packet number for each packet sent, and it will + // echo it back to us when the packet actually goes out. We just need to + // plumb that signal up to RTP's congestion control. + virtual void OnMessageSent(int64_t datagram_id) = 0; + // TODO(zhihuang): Add proof verification. }; @@ -170,6 +198,14 @@ class QuartcSession : public QuicSession, std::unique_ptr<QuartcStream> stream, spdy::SpdyPriority priority); + // Holds message until it's sent. + struct QueuedMessage { + QueuedMessage(QuicMemSlice the_message, int64_t the_datagram_id) + : message(std::move(the_message)), datagram_id(the_datagram_id) {} + QuicMemSlice message; + int64_t datagram_id; + }; + void ProcessSendMessageQueue(); // Take ownership of the QuicConnection. Note: if |connection_| changes, @@ -189,7 +225,7 @@ class QuartcSession : public QuicSession, // Queue of pending messages sent by SendQuartcMessage that were not sent // yet or blocked by congestion control. Messages are queued in the order // of sent by SendOrQueueMessage(). - QuicDeque<std::string> send_message_queue_; + QuicDeque<QueuedMessage> send_message_queue_; }; class QuartcClientSession : public QuartcSession, diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc index 31abd57231e..87174dcc4a6 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc @@ -4,8 +4,6 @@ #include "net/third_party/quiche/src/quic/quartc/quartc_session.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" @@ -36,6 +34,11 @@ constexpr QuicTime::Delta kPropagationDelayAndABit = static QuicByteCount kDefaultMaxPacketSize = 1200; +test::QuicTestMemSliceVector CreateMemSliceVector(QuicStringPiece data) { + return test::QuicTestMemSliceVector( + {std::pair<char*, size_t>(const_cast<char*>(data.data()), data.size())}); +} + class QuartcSessionTest : public QuicTest { public: ~QuartcSessionTest() override {} @@ -58,28 +61,26 @@ class QuartcSessionTest : public QuicTest { QuicBandwidth::FromKBitsPerSecond(10 * 1000), kPropagationDelay); client_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>(); - client_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>( + client_session_delegate_ = QuicMakeUnique<FakeQuartcEndpointDelegate>( client_stream_delegate_.get(), simulator_.GetClock()); - client_endpoint_delegate_ = QuicMakeUnique<FakeQuartcEndpointDelegate>( - client_session_delegate_.get()); server_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>(); - server_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>( + server_session_delegate_ = QuicMakeUnique<FakeQuartcEndpointDelegate>( server_stream_delegate_.get(), simulator_.GetClock()); - server_endpoint_delegate_ = QuicMakeUnique<FakeQuartcEndpointDelegate>( - server_session_delegate_.get()); // No 0-rtt setup, because server config is empty. // CannotCreateDataStreamBeforeHandshake depends on 1-rtt setup. if (create_client_endpoint) { client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), - client_endpoint_delegate_.get(), quic::QuartcSessionConfig(), + simulator_.GetRandomGenerator(), client_session_delegate_.get(), + quic::QuartcSessionConfig(), /*serialized_server_config=*/""); } server_endpoint_ = QuicMakeUnique<QuartcServerEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), - server_endpoint_delegate_.get(), quic::QuartcSessionConfig()); + simulator_.GetRandomGenerator(), server_session_delegate_.get(), + quic::QuartcSessionConfig()); } // Note that input session config will apply to both server and client. @@ -94,12 +95,12 @@ class QuartcSessionTest : public QuicTest { client_endpoint_->Connect(client_transport_.get()); CHECK(simulator_.RunUntil([this] { - return client_endpoint_delegate_->session() != nullptr && - server_endpoint_delegate_->session() != nullptr; + return client_session_delegate_->session() != nullptr && + server_session_delegate_->session() != nullptr; })); - client_peer_ = client_endpoint_delegate_->session(); - server_peer_ = server_endpoint_delegate_->session(); + client_peer_ = client_session_delegate_->session(); + server_peer_ = server_session_delegate_->session(); } // Runs all tasks scheduled in the next 200 ms. @@ -130,9 +131,7 @@ class QuartcSessionTest : public QuicTest { outgoing_stream->SetDelegate(server_stream_delegate_.get()); // Send a test message from peer 1 to peer 2. - char kTestMessage[] = "Hello"; - test::QuicTestMemSliceVector data( - {std::make_pair(kTestMessage, strlen(kTestMessage))}); + test::QuicTestMemSliceVector data = CreateMemSliceVector("Hello"); outgoing_stream->WriteMemSlices(data.span(), /*fin=*/false); RunTasks(); @@ -144,17 +143,15 @@ class QuartcSessionTest : public QuicTest { EXPECT_EQ(incoming->id(), stream_id); EXPECT_TRUE(client_peer_->ShouldKeepConnectionAlive()); - EXPECT_EQ(client_stream_delegate_->data()[stream_id], kTestMessage); + EXPECT_EQ(client_stream_delegate_->data()[stream_id], "Hello"); // Send a test message from peer 2 to peer 1. - char kTestResponse[] = "Response"; - test::QuicTestMemSliceVector response( - {std::make_pair(kTestResponse, strlen(kTestResponse))}); + test::QuicTestMemSliceVector response = CreateMemSliceVector("Response"); incoming->WriteMemSlices(response.span(), /*fin=*/false); RunTasks(); // Wait for peer 1 to receive messages. ASSERT_TRUE(server_stream_delegate_->has_data()); - EXPECT_EQ(server_stream_delegate_->data()[stream_id], kTestResponse); + EXPECT_EQ(server_stream_delegate_->data()[stream_id], "Response"); } // Test sending/receiving of messages for two directions. @@ -162,8 +159,14 @@ class QuartcSessionTest : public QuicTest { ASSERT_TRUE(server_peer_->CanSendMessage()); ASSERT_TRUE(client_peer_->CanSendMessage()); + int64_t server_datagram_id = 111; + int64_t client_datagram_id = 222; + // Send message from peer 1 to peer 2. - ASSERT_TRUE(server_peer_->SendOrQueueMessage("Message from server")); + test::QuicTestMemSliceVector message = + CreateMemSliceVector("Message from server"); + ASSERT_TRUE( + server_peer_->SendOrQueueMessage(message.span(), server_datagram_id)); // First message in each direction should not be queued. EXPECT_EQ(server_peer_->send_message_queue_size(), 0u); @@ -174,8 +177,13 @@ class QuartcSessionTest : public QuicTest { EXPECT_THAT(client_session_delegate_->incoming_messages(), testing::ElementsAre("Message from server")); + EXPECT_THAT(server_session_delegate_->sent_datagram_ids(), + testing::ElementsAre(server_datagram_id)); + // Send message from peer 2 to peer 1. - ASSERT_TRUE(client_peer_->SendOrQueueMessage("Message from client")); + message = CreateMemSliceVector("Message from client"); + ASSERT_TRUE( + client_peer_->SendOrQueueMessage(message.span(), client_datagram_id)); // First message in each direction should not be queued. EXPECT_EQ(client_peer_->send_message_queue_size(), 0u); @@ -185,6 +193,9 @@ class QuartcSessionTest : public QuicTest { EXPECT_THAT(server_session_delegate_->incoming_messages(), testing::ElementsAre("Message from client")); + + EXPECT_THAT(client_session_delegate_->sent_datagram_ids(), + testing::ElementsAre(client_datagram_id)); } // Test for sending multiple messages that also result in queueing. @@ -199,26 +210,38 @@ class QuartcSessionTest : public QuicTest { QuartcSession* const peer_sending = direction_from_server ? server_peer_ : client_peer_; - FakeQuartcSessionDelegate* const delegate_receiving = + FakeQuartcEndpointDelegate* const delegate_receiving = direction_from_server ? client_session_delegate_.get() : server_session_delegate_.get(); + FakeQuartcEndpointDelegate* const delegate_sending = + direction_from_server ? server_session_delegate_.get() + : client_session_delegate_.get(); + // There should be no messages in the queue before we start sending. EXPECT_EQ(peer_sending->send_message_queue_size(), 0u); // Send messages from peer 1 to peer 2 until required number of messages // are queued in unsent message queue. std::vector<std::string> sent_messages; + std::vector<int64_t> sent_datagram_ids; + int64_t current_datagram_id = 0; while (peer_sending->send_message_queue_size() < queue_size) { sent_messages.push_back( QuicStrCat("Sending message, index=", sent_messages.size())); - ASSERT_TRUE(peer_sending->SendOrQueueMessage(sent_messages.back())); + ASSERT_TRUE(peer_sending->SendOrQueueMessage( + CreateMemSliceVector(sent_messages.back()).span(), + current_datagram_id)); + + sent_datagram_ids.push_back(current_datagram_id); + ++current_datagram_id; } // Wait for peer 2 to receive all messages. RunTasks(); EXPECT_EQ(delegate_receiving->incoming_messages(), sent_messages); + EXPECT_EQ(delegate_sending->sent_datagram_ids(), sent_datagram_ids); } // Test sending long messages: @@ -231,12 +254,17 @@ class QuartcSessionTest : public QuicTest { // Send message of maximum allowed length. std::string message_max_long = std::string(server_peer_->GetCurrentLargestMessagePayload(), 'A'); - ASSERT_TRUE(server_peer_->SendOrQueueMessage(message_max_long)); + test::QuicTestMemSliceVector message = + CreateMemSliceVector(message_max_long); + ASSERT_TRUE( + server_peer_->SendOrQueueMessage(message.span(), /*datagram_id=*/0)); // Send long message which should fail. std::string message_too_long = std::string(server_peer_->GetCurrentLargestMessagePayload() + 1, 'B'); - ASSERT_FALSE(server_peer_->SendOrQueueMessage(message_too_long)); + message = CreateMemSliceVector(message_too_long); + ASSERT_FALSE( + server_peer_->SendOrQueueMessage(message.span(), /*datagram_id=*/0)); // Wait for peer 2 to receive message. RunTasks(); @@ -267,11 +295,9 @@ class QuartcSessionTest : public QuicTest { std::unique_ptr<simulator::SymmetricLink> client_server_link_; std::unique_ptr<FakeQuartcStreamDelegate> client_stream_delegate_; - std::unique_ptr<FakeQuartcSessionDelegate> client_session_delegate_; - std::unique_ptr<FakeQuartcEndpointDelegate> client_endpoint_delegate_; + std::unique_ptr<FakeQuartcEndpointDelegate> client_session_delegate_; std::unique_ptr<FakeQuartcStreamDelegate> server_stream_delegate_; - std::unique_ptr<FakeQuartcSessionDelegate> server_session_delegate_; - std::unique_ptr<FakeQuartcEndpointDelegate> server_endpoint_delegate_; + std::unique_ptr<FakeQuartcEndpointDelegate> server_session_delegate_; std::unique_ptr<QuartcClientEndpoint> client_endpoint_; std::unique_ptr<QuartcServerEndpoint> server_endpoint_; @@ -375,9 +401,7 @@ TEST_F(QuartcSessionTest, WriterGivesPacketNumberToTransport) { QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream(); stream->SetDelegate(client_stream_delegate_.get()); - char kClientMessage[] = "Hello"; - test::QuicTestMemSliceVector stream_data( - {std::make_pair(kClientMessage, strlen(kClientMessage))}); + test::QuicTestMemSliceVector stream_data = CreateMemSliceVector("Hello"); stream->WriteMemSlices(stream_data.span(), /*fin=*/false); RunTasks(); @@ -412,15 +436,13 @@ TEST_F(QuartcSessionTest, StreamRetransmissionEnabled) { client_filter_->set_packets_to_drop(1); - char kClientMessage[] = "Hello"; - test::QuicTestMemSliceVector stream_data( - {std::make_pair(kClientMessage, strlen(kClientMessage))}); + test::QuicTestMemSliceVector stream_data = CreateMemSliceVector("Hello"); stream->WriteMemSlices(stream_data.span(), /*fin=*/false); RunTasks(); // Stream data should make it despite packet loss. ASSERT_TRUE(server_stream_delegate_->has_data()); - EXPECT_EQ(server_stream_delegate_->data()[stream_id], kClientMessage); + EXPECT_EQ(server_stream_delegate_->data()[stream_id], "Hello"); } TEST_F(QuartcSessionTest, StreamRetransmissionDisabled) { @@ -450,9 +472,7 @@ TEST_F(QuartcSessionTest, StreamRetransmissionDisabled) { client_filter_->set_packets_to_drop(1); - char kMessage[] = "Hello"; - test::QuicTestMemSliceVector stream_data( - {std::make_pair(kMessage, strlen(kMessage))}); + test::QuicTestMemSliceVector stream_data = CreateMemSliceVector("Hello"); stream->WriteMemSlices(stream_data.span(), /*fin=*/false); simulator_.RunFor(QuicTime::Delta::FromMilliseconds(1)); @@ -460,9 +480,8 @@ TEST_F(QuartcSessionTest, StreamRetransmissionDisabled) { QuartcStream* stream_1 = client_peer_->CreateOutgoingBidirectionalStream(); stream_1->SetDelegate(client_stream_delegate_.get()); - char kMessage1[] = "Second message"; - test::QuicTestMemSliceVector stream_data_1( - {std::make_pair(kMessage1, strlen(kMessage1))}); + test::QuicTestMemSliceVector stream_data_1 = + CreateMemSliceVector("Second message"); stream_1->WriteMemSlices(stream_data_1.span(), /*fin=*/false); RunTasks(); @@ -512,7 +531,8 @@ TEST_F(QuartcSessionTest, PreSharedKeyHandshakeIs0RTT) { client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>( simulator_.GetAlarmFactory(), simulator_.GetClock(), - client_endpoint_delegate_.get(), QuartcSessionConfig(), + simulator_.GetRandomGenerator(), client_session_delegate_.get(), + QuartcSessionConfig(), // This is the key line here. It passes through the server config // from the server to the client. server_endpoint_->server_crypto_config()); @@ -523,8 +543,8 @@ TEST_F(QuartcSessionTest, PreSharedKeyHandshakeIs0RTT) { // client session should be created, but server won't be created yet. simulator_.RunFor(QuicTime::Delta::FromMilliseconds(1)); - client_peer_ = client_endpoint_delegate_->session(); - server_peer_ = server_endpoint_delegate_->session(); + client_peer_ = client_session_delegate_->session(); + server_peer_ = server_session_delegate_->session(); ASSERT_NE(client_peer_, nullptr); ASSERT_EQ(server_peer_, nullptr); diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc index 49ade235765..5fc10749951 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc @@ -25,7 +25,7 @@ QuartcStream::QuartcStream(QuicStreamId id, QuicSession* session) } QuartcStream::QuartcStream(PendingStream pending) - : QuicStream(std::move(pending), BIDIRECTIONAL) { + : QuicStream(std::move(pending), BIDIRECTIONAL, /*is_static=*/false) { sequencer()->set_level_triggered(true); } @@ -161,8 +161,8 @@ void QuartcStream::FinishWriting() { void QuartcStream::SetDelegate(Delegate* delegate) { if (delegate_) { - LOG(WARNING) << "The delegate for Stream " << id() - << " has already been set."; + QUIC_LOG(WARNING) << "The delegate for Stream " << id() + << " has already been set."; } delegate_ = delegate; DCHECK(delegate_); diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc index 3b5458c7870..d7599e8d9d1 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc @@ -9,8 +9,6 @@ #include <type_traits> #include <utility> -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" #include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" #include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h" diff --git a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc index cae966f4a3e..24a4f4fc49f 100644 --- a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc @@ -4,8 +4,6 @@ #include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc index 63154b9b54c..11cfefc8c5d 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc @@ -43,126 +43,6 @@ namespace quic { namespace test { -TestChannelIDKey::TestChannelIDKey(EVP_PKEY* ecdsa_key) - : ecdsa_key_(ecdsa_key) {} -TestChannelIDKey::~TestChannelIDKey() {} - -bool TestChannelIDKey::Sign(QuicStringPiece signed_data, - std::string* out_signature) const { - bssl::ScopedEVP_MD_CTX md_ctx; - if (EVP_DigestSignInit(md_ctx.get(), nullptr, EVP_sha256(), nullptr, - ecdsa_key_.get()) != 1) { - return false; - } - - EVP_DigestUpdate(md_ctx.get(), ChannelIDVerifier::kContextStr, - strlen(ChannelIDVerifier::kContextStr) + 1); - EVP_DigestUpdate(md_ctx.get(), ChannelIDVerifier::kClientToServerStr, - strlen(ChannelIDVerifier::kClientToServerStr) + 1); - EVP_DigestUpdate(md_ctx.get(), signed_data.data(), signed_data.size()); - - size_t sig_len; - if (!EVP_DigestSignFinal(md_ctx.get(), nullptr, &sig_len)) { - return false; - } - - std::unique_ptr<uint8_t[]> der_sig(new uint8_t[sig_len]); - if (!EVP_DigestSignFinal(md_ctx.get(), der_sig.get(), &sig_len)) { - return false; - } - - uint8_t* derp = der_sig.get(); - bssl::UniquePtr<ECDSA_SIG> sig( - d2i_ECDSA_SIG(nullptr, const_cast<const uint8_t**>(&derp), sig_len)); - if (sig.get() == nullptr) { - return false; - } - - // The signature consists of a pair of 32-byte numbers. - static const size_t kSignatureLength = 32 * 2; - std::unique_ptr<uint8_t[]> signature(new uint8_t[kSignatureLength]); - if (!BN_bn2bin_padded(&signature[0], 32, sig->r) || - !BN_bn2bin_padded(&signature[32], 32, sig->s)) { - return false; - } - - *out_signature = - std::string(reinterpret_cast<char*>(signature.get()), kSignatureLength); - - return true; -} - -std::string TestChannelIDKey::SerializeKey() const { - // i2d_PublicKey will produce an ANSI X9.62 public key which, for a P-256 - // key, is 0x04 (meaning uncompressed) followed by the x and y field - // elements as 32-byte, big-endian numbers. - static const int kExpectedKeyLength = 65; - - int len = i2d_PublicKey(ecdsa_key_.get(), nullptr); - if (len != kExpectedKeyLength) { - return ""; - } - - uint8_t buf[kExpectedKeyLength]; - uint8_t* derp = buf; - i2d_PublicKey(ecdsa_key_.get(), &derp); - - return std::string(reinterpret_cast<char*>(buf + 1), kExpectedKeyLength - 1); -} - -TestChannelIDSource::~TestChannelIDSource() {} - -QuicAsyncStatus TestChannelIDSource::GetChannelIDKey( - const std::string& hostname, - std::unique_ptr<ChannelIDKey>* channel_id_key, - ChannelIDSourceCallback* /*callback*/) { - *channel_id_key = QuicMakeUnique<TestChannelIDKey>(HostnameToKey(hostname)); - return QUIC_SUCCESS; -} - -// static -EVP_PKEY* TestChannelIDSource::HostnameToKey(const std::string& hostname) { - // In order to generate a deterministic key for a given hostname the - // hostname is hashed with SHA-256 and the resulting digest is treated as a - // big-endian number. The most-significant bit is cleared to ensure that - // the resulting value is less than the order of the group and then it's - // taken as a private key. Given the private key, the public key is - // calculated with a group multiplication. - SHA256_CTX sha256; - SHA256_Init(&sha256); - SHA256_Update(&sha256, hostname.data(), hostname.size()); - - unsigned char digest[SHA256_DIGEST_LENGTH]; - SHA256_Final(digest, &sha256); - - // Ensure that the digest is less than the order of the P-256 group by - // clearing the most-significant bit. - digest[0] &= 0x7f; - - bssl::UniquePtr<BIGNUM> k(BN_new()); - CHECK(BN_bin2bn(digest, sizeof(digest), k.get()) != nullptr); - - bssl::UniquePtr<EC_GROUP> p256( - EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); - CHECK(p256); - - bssl::UniquePtr<EC_KEY> ecdsa_key(EC_KEY_new()); - CHECK(ecdsa_key && EC_KEY_set_group(ecdsa_key.get(), p256.get())); - - bssl::UniquePtr<EC_POINT> point(EC_POINT_new(p256.get())); - CHECK(EC_POINT_mul(p256.get(), point.get(), k.get(), nullptr, nullptr, - nullptr)); - - EC_KEY_set_private_key(ecdsa_key.get(), k.get()); - EC_KEY_set_public_key(ecdsa_key.get(), point.get()); - - bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new()); - // EVP_PKEY_set1_EC_KEY takes a reference so no |release| here. - EVP_PKEY_set1_EC_KEY(pkey.get(), ecdsa_key.get()); - - return pkey.release(); -} - namespace crypto_test_utils { namespace { @@ -207,63 +87,15 @@ bool HexChar(char c, uint8_t* value) { return false; } -// A ChannelIDSource that works in asynchronous mode unless the |callback| -// argument to GetChannelIDKey is nullptr. -class AsyncTestChannelIDSource : public ChannelIDSource, public CallbackSource { - public: - // |sync_source| is a synchronous ChannelIDSource. - explicit AsyncTestChannelIDSource( - std::unique_ptr<ChannelIDSource> sync_source) - : sync_source_(std::move(sync_source)) {} - ~AsyncTestChannelIDSource() override {} - - // ChannelIDSource implementation. - QuicAsyncStatus GetChannelIDKey(const std::string& hostname, - std::unique_ptr<ChannelIDKey>* channel_id_key, - ChannelIDSourceCallback* callback) override { - // Synchronous mode. - if (!callback) { - return sync_source_->GetChannelIDKey(hostname, channel_id_key, nullptr); - } - - // Asynchronous mode. - QuicAsyncStatus status = - sync_source_->GetChannelIDKey(hostname, &channel_id_key_, nullptr); - if (status != QUIC_SUCCESS) { - return QUIC_FAILURE; - } - callback_.reset(callback); - return QUIC_PENDING; - } - - // CallbackSource implementation. - void RunPendingCallbacks() override { - if (callback_) { - callback_->Run(&channel_id_key_); - callback_.reset(); - } - } - - private: - std::unique_ptr<ChannelIDSource> sync_source_; - std::unique_ptr<ChannelIDSourceCallback> callback_; - std::unique_ptr<ChannelIDKey> channel_id_key_; -}; - } // anonymous namespace -FakeServerOptions::FakeServerOptions() {} - -FakeServerOptions::~FakeServerOptions() {} - -FakeClientOptions::FakeClientOptions() - : channel_id_enabled(false), channel_id_source_async(false) {} +FakeClientOptions::FakeClientOptions() {} FakeClientOptions::~FakeClientOptions() {} namespace { // This class is used by GenerateFullCHLO() to extract SCID and STK from -// REJ/SREJ and to construct a full CHLO with these fields and given inchoate +// REJ and to construct a full CHLO with these fields and given inchoate // CHLO. class FullChloGenerator { public: @@ -340,11 +172,10 @@ class FullChloGenerator { } void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> rej) { - // Verify output is a REJ or SREJ. - EXPECT_THAT(rej->tag(), - testing::AnyOf(testing::Eq(kSREJ), testing::Eq(kREJ))); + // Verify output is a REJ. + EXPECT_THAT(rej->tag(), testing::Eq(kREJ)); - VLOG(1) << "Extract valid STK and SCID from\n" << rej->DebugString(); + QUIC_VLOG(1) << "Extract valid STK and SCID from\n" << rej->DebugString(); QuicStringPiece srct; ASSERT_TRUE(rej->GetStringPiece(kSourceAddressTokenTag, &srct)); @@ -383,8 +214,7 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config, MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, PacketSavingConnection* client_conn, - QuicCryptoClientStream* client, - const FakeServerOptions& options) { + QuicCryptoClientStream* client) { PacketSavingConnection* server_conn = new PacketSavingConnection( helper, alarm_factory, Perspective::IS_SERVER, ParsedVersionOfIndex(client_conn->supported_versions(), 0)); @@ -395,9 +225,8 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config, TlsServerHandshaker::CreateSslCtx()); QuicCompressedCertsCache compressed_certs_cache( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); - SetupCryptoServerConfigForTest(server_conn->clock(), - server_conn->random_generator(), - &crypto_config, options); + SetupCryptoServerConfigForTest( + server_conn->clock(), server_conn->random_generator(), &crypto_config); TestQuicSpdyServerSession server_session( server_conn, *server_quic_config, client_conn->supported_versions(), @@ -446,19 +275,6 @@ int HandshakeWithFakeClient(MockQuicConnectionHelper* helper, QuicCryptoClientConfig crypto_config(ProofVerifierForTesting(), TlsClientHandshaker::CreateSslCtx()); - AsyncTestChannelIDSource* async_channel_id_source = nullptr; - if (options.channel_id_enabled) { - std::unique_ptr<ChannelIDSource> source = ChannelIDSourceForTesting(); - if (options.channel_id_source_async) { - auto temp = QuicMakeUnique<AsyncTestChannelIDSource>(std::move(source)); - async_channel_id_source = temp.get(); - source = std::move(temp); - } - crypto_config.SetChannelIDSource(std::move(source)); - } - if (!options.token_binding_params.empty()) { - crypto_config.tb_key_params = options.token_binding_params; - } TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(), supported_versions, server_id, &crypto_config); @@ -471,25 +287,12 @@ int HandshakeWithFakeClient(MockQuicConnectionHelper* helper, client_session.GetMutableCryptoStream()->CryptoConnect(); CHECK_EQ(1u, client_conn->encrypted_packets_.size()); - CommunicateHandshakeMessagesAndRunCallbacks( - client_conn, client_session.GetMutableCryptoStream(), server_conn, server, - async_channel_id_source); + CommunicateHandshakeMessages(client_conn, + client_session.GetMutableCryptoStream(), + server_conn, server); if (server->handshake_confirmed() && server->encryption_established()) { CompareClientAndServerKeys(client_session.GetMutableCryptoStream(), server); - - if (options.channel_id_enabled) { - std::unique_ptr<ChannelIDKey> channel_id_key; - QuicAsyncStatus status = - crypto_config.channel_id_source()->GetChannelIDKey( - server_id.host(), &channel_id_key, nullptr); - EXPECT_EQ(QUIC_SUCCESS, status); - EXPECT_EQ(channel_id_key->SerializeKey(), - server->crypto_negotiated_params().channel_id); - EXPECT_EQ( - options.channel_id_source_async, - client_session.GetCryptoStream()->WasChannelIDSourceCallbackRun()); - } } return client_session.GetCryptoStream()->num_sent_client_hellos(); @@ -497,11 +300,9 @@ int HandshakeWithFakeClient(MockQuicConnectionHelper* helper, void SetupCryptoServerConfigForTest(const QuicClock* clock, QuicRandom* rand, - QuicCryptoServerConfig* crypto_config, - const FakeServerOptions& fake_options) { + QuicCryptoServerConfig* crypto_config) { QuicCryptoServerConfig::ConfigOptions options; options.channel_id_enabled = true; - options.token_binding_params = fake_options.token_binding_params; std::unique_ptr<CryptoHandshakeMessage> scfg = crypto_config->AddDefaultConfig(rand, clock, options); } @@ -530,16 +331,6 @@ void CommunicateHandshakeMessages(PacketSavingConnection* client_conn, QuicCryptoStream* client, PacketSavingConnection* server_conn, QuicCryptoStream* server) { - CommunicateHandshakeMessagesAndRunCallbacks(client_conn, client, server_conn, - server, nullptr); -} - -void CommunicateHandshakeMessagesAndRunCallbacks( - PacketSavingConnection* client_conn, - QuicCryptoStream* client, - PacketSavingConnection* server_conn, - QuicCryptoStream* server, - CallbackSource* callback_source) { size_t client_i = 0, server_i = 0; while (!client->handshake_confirmed() || !server->handshake_confirmed()) { ASSERT_GT(client_conn->encrypted_packets_.size(), client_i); @@ -548,9 +339,6 @@ void CommunicateHandshakeMessagesAndRunCallbacks( << " packets client->server"; MovePackets(client_conn, &client_i, server, server_conn, Perspective::IS_SERVER); - if (callback_source) { - callback_source->RunPendingCallbacks(); - } if (client->handshake_confirmed() && server->handshake_confirmed()) { break; @@ -561,9 +349,6 @@ void CommunicateHandshakeMessagesAndRunCallbacks( << " packets server->client"; MovePackets(server_conn, &server_i, client, client_conn, Perspective::IS_CLIENT); - if (callback_source) { - callback_source->RunPendingCallbacks(); - } } } @@ -695,12 +480,8 @@ CommonCertSets* MockCommonCertSets(QuicStringPiece cert, return new class MockCommonCertSets(cert, hash, index); } -void FillInDummyReject(CryptoHandshakeMessage* rej, bool reject_is_stateless) { - if (reject_is_stateless) { - rej->set_tag(kSREJ); - } else { - rej->set_tag(kREJ); - } +void FillInDummyReject(CryptoHandshakeMessage* rej) { + rej->set_tag(kREJ); // Minimum SCFG that passes config validation checks. // clang-format off @@ -898,10 +679,6 @@ CryptoHandshakeMessage CreateCHLO( return *parsed; } -std::unique_ptr<ChannelIDSource> ChannelIDSourceForTesting() { - return QuicMakeUnique<TestChannelIDSource>(); -} - void MovePackets(PacketSavingConnection* source_conn, size_t* inout_packet_index, QuicCryptoStream* dest_stream, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h index 5bb4b4e42a3..421c0f3dd2d 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h @@ -20,7 +20,6 @@ namespace quic { -class ChannelIDSource; class CommonCertSets; class ProofSource; class ProofVerifier; @@ -38,37 +37,6 @@ namespace test { class PacketSavingConnection; -class TestChannelIDKey : public ChannelIDKey { - public: - explicit TestChannelIDKey(EVP_PKEY* ecdsa_key); - ~TestChannelIDKey() override; - - // ChannelIDKey implementation. - - bool Sign(QuicStringPiece signed_data, - std::string* out_signature) const override; - - std::string SerializeKey() const override; - - private: - bssl::UniquePtr<EVP_PKEY> ecdsa_key_; -}; - -class TestChannelIDSource : public ChannelIDSource { - public: - ~TestChannelIDSource() override; - - // ChannelIDSource implementation. - - QuicAsyncStatus GetChannelIDKey( - const std::string& hostname, - std::unique_ptr<ChannelIDKey>* channel_id_key, - ChannelIDSourceCallback* /*callback*/) override; - - private: - static EVP_PKEY* HostnameToKey(const std::string& hostname); -}; - namespace crypto_test_utils { // An interface for a source of callbacks. This is used for invoking @@ -85,33 +53,12 @@ class CallbackSource { virtual void RunPendingCallbacks() = 0; }; -// FakeServerOptions bundles together a number of options for configuring the -// server in HandshakeWithFakeServer. -struct FakeServerOptions { - FakeServerOptions(); - ~FakeServerOptions(); - - // The Token Binding params that the server supports and will negotiate. - QuicTagVector token_binding_params; -}; - // FakeClientOptions bundles together a number of options for configuring // HandshakeWithFakeClient. struct FakeClientOptions { FakeClientOptions(); ~FakeClientOptions(); - // If channel_id_enabled is true then the client will attempt to send a - // ChannelID. - bool channel_id_enabled; - - // 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; - - // The Token Binding params that the client supports and will negotiate. - QuicTagVector token_binding_params; - // If only_tls_versions is set, then the client will only use TLS for the // crypto handshake. bool only_tls_versions = false; @@ -122,8 +69,7 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config, MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, PacketSavingConnection* client_conn, - QuicCryptoClientStream* client, - const FakeServerOptions& options); + QuicCryptoClientStream* client); // returns: the number of client hellos that the client sent. int HandshakeWithFakeClient(MockQuicConnectionHelper* helper, @@ -137,8 +83,7 @@ int HandshakeWithFakeClient(MockQuicConnectionHelper* helper, // with sensible defaults for testing. void SetupCryptoServerConfigForTest(const QuicClock* clock, QuicRandom* rand, - QuicCryptoServerConfig* crypto_config, - const FakeServerOptions& options); + QuicCryptoServerConfig* crypto_config); // Sends the handshake message |message| to stream |stream| with the perspective // that the message is coming from |perspective|. @@ -153,18 +98,6 @@ void CommunicateHandshakeMessages(PacketSavingConnection* client_conn, PacketSavingConnection* server_conn, QuicCryptoStream* server); -// CommunicateHandshakeMessagesAndRunCallbacks moves messages from |client| -// to |server| and back until |client|'s handshake has completed. If -// |callback_source| is not nullptr, -// CommunicateHandshakeMessagesAndRunCallbacks also runs callbacks from -// |callback_source| between processing messages. -void CommunicateHandshakeMessagesAndRunCallbacks( - PacketSavingConnection* client_conn, - QuicCryptoStream* client, - PacketSavingConnection* server_conn, - QuicCryptoStream* server, - CallbackSource* callback_source); - // AdvanceHandshake attempts to moves messages from |client| to |server| and // |server| to |client|. Returns the number of messages moved. std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn, @@ -199,7 +132,7 @@ CommonCertSets* MockCommonCertSets(QuicStringPiece cert, // Creates a minimal dummy reject message that will pass the client-config // validation tests. This will include a server config, but no certs, proof // source address token, or server nonce. -void FillInDummyReject(CryptoHandshakeMessage* rej, bool reject_is_stateless); +void FillInDummyReject(CryptoHandshakeMessage* rej); // ParseTag returns a QuicTag from parsing |tagstr|. |tagstr| may either be // in the format "EXMP" (i.e. ASCII format), or "#11223344" (an explicit hex @@ -222,12 +155,6 @@ CryptoHandshakeMessage CreateCHLO( std::vector<std::pair<std::string, std::string>> tags_and_values, int minimum_size_bytes); -// ChannelIDSourceForTesting returns a ChannelIDSource that generates keys -// deterministically based on the hostname given in the GetChannelIDKey call. -// This ChannelIDSource works in synchronous mode, i.e., its GetChannelIDKey -// method never returns QUIC_PENDING. -std::unique_ptr<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 diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h index 2fbdfc38948..1cb9019033c 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h @@ -7,9 +7,9 @@ #include <string> -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_dispatcher.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_dispatcher.h index 0eaddc5fb35..3134e1fea7b 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_dispatcher.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_dispatcher.h @@ -5,10 +5,10 @@ #ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_DISPATCHER_H_ #define QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_DISPATCHER_H_ -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h" #include "net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h" diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h index d429cd42c0b..11dc24a724c 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h @@ -5,9 +5,9 @@ #ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SESSION_VISITOR_H_ #define QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SESSION_VISITOR_H_ -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h" #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_spdy_client_stream.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_spdy_client_stream.h index e41df5284b7..02fe74ecb70 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_spdy_client_stream.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_spdy_client_stream.h @@ -5,10 +5,10 @@ #ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SPDY_CLIENT_STREAM_H_ #define QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SPDY_CLIENT_STREAM_H_ -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/http/quic_header_list.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { namespace test { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h index 742fef2ae89..8a394424a73 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h @@ -5,8 +5,8 @@ #ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_TIME_WAIT_LIST_MANAGER_H_ #define QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_TIME_WAIT_LIST_MANAGER_H_ -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { namespace test { @@ -45,8 +45,9 @@ class MockTimeWaitListManager : public QuicTimeWaitListManager { PacketHeaderFormat header_format, std::unique_ptr<QuicPerPacketContext> packet_context)); - MOCK_METHOD6(SendVersionNegotiationPacket, - void(QuicConnectionId connection_id, + MOCK_METHOD7(SendVersionNegotiationPacket, + void(QuicConnectionId server_connection_id, + QuicConnectionId client_connection_id, bool ietf_quic, const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& server_address, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/packet_reordering_writer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/packet_reordering_writer.cc index 5fa5659e596..7bbec0d3533 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/packet_reordering_writer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/packet_reordering_writer.cc @@ -18,12 +18,12 @@ WriteResult PacketReorderingWriter::WritePacket( const QuicSocketAddress& peer_address, PerPacketOptions* options) { if (!delay_next_) { - VLOG(2) << "Writing a non-delayed packet"; + QUIC_VLOG(2) << "Writing a non-delayed packet"; WriteResult wr = QuicPacketWriterWrapper::WritePacket( buffer, buf_len, self_address, peer_address, options); --num_packets_to_wait_; if (num_packets_to_wait_ == 0) { - VLOG(2) << "Writing a delayed packet"; + QUIC_VLOG(2) << "Writing a delayed packet"; // It's time to write the delayed packet. QuicPacketWriterWrapper::WritePacket( delayed_data_.data(), delayed_data_.length(), delayed_self_address_, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc index f5a5b315b3f..f9ce04f1765 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc @@ -45,10 +45,16 @@ void QuicConfigPeer::SetReceivedDisableConnectionMigration(QuicConfig* config) { } // static -void QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams( +void QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams( QuicConfig* config, uint32_t max_streams) { - config->max_incoming_dynamic_streams_.SetReceivedValue(max_streams); + config->max_incoming_bidirectional_streams_.SetReceivedValue(max_streams); +} +// static +void QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams( + QuicConfig* config, + uint32_t max_streams) { + config->max_incoming_unidirectional_streams_.SetReceivedValue(max_streams); } // static diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h index 8869d270875..7faee7e6e11 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h @@ -33,8 +33,10 @@ class QuicConfigPeer { static void SetReceivedDisableConnectionMigration(QuicConfig* config); - static void SetReceivedMaxIncomingDynamicStreams(QuicConfig* config, - uint32_t max_streams); + static void SetReceivedMaxIncomingBidirectionalStreams(QuicConfig* config, + uint32_t max_streams); + static void SetReceivedMaxIncomingUnidirectionalStreams(QuicConfig* config, + uint32_t max_streams); static void SetConnectionOptionsToSend(QuicConfig* config, const QuicTagVector& options); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.cc index 13b315000ea..6eedd601bf3 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.cc @@ -22,10 +22,10 @@ uint64_t QuicFramerPeer::CalculatePacketNumberFromWire( } // static -void QuicFramerPeer::SetLastSerializedConnectionId( +void QuicFramerPeer::SetLastSerializedServerConnectionId( QuicFramer* framer, - QuicConnectionId connection_id) { - framer->last_serialized_connection_id_ = connection_id; + QuicConnectionId server_connection_id) { + framer->last_serialized_server_connection_id_ = server_connection_id; } // static @@ -199,7 +199,7 @@ bool QuicFramerPeer::ProcessMaxStreamDataFrame(QuicFramer* framer, // static bool QuicFramerPeer::AppendMaxStreamsFrame(QuicFramer* framer, - const QuicMaxStreamIdFrame& frame, + const QuicMaxStreamsFrame& frame, QuicDataWriter* writer) { return framer->AppendMaxStreamsFrame(frame, writer); } @@ -207,7 +207,7 @@ bool QuicFramerPeer::AppendMaxStreamsFrame(QuicFramer* framer, // static bool QuicFramerPeer::ProcessMaxStreamsFrame(QuicFramer* framer, QuicDataReader* reader, - QuicMaxStreamIdFrame* frame, + QuicMaxStreamsFrame* frame, uint64_t frame_type) { return framer->ProcessMaxStreamsFrame(reader, frame, frame_type); } @@ -243,7 +243,7 @@ bool QuicFramerPeer::ProcessStreamBlockedFrame(QuicFramer* framer, // static bool QuicFramerPeer::AppendStreamsBlockedFrame( QuicFramer* framer, - const QuicStreamIdBlockedFrame& frame, + const QuicStreamsBlockedFrame& frame, QuicDataWriter* writer) { return framer->AppendStreamsBlockedFrame(frame, writer); } @@ -251,7 +251,7 @@ bool QuicFramerPeer::AppendStreamsBlockedFrame( // static bool QuicFramerPeer::ProcessStreamsBlockedFrame(QuicFramer* framer, QuicDataReader* reader, - QuicStreamIdBlockedFrame* frame, + QuicStreamsBlockedFrame* frame, uint64_t frame_type) { return framer->ProcessStreamsBlockedFrame(reader, frame, frame_type); } @@ -337,11 +337,11 @@ void QuicFramerPeer::SetFirstSendingPacketNumber(QuicFramer* framer, } // static -void QuicFramerPeer::SetExpectedConnectionIDLength( +void QuicFramerPeer::SetExpectedServerConnectionIDLength( QuicFramer* framer, - uint8_t expected_connection_id_length) { - *const_cast<uint8_t*>(&framer->expected_connection_id_length_) = - expected_connection_id_length; + uint8_t expected_server_connection_id_length) { + *const_cast<uint8_t*>(&framer->expected_server_connection_id_length_) = + expected_server_connection_id_length; } // static diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h index 7b23189af24..0b17c1958d0 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h @@ -22,8 +22,9 @@ class QuicFramerPeer { QuicPacketNumberLength packet_number_length, QuicPacketNumber last_packet_number, uint64_t packet_number); - static void SetLastSerializedConnectionId(QuicFramer* framer, - QuicConnectionId connection_id); + static void SetLastSerializedServerConnectionId( + QuicFramer* framer, + QuicConnectionId server_connection_id); static void SetLargestPacketNumber(QuicFramer* framer, QuicPacketNumber packet_number); static void SetPerspective(QuicFramer* framer, Perspective perspective); @@ -111,11 +112,11 @@ class QuicFramerPeer { QuicDataReader* reader, QuicWindowUpdateFrame* frame); static bool AppendMaxStreamsFrame(QuicFramer* framer, - const QuicMaxStreamIdFrame& frame, + const QuicMaxStreamsFrame& frame, QuicDataWriter* writer); static bool ProcessMaxStreamsFrame(QuicFramer* framer, QuicDataReader* reader, - QuicMaxStreamIdFrame* frame, + QuicMaxStreamsFrame* frame, uint64_t frame_type); static bool AppendIetfBlockedFrame(QuicFramer* framer, const QuicBlockedFrame& frame, @@ -132,11 +133,11 @@ class QuicFramerPeer { QuicBlockedFrame* frame); static bool AppendStreamsBlockedFrame(QuicFramer* framer, - const QuicStreamIdBlockedFrame& frame, + const QuicStreamsBlockedFrame& frame, QuicDataWriter* writer); static bool ProcessStreamsBlockedFrame(QuicFramer* framer, QuicDataReader* reader, - QuicStreamIdBlockedFrame* frame, + QuicStreamsBlockedFrame* frame, uint64_t frame_type); static bool AppendNewConnectionIdFrame(QuicFramer* framer, @@ -159,9 +160,9 @@ class QuicFramerPeer { QuicPacketNumberLength packet_number_length); static void SetFirstSendingPacketNumber(QuicFramer* framer, uint64_t packet_number); - static void SetExpectedConnectionIDLength( + static void SetExpectedServerConnectionIDLength( QuicFramer* framer, - uint8_t expected_connection_id_length); + uint8_t expected_server_connection_id_length); static QuicPacketNumber GetLargestDecryptedPacketNumber( QuicFramer* framer, PacketNumberSpace packet_number_space); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.cc index 3057e5e189c..c48c090ffbd 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.cc @@ -79,12 +79,6 @@ RttStats* QuicSentPacketManagerPeer::GetRttStats( } // static -bool QuicSentPacketManagerPeer::HasPendingPackets( - const QuicSentPacketManager* sent_packet_manager) { - return sent_packet_manager->unacked_packets_.HasInFlightPackets(); -} - -// static bool QuicSentPacketManagerPeer::IsRetransmission( QuicSentPacketManager* sent_packet_manager, uint64_t packet_number) { @@ -142,12 +136,6 @@ QuicTime::Delta QuicSentPacketManagerPeer::GetTailLossProbeDelay( } // static -bool QuicSentPacketManagerPeer::HasUnackedCryptoPackets( - const QuicSentPacketManager* sent_packet_manager) { - return sent_packet_manager->unacked_packets_.HasPendingCryptoPackets(); -} - -// static size_t QuicSentPacketManagerPeer::GetNumRetransmittablePackets( const QuicSentPacketManager* sent_packet_manager) { size_t num_unacked_packets = 0; @@ -161,12 +149,6 @@ size_t QuicSentPacketManagerPeer::GetNumRetransmittablePackets( } // static -QuicByteCount QuicSentPacketManagerPeer::GetBytesInFlight( - const QuicSentPacketManager* sent_packet_manager) { - return sent_packet_manager->unacked_packets_.bytes_in_flight(); -} - -// static void QuicSentPacketManagerPeer::SetConsecutiveRtoCount( QuicSentPacketManager* sent_packet_manager, size_t count) { @@ -200,14 +182,6 @@ void QuicSentPacketManagerPeer::SetUsingPacing( } // static -bool QuicSentPacketManagerPeer::IsUnacked( - QuicSentPacketManager* sent_packet_manager, - uint64_t packet_number) { - return sent_packet_manager->unacked_packets_.IsUnacked( - QuicPacketNumber(packet_number)); -} - -// static bool QuicSentPacketManagerPeer::HasRetransmittableFrames( QuicSentPacketManager* sent_packet_manager, uint64_t packet_number) { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h index 23244e5d2b9..6dcce0cf4a4 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h @@ -46,9 +46,6 @@ class QuicSentPacketManagerPeer { static RttStats* GetRttStats(QuicSentPacketManager* sent_packet_manager); - static bool HasPendingPackets( - const QuicSentPacketManager* sent_packet_manager); - // Returns true if |packet_number| is a retransmission of a packet. static bool IsRetransmission(QuicSentPacketManager* sent_packet_manager, uint64_t packet_number); @@ -68,15 +65,9 @@ class QuicSentPacketManagerPeer { static QuicTime::Delta GetTailLossProbeDelay( const QuicSentPacketManager* sent_packet_manager); - static bool HasUnackedCryptoPackets( - const QuicSentPacketManager* sent_packet_manager); - static size_t GetNumRetransmittablePackets( const QuicSentPacketManager* sent_packet_manager); - static QuicByteCount GetBytesInFlight( - const QuicSentPacketManager* sent_packet_manager); - static void SetConsecutiveRtoCount(QuicSentPacketManager* sent_packet_manager, size_t count); @@ -91,9 +82,6 @@ class QuicSentPacketManagerPeer { static bool UsingPacing(const QuicSentPacketManager* sent_packet_manager); - static bool IsUnacked(QuicSentPacketManager* sent_packet_manager, - uint64_t packet_number); - static bool HasRetransmittableFrames( QuicSentPacketManager* sent_packet_manager, uint64_t packet_number); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_server_session_base_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_server_session_base_peer.h index 30c9b22836d..d2a21a6c9eb 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_server_session_base_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_server_session_base_peer.h @@ -21,9 +21,11 @@ class QuicServerSessionBasePeer { static void SetCryptoStream(QuicServerSessionBase* s, QuicCryptoServerStream* crypto_stream) { s->crypto_stream_.reset(crypto_stream); - s->RegisterStaticStream( - QuicUtils::GetCryptoStreamId(s->connection()->transport_version()), - crypto_stream); + if (!QuicVersionUsesCryptoFrames(s->connection()->transport_version())) { + s->RegisterStaticStream( + QuicUtils::GetCryptoStreamId(s->connection()->transport_version()), + crypto_stream); + } } static bool IsBandwidthResumptionEnabled(QuicServerSessionBase* s) { return s->bandwidth_resumption_enabled_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc index 37e5013cf92..9eee4944773 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc @@ -6,6 +6,7 @@ #include "net/third_party/quiche/src/quic/core/quic_session.h" #include "net/third_party/quiche/src/quic/core/quic_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" namespace quic { @@ -38,23 +39,73 @@ void QuicSessionPeer::SetNextOutgoingBidirectionalStreamId(QuicSession* session, void QuicSessionPeer::SetMaxOpenIncomingStreams(QuicSession* session, uint32_t max_streams) { if (session->connection()->transport_version() == QUIC_VERSION_99) { - session->v99_streamid_manager_.SetMaxOpenIncomingStreams(max_streams); + QUIC_BUG << "SetmaxOpenIncomingStreams deprecated for IETF QUIC/V99"; + session->v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams( + max_streams); + session->v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams( + max_streams); return; } session->stream_id_manager_.set_max_open_incoming_streams(max_streams); } // static +void QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams( + QuicSession* session, + uint32_t max_streams) { + DCHECK_EQ(QUIC_VERSION_99, session->connection()->transport_version()) + << "SetmaxOpenIncomingBidirectionalStreams not supported for Google " + "QUIC/not-V99"; + session->v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams( + max_streams); +} +// static +void QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams( + QuicSession* session, + uint32_t max_streams) { + DCHECK_EQ(QUIC_VERSION_99, session->connection()->transport_version()) + << "SetmaxOpenIncomingUnidirectionalStreams not supported for Google " + "QUIC/not-V99"; + session->v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams( + max_streams); +} + +// static void QuicSessionPeer::SetMaxOpenOutgoingStreams(QuicSession* session, uint32_t max_streams) { if (session->connection()->transport_version() == QUIC_VERSION_99) { - session->v99_streamid_manager_.SetMaxOpenOutgoingStreams(max_streams); + QUIC_BUG << "SetmaxOpenOutgoingStreams deprecated for IETF QUIC/V99"; + session->v99_streamid_manager_.SetMaxOpenOutgoingUnidirectionalStreams( + max_streams); + session->v99_streamid_manager_.SetMaxOpenOutgoingBidirectionalStreams( + max_streams); return; } session->stream_id_manager_.set_max_open_outgoing_streams(max_streams); } // static +void QuicSessionPeer::SetMaxOpenOutgoingBidirectionalStreams( + QuicSession* session, + uint32_t max_streams) { + DCHECK_EQ(QUIC_VERSION_99, session->connection()->transport_version()) + << "SetmaxOpenOutgoingBidirectionalStreams not supported for Google " + "QUIC/not-V99"; + session->v99_streamid_manager_.SetMaxOpenOutgoingBidirectionalStreams( + max_streams); +} +// static +void QuicSessionPeer::SetMaxOpenOutgoingUnidirectionalStreams( + QuicSession* session, + uint32_t max_streams) { + DCHECK_EQ(QUIC_VERSION_99, session->connection()->transport_version()) + << "SetmaxOpenOutgoingUnidirectionalStreams not supported for Google " + "QUIC/not-V99"; + session->v99_streamid_manager_.SetMaxOpenOutgoingUnidirectionalStreams( + max_streams); +} + +// static QuicCryptoStream* QuicSessionPeer::GetMutableCryptoStream( QuicSession* session) { return session->GetMutableCryptoStream(); @@ -115,22 +166,33 @@ void QuicSessionPeer::ActivateStream(QuicSession* session, } // static +void QuicSessionPeer::RegisterStaticStream(QuicSession* session, + QuicStreamId id, + QuicStream* stream) { + return session->RegisterStaticStream(id, stream); +} + +// static +void QuicSessionPeer::RegisterStaticStreamNew( + QuicSession* session, + std::unique_ptr<QuicStream> stream) { + return session->RegisterStaticStreamNew(std::move(stream)); +} + +// static bool QuicSessionPeer::IsStreamClosed(QuicSession* session, QuicStreamId id) { - DCHECK_NE(0u, id); return session->IsClosedStream(id); } // static bool QuicSessionPeer::IsStreamCreated(QuicSession* session, QuicStreamId id) { - DCHECK_NE(0u, id); return QuicContainsKey(session->dynamic_streams(), id); } // static bool QuicSessionPeer::IsStreamAvailable(QuicSession* session, QuicStreamId id) { - DCHECK_NE(0u, id); if (session->connection()->transport_version() == QUIC_VERSION_99) { - if (id % kV99StreamIdIncrement < 2) { + if (id % QuicUtils::StreamIdDelta(QUIC_VERSION_99) < 2) { return QuicContainsKey( session->v99_streamid_manager_.bidirectional_stream_id_manager_ .available_streams_, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h index 30e358f4bc6..3828981ed94 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h @@ -32,10 +32,24 @@ class QuicSessionPeer { QuicSession* session); static void SetNextOutgoingBidirectionalStreamId(QuicSession* session, QuicStreamId id); + // Following is only for Google-QUIC, will QUIC_BUG if called for IETF + // QUIC. static void SetMaxOpenIncomingStreams(QuicSession* session, uint32_t max_streams); + // Following two are only for IETF-QUIC, will QUIC_BUG if called for Google + // QUIC. + static void SetMaxOpenIncomingBidirectionalStreams(QuicSession* session, + uint32_t max_streams); + static void SetMaxOpenIncomingUnidirectionalStreams(QuicSession* session, + uint32_t max_streams); + static void SetMaxOpenOutgoingStreams(QuicSession* session, uint32_t max_streams); + static void SetMaxOpenOutgoingBidirectionalStreams(QuicSession* session, + uint32_t max_streams); + static void SetMaxOpenOutgoingUnidirectionalStreams(QuicSession* session, + uint32_t max_streams); + static QuicCryptoStream* GetMutableCryptoStream(QuicSession* session); static QuicWriteBlockedList* GetWriteBlockedStreams(QuicSession* session); static QuicStream* GetOrCreateDynamicStream(QuicSession* session, @@ -50,6 +64,11 @@ class QuicSessionPeer { QuicSession* session); static void ActivateStream(QuicSession* session, std::unique_ptr<QuicStream> stream); + static void RegisterStaticStream(QuicSession* session, + QuicStreamId stream_id, + QuicStream* stream); + static void RegisterStaticStreamNew(QuicSession* session, + std::unique_ptr<QuicStream> stream); // Discern the state of a stream. Exactly one of these should be true at a // time for any stream id > 0 (other than the special streams 1 and 3). diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc index dcba12c5fee..956cd88034f 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.cc @@ -13,7 +13,7 @@ namespace test { // static QuicHeadersStream* QuicSpdySessionPeer::GetHeadersStream( QuicSpdySession* session) { - return session->headers_stream_.get(); + return session->headers_stream(); } // static @@ -25,6 +25,20 @@ void QuicSpdySessionPeer::SetHeadersStream(QuicSpdySession* session, } } +void QuicSpdySessionPeer::SetUnownedHeadersStream( + QuicSpdySession* session, + QuicHeadersStream* headers_stream) { + for (auto& it : session->dynamic_streams()) { + if (it.first == QuicUtils::GetHeadersStreamId( + session->connection()->transport_version())) { + it.second.reset(headers_stream); + session->unowned_headers_stream_ = + static_cast<QuicHeadersStream*>(it.second.get()); + break; + } + } +} + // static const spdy::SpdyFramer& QuicSpdySessionPeer::GetSpdyFramer( QuicSpdySession* session) { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h index 83e8b0caf11..47b55e1c7c0 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h @@ -24,6 +24,8 @@ class QuicSpdySessionPeer { static QuicHeadersStream* GetHeadersStream(QuicSpdySession* session); static void SetHeadersStream(QuicSpdySession* session, QuicHeadersStream* headers_stream); + static void SetUnownedHeadersStream(QuicSpdySession* session, + QuicHeadersStream* headers_stream); static const spdy::SpdyFramer& GetSpdyFramer(QuicSpdySession* session); static void SetHpackEncoderDebugVisitor( QuicSpdySession* session, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.cc index 705ee270b55..3ce5f1f2a39 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.cc @@ -4,33 +4,26 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h" #include "net/third_party/quiche/src/quic/core/quic_stream_id_manager.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic { namespace test { // static -void QuicStreamIdManagerPeer::IncrementMaximumAllowedOutgoingStreamId( +void QuicStreamIdManagerPeer::set_incoming_actual_max_streams( QuicStreamIdManager* stream_id_manager, - int increment) { - stream_id_manager->max_allowed_outgoing_stream_id_ += - (increment * kV99StreamIdIncrement); + QuicStreamCount count) { + stream_id_manager->incoming_actual_max_streams_ = count; } // static -void QuicStreamIdManagerPeer::IncrementMaximumAllowedIncomingStreamId( - QuicStreamIdManager* stream_id_manager, - int increment) { - stream_id_manager->actual_max_allowed_incoming_stream_id_ += - (increment * kV99StreamIdIncrement); - stream_id_manager->advertised_max_allowed_incoming_stream_id_ += - (increment * kV99StreamIdIncrement); +QuicStreamId QuicStreamIdManagerPeer::GetFirstIncomingStreamId( + QuicStreamIdManager* stream_id_manager) { + return stream_id_manager->GetFirstIncomingStreamId(); } -// static -void QuicStreamIdManagerPeer::SetMaxOpenIncomingStreams( - QuicStreamIdManager* stream_id_manager, - size_t max_streams) { - stream_id_manager->SetMaxOpenIncomingStreams(max_streams); -} } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h index 2ec07b1e7fd..cc78aee5820 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h @@ -6,23 +6,25 @@ #include <stddef.h> +#include "net/third_party/quiche/src/quic/core/quic_types.h" + namespace quic { class QuicStreamIdManager; +class UberQuicStreamIdManager; namespace test { class QuicStreamIdManagerPeer { public: QuicStreamIdManagerPeer() = delete; - static void IncrementMaximumAllowedOutgoingStreamId( - QuicStreamIdManager* stream_id_manager, - int increment); - static void IncrementMaximumAllowedIncomingStreamId( + + static void set_incoming_actual_max_streams( QuicStreamIdManager* stream_id_manager, - int increment); - static void SetMaxOpenIncomingStreams(QuicStreamIdManager* stream_id_manager, - size_t max_streams); + QuicStreamCount count); + + static QuicStreamId GetFirstIncomingStreamId( + QuicStreamIdManager* stream_id_manager); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc index fb76f7a10f3..d4608ed8686 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc @@ -92,6 +92,8 @@ class RecordingProofVerifier : public ProofVerifier { QuicAsyncStatus VerifyCertChain( const std::string& hostname, const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, const ProofVerifyContext* context, std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, @@ -207,8 +209,8 @@ MockableQuicClient::MockableQuicClient( this), QuicWrapUnique( new RecordingProofVerifier(std::move(proof_verifier)))), - override_connection_id_(EmptyQuicConnectionId()), - connection_id_overridden_(false) {} + override_server_connection_id_(EmptyQuicConnectionId()), + server_connection_id_overridden_(false) {} MockableQuicClient::~MockableQuicClient() { if (connected()) { @@ -229,13 +231,15 @@ MockableQuicClient::mockable_network_helper() const { } QuicConnectionId MockableQuicClient::GenerateNewConnectionId() { - return connection_id_overridden_ ? override_connection_id_ - : QuicClient::GenerateNewConnectionId(); + return server_connection_id_overridden_ + ? override_server_connection_id_ + : QuicClient::GenerateNewConnectionId(); } -void MockableQuicClient::UseConnectionId(QuicConnectionId connection_id) { - connection_id_overridden_ = true; - override_connection_id_ = connection_id; +void MockableQuicClient::UseConnectionId( + QuicConnectionId server_connection_id) { + server_connection_id_overridden_ = true; + override_server_connection_id_ = server_connection_id; } void MockableQuicClient::UseWriter(QuicPacketWriterWrapper* writer) { @@ -396,16 +400,6 @@ ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest( stream->WriteOrBufferBody(std::string(body), fin); ret = body.length(); } - if (GetQuicReloadableFlag(enable_quic_stateless_reject_support)) { - std::unique_ptr<spdy::SpdyHeaderBlock> new_headers; - if (headers) { - new_headers = QuicMakeUnique<spdy::SpdyHeaderBlock>(headers->Clone()); - } - std::unique_ptr<QuicSpdyClientBase::QuicDataToResend> data_to_resend( - new TestClientDataToResend(std::move(new_headers), body, fin, this, - ack_listener)); - client()->MaybeAddQuicDataToResend(std::move(data_to_resend)); - } return ret; } @@ -629,8 +623,8 @@ bool QuicTestClient::WaitUntil(int timeout_ms, std::function<bool()> trigger) { epoll_server()->set_timeout_in_us(old_timeout_us); } if (trigger && !trigger()) { - VLOG(1) << "Client WaitUntil returning with trigger returning false." - << QuicStackTrace(); + QUIC_VLOG(1) << "Client WaitUntil returning with trigger returning false." + << QuicStackTrace(); return false; } return true; @@ -651,9 +645,7 @@ bool QuicTestClient::response_headers_complete() const { const spdy::SpdyHeaderBlock* QuicTestClient::response_headers() const { for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) { - size_t bytes_read = - stream.second->stream_bytes_read() + stream.second->header_bytes_read(); - if (bytes_read > 0) { + if (stream.second->headers_decompressed()) { response_headers_ = stream.second->response_headers().Clone(); break; } @@ -759,9 +751,9 @@ void QuicTestClient::UseWriter(QuicPacketWriterWrapper* writer) { client_->UseWriter(writer); } -void QuicTestClient::UseConnectionId(QuicConnectionId connection_id) { +void QuicTestClient::UseConnectionId(QuicConnectionId server_connection_id) { DCHECK(!connected()); - client_->UseConnectionId(connection_id); + client_->UseConnectionId(server_connection_id); } bool QuicTestClient::MigrateSocket(const QuicIpAddress& new_host) { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h index 02a0ed6cf8f..a4ee0d5cb80 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h @@ -9,7 +9,6 @@ #include <memory> #include <string> -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.pb.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" @@ -18,6 +17,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h" #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/tools/quic_client.h" namespace quic { @@ -55,7 +55,7 @@ class MockableQuicClient : public QuicClient { ~MockableQuicClient() override; QuicConnectionId GenerateNewConnectionId() override; - void UseConnectionId(QuicConnectionId connection_id); + void UseConnectionId(QuicConnectionId server_connection_id); void UseWriter(QuicPacketWriterWrapper* writer); void set_peer_address(const QuicSocketAddress& address); @@ -69,9 +69,9 @@ class MockableQuicClient : public QuicClient { const MockableQuicClientEpollNetworkHelper* mockable_network_helper() const; private: - // ConnectionId to use, if connection_id_overridden_ - QuicConnectionId override_connection_id_; - bool connection_id_overridden_; + // Server connection ID to use, if server_connection_id_overridden_ + QuicConnectionId override_server_connection_id_; + bool server_connection_id_overridden_; CachedNetworkParameters cached_network_paramaters_; }; @@ -185,8 +185,8 @@ class QuicTestClient : public QuicSpdyStream::Visitor, void WaitForResponseForMs(int timeout_ms) { WaitUntil(timeout_ms, [this]() { return !closed_stream_states_.empty(); }); if (response_complete()) { - VLOG(1) << "Client received response:" - << response_headers()->DebugString() << response_body(); + QUIC_VLOG(1) << "Client received response:" + << response_headers()->DebugString() << response_body(); } } @@ -219,9 +219,9 @@ class QuicTestClient : public QuicSpdyStream::Visitor, // Configures client_ to take ownership of and use the writer. // Must be called before initial connect. void UseWriter(QuicPacketWriterWrapper* writer); - // If the given ConnectionId is nonzero, configures client_ to use a specific - // ConnectionId instead of a random one. - void UseConnectionId(QuicConnectionId connection_id); + // Configures client_ to use a specific server connection ID instead of a + // random one. + void UseConnectionId(QuicConnectionId server_connection_id); // Returns nullptr if the maximum number of streams have already been created. QuicSpdyClientStream* GetOrCreateStream(); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc index bda2148731c..68c500e67b7 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc @@ -77,7 +77,7 @@ class QuicTestDispatcher : public QuicSimpleDispatcher { std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, std::unique_ptr<QuicAlarmFactory> alarm_factory, QuicSimpleServerBackend* quic_simple_server_backend, - uint8_t expected_connection_id_length) + uint8_t expected_server_connection_id_length) : QuicSimpleDispatcher(config, crypto_config, version_manager, @@ -85,7 +85,7 @@ class QuicTestDispatcher : public QuicSimpleDispatcher { std::move(session_helper), std::move(alarm_factory), quic_simple_server_backend, - expected_connection_id_length), + expected_server_connection_id_length), session_factory_(nullptr), stream_factory_(nullptr), crypto_stream_factory_(nullptr) {} @@ -170,13 +170,13 @@ QuicTestServer::QuicTestServer( const QuicConfig& config, const ParsedQuicVersionVector& supported_versions, QuicSimpleServerBackend* quic_simple_server_backend, - uint8_t expected_connection_id_length) + uint8_t expected_server_connection_id_length) : QuicServer(std::move(proof_source), config, QuicCryptoServerConfig::ConfigOptions(), supported_versions, quic_simple_server_backend, - expected_connection_id_length) {} + expected_server_connection_id_length) {} QuicDispatcher* QuicTestServer::CreateQuicDispatcher() { return new QuicTestDispatcher( @@ -186,7 +186,7 @@ QuicDispatcher* QuicTestServer::CreateQuicDispatcher() { std::unique_ptr<QuicCryptoServerStream::Helper>( new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())), QuicMakeUnique<QuicEpollAlarmFactory>(epoll_server()), server_backend(), - expected_connection_id_length()); + expected_server_connection_id_length()); } void QuicTestServer::SetSessionFactory(SessionFactory* factory) { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.h index 52fb7c531d5..3661b7a1c8e 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.h @@ -69,7 +69,7 @@ class QuicTestServer : public QuicServer { const QuicConfig& config, const ParsedQuicVersionVector& supported_versions, QuicSimpleServerBackend* quic_simple_server_backend, - uint8_t expected_connection_id_length); + uint8_t expected_server_connection_id_length); // Create a custom dispatcher which creates custom sessions. QuicDispatcher* CreateQuicDispatcher() override; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc index 870a7b82e66..e1f036d3bcd 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc @@ -5,8 +5,10 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include <algorithm> +#include <cstdint> #include <memory> +#include "third_party/boringssl/src/include/openssl/chacha.h" #include "third_party/boringssl/src/include/openssl/sha.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" @@ -152,20 +154,42 @@ std::string Sha1Hash(QuicStringPiece data) { } uint64_t SimpleRandom::RandUint64() { - std::string hash = - Sha1Hash(QuicStringPiece(reinterpret_cast<char*>(&seed_), sizeof(seed_))); - DCHECK_EQ(static_cast<size_t>(SHA_DIGEST_LENGTH), hash.length()); - memcpy(&seed_, hash.data(), sizeof(seed_)); - return seed_; + uint64_t result; + RandBytes(&result, sizeof(result)); + return result; } void SimpleRandom::RandBytes(void* data, size_t len) { - uint8_t* real_data = static_cast<uint8_t*>(data); - for (size_t offset = 0; offset < len; offset++) { - real_data[offset] = RandUint64() & 0xff; + uint8_t* data_bytes = reinterpret_cast<uint8_t*>(data); + while (len > 0) { + const size_t buffer_left = sizeof(buffer_) - buffer_offset_; + const size_t to_copy = std::min(buffer_left, len); + memcpy(data_bytes, buffer_ + buffer_offset_, to_copy); + data_bytes += to_copy; + buffer_offset_ += to_copy; + len -= to_copy; + + if (buffer_offset_ == sizeof(buffer_)) { + FillBuffer(); + } } } +void SimpleRandom::FillBuffer() { + uint8_t nonce[12]; + memcpy(nonce, buffer_, sizeof(nonce)); + CRYPTO_chacha_20(buffer_, buffer_, sizeof(buffer_), key_, nonce, 0); + buffer_offset_ = 0; +} + +void SimpleRandom::set_seed(uint64_t seed) { + static_assert(sizeof(key_) == SHA256_DIGEST_LENGTH, "Key has to be 256 bits"); + SHA256(reinterpret_cast<const uint8_t*>(&seed), sizeof(seed), key_); + + memset(buffer_, 0, sizeof(buffer_)); + FillBuffer(); +} + MockFramerVisitor::MockFramerVisitor() { // By default, we want to accept packets. ON_CALL(*this, OnProtocolVersionMismatch(_, _)) @@ -202,9 +226,8 @@ MockFramerVisitor::MockFramerVisitor() { ON_CALL(*this, OnPathResponseFrame(_)).WillByDefault(testing::Return(true)); ON_CALL(*this, OnGoAwayFrame(_)).WillByDefault(testing::Return(true)); - ON_CALL(*this, OnMaxStreamIdFrame(_)).WillByDefault(testing::Return(true)); - ON_CALL(*this, OnStreamIdBlockedFrame(_)) - .WillByDefault(testing::Return(true)); + ON_CALL(*this, OnMaxStreamsFrame(_)).WillByDefault(testing::Return(true)); + ON_CALL(*this, OnStreamsBlockedFrame(_)).WillByDefault(testing::Return(true)); } MockFramerVisitor::~MockFramerVisitor() {} @@ -310,12 +333,12 @@ bool NoOpFramerVisitor::OnGoAwayFrame(const QuicGoAwayFrame& frame) { return true; } -bool NoOpFramerVisitor::OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) { +bool NoOpFramerVisitor::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) { return true; } -bool NoOpFramerVisitor::OnStreamIdBlockedFrame( - const QuicStreamIdBlockedFrame& frame) { +bool NoOpFramerVisitor::OnStreamsBlockedFrame( + const QuicStreamsBlockedFrame& frame) { return true; } @@ -615,10 +638,8 @@ QuicCryptoServerStreamBase* TestQuicSpdyServerSession::CreateQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, QuicCompressedCertsCache* compressed_certs_cache) { - return new QuicCryptoServerStream( - crypto_config, compressed_certs_cache, - GetQuicReloadableFlag(enable_quic_stateless_reject_support), this, - &helper_); + return new QuicCryptoServerStream(crypto_config, compressed_certs_cache, this, + &helper_); } void TestQuicSpdyServerSession::OnCryptoHandshakeEvent( @@ -862,15 +883,41 @@ QuicEncryptedPacket* ConstructEncryptedPacket( QuicFrames frames; QuicFramer framer(*versions, QuicTime::Zero(), perspective, kQuicDefaultConnectionIdLength); - if (!QuicVersionUsesCryptoFrames((*versions)[0].transport_version)) { - QuicFrame frame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId((*versions)[0].transport_version), false, - 0, QuicStringPiece(data))); + ParsedQuicVersion version = (*versions)[0]; + EncryptionLevel level = + header.version_flag ? ENCRYPTION_INITIAL : ENCRYPTION_FORWARD_SECURE; + if (version.handshake_protocol == PROTOCOL_TLS1_3 && + level == ENCRYPTION_INITIAL) { + CrypterPair crypters; + CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_CLIENT, + version.transport_version, + destination_connection_id, &crypters); + framer.SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter)); + if (version.KnowsWhichDecrypterToUse()) { + framer.InstallDecrypter(ENCRYPTION_INITIAL, + std::move(crypters.decrypter)); + } else { + framer.SetDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter)); + } + } + if (!QuicVersionUsesCryptoFrames(version.transport_version)) { + QuicFrame frame( + QuicStreamFrame(QuicUtils::GetCryptoStreamId(version.transport_version), + false, 0, QuicStringPiece(data))); frames.push_back(frame); } else { - QuicFrame frame(new QuicCryptoFrame(ENCRYPTION_INITIAL, 0, data)); + QuicFrame frame(new QuicCryptoFrame(level, 0, data)); frames.push_back(frame); } + // We need a minimum number of bytes of encrypted payload. This will + // guarantee that we have at least that much. (It ignores the overhead of the + // stream/crypto framing, so it overpads slightly.) + size_t min_plaintext_size = + QuicPacketCreator::MinPlaintextPacketSize(version); + if (data.length() < min_plaintext_size) { + size_t padding_length = min_plaintext_size - data.length(); + frames.push_back(QuicFrame(QuicPaddingFrame(padding_length))); + } std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); @@ -923,9 +970,26 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( QuicFrame frame(QuicStreamFrame(1, false, 0, QuicStringPiece(data))); QuicFrames frames; frames.push_back(frame); + ParsedQuicVersion version = + (versions != nullptr ? *versions : AllSupportedVersions())[0]; QuicFramer framer(versions != nullptr ? *versions : AllSupportedVersions(), QuicTime::Zero(), perspective, kQuicDefaultConnectionIdLength); + if (version.handshake_protocol == PROTOCOL_TLS1_3 && version_flag) { + CrypterPair crypters; + CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_CLIENT, + version.transport_version, + destination_connection_id, &crypters); + framer.SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter)); + framer.SetDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter)); + } + // We need a minimum of 7 bytes of encrypted payload. This will guarantee that + // we have at least that much. (It ignores the overhead of the stream/crypto + // framing, so it overpads slightly.) + if (data.length() < 7) { + size_t padding_length = 7 - data.length(); + frames.push_back(QuicFrame(QuicPaddingFrame(padding_length))); + } std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); @@ -985,7 +1049,7 @@ QuicConfig DefaultQuicConfig() { kInitialStreamFlowControlWindowForTest); config.SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); - QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams( + QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams( &config, kDefaultMaxStreamsPerConnection); // Default enable NSTP. // This is unnecessary for versions > 44 @@ -998,14 +1062,6 @@ QuicConfig DefaultQuicConfig() { return config; } -QuicConfig DefaultQuicConfigStatelessRejects() { - QuicConfig config = DefaultQuicConfig(); - QuicTagVector copt; - copt.push_back(kSREJ); - config.SetConnectionOptionsToSend(copt); - return config; -} - QuicTransportVersionVector SupportedTransportVersions( QuicTransportVersion version) { QuicTransportVersionVector versions; @@ -1028,10 +1084,6 @@ MockReceivedPacketManager::MockReceivedPacketManager(QuicConnectionStats* stats) MockReceivedPacketManager::~MockReceivedPacketManager() {} -MockConnectionCloseDelegate::MockConnectionCloseDelegate() {} - -MockConnectionCloseDelegate::~MockConnectionCloseDelegate() {} - MockPacketCreatorDelegate::MockPacketCreatorDelegate() {} MockPacketCreatorDelegate::~MockPacketCreatorDelegate() {} @@ -1040,7 +1092,6 @@ MockSessionNotifier::~MockSessionNotifier() {} void CreateClientSessionForTest( QuicServerId server_id, - bool supports_stateless_rejects, QuicTime::Delta connection_start_time, const ParsedQuicVersionVector& supported_versions, MockQuicConnectionHelper* helper, @@ -1055,9 +1106,7 @@ void CreateClientSessionForTest( << "Connections must start at non-zero times, otherwise the " << "strike-register will be unhappy."; - QuicConfig config = supports_stateless_rejects - ? DefaultQuicConfigStatelessRejects() - : DefaultQuicConfig(); + QuicConfig config = DefaultQuicConfig(); *client_connection = new PacketSavingConnection( helper, alarm_factory, Perspective::IS_CLIENT, supported_versions); *client_session = new TestQuicSpdyClientSession(*client_connection, config, diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h index c888fef9b72..4f6a30a17c0 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h @@ -13,13 +13,11 @@ #include <utility> #include <vector> -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h" #include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" #include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" #include "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h" #include "net/third_party/quiche/src/quic/core/quic_connection.h" -#include "net/third_party/quiche/src/quic/core/quic_connection_close_delegate_interface.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" #include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h" @@ -27,6 +25,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" #include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h" #include "net/third_party/quiche/src/quic/test_tools/mock_random.h" @@ -161,9 +160,6 @@ void CompareCharArraysWithHexError(const std::string& description, // Returns QuicConfig set to default values. QuicConfig DefaultQuicConfig(); -// Returns a QuicConfig set to default values that supports stateless rejects. -QuicConfig DefaultQuicConfigStatelessRejects(); - // Returns a version vector consisting of |version|. QuicTransportVersionVector SupportedTransportVersions( QuicTransportVersion version); @@ -213,12 +209,10 @@ std::unique_ptr<QuicPacket> BuildUnsizedDataPacket( std::string Sha1Hash(QuicStringPiece data); // Simple random number generator used to compute random numbers suitable -// for pseudo-randomly dropping packets in tests. It works by computing -// the sha1 hash of the current seed, and using the first 64 bits as -// the next random number, and the next seed. +// for pseudo-randomly dropping packets in tests. class SimpleRandom : public QuicRandom { public: - SimpleRandom() : seed_(0) {} + SimpleRandom() { set_seed(0); } SimpleRandom(const SimpleRandom&) = delete; SimpleRandom& operator=(const SimpleRandom&) = delete; ~SimpleRandom() override {} @@ -228,10 +222,14 @@ class SimpleRandom : public QuicRandom { void RandBytes(void* data, size_t len) override; - void set_seed(uint64_t seed) { seed_ = seed; } + void set_seed(uint64_t seed); private: - uint64_t seed_; + uint8_t buffer_[4096]; + size_t buffer_offset_; + uint8_t key_[32]; + + void FillBuffer(); }; class MockFramerVisitor : public QuicFramerVisitorInterface { @@ -249,6 +247,10 @@ class MockFramerVisitor : public QuicFramerVisitorInterface { MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header)); MOCK_METHOD1(OnVersionNegotiationPacket, void(const QuicVersionNegotiationPacket& packet)); + MOCK_METHOD3(OnRetryPacket, + void(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token)); // The constructor sets this up to return true by default. MOCK_METHOD1(OnUnauthenticatedHeader, bool(const QuicPacketHeader& header)); // The constructor sets this up to return true by default. @@ -278,9 +280,9 @@ class MockFramerVisitor : public QuicFramerVisitorInterface { MOCK_METHOD1(OnPathChallengeFrame, bool(const QuicPathChallengeFrame& frame)); MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame& frame)); MOCK_METHOD1(OnGoAwayFrame, bool(const QuicGoAwayFrame& frame)); - MOCK_METHOD1(OnMaxStreamIdFrame, bool(const QuicMaxStreamIdFrame& frame)); - MOCK_METHOD1(OnStreamIdBlockedFrame, - bool(const QuicStreamIdBlockedFrame& frame)); + MOCK_METHOD1(OnMaxStreamsFrame, bool(const QuicMaxStreamsFrame& frame)); + MOCK_METHOD1(OnStreamsBlockedFrame, + bool(const QuicStreamsBlockedFrame& frame)); MOCK_METHOD1(OnWindowUpdateFrame, bool(const QuicWindowUpdateFrame& frame)); MOCK_METHOD1(OnBlockedFrame, bool(const QuicBlockedFrame& frame)); MOCK_METHOD1(OnMessageFrame, bool(const QuicMessageFrame& frame)); @@ -301,6 +303,9 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface { void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override {} + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override {} bool OnProtocolVersionMismatch(ParsedQuicVersion version, PacketHeaderFormat form) override; bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; @@ -329,8 +334,8 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface { bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override; bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override; bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override; - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override; - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override; + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override; + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override; bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; bool OnBlockedFrame(const QuicBlockedFrame& frame) override; bool OnMessageFrame(const QuicMessageFrame& frame) override; @@ -361,6 +366,7 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface { ConnectionCloseSource source)); MOCK_METHOD0(OnWriteBlocked, void()); MOCK_METHOD0(OnCanWrite, void()); + MOCK_METHOD0(SendProbingData, bool()); MOCK_METHOD1(OnCongestionWindowChange, void(QuicTime now)); MOCK_METHOD1(OnConnectionMigration, void(AddressChangeType type)); MOCK_METHOD0(OnPathDegrading, void()); @@ -377,9 +383,9 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface { MOCK_METHOD0(SendPing, void()); MOCK_CONST_METHOD0(AllowSelfAddressChange, bool()); MOCK_METHOD0(OnForwardProgressConfirmed, void()); - MOCK_METHOD1(OnMaxStreamIdFrame, bool(const QuicMaxStreamIdFrame& frame)); - MOCK_METHOD1(OnStreamIdBlockedFrame, - bool(const QuicStreamIdBlockedFrame& frame)); + MOCK_METHOD1(OnMaxStreamsFrame, bool(const QuicMaxStreamsFrame& frame)); + MOCK_METHOD1(OnStreamsBlockedFrame, + bool(const QuicStreamsBlockedFrame& frame)); MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame)); }; @@ -474,10 +480,8 @@ class MockQuicConnection : public QuicConnection { void(QuicErrorCode error, const std::string& details, ConnectionCloseBehavior connection_close_behavior)); - MOCK_METHOD3(SendConnectionClosePacket, - void(QuicErrorCode error, - const std::string& details, - AckBundling ack_mode)); + MOCK_METHOD2(SendConnectionClosePacket, + void(QuicErrorCode error, const std::string& details)); MOCK_METHOD3(SendRstStream, void(QuicStreamId id, QuicRstStreamErrorCode error, @@ -910,7 +914,8 @@ class MockSendAlgorithm : public SendAlgorithmInterface { MOCK_CONST_METHOD0(ShouldSendProbingPacket, bool()); MOCK_CONST_METHOD0(GetSlowStartThreshold, QuicByteCount()); MOCK_CONST_METHOD0(GetCongestionControlType, CongestionControlType()); - MOCK_METHOD2(AdjustNetworkParameters, void(QuicBandwidth, QuicTime::Delta)); + MOCK_METHOD3(AdjustNetworkParameters, + void(QuicBandwidth, QuicTime::Delta, bool)); MOCK_METHOD1(OnApplicationLimited, void(QuicByteCount)); }; @@ -1011,6 +1016,9 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { MOCK_METHOD1(OnVersionNegotiationPacket, void(const QuicVersionNegotiationPacket&)); + + MOCK_METHOD3(OnRetryPacket, + void(QuicConnectionId, QuicConnectionId, QuicStringPiece)); }; class MockReceivedPacketManager : public QuicReceivedPacketManager { @@ -1028,18 +1036,6 @@ class MockReceivedPacketManager : public QuicReceivedPacketManager { MOCK_CONST_METHOD0(ack_frame_updated, bool(void)); }; -class MockConnectionCloseDelegate - : public QuicConnectionCloseDelegateInterface { - public: - MockConnectionCloseDelegate(); - ~MockConnectionCloseDelegate() override; - - MOCK_METHOD3(OnUnrecoverableError, - void(QuicErrorCode, - const std::string&, - ConnectionCloseSource source)); -}; - class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface { public: MockPacketCreatorDelegate(); @@ -1050,10 +1046,7 @@ class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface { MOCK_METHOD0(GetPacketBuffer, char*()); MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet)); - MOCK_METHOD3(OnUnrecoverableError, - void(QuicErrorCode, - const std::string&, - ConnectionCloseSource source)); + MOCK_METHOD2(OnUnrecoverableError, void(QuicErrorCode, const std::string&)); }; class MockSessionNotifier : public SessionNotifierInterface { @@ -1073,7 +1066,6 @@ class MockSessionNotifier : public SessionNotifierInterface { // Creates a client session for testing. // // server_id: The server id associated with this stream. -// supports_stateless_rejects: Does this client support stateless rejects. // connection_start_time: The time to set for the connection clock. // Needed for strike-register nonce verification. The client // connection_start_time should be synchronized witht the server @@ -1088,7 +1080,6 @@ class MockSessionNotifier : public SessionNotifierInterface { // session. The new object will be owned by the caller. void CreateClientSessionForTest( QuicServerId server_id, - bool supports_stateless_rejects, QuicTime::Delta connection_start_time, const ParsedQuicVersionVector& supported_versions, MockQuicConnectionHelper* helper, @@ -1125,7 +1116,8 @@ void CreateServerSessionForTest( // Verifies that the relative error of |actual| with respect to |expected| is // no more than |margin|. - +// Please use EXPECT_APPROX_EQ, a wrapper around this function, for better error +// report. template <typename T> void ExpectApproxEq(T expected, T actual, float relative_margin) { // If |relative_margin| > 1 and T is an unsigned type, the comparison will @@ -1135,10 +1127,16 @@ void ExpectApproxEq(T expected, T actual, float relative_margin) { T absolute_margin = expected * relative_margin; - EXPECT_GE(expected + absolute_margin, actual); - EXPECT_LE(expected - absolute_margin, actual); + EXPECT_GE(expected + absolute_margin, actual) << "actual value too big"; + EXPECT_LE(expected - absolute_margin, actual) << "actual value too small"; } +#define EXPECT_APPROX_EQ(expected, actual, relative_margin) \ + do { \ + SCOPED_TRACE(testing::Message() << "relative_margin:" << relative_margin); \ + quic::test::ExpectApproxEq(expected, actual, relative_margin); \ + } while (0) + template <typename T> QuicHeaderList AsHeaderList(const T& container) { QuicHeaderList l; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils_test.cc index 79d2af8c908..31e48041758 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils_test.cc @@ -4,7 +4,6 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" -#include "testing/gtest/include/gtest/gtest-spi.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { @@ -23,29 +22,29 @@ TEST_F(QuicTestUtilsTest, ConnectionId) { } TEST_F(QuicTestUtilsTest, BasicApproxEq) { - ExpectApproxEq(10, 10, 1e-6f); - ExpectApproxEq(1000, 1001, 0.01f); - EXPECT_NONFATAL_FAILURE(ExpectApproxEq(1000, 1100, 0.01f), ""); + EXPECT_APPROX_EQ(10, 10, 1e-6f); + EXPECT_APPROX_EQ(1000, 1001, 0.01f); + EXPECT_NONFATAL_FAILURE(EXPECT_APPROX_EQ(1000, 1100, 0.01f), ""); - ExpectApproxEq(64, 31, 0.55f); - EXPECT_NONFATAL_FAILURE(ExpectApproxEq(31, 64, 0.55f), ""); + EXPECT_APPROX_EQ(64, 31, 0.55f); + EXPECT_NONFATAL_FAILURE(EXPECT_APPROX_EQ(31, 64, 0.55f), ""); } TEST_F(QuicTestUtilsTest, QuicTimeDelta) { - ExpectApproxEq(QuicTime::Delta::FromMicroseconds(1000), - QuicTime::Delta::FromMicroseconds(1003), 0.01f); + EXPECT_APPROX_EQ(QuicTime::Delta::FromMicroseconds(1000), + QuicTime::Delta::FromMicroseconds(1003), 0.01f); EXPECT_NONFATAL_FAILURE( - ExpectApproxEq(QuicTime::Delta::FromMicroseconds(1000), - QuicTime::Delta::FromMicroseconds(1200), 0.01f), + EXPECT_APPROX_EQ(QuicTime::Delta::FromMicroseconds(1000), + QuicTime::Delta::FromMicroseconds(1200), 0.01f), ""); } TEST_F(QuicTestUtilsTest, QuicBandwidth) { - ExpectApproxEq(QuicBandwidth::FromBytesPerSecond(1000), - QuicBandwidth::FromBitsPerSecond(8005), 0.01f); + EXPECT_APPROX_EQ(QuicBandwidth::FromBytesPerSecond(1000), + QuicBandwidth::FromBitsPerSecond(8005), 0.01f); EXPECT_NONFATAL_FAILURE( - ExpectApproxEq(QuicBandwidth::FromBytesPerSecond(1000), - QuicBandwidth::FromBitsPerSecond(9005), 0.01f), + EXPECT_APPROX_EQ(QuicBandwidth::FromBytesPerSecond(1000), + QuicBandwidth::FromBitsPerSecond(9005), 0.01f), ""); } @@ -53,8 +52,27 @@ TEST_F(QuicTestUtilsTest, QuicBandwidth) { TEST_F(QuicTestUtilsTest, SimpleRandomStability) { SimpleRandom rng; rng.set_seed(UINT64_C(0x1234567800010001)); - EXPECT_EQ(UINT64_C(14865409841904857791), rng.RandUint64()); - EXPECT_EQ(UINT64_C(12139094019410129741), rng.RandUint64()); + EXPECT_EQ(UINT64_C(12589383305231984671), rng.RandUint64()); + EXPECT_EQ(UINT64_C(17775425089941798664), rng.RandUint64()); +} + +// Ensure that the output of SimpleRandom does not depend on the size of the +// read calls. +TEST_F(QuicTestUtilsTest, SimpleRandomChunks) { + SimpleRandom rng; + std::string reference(16 * 1024, '\0'); + rng.RandBytes(&reference[0], reference.size()); + + for (size_t chunk_size : {3, 4, 7, 4096}) { + rng.set_seed(0); + size_t chunks = reference.size() / chunk_size; + std::string buffer(chunks * chunk_size, '\0'); + for (size_t i = 0; i < chunks; i++) { + rng.RandBytes(&buffer[i * chunk_size], chunk_size); + } + EXPECT_EQ(reference.substr(0, buffer.size()), buffer) + << "Failed for chunk_size = " << chunk_size; + } } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc index 6a90a79a074..06a6718439b 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc @@ -39,6 +39,10 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { QuicMakeUnique<QuicVersionNegotiationPacket>((packet)); } + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override {} + bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { return true; } @@ -160,13 +164,13 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { goaway_frames_.push_back(frame); return true; } - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override { - max_stream_id_frames_.push_back(frame); + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override { + max_streams_frames_.push_back(frame); return true; } - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override { - stream_id_blocked_frames_.push_back(frame); + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override { + streams_blocked_frames_.push_back(frame); return true; } @@ -206,12 +210,11 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { const std::vector<QuicGoAwayFrame>& goaway_frames() const { return goaway_frames_; } - const std::vector<QuicMaxStreamIdFrame>& max_stream_id_frames() const { - return max_stream_id_frames_; + const std::vector<QuicMaxStreamsFrame>& max_streams_frames() const { + return max_streams_frames_; } - const std::vector<QuicStreamIdBlockedFrame>& stream_id_blocked_frames() - const { - return stream_id_blocked_frames_; + const std::vector<QuicStreamsBlockedFrame>& streams_blocked_frames() const { + return streams_blocked_frames_; } const std::vector<QuicRstStreamFrame>& rst_stream_frames() const { return rst_stream_frames_; @@ -261,8 +264,8 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_; std::vector<QuicRstStreamFrame> rst_stream_frames_; std::vector<QuicGoAwayFrame> goaway_frames_; - std::vector<QuicStreamIdBlockedFrame> stream_id_blocked_frames_; - std::vector<QuicMaxStreamIdFrame> max_stream_id_frames_; + std::vector<QuicStreamsBlockedFrame> streams_blocked_frames_; + std::vector<QuicMaxStreamsFrame> max_streams_frames_; std::vector<QuicConnectionCloseFrame> connection_close_frames_; std::vector<QuicStopSendingFrame> stop_sending_frames_; std::vector<QuicPathChallengeFrame> path_challenge_frames_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc index 643821ab545..e72e0e1b811 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.cc @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" @@ -71,7 +72,7 @@ void SimpleSessionNotifier::OnStreamDataConsumed(QuicStreamId id, QuicByteCount data_length, bool fin) { StreamState& state = stream_map_.find(id)->second; - if (id == QuicUtils::GetCryptoStreamId(connection_->transport_version()) && + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) && data_length > 0) { crypto_bytes_transferred_[connection_->encryption_level()].Add( offset, offset + data_length); @@ -126,8 +127,11 @@ void SimpleSessionNotifier::WriteOrBufferPing() { } void SimpleSessionNotifier::NeuterUnencryptedData() { + // TODO(nharper): Handle CRYPTO frame case. + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + return; + } for (const auto& interval : crypto_bytes_transferred_[ENCRYPTION_INITIAL]) { - // TODO(nharper): Handle CRYPTO frame case. QuicStreamFrame stream_frame( QuicUtils::GetCryptoStreamId(connection_->transport_version()), false, interval.min(), interval.max() - interval.min()); @@ -145,7 +149,6 @@ void SimpleSessionNotifier::OnCanWrite() { return; } // Write new data. - // TODO(nharper): Write CRYPTO frames. for (const auto& pair : stream_map_) { const auto& state = pair.second; if (!StreamHasBufferedData(pair.first)) { @@ -319,8 +322,8 @@ void SimpleSessionNotifier::RetransmitFrames(const QuicFrames& frames, EncryptionLevel retransmission_encryption_level = connection_->encryption_level(); EncryptionLevel current_encryption_level = connection_->encryption_level(); - if (frame.stream_frame.stream_id == - QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), + frame.stream_frame.stream_id)) { for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) { if (retransmission.Intersects(crypto_bytes_transferred_[i])) { retransmission_encryption_level = static_cast<EncryptionLevel>(i); @@ -338,8 +341,8 @@ void SimpleSessionNotifier::RetransmitFrames(const QuicFrames& frames, const bool can_bundle_fin = retransmit_fin && (retransmission_offset + retransmission_length == state.bytes_sent); - if (frame.stream_frame.stream_id == - QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), + frame.stream_frame.stream_id)) { // Set appropriate encryption level for crypto stream. connection_->SetDefaultEncryptionLevel(retransmission_encryption_level); } @@ -355,8 +358,8 @@ void SimpleSessionNotifier::RetransmitFrames(const QuicFrames& frames, if (can_bundle_fin) { retransmit_fin = !consumed.fin_consumed; } - if (frame.stream_frame.stream_id == - QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), + frame.stream_frame.stream_id)) { // Restore encryption level. connection_->SetDefaultEncryptionLevel(current_encryption_level); } @@ -496,7 +499,36 @@ bool SimpleSessionNotifier::RetransmitLostControlFrames() { } bool SimpleSessionNotifier::RetransmitLostCryptoData() { - // TODO(nharper): Handle CRYPTO frame case. + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + for (EncryptionLevel level : + {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, + ENCRYPTION_FORWARD_SECURE}) { + auto& state = crypto_state_[level]; + while (!state.pending_retransmissions.Empty()) { + connection_->SetTransmissionType(HANDSHAKE_RETRANSMISSION); + EncryptionLevel current_encryption_level = + connection_->encryption_level(); + connection_->SetDefaultEncryptionLevel(level); + QuicIntervalSet<QuicStreamOffset> retransmission( + state.pending_retransmissions.begin()->min(), + state.pending_retransmissions.begin()->max()); + retransmission.Intersection(crypto_bytes_transferred_[level]); + QuicStreamOffset retransmission_offset = retransmission.begin()->min(); + QuicByteCount retransmission_length = + retransmission.begin()->max() - retransmission.begin()->min(); + size_t bytes_consumed = connection_->SendCryptoData( + level, retransmission_length, retransmission_offset); + // Restore encryption level. + connection_->SetDefaultEncryptionLevel(current_encryption_level); + state.pending_retransmissions.Difference( + retransmission_offset, retransmission_offset + bytes_consumed); + if (bytes_consumed < retransmission_length) { + return false; + } + } + } + return true; + } if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId( connection_->transport_version()))) { return true; @@ -551,7 +583,7 @@ bool SimpleSessionNotifier::RetransmitLostStreamData() { connection_->SendStreamData(pair.first, 0, state.bytes_sent, FIN); state.fin_lost = !consumed.fin_consumed; if (state.fin_lost) { - DLOG(INFO) << "Connection is write blocked"; + QUIC_DLOG(INFO) << "Connection is write blocked"; return false; } } else { @@ -573,7 +605,7 @@ bool SimpleSessionNotifier::RetransmitLostStreamData() { } if (length > consumed.bytes_consumed || (can_bundle_fin && !consumed.fin_consumed)) { - DVLOG(1) << "Connection is write blocked"; + QUIC_DVLOG(1) << "Connection is write blocked"; break; } } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h index 17616b7693f..e7d4fdc9b50 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h @@ -5,9 +5,9 @@ #ifndef QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_NOTIFIER_H_ #define QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_NOTIFIER_H_ -#include "testing/gmock/include/gmock/gmock.h" #include "net/third_party/quiche/src/quic/core/quic_interval_set.h" #include "net/third_party/quiche/src/quic/core/session_notifier_interface.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc index 53712fd5395..d2aad9f087e 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc @@ -4,10 +4,12 @@ #include "net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_data_producer.h" using testing::_; using testing::InSequence; @@ -126,6 +128,9 @@ TEST_F(SimpleSessionNotifierTest, WriteOrBufferPing) { } TEST_F(SimpleSessionNotifierTest, NeuterUnencryptedData) { + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + return; + } InSequence s; // Send crypto data [0, 1024) in ENCRYPTION_INITIAL. connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); @@ -159,6 +164,9 @@ TEST_F(SimpleSessionNotifierTest, NeuterUnencryptedData) { } TEST_F(SimpleSessionNotifierTest, OnCanWrite) { + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + return; + } InSequence s; // Send crypto data [0, 1024) in ENCRYPTION_INITIAL. connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); @@ -221,6 +229,72 @@ TEST_F(SimpleSessionNotifierTest, OnCanWrite) { EXPECT_FALSE(notifier_.WillingToWrite()); } +TEST_F(SimpleSessionNotifierTest, OnCanWriteCryptoFrames) { + if (!QuicVersionUsesCryptoFrames(connection_.transport_version())) { + return; + } + SimpleDataProducer producer; + connection_.SetDataProducer(&producer); + InSequence s; + // Send crypto data [0, 1024) in ENCRYPTION_INITIAL. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_INITIAL, 1024, 0)) + .WillOnce(Invoke(&connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + EXPECT_CALL(connection_, CloseConnection(QUIC_PACKET_WRITE_ERROR, _, _)); + producer.SaveCryptoData(ENCRYPTION_INITIAL, 0, std::string(1024, 'a')); + producer.SaveCryptoData(ENCRYPTION_INITIAL, 500, std::string(524, 'a')); + notifier_.WriteCryptoData(ENCRYPTION_INITIAL, 1024, 0); + // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<NullEncrypter>( + Perspective::IS_CLIENT)); + EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0)) + .WillOnce(Invoke(&connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + producer.SaveCryptoData(ENCRYPTION_ZERO_RTT, 0, std::string(1024, 'a')); + notifier_.WriteCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0); + // Send stream 3 [0, 1024) and connection is blocked. + EXPECT_CALL(connection_, SendStreamData(3, 1024, 0, FIN)) + .WillOnce(Return(QuicConsumedData(512, false))); + notifier_.WriteOrBufferData(3, 1024, FIN); + // Send stream 5 [0, 1024). + EXPECT_CALL(connection_, SendStreamData(5, _, _, _)).Times(0); + notifier_.WriteOrBufferData(5, 1024, NO_FIN); + // Reset stream 5 with error. + EXPECT_CALL(connection_, SendControlFrame(_)).Times(0); + notifier_.WriteOrBufferRstStream(5, QUIC_ERROR_PROCESSING_STREAM, 1024); + + // Lost crypto data [500, 1500) and stream 3 [0, 512). + QuicCryptoFrame crypto_frame1(ENCRYPTION_INITIAL, 500, 524); + QuicCryptoFrame crypto_frame2(ENCRYPTION_ZERO_RTT, 0, 476); + QuicStreamFrame stream3_frame(3, false, 0, 512); + notifier_.OnFrameLost(QuicFrame(&crypto_frame1)); + notifier_.OnFrameLost(QuicFrame(&crypto_frame2)); + notifier_.OnFrameLost(QuicFrame(stream3_frame)); + + // Connection becomes writable. + // Lost crypto data gets retransmitted as [500, 1024) and [1024, 1500), as + // they are in different encryption levels. + EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_INITIAL, 524, 500)) + .WillOnce(Invoke(&connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 476, 0)) + .WillOnce(Invoke(&connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + // Lost stream 3 data gets retransmitted. + EXPECT_CALL(connection_, SendStreamData(3, 512, 0, NO_FIN)) + .WillOnce(Return(QuicConsumedData(512, false))); + // Buffered control frames get sent. + EXPECT_CALL(connection_, SendControlFrame(_)) + .WillOnce(Invoke(this, &SimpleSessionNotifierTest::ControlFrameConsumed)); + // Buffered stream 3 data [512, 1024) gets sent. + EXPECT_CALL(connection_, SendStreamData(3, 512, 512, FIN)) + .WillOnce(Return(QuicConsumedData(512, true))); + notifier_.OnCanWrite(); + EXPECT_FALSE(notifier_.WillingToWrite()); +} + TEST_F(SimpleSessionNotifierTest, RetransmitFrames) { InSequence s; // Send stream 3 data [0, 10) and fin. diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/README.md b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/README.md new file mode 100644 index 00000000000..8582962adee --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/README.md @@ -0,0 +1,99 @@ +# QUIC network simulator + +This directory contains a discrete event network simulator which QUIC code uses +for testing congestion control and other transmission control code that requires +a network simulation for tests on QuicConnection level of abstraction. + +## Actors + +The core of the simulator is the Simulator class, which maintains a virtual +clock and an event queue. Any object in a simulation that needs to schedule +events has to subclass Actor. Subclassing Actor involves: + +1. Calling the `Actor::Actor(Simulator*, std::string)` constructor to establish + the name of the object and the simulator it is associated with. +2. Calling `Schedule(QuicTime)` to schedule the time at which `Act()` method is + called. `Schedule` will only cause the object to be rescheduled if the time + for which it is currently scheduled is later than the new time. +3. Implementing `Act()` method with the relevant logic. The actor will be + removed from the event queue right before `Act()` is called. + +Here is a simple example of an object that outputs simulation time into the log +every 100 ms. + +```c++ +class LogClock : public Actor { + public: + LogClock(Simulator* simulator, std::string name) : Actor(simulator, name) { + Schedule(clock_->Now()); + } + ~LogClock() override {} + + void Act() override { + QUIC_LOG(INFO) << "The current time is " + << clock_->Now().ToDebuggingValue(); + Schedule(clock_->Now() + QuicTime::Delta::FromMilliseconds(100)); + } +}; +``` + +A QuicAlarm object can be used to schedule events in the simulation using +`Simulator::GetAlarmFactory()`. + +## Ports + +The simulated network transfers packets, which are modelled as an instance of +struct `Packet`. A packet consists of source and destination address (which are +just plain strings), a transmission timestamp and the UDP-layer payload. + +The simulation uses the push model: any object that wishes to transfer a packet +to another component in the simulation has to explicitly do it itself. Any +object that can accept a packet is called a *port*. There are two types of +ports: unconstrained ports, which can always accept packets, and constrained +ports, which signal when they can accept a new packet. + +An endpoint is an object that is connected to the network and can both receive +and send packets. In our model, the endpoint always receives packets as an +unconstrained port (*RX port*), and always writes packets to a constrained port +(*TX port*). + +## Links + +The `SymmetricLink` class models a symmetric duplex links with finite bandwidth +and propagation delay. It consists of a pair of identical `OneWayLink`s, which +accept packets as a constrained port (where constrain comes from the finiteness +of bandwidth) and outputs them into an unconstrained port. Two endpoints +connected via a `SymmetricLink` look like this: + +```none + Endpoint A Endpoint B ++-----------+ SymmetricLink +-----------+ +| | +------------------------------+ | | +| +---------+ | +------------------------+ | +---------+ | +| | RX port <-----| OneWayLink *<-----| TX port | | +| +---------+ | +------------------------+ | +---------+ | +| | | | | | +| +---------+ | +------------------------+ | +---------+ | +| | TX port |----->* OneWayLink |-----> RX port | | +| +---------+ | +------------------------+ | +---------+ | +| | +------------------------------+ | | ++-----------+ +-----------+ + + ( -->* denotes constrained port) +``` + +In most common scenario, one of the endpoints is going to be a QUIC endpoint, +and another is going to be a switch port. + +## Other objects + +Besides `SymmetricLink`, the simulator provides the following objects: + +* `Queue` allows to convert a constrained port into an unconstrained one by + buffering packets upon arrival. The queue has a finite size, and once the + queue is full, the packets are silently dropped. +* `Switch` simulates a multi-port learning switch with a fixed queue for each + output port. +* `QuicEndpoint` allows QuicConnection to be run over the simulated network. +* `QuicEndpointMultiplexer` allows multiple connections to share the same + network endpoint. diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.cc index a016b89f937..110933e1379 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.cc @@ -39,9 +39,14 @@ void OneWayLink::AcceptPacket(std::unique_ptr<Packet> packet) { QuicTime::Delta transfer_time = bandwidth_.TransferTime(packet->size); next_write_at_ = clock_->Now() + transfer_time; - packets_in_transit_.emplace( + packets_in_transit_.emplace_back( std::move(packet), - next_write_at_ + propagation_delay_ + GetRandomDelay(transfer_time)); + // Ensure that packets are delivered in order. + std::max( + next_write_at_ + propagation_delay_ + GetRandomDelay(transfer_time), + packets_in_transit_.empty() + ? QuicTime::Zero() + : packets_in_transit_.back().dequeue_time)); ScheduleNextPacketDeparture(); } @@ -59,7 +64,7 @@ void OneWayLink::Act() { DCHECK(packets_in_transit_.front().dequeue_time >= clock_->Now()); sink_->AcceptPacket(std::move(packets_in_transit_.front().packet)); - packets_in_transit_.pop(); + packets_in_transit_.pop_front(); ScheduleNextPacketDeparture(); } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.h index 103afa0998c..531eff67cf4 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/link.h @@ -34,6 +34,13 @@ class OneWayLink : public Actor, public ConstrainedPortInterface { inline QuicBandwidth bandwidth() const { return bandwidth_; } + protected: + // Get the value of a random delay imposed on each packet. By default, this + // is a short random delay in order to avoid artifical synchronization + // artifacts during the simulation. Subclasses may override this behavior + // (for example, to provide a random component of delay). + virtual QuicTime::Delta GetRandomDelay(QuicTime::Delta transfer_time); + private: struct QueuedPacket { std::unique_ptr<Packet> packet; @@ -48,12 +55,8 @@ class OneWayLink : public Actor, public ConstrainedPortInterface { // packets on the link. void ScheduleNextPacketDeparture(); - // Get the value of a random delay imposed on each packet in order to avoid - // artifical synchronization artifacts during the simulation. - QuicTime::Delta GetRandomDelay(QuicTime::Delta transfer_time); - UnconstrainedPortInterface* sink_; - QuicQueue<QueuedPacket> packets_in_transit_; + QuicDeque<QueuedPacket> packets_in_transit_; const QuicBandwidth bandwidth_; const QuicTime::Delta propagation_delay_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc index 9e5c3fab604..043eae99e21 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc @@ -113,7 +113,7 @@ QuicEndpoint::QuicEndpoint(Simulator* simulator, CryptoHandshakeMessage peer_hello; peer_hello.SetValue(kICSL, static_cast<uint32_t>(kMaximumIdleTimeoutSecs - 1)); - peer_hello.SetValue(kMIDS, + peer_hello.SetValue(kMIBS, static_cast<uint32_t>(kDefaultMaxStreamsPerConnection)); QuicConfig config; QuicErrorCode error_code = config.ProcessPeerHello( @@ -238,6 +238,15 @@ void QuicEndpoint::OnCanWrite() { } WriteStreamData(); } + +bool QuicEndpoint::SendProbingData() { + if (connection()->sent_packet_manager().MaybeRetransmitOldestPacket( + PROBING_RETRANSMISSION)) { + return true; + } + return false; +} + bool QuicEndpoint::WillingAndAbleToWrite() const { if (notifier_ != nullptr) { return notifier_->WillingToWrite(); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h index 955ac8fcb64..8bbdbd7c5e2 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h @@ -82,6 +82,7 @@ class QuicEndpoint : public Endpoint, void OnStreamFrame(const QuicStreamFrame& frame) override; void OnCryptoFrame(const QuicCryptoFrame& frame) override; void OnCanWrite() override; + bool SendProbingData() override; bool WillingAndAbleToWrite() const override; bool HasPendingHandshake() const override; bool ShouldKeepConnectionAlive() const override; @@ -107,10 +108,10 @@ class QuicEndpoint : public Endpoint, void SendPing() override {} bool AllowSelfAddressChange() const override; void OnForwardProgressConfirmed() override {} - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override { + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override { return true; } - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override { + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override { return true; } bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc index 33ad564324e..1e7a8ce53a0 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/simulator_test.cc @@ -224,7 +224,7 @@ TEST_F(SimulatorTest, DirectLinkSaturation) { const QuicTime end_time = simulator.GetClock()->Now(); const QuicBandwidth observed_bandwidth = QuicBandwidth::FromBytesAndTimeDelta( saturator_a.bytes_transmitted(), end_time - start_time); - test::ExpectApproxEq(link.bandwidth(), observed_bandwidth, 0.01f); + EXPECT_APPROX_EQ(link.bandwidth(), observed_bandwidth, 0.01f); } // Accepts packets and stores them internally. @@ -683,15 +683,15 @@ TEST_F(SimulatorTest, TrafficPolicer) { // Ensure we've transmitted the amount of data we expected. for (auto* saturator : {&saturator1, &saturator2}) { - test::ExpectApproxEq(bandwidth * simulation_time, - saturator->bytes_transmitted(), 0.01f); + EXPECT_APPROX_EQ(bandwidth * simulation_time, + saturator->bytes_transmitted(), 0.01f); } // Check that only one direction is throttled. - test::ExpectApproxEq(saturator1.bytes_transmitted() / 4, - saturator2.counter()->bytes(), 0.1f); - test::ExpectApproxEq(saturator2.bytes_transmitted(), - saturator1.counter()->bytes(), 0.1f); + EXPECT_APPROX_EQ(saturator1.bytes_transmitted() / 4, + saturator2.counter()->bytes(), 0.1f); + EXPECT_APPROX_EQ(saturator2.bytes_transmitted(), + saturator1.counter()->bytes(), 0.1f); } // Ensure that a larger burst is allowed when the policed saturator exits @@ -740,14 +740,14 @@ TEST_F(SimulatorTest, TrafficPolicerBurst) { simulator.RunFor(2 * base_propagation_delay); // Expect the burst to pass without losses. - test::ExpectApproxEq(saturator1.bytes_transmitted(), - saturator2.counter()->bytes(), 0.1f); + EXPECT_APPROX_EQ(saturator1.bytes_transmitted(), + saturator2.counter()->bytes(), 0.1f); // Expect subsequent traffic to be policed. saturator1.Resume(); simulator.RunFor(QuicTime::Delta::FromSeconds(10)); - test::ExpectApproxEq(saturator1.bytes_transmitted() / 4, - saturator2.counter()->bytes(), 0.1f); + EXPECT_APPROX_EQ(saturator1.bytes_transmitted() / 4, + saturator2.counter()->bytes(), 0.1f); } // Test that the packet aggregation support in queues work. diff --git a/chromium/net/third_party/quiche/src/quic/tools/fake_proof_verifier.h b/chromium/net/third_party/quiche/src/quic/tools/fake_proof_verifier.h new file mode 100644 index 00000000000..ffeb6e95e72 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/fake_proof_verifier.h @@ -0,0 +1,49 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TOOLS_FAKE_PROOF_VERIFIER_H_ +#define QUICHE_QUIC_TOOLS_FAKE_PROOF_VERIFIER_H_ + +#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" + +namespace quic { + +// ProofVerifier implementation which always returns success. +class FakeProofVerifier : public ProofVerifier { + public: + ~FakeProofVerifier() override {} + QuicAsyncStatus VerifyProof( + const std::string& /*hostname*/, + const uint16_t /*port*/, + const std::string& /*server_config*/, + QuicTransportVersion /*quic_version*/, + QuicStringPiece /*chlo_hash*/, + const std::vector<std::string>& /*certs*/, + const std::string& /*cert_sct*/, + const std::string& /*signature*/, + const ProofVerifyContext* /*context*/, + std::string* /*error_details*/, + std::unique_ptr<ProofVerifyDetails>* /*details*/, + std::unique_ptr<ProofVerifierCallback> /*callback*/) override { + return QUIC_SUCCESS; + } + QuicAsyncStatus VerifyCertChain( + const std::string& /*hostname*/, + const std::vector<std::string>& /*certs*/, + const std::string& /*ocsp_response*/, + const std::string& /*cert_sct*/, + const ProofVerifyContext* /*context*/, + std::string* /*error_details*/, + std::unique_ptr<ProofVerifyDetails>* /*details*/, + std::unique_ptr<ProofVerifierCallback> /*callback*/) override { + return QUIC_SUCCESS; + } + std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { + return nullptr; + } +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TOOLS_FAKE_PROOF_VERIFIER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc index b736c71aef4..e7fe6b4830e 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc @@ -85,7 +85,7 @@ std::unique_ptr<QuicSession> QuicClient::CreateQuicClientSession( QuicConnection* connection) { return QuicMakeUnique<QuicSimpleClientSession>( *config(), supported_versions, connection, server_id(), crypto_config(), - push_promise_index(), drop_response_body_); + push_promise_index(), drop_response_body()); } QuicClientEpollNetworkHelper* QuicClient::epoll_network_helper() { diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client.h index b84c597969a..0e708ec2835 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client.h @@ -67,13 +67,8 @@ class QuicClient : public QuicSpdyClientBase { QuicClientEpollNetworkHelper* epoll_network_helper(); const QuicClientEpollNetworkHelper* epoll_network_helper() const; - void set_drop_response_body(bool drop_response_body) { - drop_response_body_ = drop_response_body; - } - private: friend class test::QuicClientPeer; - bool drop_response_body_ = false; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc index db0503c5f9b..b746ba5f6dc 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc @@ -54,11 +54,11 @@ bool QuicClientBase::Initialize() { const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB if (config()->GetInitialStreamFlowControlWindowToSend() == - kMinimumFlowControlSendWindow) { + kDefaultFlowControlSendWindow) { config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize); } if (config()->GetInitialSessionFlowControlWindowToSend() == - kMinimumFlowControlSendWindow) { + kDefaultFlowControlSendWindow) { config()->SetInitialSessionFlowControlWindowToSend( kSessionMaxRecvWindowSize); } @@ -81,11 +81,6 @@ bool QuicClientBase::Connect() { while (EncryptionBeingEstablished()) { WaitForEvents(); } - if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) && - connected()) { - // Resend any previously queued data. - ResendSavedData(); - } ParsedQuicVersion version = UnsupportedQuicVersion(); if (session() != nullptr && session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT && @@ -181,16 +176,13 @@ bool QuicClientBase::WaitForEvents() { DCHECK(session() != nullptr); ParsedQuicVersion version = UnsupportedQuicVersion(); if (!connected() && - (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT || - CanReconnectWithDifferentVersion(&version))) { - if (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { - DCHECK(GetQuicReloadableFlag(enable_quic_stateless_reject_support)); - QUIC_DLOG(INFO) << "Detected stateless reject while waiting for events. " - << "Attempting to reconnect."; - } else { - QUIC_DLOG(INFO) << "Can reconnect with version: " << version - << ", attempting to reconnect."; - } + + CanReconnectWithDifferentVersion(&version)) { + DCHECK_NE(session()->error(), QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT); + + QUIC_DLOG(INFO) << "Can reconnect with version: " << version + << ", attempting to reconnect."; + Connect(); } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h index 6ad326eb4dc..0cc4d71ff78 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h @@ -102,7 +102,7 @@ class QuicClientBase { // Wait for events until the handshake is confirmed. // Returns true if the crypto handshake succeeds, false otherwise. - bool WaitForCryptoHandshakeConfirmed() QUIC_MUST_USE_RESULT; + QUIC_MUST_USE_RESULT bool WaitForCryptoHandshakeConfirmed(); // Wait up to 50ms, and handle any events which occur. // Returns true if there are any outstanding requests. @@ -131,13 +131,6 @@ class QuicClientBase { crypto_config_.set_user_agent_id(user_agent_id); } - // SetChannelIDSource sets a ChannelIDSource that will be called, when the - // server supports channel IDs, to obtain a channel ID for signing a message - // proving possession of the channel ID. - void SetChannelIDSource(std::unique_ptr<ChannelIDSource> source) { - crypto_config_.SetChannelIDSource(std::move(source)); - } - const ParsedQuicVersionVector& supported_versions() const { return supported_versions_; } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_bin.cc index ee8262f751f..06760ce4a70 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_bin.cc @@ -34,175 +34,19 @@ // // Try to connect to a host which does not speak QUIC: // quic_client www.example.com - -#include <netdb.h> -#include <sys/socket.h> -#include <sys/types.h> +// +// This tool is available as a built binary at: +// /google/data/ro/teams/quic/tools/quic_client +// After submitting changes to this file, you will need to follow the +// instructions at go/quic_client_binary_update #include <iostream> #include <memory> #include <string> -#include <vector> -#include "net/third_party/quiche/src/quic/core/quic_packets.h" -#include "net/third_party/quiche/src/quic/core/quic_server_id.h" -#include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/quic_versions.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" -#include "net/third_party/quiche/src/quic/tools/quic_client.h" -#include "net/third_party/quiche/src/quic/tools/quic_url.h" - -namespace { - -using quic::QuicSocketAddress; -using quic::QuicStringPiece; -using quic::QuicTextUtils; -using quic::QuicUrl; - -class FakeProofVerifier : public quic::ProofVerifier { - public: - ~FakeProofVerifier() override {} - quic::QuicAsyncStatus VerifyProof( - const std::string& /*hostname*/, - const uint16_t /*port*/, - const std::string& /*server_config*/, - quic::QuicTransportVersion /*quic_version*/, - quic::QuicStringPiece /*chlo_hash*/, - const std::vector<std::string>& /*certs*/, - const std::string& /*cert_sct*/, - const std::string& /*signature*/, - const quic::ProofVerifyContext* /*context*/, - std::string* /*error_details*/, - std::unique_ptr<quic::ProofVerifyDetails>* /*details*/, - std::unique_ptr<quic::ProofVerifierCallback> /*callback*/) override { - return quic::QUIC_SUCCESS; - } - quic::QuicAsyncStatus VerifyCertChain( - const std::string& /*hostname*/, - const std::vector<std::string>& /*certs*/, - const quic::ProofVerifyContext* /*context*/, - std::string* /*error_details*/, - std::unique_ptr<quic::ProofVerifyDetails>* /*details*/, - std::unique_ptr<quic::ProofVerifierCallback> /*callback*/) override { - return quic::QUIC_SUCCESS; - } - std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override { - return nullptr; - } -}; - -QuicSocketAddress LookupAddress(std::string host, std::string port) { - addrinfo hint; - memset(&hint, 0, sizeof(hint)); - hint.ai_protocol = IPPROTO_UDP; - - addrinfo* info_list = nullptr; - int result = getaddrinfo(host.c_str(), port.c_str(), &hint, &info_list); - if (result != 0) { - QUIC_LOG(ERROR) << "Failed to look up " << host << ": " - << gai_strerror(result); - return QuicSocketAddress(); - } - - CHECK(info_list != nullptr); - std::unique_ptr<addrinfo, void (*)(addrinfo*)> info_list_owned(info_list, - freeaddrinfo); - return QuicSocketAddress(*info_list->ai_addr); -} - -} // namespace - -DEFINE_QUIC_COMMAND_LINE_FLAG( - std::string, - host, - "", - "The IP or hostname to connect to. If not provided, the host " - "will be derived from the provided URL."); - -DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to."); - -DEFINE_QUIC_COMMAND_LINE_FLAG(std::string, - body, - "", - "If set, send a POST with this body."); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - std::string, - body_hex, - "", - "If set, contents are converted from hex to ascii, before " - "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\""); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - std::string, - headers, - "", - "A semicolon separated list of key:value pairs to " - "add to request headers."); - -DEFINE_QUIC_COMMAND_LINE_FLAG(bool, - quiet, - false, - "Set to true for a quieter output experience."); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - std::string, - quic_version, - "", - "QUIC version to speak, e.g. 21. If not set, then all available " - "versions are offered in the handshake. Also supports wire versions " - "such as Q043 or T099."); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - int32_t, - quic_ietf_draft, - 0, - "QUIC IETF draft number to use over the wire, e.g. 18. " - "By default this sets quic_version to T099. " - "This also enables required internal QUIC flags."); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - bool, - version_mismatch_ok, - false, - "If true, a version mismatch in the handshake is not considered a " - "failure. Useful for probing a server to determine if it speaks " - "any version of QUIC."); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - bool, - redirect_is_success, - true, - "If true, an HTTP response code of 3xx is considered to be a " - "successful response, otherwise a failure."); - -DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, - initial_mtu, - 0, - "Initial MTU of the connection."); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - int32_t, - num_requests, - 1, - "How many sequential requests to make on a single connection."); - -DEFINE_QUIC_COMMAND_LINE_FLAG(bool, - disable_certificate_verification, - false, - "If true, don't verify the server certificate."); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - bool, - drop_response_body, - false, - "If true, drop response body immediately after it is received."); +#include "net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h" +#include "net/third_party/quiche/src/quic/tools/quic_toy_client.h" int main(int argc, char* argv[]) { QuicSystemEventLoop event_loop("quic_client"); @@ -216,188 +60,7 @@ int main(int argc, char* argv[]) { exit(0); } - QuicUrl url(urls[0], "https"); - std::string host = GetQuicFlag(FLAGS_host); - if (host.empty()) { - host = url.host(); - } - int port = GetQuicFlag(FLAGS_port); - if (port == 0) { - port = url.port(); - } - - // Determine IP address to connect to from supplied hostname. - QuicSocketAddress addr = LookupAddress(host, quic::QuicStrCat(port)); - if (!addr.IsInitialized()) { - return 1; - } - std::cerr << "Resolved " << url.ToString() << " to " << addr.ToString() - << std::endl; - - // Build the client, and try to connect. - quic::QuicEpollServer epoll_server; - quic::QuicServerId server_id(url.host(), port, false); - quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions(); - - std::string quic_version_string = GetQuicFlag(FLAGS_quic_version); - const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft); - if (quic_ietf_draft > 0) { - quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft); - if (quic_version_string.length() == 0) { - quic_version_string = "T099"; - } - } - if (quic_version_string.length() > 0) { - if (quic_version_string[0] == 'T') { - // ParseQuicVersionString checks quic_supports_tls_handshake. - SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); - } - quic::ParsedQuicVersion parsed_quic_version = - quic::ParseQuicVersionString(quic_version_string); - if (parsed_quic_version.transport_version == - quic::QUIC_VERSION_UNSUPPORTED) { - return 1; - } - versions.clear(); - versions.push_back(parsed_quic_version); - quic::QuicEnableVersion(parsed_quic_version); - } - - const int32_t num_requests(GetQuicFlag(FLAGS_num_requests)); - std::unique_ptr<quic::ProofVerifier> proof_verifier; - if (GetQuicFlag(FLAGS_disable_certificate_verification)) { - proof_verifier = quic::QuicMakeUnique<FakeProofVerifier>(); - } else { - proof_verifier = quic::CreateDefaultProofVerifier(); - } - quic::QuicClient client(addr, server_id, versions, &epoll_server, - std::move(proof_verifier)); - int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu); - client.set_initial_max_packet_length( - initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize); - client.set_drop_response_body(GetQuicFlag(FLAGS_drop_response_body)); - if (!client.Initialize()) { - std::cerr << "Failed to initialize client." << std::endl; - return 1; - } - if (!client.Connect()) { - quic::QuicErrorCode error = client.session()->error(); - if (error == quic::QUIC_INVALID_VERSION) { - std::cerr << "Server talks QUIC, but none of the versions supported by " - << "this client: " << ParsedQuicVersionVectorToString(versions) - << std::endl; - // 0: No error. - // 20: Failed to connect due to QUIC_INVALID_VERSION. - return GetQuicFlag(FLAGS_version_mismatch_ok) ? 0 : 20; - } - std::cerr << "Failed to connect to " << addr.ToString() - << ". Error: " << quic::QuicErrorCodeToString(error) << std::endl; - return 1; - } - std::cerr << "Connected to " << addr.ToString() << std::endl; - - // Construct the string body from flags, if provided. - std::string body = GetQuicFlag(FLAGS_body); - if (!GetQuicFlag(FLAGS_body_hex).empty()) { - DCHECK(GetQuicFlag(FLAGS_body).empty()) - << "Only set one of --body and --body_hex."; - body = QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex)); - } - - // Construct a GET or POST request for supplied URL. - spdy::SpdyHeaderBlock header_block; - header_block[":method"] = body.empty() ? "GET" : "POST"; - header_block[":scheme"] = url.scheme(); - header_block[":authority"] = url.HostPort(); - header_block[":path"] = url.PathParamsQuery(); - - // Append any additional headers supplied on the command line. - for (QuicStringPiece sp : - QuicTextUtils::Split(GetQuicFlag(FLAGS_headers), ';')) { - QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&sp); - if (sp.empty()) { - continue; - } - std::vector<QuicStringPiece> kv = QuicTextUtils::Split(sp, ':'); - QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[0]); - QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[1]); - header_block[kv[0]] = kv[1]; - } - - // Make sure to store the response, for later output. - client.set_store_response(true); - - for (int i = 0; i < num_requests; ++i) { - // Send the request. - client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true); - - // Print request and response details. - if (!GetQuicFlag(FLAGS_quiet)) { - std::cout << "Request:" << std::endl; - std::cout << "headers:" << header_block.DebugString(); - if (!GetQuicFlag(FLAGS_body_hex).empty()) { - // Print the user provided hex, rather than binary body. - std::cout << "body:\n" - << QuicTextUtils::HexDump( - QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex))) - << std::endl; - } else { - std::cout << "body: " << body << std::endl; - } - std::cout << std::endl; - - if (!client.preliminary_response_headers().empty()) { - std::cout << "Preliminary response headers: " - << client.preliminary_response_headers() << std::endl; - std::cout << std::endl; - } - - std::cout << "Response:" << std::endl; - std::cout << "headers: " << client.latest_response_headers() << std::endl; - std::string response_body = client.latest_response_body(); - if (!GetQuicFlag(FLAGS_body_hex).empty()) { - // Assume response is binary data. - std::cout << "body:\n" - << QuicTextUtils::HexDump(response_body) << std::endl; - } else { - std::cout << "body: " << response_body << std::endl; - } - std::cout << "trailers: " << client.latest_response_trailers() - << std::endl; - } - - if (!client.connected()) { - std::cerr << "Request caused connection failure. Error: " - << quic::QuicErrorCodeToString(client.session()->error()) - << std::endl; - return 1; - } - - size_t response_code = client.latest_response_code(); - if (response_code >= 200 && response_code < 300) { - std::cerr << "Request succeeded (" << response_code << ")." << std::endl; - } else if (response_code >= 300 && response_code < 400) { - if (GetQuicFlag(FLAGS_redirect_is_success)) { - std::cerr << "Request succeeded (redirect " << response_code << ")." - << std::endl; - } else { - std::cerr << "Request failed (redirect " << response_code << ")." - << std::endl; - return 1; - } - } else { - std::cerr << "Request failed (" << response_code << ")." << std::endl; - return 1; - } - - // Change the ephemeral port if there are more requests to do. - if (i + 1 < num_requests) { - if (!client.ChangeEphemeralPort()) { - std::cerr << "Failed to change ephemeral port." << std::endl; - return 1; - } - } - } - - return 0; + quic::QuicEpollClientFactory factory; + quic::QuicToyClient client(&factory); + return client.SendRequestsAndPrintResponses(urls); } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.cc index e545ee2c62c..117521111f5 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.cc @@ -133,7 +133,7 @@ void QuicClientEpollNetworkHelper::OnEvent(int fd, QuicEpollEvent* event) { DCHECK_EQ(fd, GetLatestFD()); if (event->in_events & EPOLLIN) { - DVLOG(1) << "Read packets on EPOLLIN"; + QUIC_DVLOG(1) << "Read packets on EPOLLIN"; int times_to_read = max_reads_per_epoll_loop_; bool more_to_read = true; QuicPacketCount packets_dropped = 0; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc new file mode 100644 index 00000000000..3b6b2eed714 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2019 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/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h" + +#include <netdb.h> +#include <sys/socket.h> +#include <sys/types.h> + +#include "net/third_party/quiche/src/quic/core/quic_server_id.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/tools/quic_client.h" + +namespace quic { + +namespace { + +QuicSocketAddress LookupAddress(std::string host, std::string port) { + addrinfo hint; + memset(&hint, 0, sizeof(hint)); + hint.ai_protocol = IPPROTO_UDP; + + addrinfo* info_list = nullptr; + int result = getaddrinfo(host.c_str(), port.c_str(), &hint, &info_list); + if (result != 0) { + QUIC_LOG(ERROR) << "Failed to look up " << host << ": " + << gai_strerror(result); + return QuicSocketAddress(); + } + + CHECK(info_list != nullptr); + std::unique_ptr<addrinfo, void (*)(addrinfo*)> info_list_owned(info_list, + freeaddrinfo); + return QuicSocketAddress(*info_list->ai_addr); +} + +} // namespace + +std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient( + std::string host, + uint16_t port, + ParsedQuicVersionVector versions, + std::unique_ptr<ProofVerifier> verifier) { + QuicSocketAddress addr = LookupAddress(host, QuicStrCat(port)); + if (!addr.IsInitialized()) { + QUIC_LOG(ERROR) << "Unable to resolve address: " << host; + return nullptr; + } + QuicServerId server_id(host, port, false); + return QuicMakeUnique<QuicClient>(addr, server_id, versions, &epoll_server_, + std::move(verifier)); +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h new file mode 100644 index 00000000000..a083643ec3e --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h @@ -0,0 +1,28 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TOOLS_EPOLL_CLIENT_FACTORY_H_ +#define QUICHE_QUIC_TOOLS_EPOLL_CLIENT_FACTORY_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h" +#include "net/third_party/quiche/src/quic/tools/quic_toy_client.h" + +namespace quic { + +// Factory creating QuicClient instances. +class QuicEpollClientFactory : public QuicToyClient::ClientFactory { + public: + std::unique_ptr<QuicSpdyClientBase> CreateClient( + std::string host, + uint16_t port, + ParsedQuicVersionVector versions, + std::unique_ptr<ProofVerifier> verifier) override; + + private: + QuicEpollServer epoll_server_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TOOLS_EPOLL_CLIENT_FACTORY_H_ diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_server_factory.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_server_factory.cc new file mode 100644 index 00000000000..f0c206a5d3f --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_server_factory.cc @@ -0,0 +1,18 @@ +// Copyright (c) 2019 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/third_party/quiche/src/quic/tools/quic_epoll_server_factory.h" + +#include "net/third_party/quiche/src/quic/tools/quic_server.h" + +namespace quic { + +std::unique_ptr<quic::QuicSpdyServerBase> QuicEpollServerFactory::CreateServer( + quic::QuicSimpleServerBackend* backend, + std::unique_ptr<quic::ProofSource> proof_source) { + return quic::QuicMakeUnique<quic::QuicServer>(std::move(proof_source), + backend); +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_server_factory.h b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_server_factory.h new file mode 100644 index 00000000000..391f3cd8d12 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_server_factory.h @@ -0,0 +1,26 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TOOLS_EPOLL_SERVER_FACTORY_H_ +#define QUICHE_QUIC_TOOLS_EPOLL_SERVER_FACTORY_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h" +#include "net/third_party/quiche/src/quic/tools/quic_toy_server.h" + +namespace quic { + +// Factory creating QuicServer instances. +class QuicEpollServerFactory : public QuicToyServer::ServerFactory { + public: + std::unique_ptr<QuicSpdyServerBase> CreateServer( + QuicSimpleServerBackend* backend, + std::unique_ptr<ProofSource> proof_source) override; + + private: + QuicEpollServer epoll_server_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TOOLS_EPOLL_SERVER_FACTORY_H_ diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc index 76a52c3bf87..96faacb6914 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc @@ -137,8 +137,8 @@ const QuicBackendResponse* QuicMemoryCacheBackend::GetResponse( auto it = responses_.find(GetKey(host, path)); if (it == responses_.end()) { - DVLOG(1) << "Get response for resource failed: host " << host << " path " - << path; + QUIC_DVLOG(1) << "Get response for resource failed: host " << host + << " path " << path; if (default_response_) { return default_response_.get(); } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc index c8cfc11ec8f..80ffd4eeb9a 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc @@ -63,6 +63,11 @@ class QuicPacketPrinter : public QuicFramerVisitorInterface { const QuicVersionNegotiationPacket& packet) override { std::cerr << "OnVersionNegotiationPacket\n"; } + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override { + std::cerr << "OnRetryPacket\n"; + } bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { std::cerr << "OnUnauthenticatedPublicHeader\n"; return true; @@ -168,12 +173,12 @@ class QuicPacketPrinter : public QuicFramerVisitorInterface { std::cerr << "OnGoAwayFrame: " << frame; return true; } - bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override { - std::cerr << "OnMaxStreamIdFrame: " << frame; + bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override { + std::cerr << "OnMaxStreamsFrame: " << frame; return true; } - bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override { - std::cerr << "OnStreamIdBlockedFrame: " << frame; + bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override { + std::cerr << "OnStreamsBlockedFrame: " << frame; return true; } bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override { diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc index d67bc3078d0..3696b7cd06b 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_server.cc @@ -64,7 +64,7 @@ QuicServer::QuicServer( const QuicCryptoServerConfig::ConfigOptions& crypto_config_options, const ParsedQuicVersionVector& supported_versions, QuicSimpleServerBackend* quic_simple_server_backend, - uint8_t expected_connection_id_length) + uint8_t expected_server_connection_id_length) : port_(0), fd_(-1), packets_dropped_(0), @@ -80,7 +80,9 @@ QuicServer::QuicServer( version_manager_(supported_versions), packet_reader_(new QuicPacketReader()), quic_simple_server_backend_(quic_simple_server_backend), - expected_connection_id_length_(expected_connection_id_length) { + expected_server_connection_id_length_( + expected_server_connection_id_length) { + DCHECK(quic_simple_server_backend_); Initialize(); } @@ -90,12 +92,12 @@ void QuicServer::Initialize() { const uint32_t kInitialSessionFlowControlWindow = 1 * 1024 * 1024; // 1 MB const uint32_t kInitialStreamFlowControlWindow = 64 * 1024; // 64 KB if (config_.GetInitialStreamFlowControlWindowToSend() == - kMinimumFlowControlSendWindow) { + kDefaultFlowControlSendWindow) { config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindow); } if (config_.GetInitialSessionFlowControlWindowToSend() == - kMinimumFlowControlSendWindow) { + kDefaultFlowControlSendWindow) { config_.SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindow); } @@ -158,7 +160,13 @@ QuicDispatcher* QuicServer::CreateQuicDispatcher() { new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())), std::unique_ptr<QuicEpollAlarmFactory>( new QuicEpollAlarmFactory(&epoll_server_)), - quic_simple_server_backend_, expected_connection_id_length_); + quic_simple_server_backend_, expected_server_connection_id_length_); +} + +void QuicServer::HandleEventsForever() { + while (true) { + WaitForEvents(); + } } void QuicServer::WaitForEvents() { diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_server.h b/chromium/net/third_party/quiche/src/quic/tools/quic_server.h index 4d7e08199a9..1f9c225a2d3 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_server.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_server.h @@ -22,6 +22,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h" +#include "net/third_party/quiche/src/quic/tools/quic_spdy_server_base.h" namespace quic { @@ -32,7 +33,8 @@ class QuicServerPeer; class QuicDispatcher; class QuicPacketReader; -class QuicServer : public QuicEpollCallbackInterface { +class QuicServer : public QuicSpdyServerBase, + public QuicEpollCallbackInterface { public: QuicServer(std::unique_ptr<ProofSource> proof_source, QuicSimpleServerBackend* quic_simple_server_backend); @@ -41,7 +43,7 @@ class QuicServer : public QuicEpollCallbackInterface { const QuicCryptoServerConfig::ConfigOptions& server_config_options, const ParsedQuicVersionVector& supported_versions, QuicSimpleServerBackend* quic_simple_server_backend, - uint8_t expected_connection_id_length); + uint8_t expected_server_connection_id_length); QuicServer(const QuicServer&) = delete; QuicServer& operator=(const QuicServer&) = delete; @@ -50,7 +52,9 @@ class QuicServer : public QuicEpollCallbackInterface { std::string Name() const override { return "QuicServer"; } // Start listening on the specified address. - bool CreateUDPSocketAndListen(const QuicSocketAddress& address); + bool CreateUDPSocketAndListen(const QuicSocketAddress& address) override; + // Handles all events. Does not return. + void HandleEventsForever() override; // Wait up to 50ms, and handle any events which occur. void WaitForEvents(); @@ -99,8 +103,8 @@ class QuicServer : public QuicEpollCallbackInterface { void set_silent_close(bool value) { silent_close_ = value; } - uint8_t expected_connection_id_length() { - return expected_connection_id_length_; + uint8_t expected_server_connection_id_length() { + return expected_server_connection_id_length_; } private: @@ -151,7 +155,7 @@ class QuicServer : public QuicEpollCallbackInterface { QuicSimpleServerBackend* quic_simple_server_backend_; // unowned. // Connection ID length expected to be read on incoming IETF short headers. - uint8_t expected_connection_id_length_; + uint8_t expected_server_connection_id_length_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_server_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_server_bin.cc index 128c873dfda..541f6f9e13e 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_server_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_server_bin.cc @@ -8,31 +8,9 @@ #include <vector> #include "net/third_party/quiche/src/quic/core/quic_versions.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" -#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h" -#include "net/third_party/quiche/src/quic/tools/quic_server.h" - -DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, - port, - 6121, - "The port the quic server will listen on."); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - std::string, - quic_response_cache_dir, - "", - "Specifies the directory used during QuicHttpResponseCache " - "construction to seed the cache. Cache directory can be " - "generated using `wget -p --save-headers <url>`"); - -DEFINE_QUIC_COMMAND_LINE_FLAG( - int32_t, - quic_ietf_draft, - 0, - "QUIC IETF draft number to use over the wire, e.g. 18. " - "This also enables required internal QUIC flags."); +#include "net/third_party/quiche/src/quic/tools/quic_epoll_server_factory.h" +#include "net/third_party/quiche/src/quic/tools/quic_toy_server.h" int main(int argc, char* argv[]) { const char* usage = "Usage: quic_server [options]"; @@ -43,28 +21,8 @@ int main(int argc, char* argv[]) { exit(0); } - const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft); - if (quic_ietf_draft > 0) { - quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft); - quic::QuicEnableVersion( - quic::ParsedQuicVersion(quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_99)); - } - - quic::QuicMemoryCacheBackend memory_cache_backend; - if (!GetQuicFlag(FLAGS_quic_response_cache_dir).empty()) { - memory_cache_backend.InitializeBackend( - GetQuicFlag(FLAGS_quic_response_cache_dir)); - } - - quic::QuicServer server(quic::CreateDefaultProofSource(), - &memory_cache_backend); - - if (!server.CreateUDPSocketAndListen(quic::QuicSocketAddress( - quic::QuicIpAddress::Any6(), GetQuicFlag(FLAGS_port)))) { - return 1; - } - - while (true) { - server.WaitForEvents(); - } + quic::QuicToyServer::MemoryCacheBackendFactory backend_factory; + quic::QuicEpollServerFactory server_factory; + quic::QuicToyServer server(&backend_factory, &server_factory); + return server.Start(); } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.cc index 4706b606843..0f4d4476848 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.cc @@ -16,14 +16,14 @@ QuicSimpleDispatcher::QuicSimpleDispatcher( std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, std::unique_ptr<QuicAlarmFactory> alarm_factory, QuicSimpleServerBackend* quic_simple_server_backend, - uint8_t expected_connection_id_length) + uint8_t expected_server_connection_id_length) : QuicDispatcher(config, crypto_config, version_manager, std::move(helper), std::move(session_helper), std::move(alarm_factory), - expected_connection_id_length), + expected_server_connection_id_length), quic_simple_server_backend_(quic_simple_server_backend) {} QuicSimpleDispatcher::~QuicSimpleDispatcher() = default; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h index 46d976c7b5b..8a6cf85e6c5 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h @@ -21,7 +21,7 @@ class QuicSimpleDispatcher : public QuicDispatcher { std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, std::unique_ptr<QuicAlarmFactory> alarm_factory, QuicSimpleServerBackend* quic_simple_server_backend, - uint8_t expected_connection_id_length); + uint8_t expected_server_connection_id_length); ~QuicSimpleDispatcher() override; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc index a722d373dd7..2b4cae71fc3 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc @@ -33,7 +33,9 @@ QuicSimpleServerSession::QuicSimpleServerSession( compressed_certs_cache), highest_promised_stream_id_( QuicUtils::GetInvalidStreamId(connection->transport_version())), - quic_simple_server_backend_(quic_simple_server_backend) {} + quic_simple_server_backend_(quic_simple_server_backend) { + DCHECK(quic_simple_server_backend_); +} QuicSimpleServerSession::~QuicSimpleServerSession() { delete connection(); @@ -43,10 +45,8 @@ QuicCryptoServerStreamBase* QuicSimpleServerSession::CreateQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, QuicCompressedCertsCache* compressed_certs_cache) { - return new QuicCryptoServerStream( - crypto_config, compressed_certs_cache, - GetQuicReloadableFlag(enable_quic_stateless_reject_support), this, - stream_helper()); + return new QuicCryptoServerStream(crypto_config, compressed_certs_cache, this, + stream_helper()); } void QuicSimpleServerSession::OnStreamFrame(const QuicStreamFrame& frame) { diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc index 7203f128caa..58c98dd39f8 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc @@ -46,7 +46,12 @@ using testing::StrictMock; namespace quic { namespace test { namespace { + typedef QuicSimpleServerSession::PromisedStreamInfo PromisedStreamInfo; + +const QuicByteCount kHeadersFrameHeaderLength = 2; +const QuicByteCount kHeadersFramePayloadLength = 9; + } // namespace class QuicSimpleServerSessionPeer { @@ -54,9 +59,11 @@ class QuicSimpleServerSessionPeer { static void SetCryptoStream(QuicSimpleServerSession* s, QuicCryptoServerStream* crypto_stream) { s->crypto_stream_.reset(crypto_stream); - s->RegisterStaticStream( - QuicUtils::GetCryptoStreamId(s->connection()->transport_version()), - crypto_stream); + if (!QuicVersionUsesCryptoFrames(s->connection()->transport_version())) { + s->RegisterStaticStream( + QuicUtils::GetCryptoStreamId(s->connection()->transport_version()), + crypto_stream); + } } static QuicSpdyStream* CreateIncomingStream(QuicSimpleServerSession* s, @@ -84,8 +91,6 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { : QuicCryptoServerStream( crypto_config, compressed_certs_cache, - GetQuicReloadableFlag( - enable_quic_stateless_reject_support), // NOLINT session, helper) {} MockQuicCryptoServerStream(const MockQuicCryptoServerStream&) = delete; @@ -178,13 +183,13 @@ class QuicSimpleServerSessionTest return true; } - // The function ensures that A) the max stream id frames get properly deleted + // The function ensures that A) the MAX_STREAMS frames get properly deleted // (since the test uses a 'did we leak memory' check ... if we just lose the // frame, the test fails) and B) returns true (instead of the default, false) // which ensures that the rest of the system thinks that the frame actually // was transmitted. - bool ClearMaxStreamIdControlFrame(const QuicFrame& frame) { - if (frame.type == MAX_STREAM_ID_FRAME) { + bool ClearMaxStreamsControlFrame(const QuicFrame& frame) { + if (frame.type == MAX_STREAMS_FRAME) { DeleteFrame(&const_cast<QuicFrame&>(frame)); return true; } @@ -200,9 +205,13 @@ class QuicSimpleServerSessionTest TlsServerHandshaker::CreateSslCtx()), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { - config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest); - QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_, - kMaxStreamsForTest); + config_.SetMaxIncomingBidirectionalStreamsToSend(kMaxStreamsForTest); + QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams( + &config_, kMaxStreamsForTest); + config_.SetMaxIncomingUnidirectionalStreamsToSend(kMaxStreamsForTest); + QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams( + &config_, kMaxStreamsForTest); + config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config_.SetInitialSessionFlowControlWindowToSend( @@ -227,8 +236,7 @@ class QuicSimpleServerSessionTest if (IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillRepeatedly(Invoke( - this, - &QuicSimpleServerSessionTest::ClearMaxStreamIdControlFrame)); + this, &QuicSimpleServerSessionTest::ClearMaxStreamsControlFrame)); } session_->OnConfigNegotiated(); } @@ -566,7 +574,7 @@ class QuicSimpleServerSessionServerPushTest if (IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillRepeatedly(Invoke(this, &QuicSimpleServerSessionServerPushTest:: - ClearMaxStreamIdControlFrame)); + ClearMaxStreamsControlFrame)); } session_->OnConfigNegotiated(); @@ -640,6 +648,22 @@ class QuicSimpleServerSessionServerPushTest // Since flow control window is smaller than response body, not the // whole body will be sent. QuicStreamOffset offset = 0; + if (VersionHasStreamType(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(stream_id, 1, offset, NO_FIN)); + offset++; + } + + if (VersionUsesQpack(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(stream_id, kHeadersFrameHeaderLength, + offset, NO_FIN)); + offset += kHeadersFrameHeaderLength; + EXPECT_CALL(*connection_, + SendStreamData(stream_id, kHeadersFramePayloadLength, + offset, NO_FIN)); + offset += kHeadersFramePayloadLength; + } if (VersionHasDataFrameHeader(connection_->transport_version())) { EXPECT_CALL(*connection_, SendStreamData(stream_id, data_frame_header_length, @@ -658,11 +682,13 @@ class QuicSimpleServerSessionServerPushTest return data_frame_header_length; } - void ConsumeHeadersStreamData() { - QuicStreamId headers_stream_id = - QuicUtils::GetHeadersStreamId(connection_->transport_version()); - EXPECT_CALL(*connection_, SendStreamData(headers_stream_id, _, _, _)) - .Times(AtLeast(1)); + void MaybeConsumeHeadersStreamData() { + if (!VersionUsesQpack(connection_->transport_version())) { + QuicStreamId headers_stream_id = + QuicUtils::GetHeadersStreamId(connection_->transport_version()); + EXPECT_CALL(*connection_, SendStreamData(headers_stream_id, _, _, _)) + .Times(AtLeast(1)); + } } }; @@ -674,7 +700,7 @@ INSTANTIATE_TEST_SUITE_P(Tests, // PUSH_PROMISE's will be sent out and only kMaxStreamsForTest streams will be // opened and send push response. TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) { - ConsumeHeadersStreamData(); + MaybeConsumeHeadersStreamData(); size_t num_resources = kMaxStreamsForTest + 5; PromisePushResources(num_resources); EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams()); @@ -684,7 +710,7 @@ TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) { // draining, a queued promised stream will become open and send push response. TEST_P(QuicSimpleServerSessionServerPushTest, HandlePromisedPushRequestsAfterStreamDraining) { - ConsumeHeadersStreamData(); + MaybeConsumeHeadersStreamData(); size_t num_resources = kMaxStreamsForTest + 1; QuicByteCount data_frame_header_length = PromisePushResources(num_resources); QuicStreamId next_out_going_stream_id = @@ -693,6 +719,21 @@ TEST_P(QuicSimpleServerSessionServerPushTest, // After an open stream is marked draining, a new stream is expected to be // created and a response sent on the stream. QuicStreamOffset offset = 0; + if (VersionHasStreamType(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(next_out_going_stream_id, 1, offset, NO_FIN)); + offset++; + } + if (VersionUsesQpack(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(next_out_going_stream_id, + kHeadersFrameHeaderLength, offset, NO_FIN)); + offset += kHeadersFrameHeaderLength; + EXPECT_CALL(*connection_, + SendStreamData(next_out_going_stream_id, + kHeadersFramePayloadLength, offset, NO_FIN)); + offset += kHeadersFramePayloadLength; + } if (VersionHasDataFrameHeader(connection_->transport_version())) { EXPECT_CALL(*connection_, SendStreamData(next_out_going_stream_id, @@ -708,12 +749,13 @@ TEST_P(QuicSimpleServerSessionServerPushTest, if (IsVersion99()) { // The PromisePushedResources call, above, will have used all available // stream ids. For version 99, stream ids are not made available until - // a MAX_STREAM_ID frame is received. This emulates the reception of one. + // a MAX_STREAMS frame is received. This emulates the reception of one. // For pre-v-99, the node monitors its own stream usage and makes streams // available as it closes/etc them. - session_->OnMaxStreamIdFrame( - QuicMaxStreamIdFrame(0, GetNthServerInitiatedUnidirectionalId(10))); + session_->OnMaxStreamsFrame( + QuicMaxStreamsFrame(0, num_resources, /*unidirectional=*/true)); } + session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(0)); // Number of open outgoing streams should still be the same, because a new // stream is opened. And the queue should be empty. @@ -724,14 +766,14 @@ TEST_P(QuicSimpleServerSessionServerPushTest, // prevent a promised resource to be send out. TEST_P(QuicSimpleServerSessionServerPushTest, ResetPromisedStreamToCancelServerPush) { - ConsumeHeadersStreamData(); + MaybeConsumeHeadersStreamData(); // Having two extra resources to be send later. One of them will be reset, so // when opened stream become close, only one will become open. size_t num_resources = kMaxStreamsForTest + 2; if (IsVersion99()) { - // V99 will send out a stream-id-blocked frame when the we desired to exceed - // the limit. This will clear the frames so that they do not block the later + // V99 will send out a STREAMS_BLOCKED frame when it tries to exceed the + // limit. This will clear the frames so that they do not block the later // rst-stream frame. EXPECT_CALL(*connection_, SendControlFrame(_)) .WillOnce(Invoke( @@ -759,6 +801,21 @@ TEST_P(QuicSimpleServerSessionServerPushTest, GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest); InSequence s; QuicStreamOffset offset = 0; + if (VersionHasStreamType(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(stream_not_reset, 1, offset, NO_FIN)); + offset++; + } + if (VersionUsesQpack(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(stream_not_reset, kHeadersFrameHeaderLength, + offset, NO_FIN)); + offset += kHeadersFrameHeaderLength; + EXPECT_CALL(*connection_, + SendStreamData(stream_not_reset, kHeadersFramePayloadLength, + offset, NO_FIN)); + offset += kHeadersFramePayloadLength; + } if (VersionHasDataFrameHeader(connection_->transport_version())) { EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, data_frame_header_length, @@ -773,11 +830,11 @@ TEST_P(QuicSimpleServerSessionServerPushTest, if (IsVersion99()) { // The PromisePushedResources call, above, will have used all available // stream ids. For version 99, stream ids are not made available until - // a MAX_STREAM_ID frame is received. This emulates the reception of one. + // a MAX_STREAMS frame is received. This emulates the reception of one. // For pre-v-99, the node monitors its own stream usage and makes streams // available as it closes/etc them. - session_->OnMaxStreamIdFrame( - QuicMaxStreamIdFrame(0, GetNthServerInitiatedUnidirectionalId(11))); + session_->OnMaxStreamsFrame( + QuicMaxStreamsFrame(0, num_resources, /*unidirectional=*/true)); } session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(0)); session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(1)); @@ -787,7 +844,7 @@ TEST_P(QuicSimpleServerSessionServerPushTest, // the queue to be send out. TEST_P(QuicSimpleServerSessionServerPushTest, CloseStreamToHandleMorePromisedStream) { - ConsumeHeadersStreamData(); + MaybeConsumeHeadersStreamData(); size_t num_resources = kMaxStreamsForTest + 1; if (IsVersion99()) { // V99 will send out a stream-id-blocked frame when the we desired to exceed @@ -812,6 +869,21 @@ TEST_P(QuicSimpleServerSessionServerPushTest, OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT)); } QuicStreamOffset offset = 0; + if (VersionHasStreamType(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(stream_to_open, 1, offset, NO_FIN)); + offset++; + } + if (VersionUsesQpack(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(stream_to_open, kHeadersFrameHeaderLength, + offset, NO_FIN)); + offset += kHeadersFrameHeaderLength; + EXPECT_CALL(*connection_, + SendStreamData(stream_to_open, kHeadersFramePayloadLength, + offset, NO_FIN)); + offset += kHeadersFramePayloadLength; + } if (VersionHasDataFrameHeader(connection_->transport_version())) { EXPECT_CALL(*connection_, SendStreamData(stream_to_open, data_frame_header_length, offset, @@ -828,11 +900,11 @@ TEST_P(QuicSimpleServerSessionServerPushTest, if (IsVersion99()) { // The PromisePushedResources call, above, will have used all available // stream ids. For version 99, stream ids are not made available until - // a MAX_STREAM_ID frame is received. This emulates the reception of one. + // a MAX_STREAMS frame is received. This emulates the reception of one. // For pre-v-99, the node monitors its own stream usage and makes streams // available as it closes/etc them. - session_->OnMaxStreamIdFrame( - QuicMaxStreamIdFrame(0, GetNthServerInitiatedUnidirectionalId(10))); + session_->OnMaxStreamsFrame( + QuicMaxStreamsFrame(0, num_resources, /*unidirectional=*/true)); } visitor_->OnRstStream(rst); // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc index 4e25552d03c..55d93dcd54d 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc @@ -29,7 +29,9 @@ QuicSimpleServerStream::QuicSimpleServerStream( QuicSimpleServerBackend* quic_simple_server_backend) : QuicSpdyServerStreamBase(id, session, type), content_length_(-1), - quic_simple_server_backend_(quic_simple_server_backend) {} + quic_simple_server_backend_(quic_simple_server_backend) { + DCHECK(quic_simple_server_backend_); +} QuicSimpleServerStream::QuicSimpleServerStream( PendingStream pending, @@ -38,7 +40,9 @@ QuicSimpleServerStream::QuicSimpleServerStream( QuicSimpleServerBackend* quic_simple_server_backend) : QuicSpdyServerStreamBase(std::move(pending), session, type), content_length_(-1), - quic_simple_server_backend_(quic_simple_server_backend) {} + quic_simple_server_backend_(quic_simple_server_backend) { + DCHECK(quic_simple_server_backend_); +} QuicSimpleServerStream::~QuicSimpleServerStream() { quic_simple_server_backend_->CloseBackendResponseStream(this); @@ -141,6 +145,12 @@ void QuicSimpleServerStream::SendResponse() { return; } + if (quic_simple_server_backend_ == nullptr) { + QUIC_DVLOG(1) << "Backend is missing."; + SendErrorResponse(); + return; + } + // Fetch the response from the backend interface and wait for callback once // response is ready quic_simple_server_backend_->FetchResponseFromBackend(request_headers_, body_, diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc index 7572a75da84..8aaaf6b73db 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc @@ -100,8 +100,15 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession { crypto_config, compressed_certs_cache, quic_simple_server_backend) { - QuicSessionPeer::SetMaxOpenIncomingStreams(this, kMaxStreamsForTest); - QuicSessionPeer::SetMaxOpenOutgoingStreams(this, kMaxStreamsForTest); + if (connection->transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams( + this, kMaxStreamsForTest); + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams( + this, kMaxStreamsForTest); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(this, kMaxStreamsForTest); + QuicSessionPeer::SetMaxOpenOutgoingStreams(this, kMaxStreamsForTest); + } ON_CALL(*this, WritevData(_, _, _, _, _)) .WillByDefault(Invoke(MockQuicSession::ConsumeData)); } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc index 3d7ef028e8a..e9e08fd548b 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc @@ -76,9 +76,11 @@ void QuicSpdyClientBase::OnClose(QuicSpdyStream* stream) { // Store response headers and body. if (store_response_) { auto status = response_headers.find(":status"); - if (status == response_headers.end() || - !QuicTextUtils::StringToInt(status->second, &latest_response_code_)) { - QUIC_LOG(ERROR) << "Invalid response headers"; + if (status == response_headers.end()) { + QUIC_LOG(ERROR) << "Missing :status response header"; + } else if (!QuicTextUtils::StringToInt(status->second, + &latest_response_code_)) { + QUIC_LOG(ERROR) << "Invalid :status response header: " << status->second; } latest_response_headers_ = response_headers.DebugString(); preliminary_response_headers_ = @@ -118,8 +120,6 @@ void QuicSpdyClientBase::SendRequest(const SpdyHeaderBlock& headers, return; } stream->SendRequest(headers.Clone(), body, fin); - // Record this in case we need to resend. - MaybeAddDataToResend(headers, body, fin); } void QuicSpdyClientBase::SendRequestAndWaitForResponse( @@ -167,29 +167,6 @@ int QuicSpdyClientBase::GetNumReceivedServerConfigUpdatesFromSession() { return client_session()->GetNumReceivedServerConfigUpdates(); } -void QuicSpdyClientBase::MaybeAddDataToResend(const SpdyHeaderBlock& headers, - QuicStringPiece body, - bool fin) { - if (!GetQuicReloadableFlag(enable_quic_stateless_reject_support)) { - return; - } - - if (client_session()->IsCryptoHandshakeConfirmed()) { - // The handshake is confirmed. No need to continue saving requests to - // resend. - data_to_resend_on_connect_.clear(); - return; - } - - // The handshake is not confirmed. Push the data onto the queue of data to - // resend if statelessly rejected. - std::unique_ptr<SpdyHeaderBlock> new_headers( - new SpdyHeaderBlock(headers.Clone())); - std::unique_ptr<QuicDataToResend> data_to_resend( - new ClientQuicDataToResend(std::move(new_headers), body, fin, this)); - MaybeAddQuicDataToResend(std::move(data_to_resend)); -} - void QuicSpdyClientBase::MaybeAddQuicDataToResend( std::unique_ptr<QuicDataToResend> data_to_resend) { data_to_resend_on_connect_.push_back(std::move(data_to_resend)); diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h index 03a981e1b1c..7481bfaa7f8 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h @@ -135,6 +135,11 @@ class QuicSpdyClientBase : public QuicClientBase, response_listener_ = std::move(listener); } + void set_drop_response_body(bool drop_response_body) { + drop_response_body_ = drop_response_body; + } + bool drop_response_body() const { return drop_response_body_; } + protected: int GetNumSentClientHellosFromSession() override; int GetNumReceivedServerConfigUpdatesFromSession() override; @@ -144,13 +149,6 @@ class QuicSpdyClientBase : public QuicClientBase, const quic::ParsedQuicVersionVector& supported_versions, QuicConnection* connection) override; - // If the crypto handshake has not yet been confirmed, adds the data to the - // queue of data to resend if the client receives a stateless reject. - // Otherwise, deletes the data. - void MaybeAddDataToResend(const spdy::SpdyHeaderBlock& headers, - QuicStringPiece body, - bool fin); - void ClearDataToResend() override; void ResendSavedData() override; @@ -209,6 +207,8 @@ class QuicSpdyClientBase : public QuicClientBase, std::vector<std::unique_ptr<QuicDataToResend>> data_to_resend_on_connect_; std::unique_ptr<ClientQuicDataToResend> push_promise_data_to_resend_; + + bool drop_response_body_ = false; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_server_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_server_base.h new file mode 100644 index 00000000000..1130cfcba4e --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_server_base.h @@ -0,0 +1,30 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A toy server, which connects to a specified port and sends QUIC +// requests to that endpoint. + +#ifndef QUICHE_QUIC_TOOLS_QUIC_SPDY_SERVER_BASE_H_ +#define QUICHE_QUIC_TOOLS_QUIC_SPDY_SERVER_BASE_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" + +namespace quic { + +// Base class for service instances to be used with QuicToyServer. +class QuicSpdyServerBase { + public: + virtual ~QuicSpdyServerBase() = default; + + // Creates a UDP socket and listens on |address|. Returns true on success + // and false otherwise. + virtual bool CreateUDPSocketAndListen(const QuicSocketAddress& address) = 0; + + // Handles incoming requests. Does not return. + virtual void HandleEventsForever() = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TOOLS_QUIC_SPDY_SERVER_BASE_H_ diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc index 63bbc5d549c..3301ef5d014 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc @@ -95,8 +95,7 @@ QuicInterval<uint64_t> QuicTcpLikeTraceConverter::OnControlFrameSent( QuicInterval<uint64_t> connection_offset = QuicInterval<uint64_t>( connection_offset_, connection_offset_ + control_frame_length); connection_offset_ += control_frame_length; - control_frames_info_[control_frame_id] = QuicInterval<uint64_t>( - connection_offset_, connection_offset_ + control_frame_length); + control_frames_info_[control_frame_id] = connection_offset; largest_observed_control_frame_id_ = control_frame_id; return connection_offset; } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc index 44f7351036b..a6ce81a8dcd 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc @@ -70,7 +70,7 @@ TEST(QuicTcpLikeTraceConverterTest, BasicTest) { EXPECT_EQ(expected2, converter.OnControlFrameSent(1, 100)); // Ignore passed in length for retransmitted frame. - expected2 = {450, 600}; + expected2 = {300, 450}; EXPECT_EQ(expected2, converter.OnControlFrameSent(2, 200)); expected2 = {1602, 1702}; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc new file mode 100644 index 00000000000..f6e2e155e86 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc @@ -0,0 +1,357 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A binary wrapper for QuicClient. +// Connects to a host using QUIC, sends a request to the provided URL, and +// displays the response. +// +// Some usage examples: +// +// Standard request/response: +// quic_client www.google.com +// quic_client www.google.com --quiet +// quic_client www.google.com --port=443 +// +// Use a specific version: +// quic_client www.google.com --quic_version=23 +// +// Send a POST instead of a GET: +// quic_client www.google.com --body="this is a POST body" +// +// Append additional headers to the request: +// quic_client www.google.com --headers="Header-A: 1234; Header-B: 5678" +// +// Connect to a host different to the URL being requested: +// quic_client mail.google.com --host=www.google.com +// +// Connect to a specific IP: +// IP=`dig www.google.com +short | head -1` +// quic_client www.google.com --host=${IP} +// +// Send repeated requests and change ephemeral port between requests +// quic_client www.google.com --num_requests=10 +// +// Try to connect to a host which does not speak QUIC: +// quic_client www.example.com +// +// This tool is available as a built binary at: +// /google/data/ro/teams/quic/tools/quic_client +// After submitting changes to this file, you will need to follow the +// instructions at go/quic_client_binary_update + +#include "net/third_party/quiche/src/quic/tools/quic_toy_client.h" + +#include <iostream> +#include <memory> +#include <string> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_server_id.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h" +#include "net/third_party/quiche/src/quic/tools/quic_url.h" + +namespace { + +using quic::QuicSocketAddress; +using quic::QuicStringPiece; +using quic::QuicTextUtils; +using quic::QuicUrl; + +} // namespace + +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, + host, + "", + "The IP or hostname to connect to. If not provided, the host " + "will be derived from the provided URL."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(std::string, + body, + "", + "If set, send a POST with this body."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, + body_hex, + "", + "If set, contents are converted from hex to ascii, before " + "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\""); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, + headers, + "", + "A semicolon separated list of key:value pairs to " + "add to request headers."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(bool, + quiet, + false, + "Set to true for a quieter output experience."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, + quic_version, + "", + "QUIC version to speak, e.g. 21. If not set, then all available " + "versions are offered in the handshake. Also supports wire versions " + "such as Q043 or T099."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + int32_t, + quic_ietf_draft, + 0, + "QUIC IETF draft number to use over the wire, e.g. 18. " + "By default this sets quic_version to T099. " + "This also enables required internal QUIC flags."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + bool, + version_mismatch_ok, + false, + "If true, a version mismatch in the handshake is not considered a " + "failure. Useful for probing a server to determine if it speaks " + "any version of QUIC."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + bool, + force_version_negotiation, + false, + "If true, start by proposing a version that is reserved for version " + "negotiation."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + bool, + redirect_is_success, + true, + "If true, an HTTP response code of 3xx is considered to be a " + "successful response, otherwise a failure."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, + initial_mtu, + 0, + "Initial MTU of the connection."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + int32_t, + num_requests, + 1, + "How many sequential requests to make on a single connection."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(bool, + disable_certificate_verification, + false, + "If true, don't verify the server certificate."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + bool, + drop_response_body, + false, + "If true, drop response body immediately after it is received."); + +namespace quic { + +QuicToyClient::QuicToyClient(ClientFactory* client_factory) + : client_factory_(client_factory) {} + +int QuicToyClient::SendRequestsAndPrintResponses( + std::vector<std::string> urls) { + QuicUrl url(urls[0], "https"); + std::string host = GetQuicFlag(FLAGS_host); + if (host.empty()) { + host = url.host(); + } + int port = GetQuicFlag(FLAGS_port); + if (port == 0) { + port = url.port(); + } + + quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions(); + + std::string quic_version_string = GetQuicFlag(FLAGS_quic_version); + const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft); + if (quic_ietf_draft > 0) { + quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft); + if (quic_version_string.length() == 0) { + quic_version_string = "T099"; + } + } + if (quic_version_string.length() > 0) { + if (quic_version_string[0] == 'T') { + // ParseQuicVersionString checks quic_supports_tls_handshake. + SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); + } + quic::ParsedQuicVersion parsed_quic_version = + quic::ParseQuicVersionString(quic_version_string); + if (parsed_quic_version.transport_version == + quic::QUIC_VERSION_UNSUPPORTED) { + return 1; + } + versions.clear(); + versions.push_back(parsed_quic_version); + quic::QuicEnableVersion(parsed_quic_version); + } + + if (GetQuicFlag(FLAGS_force_version_negotiation)) { + versions.insert(versions.begin(), + quic::QuicVersionReservedForNegotiation()); + } + + const int32_t num_requests(GetQuicFlag(FLAGS_num_requests)); + std::unique_ptr<quic::ProofVerifier> proof_verifier; + if (GetQuicFlag(FLAGS_disable_certificate_verification)) { + proof_verifier = quic::QuicMakeUnique<FakeProofVerifier>(); + } else { + proof_verifier = quic::CreateDefaultProofVerifier(); + } + + // Build the client, and try to connect. + std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient( + host, port, versions, std::move(proof_verifier)); + + int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu); + client->set_initial_max_packet_length( + initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize); + client->set_drop_response_body(GetQuicFlag(FLAGS_drop_response_body)); + if (!client->Initialize()) { + std::cerr << "Failed to initialize client." << std::endl; + return 1; + } + if (!client->Connect()) { + quic::QuicErrorCode error = client->session()->error(); + if (error == quic::QUIC_INVALID_VERSION) { + std::cerr << "Server talks QUIC, but none of the versions supported by " + << "this client: " << ParsedQuicVersionVectorToString(versions) + << std::endl; + // 0: No error. + // 20: Failed to connect due to QUIC_INVALID_VERSION. + return GetQuicFlag(FLAGS_version_mismatch_ok) ? 0 : 20; + } + std::cerr << "Failed to connect to " << host << ":" << port + << ". Error: " << quic::QuicErrorCodeToString(error) << std::endl; + return 1; + } + std::cerr << "Connected to " << host << ":" << port << std::endl; + + // Construct the string body from flags, if provided. + std::string body = GetQuicFlag(FLAGS_body); + if (!GetQuicFlag(FLAGS_body_hex).empty()) { + DCHECK(GetQuicFlag(FLAGS_body).empty()) + << "Only set one of --body and --body_hex."; + body = QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex)); + } + + // Construct a GET or POST request for supplied URL. + spdy::SpdyHeaderBlock header_block; + header_block[":method"] = body.empty() ? "GET" : "POST"; + header_block[":scheme"] = url.scheme(); + header_block[":authority"] = url.HostPort(); + header_block[":path"] = url.PathParamsQuery(); + + // Append any additional headers supplied on the command line. + const std::string headers = GetQuicFlag(FLAGS_headers); + for (QuicStringPiece sp : QuicTextUtils::Split(headers, ';')) { + QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&sp); + if (sp.empty()) { + continue; + } + std::vector<QuicStringPiece> kv = QuicTextUtils::Split(sp, ':'); + QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[0]); + QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[1]); + header_block[kv[0]] = kv[1]; + } + + // Make sure to store the response, for later output. + client->set_store_response(true); + + for (int i = 0; i < num_requests; ++i) { + // Send the request. + client->SendRequestAndWaitForResponse(header_block, body, /*fin=*/true); + + // Print request and response details. + if (!GetQuicFlag(FLAGS_quiet)) { + std::cout << "Request:" << std::endl; + std::cout << "headers:" << header_block.DebugString(); + if (!GetQuicFlag(FLAGS_body_hex).empty()) { + // Print the user provided hex, rather than binary body. + std::cout << "body:\n" + << QuicTextUtils::HexDump( + QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex))) + << std::endl; + } else { + std::cout << "body: " << body << std::endl; + } + std::cout << std::endl; + + if (!client->preliminary_response_headers().empty()) { + std::cout << "Preliminary response headers: " + << client->preliminary_response_headers() << std::endl; + std::cout << std::endl; + } + + std::cout << "Response:" << std::endl; + std::cout << "headers: " << client->latest_response_headers() + << std::endl; + std::string response_body = client->latest_response_body(); + if (!GetQuicFlag(FLAGS_body_hex).empty()) { + // Assume response is binary data. + std::cout << "body:\n" + << QuicTextUtils::HexDump(response_body) << std::endl; + } else { + std::cout << "body: " << response_body << std::endl; + } + std::cout << "trailers: " << client->latest_response_trailers() + << std::endl; + } + + if (!client->connected()) { + std::cerr << "Request caused connection failure. Error: " + << quic::QuicErrorCodeToString(client->session()->error()) + << std::endl; + return 1; + } + + size_t response_code = client->latest_response_code(); + if (response_code >= 200 && response_code < 300) { + std::cout << "Request succeeded (" << response_code << ")." << std::endl; + } else if (response_code >= 300 && response_code < 400) { + if (GetQuicFlag(FLAGS_redirect_is_success)) { + std::cout << "Request succeeded (redirect " << response_code << ")." + << std::endl; + } else { + std::cout << "Request failed (redirect " << response_code << ")." + << std::endl; + return 1; + } + } else { + std::cout << "Request failed (" << response_code << ")." << std::endl; + return 1; + } + + // Change the ephemeral port if there are more requests to do. + if (i + 1 < num_requests) { + if (!client->ChangeEphemeralPort()) { + std::cerr << "Failed to change ephemeral port." << std::endl; + return 1; + } + } + } + + return 0; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h new file mode 100644 index 00000000000..e832ac76697 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h @@ -0,0 +1,45 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A toy client, which connects to a specified port and sends QUIC +// requests to that endpoint. + +#ifndef QUICHE_QUIC_TOOLS_QUIC_TOY_CLIENT_H_ +#define QUICHE_QUIC_TOOLS_QUIC_TOY_CLIENT_H_ + +#include "net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h" + +namespace quic { + +class QuicToyClient { + public: + class ClientFactory { + public: + virtual ~ClientFactory() = default; + + // Creates a new client configured to connect to |host:port| supporting + // |versions|, and using |verifier| to verify proofs. + virtual std::unique_ptr<QuicSpdyClientBase> CreateClient( + std::string host, + uint16_t port, + ParsedQuicVersionVector versions, + std::unique_ptr<ProofVerifier> verifier) = 0; + }; + + // Constructs a new toy client that will use |client_factory| to create the + // actual QuicSpdyClientBase instance. + QuicToyClient(ClientFactory* client_factory); + + // Connects to the QUIC server based on the various flags defined in the + // .cc file, sends requests and prints the responses. Returns 0 on success + // and non-zero otherwise. + int SendRequestsAndPrintResponses(std::vector<std::string> urls); + + private: + ClientFactory* client_factory_; // Unowned. +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TOOLS_QUIC_TOY_CLIENT_H_ diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc new file mode 100644 index 00000000000..633b465960e --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.cc @@ -0,0 +1,73 @@ +// Copyright 2014 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/third_party/quiche/src/quic/tools/quic_toy_server.h" + +#include <vector> + +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h" + +DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, + port, + 6121, + "The port the quic server will listen on."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, + quic_response_cache_dir, + "", + "Specifies the directory used during QuicHttpResponseCache " + "construction to seed the cache. Cache directory can be " + "generated using `wget -p --save-headers <url>`"); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + int32_t, + quic_ietf_draft, + 0, + "QUIC IETF draft number to use over the wire, e.g. 18. " + "This also enables required internal QUIC flags."); + +namespace quic { + +std::unique_ptr<quic::QuicSimpleServerBackend> +QuicToyServer::MemoryCacheBackendFactory::CreateBackend() { + auto memory_cache_backend = QuicMakeUnique<QuicMemoryCacheBackend>(); + if (!GetQuicFlag(FLAGS_quic_response_cache_dir).empty()) { + memory_cache_backend->InitializeBackend( + GetQuicFlag(FLAGS_quic_response_cache_dir)); + } + return memory_cache_backend; +} + +QuicToyServer::QuicToyServer(BackendFactory* backend_factory, + ServerFactory* server_factory) + : backend_factory_(backend_factory), server_factory_(server_factory) {} + +int QuicToyServer::Start() { + const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft); + if (quic_ietf_draft > 0) { + quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft); + quic::QuicEnableVersion( + quic::ParsedQuicVersion(quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_99)); + } + auto proof_source = quic::CreateDefaultProofSource(); + auto backend = backend_factory_->CreateBackend(); + auto server = + server_factory_->CreateServer(backend.get(), std::move(proof_source)); + + if (!server->CreateUDPSocketAndListen(quic::QuicSocketAddress( + quic::QuicIpAddress::Any6(), GetQuicFlag(FLAGS_port)))) { + return 1; + } + + server->HandleEventsForever(); + return 0; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.h b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.h new file mode 100644 index 00000000000..6c5c486c493 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_server.h @@ -0,0 +1,62 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_TOOLS_QUIC_TOY_SERVER_H_ +#define QUICHE_QUIC_TOOLS_QUIC_TOY_SERVER_H_ + +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h" +#include "net/third_party/quiche/src/quic/tools/quic_spdy_server_base.h" + +namespace quic { + +// A binary wrapper for QuicServer. It listens forever on --port +// (default 6121) until it's killed or ctrl-cd to death. +class QuicToyServer { + public: + // A factory for creating QuicSpdyServerBase instances. + class ServerFactory { + public: + virtual ~ServerFactory() = default; + + // Creates a QuicSpdyServerBase instance using |backend| for generating + // responses, and |proof_source| for certificates. + virtual std::unique_ptr<QuicSpdyServerBase> CreateServer( + QuicSimpleServerBackend* backend, + std::unique_ptr<ProofSource> proof_source) = 0; + }; + + // A facotry for creating QuicSimpleServerBackend instances. + class BackendFactory { + public: + virtual ~BackendFactory() = default; + + // Creates a new backend. + virtual std::unique_ptr<QuicSimpleServerBackend> CreateBackend() = 0; + }; + + // A factory for creating QuicMemoryCacheBackend instances, configured + // to load files from disk, if necessary. + class MemoryCacheBackendFactory : public BackendFactory { + public: + std::unique_ptr<quic::QuicSimpleServerBackend> CreateBackend() override; + }; + + // Constructs a new toy server that will use |server_factory| to create the + // actual QuicSpdyServerBase instance. + QuicToyServer(BackendFactory* backend_factory, ServerFactory* server_factory); + + // Connects to the QUIC server based on the various flags defined in the + // .cc file, listends for requests and sends the responses. Returns 1 on + // failure and does not return otherwise. + int Start(); + + private: + BackendFactory* backend_factory_; // Unowned. + ServerFactory* server_factory_; // Unowned. +}; + +} // namespace quic + +#endif // QUICHE_QUIC_TOOLS_QUIC_TOY_SERVER_H_ diff --git a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h index b02d4634715..067153ba8bc 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h +++ b/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler.h @@ -45,7 +45,9 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { using typename WriteScheduler<StreamIdType>::StreamPrecedenceType; // Creates scheduler with no streams. - PriorityWriteScheduler() = default; + PriorityWriteScheduler() : PriorityWriteScheduler(kHttp2RootStreamId) {} + explicit PriorityWriteScheduler(StreamIdType root_stream_id) + : root_stream_id_(root_stream_id) {} void RegisterStream(StreamIdType stream_id, const StreamPrecedenceType& precedence) override { @@ -55,12 +57,12 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // parent_id not used here, but may as well validate it. However, // parent_id may legitimately not be registered yet--see b/15676312. StreamIdType parent_id = precedence.parent_id(); - SPDY_DVLOG_IF( - 1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id)) + SPDY_DVLOG_IF(1, + parent_id != root_stream_id_ && !StreamRegistered(parent_id)) << "Parent stream " << parent_id << " not registered"; - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG << "Stream " << kHttp2RootStreamId << " already registered"; + if (stream_id == root_stream_id_) { + SPDY_BUG << "Stream " << root_stream_id_ << " already registered"; return; } StreamInfo stream_info = {precedence.spdy3_priority(), stream_id, false}; @@ -106,8 +108,8 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { // parent_id not used here, but may as well validate it. However, // parent_id may legitimately not be registered yet--see b/15676312. StreamIdType parent_id = precedence.parent_id(); - SPDY_DVLOG_IF( - 1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id)) + SPDY_DVLOG_IF(1, + parent_id != root_stream_id_ && !StreamRegistered(parent_id)) << "Parent stream " << parent_id << " not registered"; auto it = stream_infos_.find(stream_id); @@ -315,6 +317,7 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { PriorityInfo priority_infos_[kV3LowestPriority + 1]; // StreamInfos for all registered streams. StreamInfoMap stream_infos_; + StreamIdType root_stream_id_; }; } // namespace spdy diff --git a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler_test.cc index a285cb2e4bd..08a4ff69281 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler_test.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/priority_write_scheduler_test.cc @@ -7,6 +7,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h" namespace spdy { namespace test { diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.h index ac172af0942..f5795790e5e 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.h +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_header_block.h @@ -180,7 +180,7 @@ class SPDY_EXPORT_PRIVATE SpdyHeaderBlock { const SpdyStringPiece value); // Allows either lookup or mutation of the value associated with a key. - ValueProxy operator[](const SpdyStringPiece key) SPDY_MUST_USE_RESULT; + SPDY_MUST_USE_RESULT ValueProxy operator[](const SpdyStringPiece key); // This object provides automatic conversions that allow SpdyHeaderBlock to be // nearly a drop-in replacement for SpdyLinkedHashMap<SpdyString, SpdyString>. diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test.cc index 09a56cbe4f4..fc595a23f06 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test.cc @@ -11,6 +11,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "net/third_party/quiche/src/spdy/core/spdy_bitmasks.h" #include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h" namespace spdy { diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h index ce2c9d538e7..bb8bea31268 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h @@ -21,6 +21,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h" #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" #include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h" diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena.cc b/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena.cc index 08cdc62db0c..f7d48b47017 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_simple_arena.cc @@ -4,6 +4,8 @@ #include "net/third_party/quiche/src/spdy/core/spdy_simple_arena.h" +#include <algorithm> + #include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h" namespace spdy { diff --git a/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.h b/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.h index bf62eeba930..03a6caf896d 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.h +++ b/chromium/net/third_party/quiche/src/spdy/core/spdy_test_utils.h @@ -8,14 +8,12 @@ #include <cstddef> #include <cstdint> -#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h" #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h" #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h" #include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h" #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h" -#include "net/third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h" namespace spdy { |