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 19namespace net { 20 21namespace { 22 23const char kData[] = "hello!\0hi."; 24const size_t kDataSize = arraysize(kData); 25 26class SpdyBufferTest : public ::testing::Test {}; 27 28// Make a string from the data remaining in |buffer|. 29std::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. 35TEST_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. 47TEST_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 58void 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. 69TEST_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. 94TEST_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(). 109TEST_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. 124TEST_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