proxygen
QPACKHeaderTableTests.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
11 #include <memory>
14 #include <sstream>
15 
16 using namespace std;
17 using namespace testing;
18 
19 namespace proxygen {
20 
22  public:
23 
24  protected:
25  QPACKHeaderTable table_{320, true};
26 };
27 
29  HPACKHeader accept("accept-encoding", "gzip");
30  HPACKHeader agent("user-agent", "SeaMonkey");
31 
32  EXPECT_EQ(table_.getBaseIndex(), 0);
33  table_.add(accept.copy());
34  EXPECT_EQ(table_.getBaseIndex(), 1);
35  // Vulnerable - in the table
36  EXPECT_EQ(table_.getIndex(accept, false),
38  // Allow vulnerable, get the index
39  EXPECT_EQ(table_.getIndex(accept, true), 1);
40  EXPECT_TRUE(table_.onTableStateSync(1));
41  EXPECT_EQ(table_.getIndex(accept, false), 1);
42  table_.add(agent.copy());
43  // Indexes move
44  EXPECT_EQ(table_.getIndex(agent, true), 1);
45  EXPECT_EQ(table_.getIndex(accept, true), 2);
46 }
47 
49  HPACKHeader accept("accept-encoding", "gzip");
50 
51  int32_t max = 4;
52  uint32_t capacity = accept.bytes() * max;
53  table_.setCapacity(capacity);
54 
55  for (auto i = 0; i < max; i++) {
56  EXPECT_TRUE(table_.add(accept.copy()));
57  }
58  for (auto i = 1; i <= max; i++) {
59  table_.addRef(i);
60  }
61  table_.setMaxAcked(max);
62  EXPECT_FALSE(table_.canIndex(accept));
63  EXPECT_FALSE(table_.add(accept.copy()));
64  table_.subRef(1);
65  EXPECT_TRUE(table_.canIndex(accept));
66  EXPECT_TRUE(table_.add(accept.copy()));
67 
68  table_.subRef(3);
69  EXPECT_FALSE(table_.canIndex(accept));
70  table_.subRef(2);
71  EXPECT_TRUE(table_.canIndex(accept));
72 }
73 
75  HPACKHeader accept("accept-encoding", "gzip");
76 
77  int32_t max = 4;
78  uint32_t capacity = accept.bytes() * max;
79  table_.setCapacity(capacity);
80 
81  for (auto i = 0; i < max; i++) {
82  EXPECT_TRUE(table_.add(accept.copy()));
83  }
84  EXPECT_EQ(table_.size(), max);
85  EXPECT_FALSE(table_.setCapacity(capacity / 2));
86  EXPECT_EQ(table_.size(), max);
87 
88  // Ack all headers but mark the first as in use
89  table_.setMaxAcked(max);
90  table_.addRef(1);
91  EXPECT_FALSE(table_.setCapacity(capacity / 2));
92 
93  // Clear all refs
94  table_.subRef(1);
95  EXPECT_TRUE(table_.setCapacity(capacity / 2));
96  EXPECT_EQ(table_.size(), max / 2);
97 }
98 
100  HPACKHeader accept("accept-encoding", "gzip");
101  HPACKHeader agent("user-agent", "SeaMonkey");
102  HPACKHeader cookie("Cookie", "choco=chip");
103 
104  for (auto i = 0; i < 10; i++) {
105  EXPECT_TRUE(table_.add(accept.copy()));
106  table_.setMaxAcked(i + 1);
107  }
108  EXPECT_TRUE(table_.add(cookie.copy()));
109  EXPECT_TRUE(table_.add(agent.copy()));
110 
111  EXPECT_EQ(table_.getBaseIndex(), 12);
112  EXPECT_EQ(table_.getIndex(agent, true), 1);
113  EXPECT_EQ(table_.getIndex(cookie, true), 2);
114  EXPECT_EQ(table_.getIndex(accept, true), 3);
115  EXPECT_EQ(table_.getHeader(1, table_.getBaseIndex()), agent);
116  EXPECT_EQ(table_.getHeader(2, table_.getBaseIndex()), cookie);
117  EXPECT_EQ(table_.getHeader(table_.size(), table_.getBaseIndex()), accept);
118 }
119 
121  HPACKHeader accept("accept-encoding", "gzip");
122  EXPECT_EQ(table_.nameIndex(accept.name), 0);
123  EXPECT_TRUE(table_.add(accept.copy()));
124  EXPECT_EQ(table_.nameIndex(accept.name), 1);
125 }
126 
128  HPACKHeader accept1("accept-encoding", "gzip");
129  HPACKHeader accept2("accept-encoding", "blarf");
130  EXPECT_EQ(table_.getIndex(accept1), 0);
131  EXPECT_TRUE(table_.add(accept1.copy()));
132  EXPECT_EQ(table_.getIndex(accept1), 1);
133  EXPECT_EQ(table_.getIndex(accept2), 0);
134 }
135 
137  HPACKHeader accept("accept-encoding", "gzip");
138 
139  EXPECT_TRUE(table_.add(accept.copy()));
140 
141  // Unnecessary duplicate
142  auto res = table_.maybeDuplicate(1, true);
143  EXPECT_FALSE(res.first);
144  EXPECT_EQ(res.second, 1);
145 
146  for (auto i = 0; i < 6; i++) {
147  EXPECT_TRUE(table_.add(accept.copy()));
148  // Ack the first few entries so they can be evicted
149  table_.setMaxAcked(std::min(3u, table_.getBaseIndex()));
150  }
151 
152  // successful duplicate, vulnerable allowed
153  EXPECT_TRUE(table_.isDraining(table_.size()));
154  res = table_.maybeDuplicate(table_.size(), true);
155  EXPECT_TRUE(res.first);
156  EXPECT_EQ(res.second, 8);
157  EXPECT_EQ(table_.size(), 6); // evicted 1
158 
159  // successful duplicate, vulnerable disallowed
160  EXPECT_TRUE(table_.onTableStateSync(3));
161  res = table_.maybeDuplicate(table_.size(), false);
162  EXPECT_TRUE(res.first);
163  EXPECT_EQ(res.second, 0);
164  EXPECT_EQ(table_.size(), 6); // evicted 2
165 
166  // Attempt to duplicate UNACKED
167  res = table_.maybeDuplicate(QPACKHeaderTable::UNACKED, true);
168  EXPECT_FALSE(res.first);
169  EXPECT_EQ(res.second, 0);
170  EXPECT_EQ(table_.size(), 6); // nothing changed
171  EXPECT_EQ(table_.getBaseIndex(), 9);
172 
173  // Hold a ref to oldest entry, prevents eviction
174  auto oldestAbsolute = table_.getBaseIndex() - table_.size() + 1;
175  table_.addRef(oldestAbsolute);
176 
177  // Table should be full
178  EXPECT_FALSE(table_.canIndex(accept));
179 
180  res = table_.maybeDuplicate(table_.size(), true);
181  EXPECT_FALSE(res.first);
182  EXPECT_EQ(res.second, 0);
183 
184 }
185 
186 TEST_F(QPACKHeaderTableTests, CanEvictWithRoom) {
187  HPACKHeader thirtyNineBytes("abcd", "efg");
188  HPACKHeader fortySevenBytes("abcd", "efghijklmno");
189  for (auto i = 0; i < 8; i++) {
190  EXPECT_TRUE(table_.add(thirtyNineBytes.copy()));
191  }
192  table_.setMaxAcked(table_.getBaseIndex());
193  // abs index = 1 is evictable, but index = 2 is referenced, so we can
194  // insert up to (320 - 8 * 39) + 39 = 47
195  table_.addRef(2);
196  EXPECT_TRUE(table_.canIndex(fortySevenBytes));
197  EXPECT_TRUE(table_.add(fortySevenBytes.copy()));
198 }
199 
200 TEST_F(QPACKHeaderTableTests, EvictNonDrained) {
201  HPACKHeader small("ab", "cd"); // 36 bytes
202  HPACKHeader small2("abcd", std::string(14, 'b')); // 50 bytes
203  HPACKHeader med(std::string(20, 'a'), std::string(20, 'b')); // 72
204  HPACKHeader large(std::string(34, 'a'), std::string(34, 'b')); // 100
205 
206  table_.setCapacity(220);
207  EXPECT_TRUE(table_.add(small.copy()));
208  EXPECT_TRUE(table_.add(med.copy()));
209  EXPECT_TRUE(table_.add(large.copy()));
210  EXPECT_TRUE(table_.isDraining(3));
211  EXPECT_FALSE(table_.isDraining(2));
212 
213  table_.setMaxAcked(3);
214  // Evicts small and med
215  EXPECT_TRUE(table_.add(small2.copy()));
216  EXPECT_EQ(table_.size(), 2);
217  EXPECT_FALSE(table_.isDraining(1));
218  EXPECT_FALSE(table_.isDraining(2));
219 
220  // Now lg should be draining
221  EXPECT_TRUE(table_.add(small.copy()));
222  EXPECT_TRUE(table_.isDraining(3));
223 
224  // Evict large
225  EXPECT_TRUE(table_.add(small.copy()));
226 }
227 
229  // Can't ack more than is in the table
230  EXPECT_FALSE(table_.onTableStateSync(1));
231 }
232 
233 }
LogLevel max
Definition: LogLevel.cpp:31
StringPiece cookie
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
auto large
STL namespace.
uint32_t bytes() const
Definition: HPACKHeader.h:49
auto small
LogLevel min
Definition: LogLevel.cpp:30
HPACKHeaderName name
Definition: HPACKHeader.h:82
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
TEST_F(QPACKHeaderTableTests, BadSync)
const char * string
Definition: Conv.cpp:212
HPACKHeader copy() const
Definition: HPACKHeader.h:71
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
NetworkSocket accept(NetworkSocket s, sockaddr *addr, socklen_t *addrlen)
Definition: NetOps.cpp:71