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 = absl::HexStringToBytes(
77 "00" // DATAGRAM capsule type
78 "08" // capsule length
79 "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
80 );
81 std::string datagram_payload = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
82 Capsule expected_capsule = Capsule::Datagram(datagram_payload);
83 {
84 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
85 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
86 }
87 ValidateParserIsEmpty();
88 TestSerialization(expected_capsule, capsule_fragment);
89 }
90
TEST_F(CapsuleTest,DatagramCapsuleViaHeader)91 TEST_F(CapsuleTest, DatagramCapsuleViaHeader) {
92 std::string datagram_payload = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
93 quiche::QuicheBuffer expected_capsule = SerializeCapsule(
94 Capsule::Datagram(datagram_payload), SimpleBufferAllocator::Get());
95 quiche::QuicheBuffer actual_header = SerializeDatagramCapsuleHeader(
96 datagram_payload.size(), SimpleBufferAllocator::Get());
97 EXPECT_EQ(expected_capsule.AsStringView(),
98 absl::StrCat(actual_header.AsStringView(), datagram_payload));
99 }
100
TEST_F(CapsuleTest,LegacyDatagramCapsule)101 TEST_F(CapsuleTest, LegacyDatagramCapsule) {
102 std::string capsule_fragment = absl::HexStringToBytes(
103 "80ff37a0" // LEGACY_DATAGRAM capsule type
104 "08" // capsule length
105 "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
106 );
107 std::string datagram_payload = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
108 Capsule expected_capsule = Capsule::LegacyDatagram(datagram_payload);
109 {
110 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
111 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
112 }
113 ValidateParserIsEmpty();
114 TestSerialization(expected_capsule, capsule_fragment);
115 }
116
TEST_F(CapsuleTest,LegacyDatagramWithoutContextCapsule)117 TEST_F(CapsuleTest, LegacyDatagramWithoutContextCapsule) {
118 std::string capsule_fragment = absl::HexStringToBytes(
119 "80ff37a5" // LEGACY_DATAGRAM_WITHOUT_CONTEXT capsule type
120 "08" // capsule length
121 "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
122 );
123 std::string datagram_payload = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
124 Capsule expected_capsule =
125 Capsule::LegacyDatagramWithoutContext(datagram_payload);
126 {
127 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
128 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
129 }
130 ValidateParserIsEmpty();
131 TestSerialization(expected_capsule, capsule_fragment);
132 }
133
TEST_F(CapsuleTest,CloseWebTransportStreamCapsule)134 TEST_F(CapsuleTest, CloseWebTransportStreamCapsule) {
135 std::string capsule_fragment = absl::HexStringToBytes(
136 "6843" // CLOSE_WEBTRANSPORT_STREAM capsule type
137 "09" // capsule length
138 "00001234" // 0x1234 error code
139 "68656c6c6f" // "hello" error message
140 );
141 Capsule expected_capsule = Capsule::CloseWebTransportSession(
142 /*error_code=*/0x1234, /*error_message=*/"hello");
143 {
144 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
145 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
146 }
147 ValidateParserIsEmpty();
148 TestSerialization(expected_capsule, capsule_fragment);
149 }
150
TEST_F(CapsuleTest,DrainWebTransportStreamCapsule)151 TEST_F(CapsuleTest, DrainWebTransportStreamCapsule) {
152 std::string capsule_fragment = absl::HexStringToBytes(
153 "800078ae" // DRAIN_WEBTRANSPORT_STREAM capsule type
154 "00" // capsule length
155 );
156 Capsule expected_capsule = Capsule(DrainWebTransportSessionCapsule());
157 {
158 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
159 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
160 }
161 ValidateParserIsEmpty();
162 TestSerialization(expected_capsule, capsule_fragment);
163 }
164
TEST_F(CapsuleTest,AddressAssignCapsule)165 TEST_F(CapsuleTest, AddressAssignCapsule) {
166 std::string capsule_fragment = absl::HexStringToBytes(
167 "9ECA6A00" // ADDRESS_ASSIGN capsule type
168 "1A" // capsule length = 26
169 // first assigned address
170 "00" // request ID = 0
171 "04" // IP version = 4
172 "C000022A" // 192.0.2.42
173 "1F" // prefix length = 31
174 // second assigned address
175 "01" // request ID = 1
176 "06" // IP version = 6
177 "20010db8123456780000000000000000" // 2001:db8:1234:5678::
178 "40" // prefix length = 64
179 );
180 Capsule expected_capsule = Capsule::AddressAssign();
181 quiche::QuicheIpAddress ip_address1;
182 ip_address1.FromString("192.0.2.42");
183 PrefixWithId assigned_address1;
184 assigned_address1.request_id = 0;
185 assigned_address1.ip_prefix =
186 quiche::QuicheIpPrefix(ip_address1, /*prefix_length=*/31);
187 expected_capsule.address_assign_capsule().assigned_addresses.push_back(
188 assigned_address1);
189 quiche::QuicheIpAddress ip_address2;
190 ip_address2.FromString("2001:db8:1234:5678::");
191 PrefixWithId assigned_address2;
192 assigned_address2.request_id = 1;
193 assigned_address2.ip_prefix =
194 quiche::QuicheIpPrefix(ip_address2, /*prefix_length=*/64);
195 expected_capsule.address_assign_capsule().assigned_addresses.push_back(
196 assigned_address2);
197 {
198 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
199 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
200 }
201 ValidateParserIsEmpty();
202 TestSerialization(expected_capsule, capsule_fragment);
203 }
204
TEST_F(CapsuleTest,AddressRequestCapsule)205 TEST_F(CapsuleTest, AddressRequestCapsule) {
206 std::string capsule_fragment = absl::HexStringToBytes(
207 "9ECA6A01" // ADDRESS_REQUEST capsule type
208 "1A" // capsule length = 26
209 // first requested address
210 "00" // request ID = 0
211 "04" // IP version = 4
212 "C000022A" // 192.0.2.42
213 "1F" // prefix length = 31
214 // second requested address
215 "01" // request ID = 1
216 "06" // IP version = 6
217 "20010db8123456780000000000000000" // 2001:db8:1234:5678::
218 "40" // prefix length = 64
219 );
220 Capsule expected_capsule = Capsule::AddressRequest();
221 quiche::QuicheIpAddress ip_address1;
222 ip_address1.FromString("192.0.2.42");
223 PrefixWithId requested_address1;
224 requested_address1.request_id = 0;
225 requested_address1.ip_prefix =
226 quiche::QuicheIpPrefix(ip_address1, /*prefix_length=*/31);
227 expected_capsule.address_request_capsule().requested_addresses.push_back(
228 requested_address1);
229 quiche::QuicheIpAddress ip_address2;
230 ip_address2.FromString("2001:db8:1234:5678::");
231 PrefixWithId requested_address2;
232 requested_address2.request_id = 1;
233 requested_address2.ip_prefix =
234 quiche::QuicheIpPrefix(ip_address2, /*prefix_length=*/64);
235 expected_capsule.address_request_capsule().requested_addresses.push_back(
236 requested_address2);
237 {
238 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
239 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
240 }
241 ValidateParserIsEmpty();
242 TestSerialization(expected_capsule, capsule_fragment);
243 }
244
TEST_F(CapsuleTest,RouteAdvertisementCapsule)245 TEST_F(CapsuleTest, RouteAdvertisementCapsule) {
246 std::string capsule_fragment = absl::HexStringToBytes(
247 "9ECA6A02" // ROUTE_ADVERTISEMENT capsule type
248 "2C" // capsule length = 44
249 // first IP address range
250 "04" // IP version = 4
251 "C0000218" // 192.0.2.24
252 "C000022A" // 192.0.2.42
253 "00" // ip protocol = 0
254 // second IP address range
255 "06" // IP version = 6
256 "00000000000000000000000000000000" // ::
257 "ffffffffffffffffffffffffffffffff" // all ones IPv6 address
258 "01" // ip protocol = 1 (ICMP)
259 );
260 Capsule expected_capsule = Capsule::RouteAdvertisement();
261 IpAddressRange ip_address_range1;
262 ip_address_range1.start_ip_address.FromString("192.0.2.24");
263 ip_address_range1.end_ip_address.FromString("192.0.2.42");
264 ip_address_range1.ip_protocol = 0;
265 expected_capsule.route_advertisement_capsule().ip_address_ranges.push_back(
266 ip_address_range1);
267 IpAddressRange ip_address_range2;
268 ip_address_range2.start_ip_address.FromString("::");
269 ip_address_range2.end_ip_address.FromString(
270 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
271 ip_address_range2.ip_protocol = 1;
272 expected_capsule.route_advertisement_capsule().ip_address_ranges.push_back(
273 ip_address_range2);
274 {
275 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
276 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
277 }
278 ValidateParserIsEmpty();
279 TestSerialization(expected_capsule, capsule_fragment);
280 }
281
TEST_F(CapsuleTest,WebTransportStreamData)282 TEST_F(CapsuleTest, WebTransportStreamData) {
283 std::string capsule_fragment = absl::HexStringToBytes(
284 "990b4d3b" // WT_STREAM without FIN
285 "04" // capsule length
286 "17" // stream ID
287 "abcdef" // stream payload
288 );
289 Capsule expected_capsule = Capsule(WebTransportStreamDataCapsule());
290 expected_capsule.web_transport_stream_data().stream_id = 0x17;
291 expected_capsule.web_transport_stream_data().data = "\xab\xcd\xef";
292 expected_capsule.web_transport_stream_data().fin = false;
293 {
294 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
295 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
296 }
297 ValidateParserIsEmpty();
298 TestSerialization(expected_capsule, capsule_fragment);
299 }
TEST_F(CapsuleTest,WebTransportStreamDataWithFin)300 TEST_F(CapsuleTest, WebTransportStreamDataWithFin) {
301 std::string capsule_fragment = absl::HexStringToBytes(
302 "990b4d3c" // data with FIN
303 "04" // capsule length
304 "17" // stream ID
305 "abcdef" // stream payload
306 );
307 Capsule expected_capsule = Capsule(WebTransportStreamDataCapsule());
308 expected_capsule.web_transport_stream_data().stream_id = 0x17;
309 expected_capsule.web_transport_stream_data().data = "\xab\xcd\xef";
310 expected_capsule.web_transport_stream_data().fin = true;
311 {
312 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
313 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
314 }
315 ValidateParserIsEmpty();
316 TestSerialization(expected_capsule, capsule_fragment);
317 }
318
TEST_F(CapsuleTest,WebTransportResetStream)319 TEST_F(CapsuleTest, WebTransportResetStream) {
320 std::string capsule_fragment = absl::HexStringToBytes(
321 "990b4d39" // WT_RESET_STREAM
322 "02" // capsule length
323 "17" // stream ID
324 "07" // error code
325 );
326 Capsule expected_capsule = Capsule(WebTransportResetStreamCapsule());
327 expected_capsule.web_transport_reset_stream().stream_id = 0x17;
328 expected_capsule.web_transport_reset_stream().error_code = 0x07;
329 {
330 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
331 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
332 }
333 ValidateParserIsEmpty();
334 TestSerialization(expected_capsule, capsule_fragment);
335 }
336
TEST_F(CapsuleTest,WebTransportStopSending)337 TEST_F(CapsuleTest, WebTransportStopSending) {
338 std::string capsule_fragment = absl::HexStringToBytes(
339 "990b4d3a" // WT_STOP_SENDING
340 "02" // capsule length
341 "17" // stream ID
342 "07" // error code
343 );
344 Capsule expected_capsule = Capsule(WebTransportStopSendingCapsule());
345 expected_capsule.web_transport_stop_sending().stream_id = 0x17;
346 expected_capsule.web_transport_stop_sending().error_code = 0x07;
347 {
348 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
349 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
350 }
351 ValidateParserIsEmpty();
352 TestSerialization(expected_capsule, capsule_fragment);
353 }
354
TEST_F(CapsuleTest,WebTransportMaxStreamData)355 TEST_F(CapsuleTest, WebTransportMaxStreamData) {
356 std::string capsule_fragment = absl::HexStringToBytes(
357 "990b4d3e" // WT_MAX_STREAM_DATA
358 "02" // capsule length
359 "17" // stream ID
360 "10" // max stream data
361 );
362 Capsule expected_capsule = Capsule(WebTransportMaxStreamDataCapsule());
363 expected_capsule.web_transport_max_stream_data().stream_id = 0x17;
364 expected_capsule.web_transport_max_stream_data().max_stream_data = 0x10;
365 {
366 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
367 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
368 }
369 ValidateParserIsEmpty();
370 TestSerialization(expected_capsule, capsule_fragment);
371 }
372
TEST_F(CapsuleTest,WebTransportMaxStreamsBi)373 TEST_F(CapsuleTest, WebTransportMaxStreamsBi) {
374 std::string capsule_fragment = absl::HexStringToBytes(
375 "990b4d3f" // WT_MAX_STREAMS (bidi)
376 "01" // capsule length
377 "17" // max streams
378 );
379 Capsule expected_capsule = Capsule(WebTransportMaxStreamsCapsule());
380 expected_capsule.web_transport_max_streams().stream_type =
381 StreamType::kBidirectional;
382 expected_capsule.web_transport_max_streams().max_stream_count = 0x17;
383 {
384 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
385 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
386 }
387 ValidateParserIsEmpty();
388 TestSerialization(expected_capsule, capsule_fragment);
389 }
390
TEST_F(CapsuleTest,WebTransportMaxStreamsUni)391 TEST_F(CapsuleTest, WebTransportMaxStreamsUni) {
392 std::string capsule_fragment = absl::HexStringToBytes(
393 "990b4d40" // WT_MAX_STREAMS (unidi)
394 "01" // capsule length
395 "17" // max streams
396 );
397 Capsule expected_capsule = Capsule(WebTransportMaxStreamsCapsule());
398 expected_capsule.web_transport_max_streams().stream_type =
399 StreamType::kUnidirectional;
400 expected_capsule.web_transport_max_streams().max_stream_count = 0x17;
401 {
402 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
403 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
404 }
405 ValidateParserIsEmpty();
406 TestSerialization(expected_capsule, capsule_fragment);
407 }
408
TEST_F(CapsuleTest,UnknownCapsule)409 TEST_F(CapsuleTest, UnknownCapsule) {
410 std::string capsule_fragment = absl::HexStringToBytes(
411 "17" // unknown capsule type of 0x17
412 "08" // capsule length
413 "a1a2a3a4a5a6a7a8" // unknown capsule data
414 );
415 std::string unknown_capsule_data = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
416 Capsule expected_capsule = Capsule::Unknown(0x17, unknown_capsule_data);
417 {
418 EXPECT_CALL(visitor_, OnCapsule(expected_capsule));
419 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
420 }
421 ValidateParserIsEmpty();
422 TestSerialization(expected_capsule, capsule_fragment);
423 }
424
TEST_F(CapsuleTest,TwoCapsules)425 TEST_F(CapsuleTest, TwoCapsules) {
426 std::string capsule_fragment = absl::HexStringToBytes(
427 "00" // DATAGRAM capsule type
428 "08" // capsule length
429 "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
430 "00" // DATAGRAM capsule type
431 "08" // capsule length
432 "b1b2b3b4b5b6b7b8" // HTTP Datagram payload
433 );
434 std::string datagram_payload1 = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
435 std::string datagram_payload2 = absl::HexStringToBytes("b1b2b3b4b5b6b7b8");
436 Capsule expected_capsule1 = Capsule::Datagram(datagram_payload1);
437 Capsule expected_capsule2 = Capsule::Datagram(datagram_payload2);
438 {
439 InSequence s;
440 EXPECT_CALL(visitor_, OnCapsule(expected_capsule1));
441 EXPECT_CALL(visitor_, OnCapsule(expected_capsule2));
442 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
443 }
444 ValidateParserIsEmpty();
445 }
446
TEST_F(CapsuleTest,TwoCapsulesPartialReads)447 TEST_F(CapsuleTest, TwoCapsulesPartialReads) {
448 std::string capsule_fragment1 = absl::HexStringToBytes(
449 "00" // first capsule DATAGRAM capsule type
450 "08" // first capsule length
451 "a1a2a3a4" // first half of HTTP Datagram payload of first capsule
452 );
453 std::string capsule_fragment2 = absl::HexStringToBytes(
454 "a5a6a7a8" // second half of HTTP Datagram payload 1
455 "00" // second capsule DATAGRAM capsule type
456 );
457 std::string capsule_fragment3 = absl::HexStringToBytes(
458 "08" // second capsule length
459 "b1b2b3b4b5b6b7b8" // HTTP Datagram payload of second capsule
460 );
461 capsule_parser_.ErrorIfThereIsRemainingBufferedData();
462 std::string datagram_payload1 = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
463 std::string datagram_payload2 = absl::HexStringToBytes("b1b2b3b4b5b6b7b8");
464 Capsule expected_capsule1 = Capsule::Datagram(datagram_payload1);
465 Capsule expected_capsule2 = Capsule::Datagram(datagram_payload2);
466 {
467 InSequence s;
468 EXPECT_CALL(visitor_, OnCapsule(expected_capsule1));
469 EXPECT_CALL(visitor_, OnCapsule(expected_capsule2));
470 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment1));
471 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment2));
472 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment3));
473 }
474 ValidateParserIsEmpty();
475 }
476
TEST_F(CapsuleTest,TwoCapsulesOneByteAtATime)477 TEST_F(CapsuleTest, TwoCapsulesOneByteAtATime) {
478 std::string capsule_fragment = absl::HexStringToBytes(
479 "00" // DATAGRAM capsule type
480 "08" // capsule length
481 "a1a2a3a4a5a6a7a8" // HTTP Datagram payload
482 "00" // DATAGRAM capsule type
483 "08" // capsule length
484 "b1b2b3b4b5b6b7b8" // HTTP Datagram payload
485 );
486 std::string datagram_payload1 = absl::HexStringToBytes("a1a2a3a4a5a6a7a8");
487 std::string datagram_payload2 = absl::HexStringToBytes("b1b2b3b4b5b6b7b8");
488 Capsule expected_capsule1 = Capsule::Datagram(datagram_payload1);
489 Capsule expected_capsule2 = Capsule::Datagram(datagram_payload2);
490 for (size_t i = 0; i < capsule_fragment.size(); i++) {
491 if (i < capsule_fragment.size() / 2 - 1) {
492 EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
493 ASSERT_TRUE(
494 capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
495 } else if (i == capsule_fragment.size() / 2 - 1) {
496 EXPECT_CALL(visitor_, OnCapsule(expected_capsule1));
497 ASSERT_TRUE(
498 capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
499 EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
500 } else if (i < capsule_fragment.size() - 1) {
501 EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
502 ASSERT_TRUE(
503 capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
504 } else {
505 EXPECT_CALL(visitor_, OnCapsule(expected_capsule2));
506 ASSERT_TRUE(
507 capsule_parser_.IngestCapsuleFragment(capsule_fragment.substr(i, 1)));
508 EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
509 }
510 }
511 capsule_parser_.ErrorIfThereIsRemainingBufferedData();
512 EXPECT_TRUE(CapsuleParserPeer::buffered_data(&capsule_parser_)->empty());
513 }
514
TEST_F(CapsuleTest,PartialCapsuleThenError)515 TEST_F(CapsuleTest, PartialCapsuleThenError) {
516 std::string capsule_fragment = absl::HexStringToBytes(
517 "00" // DATAGRAM capsule type
518 "08" // capsule length
519 "a1a2a3a4" // first half of HTTP Datagram payload
520 );
521 EXPECT_CALL(visitor_, OnCapsule(_)).Times(0);
522 {
523 EXPECT_CALL(visitor_, OnCapsuleParseFailure(_)).Times(0);
524 ASSERT_TRUE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
525 }
526 {
527 EXPECT_CALL(visitor_,
528 OnCapsuleParseFailure(
529 "Incomplete capsule left at the end of the stream"));
530 capsule_parser_.ErrorIfThereIsRemainingBufferedData();
531 }
532 }
533
TEST_F(CapsuleTest,RejectOverlyLongCapsule)534 TEST_F(CapsuleTest, RejectOverlyLongCapsule) {
535 std::string capsule_fragment = absl::HexStringToBytes(
536 "17" // unknown capsule type of 0x17
537 "80123456" // capsule length
538 ) +
539 std::string(1111111, '?');
540 EXPECT_CALL(visitor_, OnCapsuleParseFailure(
541 "Refusing to buffer too much capsule data"));
542 EXPECT_FALSE(capsule_parser_.IngestCapsuleFragment(capsule_fragment));
543 }
544
545 } // namespace
546 } // namespace test
547 } // namespace quiche
548