Home | History | Annotate | Download | only in spdy
      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