• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/spdy/spdy_buffer.h"
11 
12 #include <cstddef>
13 #include <cstring>
14 #include <string>
15 #include <utility>
16 
17 #include "base/functional/bind.h"
18 #include "base/functional/callback.h"
19 #include "base/memory/ref_counted.h"
20 #include "net/base/io_buffer.h"
21 #include "net/third_party/quiche/src/quiche/http2/core/spdy_protocol.h"
22 #include "net/third_party/quiche/src/quiche/http2/test_tools/spdy_test_utils.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 namespace net {
26 
27 namespace {
28 
29 const char kData[] = "hello!\0hi.";
30 const size_t kDataSize = std::size(kData);
31 
32 class SpdyBufferTest : public ::testing::Test {};
33 
34 // Make a string from the data remaining in |buffer|.
BufferToString(const SpdyBuffer & buffer)35 std::string BufferToString(const SpdyBuffer& buffer) {
36   return std::string(buffer.GetRemainingData(), buffer.GetRemainingSize());
37 }
38 
39 // Construct a SpdyBuffer from a spdy::SpdySerializedFrame and make sure its
40 // data is same as the original data.
TEST_F(SpdyBufferTest,FrameConstructor)41 TEST_F(SpdyBufferTest, FrameConstructor) {
42   SpdyBuffer buffer(std::make_unique<spdy::SpdySerializedFrame>(
43       spdy::test::MakeSerializedFrame(const_cast<char*>(kData), kDataSize)));
44 
45   EXPECT_EQ(kDataSize, buffer.GetRemainingSize());
46   EXPECT_EQ(
47       std::string_view(kData, kDataSize),
48       std::string_view(buffer.GetRemainingData(), buffer.GetRemainingSize()));
49 }
50 
51 // Construct a SpdyBuffer from a const char*/size_t pair and make sure
52 // it makes a copy of the data.
TEST_F(SpdyBufferTest,DataConstructor)53 TEST_F(SpdyBufferTest, DataConstructor) {
54   std::string data(kData, kDataSize);
55   SpdyBuffer buffer(data.data(), data.size());
56   // This mutation shouldn't affect |buffer|'s data.
57   data[0] = 'H';
58 
59   EXPECT_NE(kData, buffer.GetRemainingData());
60   EXPECT_EQ(kDataSize, buffer.GetRemainingSize());
61   EXPECT_EQ(std::string(kData, kDataSize), BufferToString(buffer));
62 }
63 
IncrementBy(size_t * x,SpdyBuffer::ConsumeSource expected_consume_source,size_t delta,SpdyBuffer::ConsumeSource consume_source)64 void IncrementBy(size_t* x,
65                  SpdyBuffer::ConsumeSource expected_consume_source,
66                  size_t delta,
67                  SpdyBuffer::ConsumeSource consume_source) {
68   EXPECT_EQ(expected_consume_source, consume_source);
69   *x += delta;
70 }
71 
72 // Construct a SpdyBuffer and call Consume() on it, which should
73 // update the remaining data pointer and size appropriately, as well
74 // as calling the consume callbacks.
TEST_F(SpdyBufferTest,Consume)75 TEST_F(SpdyBufferTest, Consume) {
76   SpdyBuffer buffer(kData, kDataSize);
77 
78   size_t x1 = 0;
79   size_t x2 = 0;
80   buffer.AddConsumeCallback(
81       base::BindRepeating(&IncrementBy, &x1, SpdyBuffer::CONSUME));
82   buffer.AddConsumeCallback(
83       base::BindRepeating(&IncrementBy, &x2, SpdyBuffer::CONSUME));
84 
85   EXPECT_EQ(std::string(kData, kDataSize), BufferToString(buffer));
86 
87   buffer.Consume(5);
88   EXPECT_EQ(std::string(kData + 5, kDataSize - 5), BufferToString(buffer));
89   EXPECT_EQ(5u, x1);
90   EXPECT_EQ(5u, x2);
91 
92   buffer.Consume(kDataSize - 5);
93   EXPECT_EQ(0u, buffer.GetRemainingSize());
94   EXPECT_EQ(kDataSize, x1);
95   EXPECT_EQ(kDataSize, x2);
96 }
97 
98 // Construct a SpdyBuffer and attach a ConsumeCallback to it. The
99 // callback should be called when the SpdyBuffer is destroyed.
TEST_F(SpdyBufferTest,ConsumeOnDestruction)100 TEST_F(SpdyBufferTest, ConsumeOnDestruction) {
101   size_t x = 0;
102 
103   {
104     SpdyBuffer buffer(kData, kDataSize);
105     buffer.AddConsumeCallback(
106         base::BindRepeating(&IncrementBy, &x, SpdyBuffer::DISCARD));
107   }
108 
109   EXPECT_EQ(kDataSize, x);
110 }
111 
112 // Make sure the IOBuffer returned by GetIOBufferForRemainingData()
113 // points to the buffer's remaining data and isn't updated by
114 // Consume().
TEST_F(SpdyBufferTest,GetIOBufferForRemainingData)115 TEST_F(SpdyBufferTest, GetIOBufferForRemainingData) {
116   SpdyBuffer buffer(kData, kDataSize);
117 
118   buffer.Consume(5);
119   scoped_refptr<IOBuffer> io_buffer = buffer.GetIOBufferForRemainingData();
120   size_t io_buffer_size = buffer.GetRemainingSize();
121   const std::string expectedData(kData + 5, kDataSize - 5);
122   EXPECT_EQ(expectedData, std::string(io_buffer->data(), io_buffer_size));
123 
124   buffer.Consume(kDataSize - 5);
125   EXPECT_EQ(expectedData, std::string(io_buffer->data(), io_buffer_size));
126 }
127 
128 // Make sure the IOBuffer returned by GetIOBufferForRemainingData()
129 // outlives the buffer itself.
TEST_F(SpdyBufferTest,IOBufferForRemainingDataOutlivesBuffer)130 TEST_F(SpdyBufferTest, IOBufferForRemainingDataOutlivesBuffer) {
131   auto buffer = std::make_unique<SpdyBuffer>(kData, kDataSize);
132   scoped_refptr<IOBuffer> io_buffer = buffer->GetIOBufferForRemainingData();
133   buffer.reset();
134 
135   // This will cause a use-after-free error if |io_buffer| doesn't
136   // outlive |buffer|.
137   std::memcpy(io_buffer->data(), kData, kDataSize);
138 }
139 
140 }  // namespace
141 
142 }  // namespace net
143