1 // Copyright (c) 2021 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/common/capsule.h"
6
7 #include <cstddef>
8 #include <deque>
9 #include <string>
10 #include <vector>
11
12 #include "absl/strings/escaping.h"
13 #include "absl/strings/str_cat.h"
14 #include "absl/strings/string_view.h"
15 #include "quiche/common/platform/api/quiche_test.h"
16 #include "quiche/common/quiche_buffer_allocator.h"
17 #include "quiche/common/quiche_ip_address.h"
18 #include "quiche/common/simple_buffer_allocator.h"
19 #include "quiche/common/test_tools/quiche_test_utils.h"
20 #include "quiche/web_transport/web_transport.h"
21
22 using ::testing::_;
23 using ::testing::InSequence;
24 using ::testing::Return;
25 using ::webtransport::StreamType;
26
27 namespace quiche {
28 namespace test {
29
30 class CapsuleParserPeer {
31 public:
buffered_data(CapsuleParser * capsule_parser)32 static std::string* buffered_data(CapsuleParser* capsule_parser) {
33 return &capsule_parser->buffered_data_;
34 }
35 };
36
37 namespace {
38
39 class MockCapsuleParserVisitor : public CapsuleParser::Visitor {
40 public:
MockCapsuleParserVisitor()41 MockCapsuleParserVisitor() {
42 ON_CALL(*this, OnCapsule(_)).WillByDefault(Return(true));
43 }
44 ~MockCapsuleParserVisitor() override = default;
45 MOCK_METHOD(bool, OnCapsule, (const Capsule& capsule), (override));
46 MOCK_METHOD(void, OnCapsuleParseFailure, (absl::string_view error_message),
47 (override));
48 };
49
50 class CapsuleTest : public QuicheTest {
51 public:
CapsuleTest()52 CapsuleTest() : capsule_parser_(&visitor_) {}
53
ValidateParserIsEmpty()54 void ValidateParserIsEmpty() {
55 EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
56 EXPECT_CALL(visitor_, OnCapsuleParseFailure(_)).Times(0);
57 capsule_parser_.ErrorIfThereIsRemainingBufferedData();
58 EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
59 }
60
TestSerialization(const Capsule & capsule,const std::string & expected_bytes)61 void TestSerialization(const Capsule& capsule,
62 const std::string& expected_bytes) {
63 quiche::QuicheBuffer serialized_capsule =
64 SerializeCapsule(capsule, SimpleBufferAllocator::Get());
65 quiche::test::CompareCharArraysWithHexError(
66 "Serialized capsule", serialized_capsule.data(),
67 serialized_capsule.size(), expected_bytes.data(),
68 expected_bytes.size());
69 }
70
71 ::testing::StrictMock<MockCapsuleParserVisitor> visitor_;
72 CapsuleParser capsule_parser_;
73 };
74
TEST_F(CapsuleTest,DatagramCapsule)75 TEST_F(CapsuleTest, DatagramCapsule) {
76 std::string capsule_fragment;
77 ASSERT_TRUE(
78 absl::HexStringToBytes("00" // DATAGRAM capsule type
79 "08" // capsule length
80 "a1a2a3a4a5a6a7a8", // HTTP Datagram payload
81 &capsule_fragment));
82 std::string datagram_payload;
83 ASSERT_TRUE(absl::HexStringToBytes("a1a2a3a4a5a6a7a8", &datagram_payload));
84 Capsule expected_capsule = Capsule::Datagram(datagram_payload);
85 {
86 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
87 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
88 }
89 ValidateParserIsEmpty();
90 TestSerialization(expected_capsule, capsule_fragment);
91 }
92
TEST_F(CapsuleTest,DatagramCapsuleViaHeader)93 TEST_F(CapsuleTest, DatagramCapsuleViaHeader) {
94 std::string datagram_payload;
95 ASSERT_TRUE(absl::HexStringToBytes("a1a2a3a4a5a6a7a8", &datagram_payload));
96 quiche::QuicheBuffer expected_capsule = SerializeCapsule(
97 Capsule::Datagram(datagram_payload), SimpleBufferAllocator::Get());
98 quiche::QuicheBuffer actual_header = SerializeDatagramCapsuleHeader(
99 datagram_payload.size(), SimpleBufferAllocator::Get());
100 EXPECT_EQ(expected_capsule.AsStringView(),
101 absl::StrCat(actual_header.AsStringView(), datagram_payload));
102 }
103
TEST_F(CapsuleTest,LegacyDatagramCapsule)104 TEST_F(CapsuleTest, LegacyDatagramCapsule) {
105 std::string capsule_fragment;
106 ASSERT_TRUE(
107 absl::HexStringToBytes("80ff37a0" // LEGACY_DATAGRAM capsule type
108 "08" // capsule length
109 "a1a2a3a4a5a6a7a8", // HTTP Datagram payload
110 &capsule_fragment));
111 std::string datagram_payload;
112 ASSERT_TRUE(absl::HexStringToBytes("a1a2a3a4a5a6a7a8", &datagram_payload));
113 Capsule expected_capsule = Capsule::LegacyDatagram(datagram_payload);
114 {
115 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
116 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
117 }
118 ValidateParserIsEmpty();
119 TestSerialization(expected_capsule, capsule_fragment);
120 }
121
TEST_F(CapsuleTest,LegacyDatagramWithoutContextCapsule)122 TEST_F(CapsuleTest, LegacyDatagramWithoutContextCapsule) {
123 std::string capsule_fragment;
124 ASSERT_TRUE(absl::HexStringToBytes(
125 "80ff37a5" // LEGACY_DATAGRAM_WITHOUT_CONTEXT capsule type
126 "08" // capsule length
127 "a1a2a3a4a5a6a7a8", // HTTP Datagram payload
128 &capsule_fragment));
129 std::string datagram_payload;
130 ASSERT_TRUE(absl::HexStringToBytes("a1a2a3a4a5a6a7a8", &datagram_payload));
131 Capsule expected_capsule =
132 Capsule::LegacyDatagramWithoutContext(datagram_payload);
133 {
134 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
135 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
136 }
137 ValidateParserIsEmpty();
138 TestSerialization(expected_capsule, capsule_fragment);
139 }
140
TEST_F(CapsuleTest,CloseWebTransportStreamCapsule)141 TEST_F(CapsuleTest, CloseWebTransportStreamCapsule) {
142 std::string capsule_fragment;
143 ASSERT_TRUE(
144 absl::HexStringToBytes("6843" // CLOSE_WEBTRANSPORT_STREAM capsule type
145 "09" // capsule length
146 "00001234" // 0x1234 error code
147 "68656c6c6f", // "hello" error message
148 &capsule_fragment));
149 Capsule expected_capsule = Capsule::CloseWebTransportSession(
150 /*error_code=*/0x1234, /*error_message=*/"hello");
151 {
152 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
153 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
154 }
155 ValidateParserIsEmpty();
156 TestSerialization(expected_capsule, capsule_fragment);
157 }
158
TEST_F(CapsuleTest,DrainWebTransportStreamCapsule)159 TEST_F(CapsuleTest, DrainWebTransportStreamCapsule) {
160 std::string capsule_fragment;
161 ASSERT_TRUE(absl::HexStringToBytes(
162 "800078ae" // DRAIN_WEBTRANSPORT_STREAM capsule type
163 "00", // capsule length
164 &capsule_fragment));
165 Capsule expected_capsule = Capsule(DrainWebTransportSessionCapsule());
166 {
167 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
168 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
169 }
170 ValidateParserIsEmpty();
171 TestSerialization(expected_capsule, capsule_fragment);
172 }
173
TEST_F(CapsuleTest,AddressAssignCapsule)174 TEST_F(CapsuleTest, AddressAssignCapsule) {
175 std::string capsule_fragment;
176 ASSERT_TRUE(absl::HexStringToBytes(
177 "9ECA6A00" // ADDRESS_ASSIGN capsule type
178 "1A" // capsule length = 26
179 // first assigned address
180 "00" // request ID = 0
181 "04" // IP version = 4
182 "C000022A" // 192.0.2.42
183 "1F" // prefix length = 31
184 // second assigned address
185 "01" // request ID = 1
186 "06" // IP version = 6
187 "20010db8123456780000000000000000" // 2001:db8:1234:5678::
188 "40", // prefix length = 64
189 &capsule_fragment));
190 Capsule expected_capsule = Capsule::AddressAssign();
191 quiche::QuicheIpAddress ip_address1;
192 ip_address1.FromString("192.0.2.42");
193 PrefixWithId assigned_address1;
194 assigned_address1.request_id = 0;
195 assigned_address1.ip_prefix =
196 quiche::QuicheIpPrefix(ip_address1, /*prefix_length=*/31);
197 expected_capsule.address_assign_capsule().assigned_addresses.push_back(
198 assigned_address1);
199 quiche::QuicheIpAddress ip_address2;
200 ip_address2.FromString("2001:db8:1234:5678::");
201 PrefixWithId assigned_address2;
202 assigned_address2.request_id = 1;
203 assigned_address2.ip_prefix =
204 quiche::QuicheIpPrefix(ip_address2, /*prefix_length=*/64);
205 expected_capsule.address_assign_capsule().assigned_addresses.push_back(
206 assigned_address2);
207 {
208 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
209 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
210 }
211 ValidateParserIsEmpty();
212 TestSerialization(expected_capsule, capsule_fragment);
213 }
214
TEST_F(CapsuleTest,AddressRequestCapsule)215 TEST_F(CapsuleTest, AddressRequestCapsule) {
216 std::string capsule_fragment;
217 ASSERT_TRUE(absl::HexStringToBytes(
218 "9ECA6A01" // ADDRESS_REQUEST capsule type
219 "1A" // capsule length = 26
220 // first requested address
221 "00" // request ID = 0
222 "04" // IP version = 4
223 "C000022A" // 192.0.2.42
224 "1F" // prefix length = 31
225 // second requested address
226 "01" // request ID = 1
227 "06" // IP version = 6
228 "20010db8123456780000000000000000" // 2001:db8:1234:5678::
229 "40", // prefix length = 64
230 &capsule_fragment));
231 Capsule expected_capsule = Capsule::AddressRequest();
232 quiche::QuicheIpAddress ip_address1;
233 ip_address1.FromString("192.0.2.42");
234 PrefixWithId requested_address1;
235 requested_address1.request_id = 0;
236 requested_address1.ip_prefix =
237 quiche::QuicheIpPrefix(ip_address1, /*prefix_length=*/31);
238 expected_capsule.address_request_capsule().requested_addresses.push_back(
239 requested_address1);
240 quiche::QuicheIpAddress ip_address2;
241 ip_address2.FromString("2001:db8:1234:5678::");
242 PrefixWithId requested_address2;
243 requested_address2.request_id = 1;
244 requested_address2.ip_prefix =
245 quiche::QuicheIpPrefix(ip_address2, /*prefix_length=*/64);
246 expected_capsule.address_request_capsule().requested_addresses.push_back(
247 requested_address2);
248 {
249 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
250 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
251 }
252 ValidateParserIsEmpty();
253 TestSerialization(expected_capsule, capsule_fragment);
254 }
255
TEST_F(CapsuleTest,RouteAdvertisementCapsule)256 TEST_F(CapsuleTest, RouteAdvertisementCapsule) {
257 std::string capsule_fragment;
258 ASSERT_TRUE(absl::HexStringToBytes(
259 "9ECA6A02" // ROUTE_ADVERTISEMENT capsule type
260 "2C" // capsule length = 44
261 // first IP address range
262 "04" // IP version = 4
263 "C0000218" // 192.0.2.24
264 "C000022A" // 192.0.2.42
265 "00" // ip protocol = 0
266 // second IP address range
267 "06" // IP version = 6
268 "00000000000000000000000000000000" // ::
269 "ffffffffffffffffffffffffffffffff" // all ones IPv6 address
270 "01", // ip protocol = 1 (ICMP)
271 &capsule_fragment));
272 Capsule expected_capsule = Capsule::RouteAdvertisement();
273 IpAddressRange ip_address_range1;
274 ip_address_range1.start_ip_address.FromString("192.0.2.24");
275 ip_address_range1.end_ip_address.FromString("192.0.2.42");
276 ip_address_range1.ip_protocol = 0;
277 expected_capsule.route_advertisement_capsule().ip_address_ranges.push_back(
278 ip_address_range1);
279 IpAddressRange ip_address_range2;
280 ip_address_range2.start_ip_address.FromString("::");
281 ip_address_range2.end_ip_address.FromString(
282 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
283 ip_address_range2.ip_protocol = 1;
284 expected_capsule.route_advertisement_capsule().ip_address_ranges.push_back(
285 ip_address_range2);
286 {
287 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
288 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
289 }
290 ValidateParserIsEmpty();
291 TestSerialization(expected_capsule, capsule_fragment);
292 }
293
TEST_F(CapsuleTest,WebTransportStreamData)294 TEST_F(CapsuleTest, WebTransportStreamData) {
295 std::string capsule_fragment;
296 ASSERT_TRUE(
297 absl::HexStringToBytes("990b4d3b" // WT_STREAM without FIN
298 "04" // capsule length
299 "17" // stream ID
300 "abcdef", // stream payload
301 &capsule_fragment));
302 Capsule expected_capsule = Capsule(WebTransportStreamDataCapsule());
303 expected_capsule.web_transport_stream_data().stream_id = 0x17;
304 expected_capsule.web_transport_stream_data().data = "\xab\xcd\xef";
305 expected_capsule.web_transport_stream_data().fin = false;
306 {
307 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
308 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
309 }
310 ValidateParserIsEmpty();
311 TestSerialization(expected_capsule, capsule_fragment);
312 }
TEST_F(CapsuleTest,WebTransportStreamDataHeader)313 TEST_F(CapsuleTest, WebTransportStreamDataHeader) {
314 std::string capsule_fragment;
315 ASSERT_TRUE(absl::HexStringToBytes(
316 "990b4d3b" // WT_STREAM without FIN
317 "04" // capsule length
318 "17", // stream ID
319 // three bytes of stream payload implied below
320 &capsule_fragment));
321 QuicheBufferAllocator* allocator = SimpleBufferAllocator::Get();
322 QuicheBuffer capsule_header =
323 quiche::SerializeWebTransportStreamCapsuleHeader(0x17, /*fin=*/false, 3,
324 allocator);
325 EXPECT_EQ(capsule_header.AsStringView(), capsule_fragment);
326 }
TEST_F(CapsuleTest,WebTransportStreamDataWithFin)327 TEST_F(CapsuleTest, WebTransportStreamDataWithFin) {
328 std::string capsule_fragment;
329 ASSERT_TRUE(
330 absl::HexStringToBytes("990b4d3c" // data with FIN
331 "04" // capsule length
332 "17" // stream ID
333 "abcdef", // stream payload
334 &capsule_fragment));
335 Capsule expected_capsule = Capsule(WebTransportStreamDataCapsule());
336 expected_capsule.web_transport_stream_data().stream_id = 0x17;
337 expected_capsule.web_transport_stream_data().data = "\xab\xcd\xef";
338 expected_capsule.web_transport_stream_data().fin = true;
339 {
340 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
341 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
342 }
343 ValidateParserIsEmpty();
344 TestSerialization(expected_capsule, capsule_fragment);
345 }
346
TEST_F(CapsuleTest,WebTransportResetStream)347 TEST_F(CapsuleTest, WebTransportResetStream) {
348 std::string capsule_fragment;
349 ASSERT_TRUE(
350 absl::HexStringToBytes("990b4d39" // WT_RESET_STREAM
351 "02" // capsule length
352 "17" // stream ID
353 "07", // error code
354 &capsule_fragment));
355 Capsule expected_capsule = Capsule(WebTransportResetStreamCapsule());
356 expected_capsule.web_transport_reset_stream().stream_id = 0x17;
357 expected_capsule.web_transport_reset_stream().error_code = 0x07;
358 {
359 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
360 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
361 }
362 ValidateParserIsEmpty();
363 TestSerialization(expected_capsule, capsule_fragment);
364 }
365
TEST_F(CapsuleTest,WebTransportStopSending)366 TEST_F(CapsuleTest, WebTransportStopSending) {
367 std::string capsule_fragment;
368 ASSERT_TRUE(
369 absl::HexStringToBytes("990b4d3a" // WT_STOP_SENDING
370 "02" // capsule length
371 "17" // stream ID
372 "07", // error code
373 &capsule_fragment));
374 Capsule expected_capsule = Capsule(WebTransportStopSendingCapsule());
375 expected_capsule.web_transport_stop_sending().stream_id = 0x17;
376 expected_capsule.web_transport_stop_sending().error_code = 0x07;
377 {
378 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
379 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
380 }
381 ValidateParserIsEmpty();
382 TestSerialization(expected_capsule, capsule_fragment);
383 }
384
TEST_F(CapsuleTest,WebTransportMaxStreamData)385 TEST_F(CapsuleTest, WebTransportMaxStreamData) {
386 std::string capsule_fragment;
387 ASSERT_TRUE(
388 absl::HexStringToBytes("990b4d3e" // WT_MAX_STREAM_DATA
389 "02" // capsule length
390 "17" // stream ID
391 "10", // max stream data
392 &capsule_fragment));
393 Capsule expected_capsule = Capsule(WebTransportMaxStreamDataCapsule());
394 expected_capsule.web_transport_max_stream_data().stream_id = 0x17;
395 expected_capsule.web_transport_max_stream_data().max_stream_data = 0x10;
396 {
397 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
398 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
399 }
400 ValidateParserIsEmpty();
401 TestSerialization(expected_capsule, capsule_fragment);
402 }
403
TEST_F(CapsuleTest,WebTransportMaxStreamsBi)404 TEST_F(CapsuleTest, WebTransportMaxStreamsBi) {
405 std::string capsule_fragment;
406 ASSERT_TRUE(
407 absl::HexStringToBytes("990b4d3f" // WT_MAX_STREAMS (bidi)
408 "01" // capsule length
409 "17", // max streams
410 &capsule_fragment));
411 Capsule expected_capsule = Capsule(WebTransportMaxStreamsCapsule());
412 expected_capsule.web_transport_max_streams().stream_type =
413 StreamType::kBidirectional;
414 expected_capsule.web_transport_max_streams().max_stream_count = 0x17;
415 {
416 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
417 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
418 }
419 ValidateParserIsEmpty();
420 TestSerialization(expected_capsule, capsule_fragment);
421 }
422
TEST_F(CapsuleTest,WebTransportMaxStreamsUni)423 TEST_F(CapsuleTest, WebTransportMaxStreamsUni) {
424 std::string capsule_fragment;
425 ASSERT_TRUE(
426 absl::HexStringToBytes("990b4d40" // WT_MAX_STREAMS (unidi)
427 "01" // capsule length
428 "17", // max streams
429 &capsule_fragment));
430 Capsule expected_capsule = Capsule(WebTransportMaxStreamsCapsule());
431 expected_capsule.web_transport_max_streams().stream_type =
432 StreamType::kUnidirectional;
433 expected_capsule.web_transport_max_streams().max_stream_count = 0x17;
434 {
435 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
436 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
437 }
438 ValidateParserIsEmpty();
439 TestSerialization(expected_capsule, capsule_fragment);
440 }
441
TEST_F(CapsuleTest,UnknownCapsule)442 TEST_F(CapsuleTest, UnknownCapsule) {
443 std::string capsule_fragment;
444 ASSERT_TRUE(
445 absl::HexStringToBytes("17" // unknown capsule type of 0x17
446 "08" // capsule length
447 "a1a2a3a4a5a6a7a8", // unknown capsule data
448 &capsule_fragment));
449 std::string unknown_capsule_data;
450 ASSERT_TRUE(
451 absl::HexStringToBytes("a1a2a3a4a5a6a7a8", &unknown_capsule_data));
452 Capsule expected_capsule = Capsule::Unknown(0x17, unknown_capsule_data);
453 {
454 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
455 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
456 }
457 ValidateParserIsEmpty();
458 TestSerialization(expected_capsule, capsule_fragment);
459 }
460
TEST_F(CapsuleTest,TwoCapsules)461 TEST_F(CapsuleTest, TwoCapsules) {
462 std::string capsule_fragment;
463 ASSERT_TRUE(
464 absl::HexStringToBytes("00" // DATAGRAM capsule type
465 "08" // capsule length
466 "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
467 "00" // DATAGRAM capsule type
468 "08" // capsule length
469 "b1b2b3b4b5b6b7b8", // HTTP Datagram payload
470 &capsule_fragment));
471 std::string datagram_payload1;
472 ASSERT_TRUE(absl::HexStringToBytes("a1a2a3a4a5a6a7a8", &datagram_payload1));
473 std::string datagram_payload2;
474 ASSERT_TRUE(absl::HexStringToBytes("b1b2b3b4b5b6b7b8", &datagram_payload2));
475 Capsule expected_capsule1 = Capsule::Datagram(datagram_payload1);
476 Capsule expected_capsule2 = Capsule::Datagram(datagram_payload2);
477 {
478 InSequence s;
479 EXPECT_CALL(visitor_, OnCapsule(expected_capsule1));
480 EXPECT_CALL(visitor_, OnCapsule(expected_capsule2));
481 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
482 }
483 ValidateParserIsEmpty();
484 }
485
TEST_F(CapsuleTest,TwoCapsulesPartialReads)486 TEST_F(CapsuleTest, TwoCapsulesPartialReads) {
487 std::string capsule_fragment1;
488 ASSERT_TRUE(absl::HexStringToBytes(
489 "00" // first capsule DATAGRAM capsule type
490 "08" // first capsule length
491 "a1a2a3a4", // first half of HTTP Datagram payload of first capsule
492 &capsule_fragment1));
493 std::string capsule_fragment2;
494 ASSERT_TRUE(absl::HexStringToBytes(
495 "a5a6a7a8" // second half of HTTP Datagram payload 1
496 "00", // second capsule DATAGRAM capsule type
497 &capsule_fragment2));
498 std::string capsule_fragment3;
499 ASSERT_TRUE(absl::HexStringToBytes(
500 "08" // second capsule length
501 "b1b2b3b4b5b6b7b8", // HTTP Datagram payload of second capsule
502 &capsule_fragment3));
503 capsule_parser_.ErrorIfThereIsRemainingBufferedData();
504 std::string datagram_payload1;
505 ASSERT_TRUE(absl::HexStringToBytes("a1a2a3a4a5a6a7a8", &datagram_payload1));
506 std::string datagram_payload2;
507 ASSERT_TRUE(absl::HexStringToBytes("b1b2b3b4b5b6b7b8", &datagram_payload2));
508 Capsule expected_capsule1 = Capsule::Datagram(datagram_payload1);
509 Capsule expected_capsule2 = Capsule::Datagram(datagram_payload2);
510 {
511 InSequence s;
512 EXPECT_CALL(visitor_, OnCapsule(expected_capsule1));
513 EXPECT_CALL(visitor_, OnCapsule(expected_capsule2));
514 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment1));
515 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment2));
516 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment3));
517 }
518 ValidateParserIsEmpty();
519 }
520
TEST_F(CapsuleTest,TwoCapsulesOneByteAtATime)521 TEST_F(CapsuleTest, TwoCapsulesOneByteAtATime) {
522 std::string capsule_fragment;
523 ASSERT_TRUE(
524 absl::HexStringToBytes("00" // DATAGRAM capsule type
525 "08" // capsule length
526 "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
527 "00" // DATAGRAM capsule type
528 "08" // capsule length
529 "b1b2b3b4b5b6b7b8", // HTTP Datagram payload
530 &capsule_fragment));
531 std::string datagram_payload1;
532 ASSERT_TRUE(absl::HexStringToBytes("a1a2a3a4a5a6a7a8", &datagram_payload1));
533 std::string datagram_payload2;
534 ASSERT_TRUE(absl::HexStringToBytes("b1b2b3b4b5b6b7b8", &datagram_payload2));
535 Capsule expected_capsule1 = Capsule::Datagram(datagram_payload1);
536 Capsule expected_capsule2 = Capsule::Datagram(datagram_payload2);
537 for (size_t i = 0; i < capsule_fragment.size(); i++) {
538 if (i < capsule_fragment.size() / 2 - 1) {
539 EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
540 ASSERT_TRUE(
541 capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
542 } else if (i == capsule_fragment.size() / 2 - 1) {
543 EXPECT_CALL(visitor_, OnCapsule(expected_capsule1));
544 ASSERT_TRUE(
545 capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
546 EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
547 } else if (i < capsule_fragment.size() - 1) {
548 EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
549 ASSERT_TRUE(
550 capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
551 } else {
552 EXPECT_CALL(visitor_, OnCapsule(expected_capsule2));
553 ASSERT_TRUE(
554 capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
555 EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
556 }
557 }
558 capsule_parser_.ErrorIfThereIsRemainingBufferedData();
559 EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
560 }
561
TEST_F(CapsuleTest,PartialCapsuleThenError)562 TEST_F(CapsuleTest, PartialCapsuleThenError) {
563 std::string capsule_fragment;
564 ASSERT_TRUE(
565 absl::HexStringToBytes("00" // DATAGRAM capsule type
566 "08" // capsule length
567 "a1a2a3a4", // first half of HTTP Datagram payload
568 &capsule_fragment));
569 EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
570 {
571 EXPECT_CALL(visitor_, OnCapsuleParseFailure(_)).Times(0);
572 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
573 }
574 {
575 EXPECT_CALL(visitor_,
576 OnCapsuleParseFailure(
577 "Incomplete capsule left at the end of the stream"));
578 capsule_parser_.ErrorIfThereIsRemainingBufferedData();
579 }
580 }
581
TEST_F(CapsuleTest,RejectOverlyLongCapsule)582 TEST_F(CapsuleTest, RejectOverlyLongCapsule) {
583 std::string capsule_fragment;
584 ASSERT_TRUE(
585 absl::HexStringToBytes("17" // unknown capsule type of 0x17
586 "80123456", // capsule length
587 &capsule_fragment));
588 absl::StrAppend(&capsule_fragment, std::string(1111111, '?'));
589 EXPECT_CALL(visitor_, OnCapsuleParseFailure(
590 "Refusing to buffer too much capsule data"));
591 EXPECT_FALSE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
592 }
593
594 } // namespace
595 } // namespace test
596 } // namespace quiche
597