tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }