1 // Copyright (c) 2013 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 "net/spdy/spdy_buffer.h" 6 7 #include <cstddef> 8 #include <cstring> 9 #include <string> 10 11 #include "base/basictypes.h" 12 #include "base/bind.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "net/base/io_buffer.h" 16 #include "net/spdy/spdy_protocol.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 19 namespace net { 20 21 namespace { 22 23 const char kData[] = "hello!\0hi."; 24 const size_t kDataSize = arraysize(kData); 25 26 class SpdyBufferTest : public ::testing::Test {}; 27 28 // Make a string from the data remaining in |buffer|. 29 std::string BufferToString(const SpdyBuffer& buffer) { 30 return std::string(buffer.GetRemainingData(), buffer.GetRemainingSize()); 31 } 32 33 // Construct a SpdyBuffer from a SpdyFrame and make sure its data 34 // points to the frame's underlying data. 35 TEST_F(SpdyBufferTest, FrameConstructor) { 36 SpdyBuffer buffer( 37 scoped_ptr<SpdyFrame>( 38 new SpdyFrame(const_cast<char*>(kData), kDataSize, 39 false /* owns_buffer */))); 40 41 EXPECT_EQ(kData, buffer.GetRemainingData()); 42 EXPECT_EQ(kDataSize, buffer.GetRemainingSize()); 43 } 44 45 // Construct a SpdyBuffer from a const char*/size_t pair and make sure 46 // it makes a copy of the data. 47 TEST_F(SpdyBufferTest, DataConstructor) { 48 std::string data(kData, kDataSize); 49 SpdyBuffer buffer(data.data(), data.size()); 50 // This mutation shouldn't affect |buffer|'s data. 51 data[0] = 'H'; 52 53 EXPECT_NE(kData, buffer.GetRemainingData()); 54 EXPECT_EQ(kDataSize, buffer.GetRemainingSize()); 55 EXPECT_EQ(std::string(kData, kDataSize), BufferToString(buffer)); 56 } 57 58 void IncrementBy(size_t* x, 59 SpdyBuffer::ConsumeSource expected_consume_source, 60 size_t delta, 61 SpdyBuffer::ConsumeSource consume_source) { 62 EXPECT_EQ(expected_consume_source, consume_source); 63 *x += delta; 64 } 65 66 // Construct a SpdyBuffer and call Consume() on it, which should 67 // update the remaining data pointer and size appropriately, as well 68 // as calling the consume callbacks. 69 TEST_F(SpdyBufferTest, Consume) { 70 SpdyBuffer buffer(kData, kDataSize); 71 72 size_t x1 = 0; 73 size_t x2 = 0; 74 buffer.AddConsumeCallback( 75 base::Bind(&IncrementBy, &x1, SpdyBuffer::CONSUME)); 76 buffer.AddConsumeCallback( 77 base::Bind(&IncrementBy, &x2, SpdyBuffer::CONSUME)); 78 79 EXPECT_EQ(std::string(kData, kDataSize), BufferToString(buffer)); 80 81 buffer.Consume(5); 82 EXPECT_EQ(std::string(kData + 5, kDataSize - 5), BufferToString(buffer)); 83 EXPECT_EQ(5u, x1); 84 EXPECT_EQ(5u, x2); 85 86 buffer.Consume(kDataSize - 5); 87 EXPECT_EQ(0u, buffer.GetRemainingSize()); 88 EXPECT_EQ(kDataSize, x1); 89 EXPECT_EQ(kDataSize, x2); 90 } 91 92 // Construct a SpdyBuffer and attach a ConsumeCallback to it. The 93 // callback should be called when the SpdyBuffer is destroyed. 94 TEST_F(SpdyBufferTest, ConsumeOnDestruction) { 95 size_t x = 0; 96 97 { 98 SpdyBuffer buffer(kData, kDataSize); 99 buffer.AddConsumeCallback( 100 base::Bind(&IncrementBy, &x, SpdyBuffer::DISCARD)); 101 } 102 103 EXPECT_EQ(kDataSize, x); 104 } 105 106 // Make sure the IOBuffer returned by GetIOBufferForRemainingData() 107 // points to the buffer's remaining data and isn't updated by 108 // Consume(). 109 TEST_F(SpdyBufferTest, GetIOBufferForRemainingData) { 110 SpdyBuffer buffer(kData, kDataSize); 111 112 buffer.Consume(5); 113 scoped_refptr<IOBuffer> io_buffer = buffer.GetIOBufferForRemainingData(); 114 size_t io_buffer_size = buffer.GetRemainingSize(); 115 const std::string expectedData(kData + 5, kDataSize - 5); 116 EXPECT_EQ(expectedData, std::string(io_buffer->data(), io_buffer_size)); 117 118 buffer.Consume(kDataSize - 5); 119 EXPECT_EQ(expectedData, std::string(io_buffer->data(), io_buffer_size)); 120 } 121 122 // Make sure the IOBuffer returned by GetIOBufferForRemainingData() 123 // outlives the buffer itself. 124 TEST_F(SpdyBufferTest, IOBufferForRemainingDataOutlivesBuffer) { 125 scoped_ptr<SpdyBuffer> buffer(new SpdyBuffer(kData, kDataSize)); 126 127 scoped_refptr<IOBuffer> io_buffer = buffer->GetIOBufferForRemainingData(); 128 buffer.reset(); 129 130 // This will cause a use-after-free error if |io_buffer| doesn't 131 // outlive |buffer|. 132 std::memcpy(io_buffer->data(), kData, kDataSize); 133 } 134 135 } // namespace 136 137 } // namespace net 138