TestCapsule.cpp (11117B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "TestCommon.h" 7 #include "gtest/gtest.h" 8 #include "Capsule.h" 9 #include "CapsuleEncoder.h" 10 #include "CapsuleParser.h" 11 12 using namespace mozilla; 13 using namespace mozilla::net; 14 15 TEST(TestCapsule, UnknownCapsule) 16 { 17 nsTArray<uint8_t> data({0x1, 0x2}); 18 nsTArray<uint8_t> cloned(data.Clone()); 19 Capsule capsule = Capsule::Unknown(0x1234, std::move(cloned)); 20 CapsuleEncoder encoder; 21 encoder.EncodeCapsule(capsule); 22 auto buffer = encoder.GetBuffer(); 23 24 RefPtr<CapsuleParserListener> listener = new CapsuleParserListener(); 25 UniquePtr<CapsuleParser> parser = MakeUnique<CapsuleParser>(listener); 26 bool res = parser->ProcessCapsuleData(buffer.Elements(), buffer.Length()); 27 ASSERT_TRUE(res); 28 29 Maybe<nsresult> error = listener->GetErrorResult(); 30 ASSERT_TRUE(error.isNothing()); 31 32 nsTArray<Capsule> parsed = listener->GetParsedCapsules(); 33 ASSERT_EQ(parsed.Length(), 1u); 34 35 UnknownCapsule& unknown = parsed[0].GetUnknownCapsule(); 36 ASSERT_EQ(unknown.mData, data); 37 38 ASSERT_TRUE(parser->IsBufferEmpty()); 39 } 40 41 TEST(TestCapsule, CloseWebTransportSessionCapsule) 42 { 43 nsCString reason("test"); 44 Capsule capsule = Capsule::CloseWebTransportSession(42, reason); 45 CapsuleEncoder encoder; 46 encoder.EncodeCapsule(capsule); 47 auto buffer = encoder.GetBuffer(); 48 49 RefPtr<CapsuleParserListener> listener = new CapsuleParserListener(); 50 UniquePtr<CapsuleParser> parser = MakeUnique<CapsuleParser>(listener); 51 bool res = parser->ProcessCapsuleData(buffer.Elements(), buffer.Length()); 52 ASSERT_TRUE(res); 53 54 Maybe<nsresult> error = listener->GetErrorResult(); 55 ASSERT_TRUE(error.isNothing()); 56 57 nsTArray<Capsule> parsed = listener->GetParsedCapsules(); 58 ASSERT_EQ(parsed.Length(), 1u); 59 60 CloseWebTransportSessionCapsule& parsedCapsule = 61 parsed[0].GetCloseWebTransportSessionCapsule(); 62 ASSERT_EQ(parsedCapsule.mStatus, 42u); 63 ASSERT_EQ(parsedCapsule.mReason, reason); 64 65 ASSERT_TRUE(parser->IsBufferEmpty()); 66 } 67 68 TEST(TestCapsule, CloseWebTransportSessionCapsuleWithReasonTooLong) 69 { 70 nsCString reason; 71 for (uint32_t i = 0; i < 1025; i++) { 72 reason.AppendLiteral("1"); 73 } 74 75 Capsule capsule = Capsule::CloseWebTransportSession(42, reason); 76 CapsuleEncoder encoder; 77 encoder.EncodeCapsule(capsule); 78 auto buffer = encoder.GetBuffer(); 79 80 RefPtr<CapsuleParserListener> listener = new CapsuleParserListener(); 81 UniquePtr<CapsuleParser> parser = MakeUnique<CapsuleParser>(listener); 82 bool res = parser->ProcessCapsuleData(buffer.Elements(), buffer.Length()); 83 ASSERT_FALSE(res); 84 85 Maybe<nsresult> error = listener->GetErrorResult(); 86 ASSERT_TRUE(error.isSome()); 87 ASSERT_EQ(*error, NS_ERROR_UNEXPECTED); 88 89 nsTArray<Capsule> parsed = listener->GetParsedCapsules(); 90 ASSERT_EQ(parsed.Length(), 0u); 91 92 ASSERT_TRUE(parser->IsBufferEmpty()); 93 } 94 95 TEST(TestCapsule, MultipleCapsules) 96 { 97 nsCString reason("test"); 98 Capsule capsule1 = Capsule::CloseWebTransportSession(42, reason); 99 100 nsTArray<uint8_t> data({0x1, 0x2, 0x3, 0x4}); 101 Capsule capsule2 = Capsule::WebTransportStreamData(0, true, std::move(data)); 102 103 CapsuleEncoder encoder; 104 encoder.EncodeCapsule(capsule1); 105 encoder.EncodeCapsule(capsule2); 106 107 auto buffer = encoder.GetBuffer(); 108 109 RefPtr<CapsuleParserListener> listener = new CapsuleParserListener(); 110 UniquePtr<CapsuleParser> parser = MakeUnique<CapsuleParser>(listener); 111 bool res = parser->ProcessCapsuleData(buffer.Elements(), buffer.Length()); 112 ASSERT_TRUE(res); 113 114 Maybe<nsresult> error = listener->GetErrorResult(); 115 ASSERT_TRUE(error.isNothing()); 116 117 nsTArray<Capsule> parsed = listener->GetParsedCapsules(); 118 ASSERT_EQ(parsed.Length(), 2u); 119 120 CloseWebTransportSessionCapsule& parsedCapsule = 121 parsed[0].GetCloseWebTransportSessionCapsule(); 122 ASSERT_EQ(parsedCapsule.mStatus, 42u); 123 ASSERT_EQ(parsedCapsule.mReason, reason); 124 125 WebTransportStreamDataCapsule& streamData = 126 parsed[1].GetWebTransportStreamDataCapsule(); 127 ASSERT_EQ(streamData.mID, 0u); 128 ASSERT_EQ(streamData.mData.Length(), 4u); 129 130 ASSERT_TRUE(parser->IsBufferEmpty()); 131 } 132 133 TEST(TestCapsule, WouldBlock) 134 { 135 nsCString reason("test"); 136 Capsule capsule1 = Capsule::CloseWebTransportSession(42, reason); 137 138 nsTArray<uint8_t> data; 139 for (uint32_t i = 0; i < 4096; i++) { 140 data.AppendElement(0x2); 141 } 142 Capsule capsule2 = Capsule::WebTransportStreamData(0, true, std::move(data)); 143 144 CapsuleEncoder encoder; 145 encoder.EncodeCapsule(capsule1); 146 encoder.EncodeCapsule(capsule2); 147 148 auto buffer = encoder.GetBuffer(); 149 150 const uint8_t* buf1 = buffer.Elements(); 151 uint32_t firstHalf = buffer.Length() / 2; 152 153 const uint8_t* buf2 = buffer.Elements() + firstHalf; 154 uint32_t secondHalf = buffer.Length() - firstHalf; 155 156 RefPtr<CapsuleParserListener> listener = new CapsuleParserListener(); 157 UniquePtr<CapsuleParser> parser = MakeUnique<CapsuleParser>(listener); 158 bool res = parser->ProcessCapsuleData(buf1, firstHalf); 159 ASSERT_TRUE(res); 160 161 Maybe<nsresult> error = listener->GetErrorResult(); 162 ASSERT_TRUE(error.isNothing()); 163 164 nsTArray<Capsule> parsed = listener->GetParsedCapsules(); 165 ASSERT_EQ(parsed.Length(), 1u); 166 167 CloseWebTransportSessionCapsule& parsedCapsule = 168 parsed[0].GetCloseWebTransportSessionCapsule(); 169 ASSERT_EQ(parsedCapsule.mStatus, 42u); 170 ASSERT_EQ(parsedCapsule.mReason, reason); 171 172 ASSERT_FALSE(parser->IsBufferEmpty()); 173 174 res = parser->ProcessCapsuleData(buf2, secondHalf); 175 parsed = listener->GetParsedCapsules(); 176 ASSERT_EQ(parsed.Length(), 1u); 177 178 WebTransportStreamDataCapsule& streamData = 179 parsed[0].GetWebTransportStreamDataCapsule(); 180 ASSERT_EQ(streamData.mID, 0u); 181 ASSERT_EQ(streamData.mData.Length(), 4096u); 182 183 ASSERT_TRUE(parser->IsBufferEmpty()); 184 } 185 186 TEST(TestCapsule, WouldBlock1) 187 { 188 nsTArray<uint8_t> data; 189 for (uint32_t i = 0; i < 4096; i++) { 190 data.AppendElement(0x2); 191 } 192 Capsule capsule1 = Capsule::WebTransportStreamData(0, true, std::move(data)); 193 194 nsCString reason("test"); 195 Capsule capsule2 = Capsule::CloseWebTransportSession(42, reason); 196 197 CapsuleEncoder encoder; 198 encoder.EncodeCapsule(capsule1); 199 encoder.EncodeCapsule(capsule2); 200 201 auto buffer = encoder.GetBuffer(); 202 203 const uint8_t* buf1 = buffer.Elements(); 204 uint32_t firstHalf = buffer.Length() / 2; 205 206 const uint8_t* buf2 = buffer.Elements() + firstHalf; 207 uint32_t secondHalf = buffer.Length() - firstHalf; 208 209 RefPtr<CapsuleParserListener> listener = new CapsuleParserListener(); 210 UniquePtr<CapsuleParser> parser = MakeUnique<CapsuleParser>(listener); 211 bool res = parser->ProcessCapsuleData(buf1, firstHalf); 212 ASSERT_TRUE(res); 213 214 Maybe<nsresult> error = listener->GetErrorResult(); 215 ASSERT_TRUE(error.isNothing()); 216 217 nsTArray<Capsule> parsed = listener->GetParsedCapsules(); 218 ASSERT_EQ(parsed.Length(), 0u); 219 220 ASSERT_FALSE(parser->IsBufferEmpty()); 221 222 res = parser->ProcessCapsuleData(buf2, secondHalf); 223 parsed = listener->GetParsedCapsules(); 224 ASSERT_EQ(parsed.Length(), 2u); 225 error = listener->GetErrorResult(); 226 ASSERT_TRUE(error.isNothing()); 227 228 WebTransportStreamDataCapsule& streamData = 229 parsed[0].GetWebTransportStreamDataCapsule(); 230 ASSERT_EQ(streamData.mID, 0u); 231 ASSERT_EQ(streamData.mData.Length(), 4096u); 232 233 CloseWebTransportSessionCapsule& parsedCapsule = 234 parsed[1].GetCloseWebTransportSessionCapsule(); 235 ASSERT_EQ(parsedCapsule.mStatus, 42u); 236 ASSERT_EQ(parsedCapsule.mReason, reason); 237 238 ASSERT_TRUE(parser->IsBufferEmpty()); 239 } 240 241 TEST(TestCapsule, WouldBlock2) 242 { 243 nsTArray<uint8_t> data; 244 for (uint32_t i = 0; i < 4096; i++) { 245 data.AppendElement(0x2); 246 } 247 Capsule capsule1 = Capsule::WebTransportStreamData(0, true, std::move(data)); 248 249 nsCString reason("test"); 250 Capsule capsule2 = Capsule::CloseWebTransportSession(42, reason); 251 252 CapsuleEncoder encoder; 253 encoder.EncodeCapsule(capsule1); 254 encoder.EncodeCapsule(capsule2); 255 256 auto buffer = encoder.GetBuffer(); 257 uint32_t totalLength = buffer.Length(); 258 259 // Split the buffer into three parts. 260 uint32_t part1Length = totalLength / 3; 261 uint32_t part2Length = totalLength / 3; 262 uint32_t part3Length = totalLength - part1Length - part2Length; 263 264 const uint8_t* buf1 = buffer.Elements(); 265 const uint8_t* buf2 = buffer.Elements() + part1Length; 266 const uint8_t* buf3 = buffer.Elements() + part1Length + part2Length; 267 268 RefPtr<CapsuleParserListener> listener = new CapsuleParserListener(); 269 UniquePtr<CapsuleParser> parser = MakeUnique<CapsuleParser>(listener); 270 271 // Process first part. 272 bool res = parser->ProcessCapsuleData(buf1, part1Length); 273 ASSERT_TRUE(res); 274 Maybe<nsresult> error = listener->GetErrorResult(); 275 ASSERT_TRUE(error.isNothing()); 276 nsTArray<Capsule> parsed = listener->GetParsedCapsules(); 277 // At this stage, we might not have a complete capsule yet. 278 ASSERT_EQ(parsed.Length(), 0u); 279 // The parser's internal buffer should not be empty. 280 ASSERT_FALSE(parser->IsBufferEmpty()); 281 282 // Process second part. 283 res = parser->ProcessCapsuleData(buf2, part2Length); 284 ASSERT_TRUE(res); 285 error = listener->GetErrorResult(); 286 ASSERT_TRUE(error.isNothing()); 287 // Still, we might be waiting for more data to form a complete capsule. 288 parsed = listener->GetParsedCapsules(); 289 // It's possible that no complete capsule is parsed yet, depending on how the 290 // data splits. We won't assert parsed.Length() here since it may vary. 291 292 // Process third part. 293 res = parser->ProcessCapsuleData(buf3, part3Length); 294 ASSERT_TRUE(res); 295 parsed = listener->GetParsedCapsules(); 296 // At the end, we should have parsed both capsules. 297 ASSERT_EQ(parsed.Length(), 2u); 298 error = listener->GetErrorResult(); 299 ASSERT_TRUE(error.isNothing()); 300 301 WebTransportStreamDataCapsule& streamData = 302 parsed[0].GetWebTransportStreamDataCapsule(); 303 ASSERT_EQ(streamData.mID, 0u); 304 ASSERT_EQ(streamData.mData.Length(), 4096u); 305 306 CloseWebTransportSessionCapsule& parsedCapsule = 307 parsed[1].GetCloseWebTransportSessionCapsule(); 308 ASSERT_EQ(parsedCapsule.mStatus, 42u); 309 ASSERT_EQ(parsedCapsule.mReason, reason); 310 311 ASSERT_TRUE(parser->IsBufferEmpty()); 312 } 313 314 TEST(TestCapsule, WebTransportMaxDataCapsule) 315 { 316 Capsule capsule = Capsule::WebTransportMaxData(16384); 317 CapsuleEncoder encoder; 318 encoder.EncodeCapsule(capsule); 319 320 auto buffer = encoder.GetBuffer(); 321 322 Capsule::LogBuffer(buffer.Elements(), buffer.Length()); 323 324 RefPtr<CapsuleParserListener> listener = new CapsuleParserListener(); 325 UniquePtr<CapsuleParser> parser = MakeUnique<CapsuleParser>(listener); 326 bool res = parser->ProcessCapsuleData(buffer.Elements(), buffer.Length()); 327 ASSERT_TRUE(res); 328 329 Maybe<nsresult> error = listener->GetErrorResult(); 330 ASSERT_TRUE(error.isNothing()); 331 332 nsTArray<Capsule> parsed = listener->GetParsedCapsules(); 333 ASSERT_EQ(parsed.Length(), 1u); 334 335 WebTransportMaxDataCapsule& parsedCapsule = 336 parsed[0].GetWebTransportMaxDataCapsule(); 337 ASSERT_EQ(parsedCapsule.mMaxDataSize, 16384u); 338 339 ASSERT_TRUE(parser->IsBufferEmpty()); 340 }