• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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