tor-browser

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

TestDataPipe.cpp (10866B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "chrome/common/ipc_message.h"
      8 #include "gtest/gtest.h"
      9 
     10 #include "mozilla/gtest/MozAssertions.h"
     11 #include "mozilla/ipc/DataPipe.h"
     12 #include "nsIAsyncInputStream.h"
     13 #include "nsIAsyncOutputStream.h"
     14 #include "nsNetUtil.h"
     15 #include "nsStreamUtils.h"
     16 
     17 namespace mozilla::ipc {
     18 
     19 namespace {
     20 
     21 struct InputStreamCallback : public nsIInputStreamCallback {
     22 public:
     23  NS_DECL_THREADSAFE_ISUPPORTS
     24 
     25  explicit InputStreamCallback(
     26      std::function<nsresult(nsIAsyncInputStream*)> aFunc = nullptr)
     27      : mFunc(std::move(aFunc)) {}
     28 
     29  NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream* aStream) override {
     30    MOZ_ALWAYS_FALSE(mCalled.exchange(true));
     31    return mFunc ? mFunc(aStream) : NS_OK;
     32  }
     33 
     34  bool Called() const { return mCalled; }
     35 
     36 private:
     37  virtual ~InputStreamCallback() = default;
     38 
     39  std::atomic<bool> mCalled = false;
     40  std::function<nsresult(nsIAsyncInputStream*)> mFunc;
     41 };
     42 
     43 NS_IMPL_ISUPPORTS(InputStreamCallback, nsIInputStreamCallback)
     44 
     45 struct OutputStreamCallback : public nsIOutputStreamCallback {
     46 public:
     47  NS_DECL_THREADSAFE_ISUPPORTS
     48 
     49  explicit OutputStreamCallback(
     50      std::function<nsresult(nsIAsyncOutputStream*)> aFunc = nullptr)
     51      : mFunc(std::move(aFunc)) {}
     52 
     53  NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream* aStream) override {
     54    MOZ_ALWAYS_FALSE(mCalled.exchange(true));
     55    return mFunc ? mFunc(aStream) : NS_OK;
     56  }
     57 
     58  bool Called() const { return mCalled; }
     59 
     60 private:
     61  virtual ~OutputStreamCallback() = default;
     62 
     63  std::atomic<bool> mCalled = false;
     64  std::function<nsresult(nsIAsyncOutputStream*)> mFunc;
     65 };
     66 
     67 NS_IMPL_ISUPPORTS(OutputStreamCallback, nsIOutputStreamCallback)
     68 
     69 // Populate an array with the given number of bytes.  Data is lorem ipsum
     70 // random text, but deterministic across multiple calls.
     71 void CreateData(uint32_t aNumBytes, nsCString& aDataOut) {
     72  static const char data[] =
     73      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec egestas "
     74      "purus eu condimentum iaculis. In accumsan leo eget odio porttitor, non "
     75      "rhoncus nulla vestibulum. Etiam lacinia consectetur nisl nec "
     76      "sollicitudin. Sed fringilla accumsan diam, pulvinar varius massa. Duis "
     77      "mollis dignissim felis, eget tempus nisi tristique ut. Fusce euismod, "
     78      "lectus non lacinia tempor, tellus diam suscipit quam, eget hendrerit "
     79      "lacus nunc fringilla ante. Sed ultrices massa vitae risus molestie, ut "
     80      "finibus quam laoreet nullam.";
     81  static const uint32_t dataLength = sizeof(data) - 1;
     82 
     83  aDataOut.SetCapacity(aNumBytes);
     84 
     85  while (aNumBytes > 0) {
     86    uint32_t amount = std::min(dataLength, aNumBytes);
     87    aDataOut.Append(data, amount);
     88    aNumBytes -= amount;
     89  }
     90 }
     91 
     92 // Synchronously consume the given input stream and validate the resulting data
     93 // against the given string of expected values.
     94 void ConsumeAndValidateStream(nsIInputStream* aStream,
     95                              const nsACString& aExpectedData) {
     96  nsAutoCString outputData;
     97  nsresult rv = NS_ConsumeStream(aStream, UINT32_MAX, outputData);
     98  ASSERT_NS_SUCCEEDED(rv);
     99  ASSERT_EQ(aExpectedData.Length(), outputData.Length());
    100  ASSERT_TRUE(aExpectedData.Equals(outputData));
    101 }
    102 
    103 }  // namespace
    104 
    105 TEST(DataPipe, SegmentedReadWrite)
    106 {
    107  RefPtr<DataPipeReceiver> reader;
    108  RefPtr<DataPipeSender> writer;
    109 
    110  nsresult rv =
    111      NewDataPipe(1024, getter_AddRefs(writer), getter_AddRefs(reader));
    112  ASSERT_NS_SUCCEEDED(rv);
    113 
    114  nsCString inputData1;
    115  CreateData(512, inputData1);
    116 
    117  uint32_t numWritten = 0;
    118  rv = writer->Write(inputData1.BeginReading(), inputData1.Length(),
    119                     &numWritten);
    120  ASSERT_NS_SUCCEEDED(rv);
    121  EXPECT_EQ(numWritten, 512u);
    122 
    123  uint64_t available = 0;
    124  rv = reader->Available(&available);
    125  EXPECT_EQ(available, 512u);
    126  ConsumeAndValidateStream(reader, inputData1);
    127 
    128  nsCString inputData2;
    129  CreateData(1024, inputData2);
    130 
    131  rv = writer->Write(inputData2.BeginReading(), inputData2.Length(),
    132                     &numWritten);
    133  ASSERT_NS_SUCCEEDED(rv);
    134  EXPECT_EQ(numWritten, 1024u);
    135 
    136  rv = reader->Available(&available);
    137  EXPECT_EQ(available, 1024u);
    138  ConsumeAndValidateStream(reader, inputData2);
    139 }
    140 
    141 TEST(DataPipe, SegmentedPartialRead)
    142 {
    143  RefPtr<DataPipeReceiver> reader;
    144  RefPtr<DataPipeSender> writer;
    145 
    146  nsresult rv =
    147      NewDataPipe(1024, getter_AddRefs(writer), getter_AddRefs(reader));
    148  ASSERT_NS_SUCCEEDED(rv);
    149 
    150  nsCString inputData1;
    151  CreateData(512, inputData1);
    152 
    153  uint32_t numWritten = 0;
    154  rv = writer->Write(inputData1.BeginReading(), inputData1.Length(),
    155                     &numWritten);
    156  ASSERT_NS_SUCCEEDED(rv);
    157  EXPECT_EQ(numWritten, 512u);
    158 
    159  uint64_t available = 0;
    160  rv = reader->Available(&available);
    161  EXPECT_EQ(available, 512u);
    162  ConsumeAndValidateStream(reader, inputData1);
    163 
    164  nsCString inputData2;
    165  CreateData(1024, inputData2);
    166 
    167  rv = writer->Write(inputData2.BeginReading(), inputData2.Length(),
    168                     &numWritten);
    169  ASSERT_NS_SUCCEEDED(rv);
    170  EXPECT_EQ(numWritten, 1024u);
    171 
    172  rv = reader->Available(&available);
    173  EXPECT_EQ(available, 1024u);
    174 
    175  nsAutoCString outputData;
    176  rv = NS_ReadInputStreamToString(reader, outputData, 768);
    177  ASSERT_NS_SUCCEEDED(rv);
    178  ASSERT_EQ(768u, outputData.Length());
    179  ASSERT_TRUE(Substring(inputData2, 0, 768).Equals(outputData));
    180 
    181  rv = reader->Available(&available);
    182  EXPECT_EQ(available, 256u);
    183 
    184  nsAutoCString outputData2;
    185  rv = NS_ReadInputStreamToString(reader, outputData2, 256);
    186  ASSERT_NS_SUCCEEDED(rv);
    187  ASSERT_EQ(256u, outputData2.Length());
    188  ASSERT_TRUE(Substring(inputData2, 768).Equals(outputData2));
    189 }
    190 
    191 TEST(DataPipe, Write_AsyncWait)
    192 {
    193  RefPtr<DataPipeReceiver> reader;
    194  RefPtr<DataPipeSender> writer;
    195 
    196  const uint32_t segmentSize = 1024;
    197 
    198  nsresult rv =
    199      NewDataPipe(segmentSize, getter_AddRefs(writer), getter_AddRefs(reader));
    200  ASSERT_NS_SUCCEEDED(rv);
    201 
    202  nsCString inputData;
    203  CreateData(segmentSize, inputData);
    204 
    205  uint32_t numWritten = 0;
    206  rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten);
    207  ASSERT_NS_SUCCEEDED(rv);
    208  EXPECT_EQ(numWritten, segmentSize);
    209 
    210  rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten);
    211  ASSERT_EQ(NS_BASE_STREAM_WOULD_BLOCK, rv);
    212 
    213  RefPtr<OutputStreamCallback> cb = new OutputStreamCallback();
    214 
    215  rv = writer->AsyncWait(cb, 0, 0, GetCurrentSerialEventTarget());
    216  ASSERT_NS_SUCCEEDED(rv);
    217 
    218  NS_ProcessPendingEvents(nullptr);
    219 
    220  ASSERT_FALSE(cb->Called());
    221 
    222  ConsumeAndValidateStream(reader, inputData);
    223 
    224  ASSERT_FALSE(cb->Called());
    225 
    226  NS_ProcessPendingEvents(nullptr);
    227 
    228  ASSERT_TRUE(cb->Called());
    229 }
    230 
    231 TEST(DataPipe, Read_AsyncWait)
    232 {
    233  RefPtr<DataPipeReceiver> reader;
    234  RefPtr<DataPipeSender> writer;
    235 
    236  const uint32_t segmentSize = 1024;
    237 
    238  nsresult rv =
    239      NewDataPipe(segmentSize, getter_AddRefs(writer), getter_AddRefs(reader));
    240  ASSERT_NS_SUCCEEDED(rv);
    241 
    242  nsCString inputData;
    243  CreateData(segmentSize, inputData);
    244 
    245  RefPtr<InputStreamCallback> cb = new InputStreamCallback();
    246 
    247  rv = reader->AsyncWait(cb, 0, 0, GetCurrentSerialEventTarget());
    248  ASSERT_NS_SUCCEEDED(rv);
    249 
    250  NS_ProcessPendingEvents(nullptr);
    251 
    252  ASSERT_FALSE(cb->Called());
    253 
    254  uint32_t numWritten = 0;
    255  rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten);
    256  ASSERT_NS_SUCCEEDED(rv);
    257 
    258  ASSERT_FALSE(cb->Called());
    259 
    260  NS_ProcessPendingEvents(nullptr);
    261 
    262  ASSERT_TRUE(cb->Called());
    263 
    264  ConsumeAndValidateStream(reader, inputData);
    265 }
    266 
    267 TEST(DataPipe, Write_AsyncWait_Cancel)
    268 {
    269  RefPtr<DataPipeReceiver> reader;
    270  RefPtr<DataPipeSender> writer;
    271 
    272  const uint32_t segmentSize = 1024;
    273 
    274  nsresult rv =
    275      NewDataPipe(segmentSize, getter_AddRefs(writer), getter_AddRefs(reader));
    276  ASSERT_NS_SUCCEEDED(rv);
    277 
    278  nsCString inputData;
    279  CreateData(segmentSize, inputData);
    280 
    281  uint32_t numWritten = 0;
    282  rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten);
    283  ASSERT_NS_SUCCEEDED(rv);
    284  EXPECT_EQ(numWritten, segmentSize);
    285 
    286  rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten);
    287  ASSERT_EQ(NS_BASE_STREAM_WOULD_BLOCK, rv);
    288 
    289  RefPtr<OutputStreamCallback> cb = new OutputStreamCallback();
    290 
    291  // Register a callback and immediately cancel it.
    292  rv = writer->AsyncWait(cb, 0, 0, GetCurrentSerialEventTarget());
    293  ASSERT_NS_SUCCEEDED(rv);
    294  rv = writer->AsyncWait(nullptr, 0, 0, nullptr);
    295  ASSERT_NS_SUCCEEDED(rv);
    296 
    297  // Even after consuming the stream and processing pending events, the callback
    298  // shouldn't be called as it was cancelled.
    299  ConsumeAndValidateStream(reader, inputData);
    300  NS_ProcessPendingEvents(nullptr);
    301  ASSERT_FALSE(cb->Called());
    302 }
    303 
    304 TEST(DataPipe, Read_AsyncWait_Cancel)
    305 {
    306  RefPtr<DataPipeReceiver> reader;
    307  RefPtr<DataPipeSender> writer;
    308 
    309  const uint32_t segmentSize = 1024;
    310 
    311  nsresult rv =
    312      NewDataPipe(segmentSize, getter_AddRefs(writer), getter_AddRefs(reader));
    313  ASSERT_NS_SUCCEEDED(rv);
    314 
    315  nsCString inputData;
    316  CreateData(segmentSize, inputData);
    317 
    318  RefPtr<InputStreamCallback> cb = new InputStreamCallback();
    319 
    320  // Register a callback and immediately cancel it.
    321  rv = reader->AsyncWait(cb, 0, 0, GetCurrentSerialEventTarget());
    322  ASSERT_NS_SUCCEEDED(rv);
    323 
    324  rv = reader->AsyncWait(nullptr, 0, 0, nullptr);
    325  ASSERT_NS_SUCCEEDED(rv);
    326 
    327  // Write data into the pipe to make the callback become ready.
    328  uint32_t numWritten = 0;
    329  rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten);
    330  ASSERT_NS_SUCCEEDED(rv);
    331 
    332  // Even after processing pending events, the callback shouldn't be called as
    333  // it was cancelled.
    334  NS_ProcessPendingEvents(nullptr);
    335  ASSERT_FALSE(cb->Called());
    336 
    337  ConsumeAndValidateStream(reader, inputData);
    338 }
    339 
    340 TEST(DataPipe, SerializeReader)
    341 {
    342  RefPtr<DataPipeReceiver> reader;
    343  RefPtr<DataPipeSender> writer;
    344  nsresult rv =
    345      NewDataPipe(1024, getter_AddRefs(writer), getter_AddRefs(reader));
    346  ASSERT_NS_SUCCEEDED(rv);
    347 
    348  IPC::Message msg(MSG_ROUTING_NONE, 0);
    349  IPC::MessageWriter msgWriter(msg);
    350  IPC::WriteParam(&msgWriter, reader);
    351 
    352  uint64_t available = 0;
    353  rv = reader->Available(&available);
    354  ASSERT_NS_FAILED(rv);
    355 
    356  nsCString inputData;
    357  CreateData(512, inputData);
    358 
    359  uint32_t numWritten = 0;
    360  rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten);
    361  ASSERT_NS_SUCCEEDED(rv);
    362 
    363  RefPtr<DataPipeReceiver> reader2;
    364  IPC::MessageReader msgReader(msg);
    365  ASSERT_TRUE(IPC::ReadParam(&msgReader, &reader2));
    366  ASSERT_TRUE(reader2);
    367 
    368  rv = reader2->Available(&available);
    369  ASSERT_NS_SUCCEEDED(rv);
    370  ASSERT_EQ(available, 512u);
    371  ConsumeAndValidateStream(reader2, inputData);
    372 }
    373 
    374 }  // namespace mozilla::ipc