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 <cstring> 8 9 #include "base/callback.h" 10 #include "base/logging.h" 11 #include "net/base/io_buffer.h" 12 #include "net/spdy/spdy_protocol.h" 13 14 namespace net { 15 16 namespace { 17 18 // Bound on largest frame any SPDY version has allowed. 19 const size_t kMaxSpdyFrameSize = 0x00ffffff; 20 21 // Makes a SpdyFrame with |size| bytes of data copied from 22 // |data|. |data| must be non-NULL and |size| must be positive. 23 scoped_ptr<SpdyFrame> MakeSpdyFrame(const char* data, size_t size) { 24 DCHECK(data); 25 CHECK_GT(size, 0u); 26 CHECK_LE(size, kMaxSpdyFrameSize); 27 scoped_ptr<char[]> frame_data(new char[size]); 28 std::memcpy(frame_data.get(), data, size); 29 scoped_ptr<SpdyFrame> frame( 30 new SpdyFrame(frame_data.release(), size, true /* owns_buffer */)); 31 return frame.Pass(); 32 } 33 34 } // namespace 35 36 // This class is an IOBuffer implementation that simply holds a 37 // reference to a SharedFrame object and a fixed offset. Used by 38 // SpdyBuffer::GetIOBufferForRemainingData(). 39 class SpdyBuffer::SharedFrameIOBuffer : public IOBuffer { 40 public: 41 SharedFrameIOBuffer(const scoped_refptr<SharedFrame>& shared_frame, 42 size_t offset) 43 : IOBuffer(shared_frame->data->data() + offset), 44 shared_frame_(shared_frame), 45 offset_(offset) {} 46 47 private: 48 virtual ~SharedFrameIOBuffer() { 49 // Prevent ~IOBuffer() from trying to delete |data_|. 50 data_ = NULL; 51 } 52 53 const scoped_refptr<SharedFrame> shared_frame_; 54 const size_t offset_; 55 56 DISALLOW_COPY_AND_ASSIGN(SharedFrameIOBuffer); 57 }; 58 59 SpdyBuffer::SpdyBuffer(scoped_ptr<SpdyFrame> frame) 60 : shared_frame_(new SharedFrame()), 61 offset_(0) { 62 shared_frame_->data = frame.Pass(); 63 } 64 65 // The given data may not be strictly a SPDY frame; we (ab)use 66 // |frame_| just as a container. 67 SpdyBuffer::SpdyBuffer(const char* data, size_t size) : 68 shared_frame_(new SharedFrame()), 69 offset_(0) { 70 CHECK_GT(size, 0u); 71 CHECK_LE(size, kMaxSpdyFrameSize); 72 shared_frame_->data = MakeSpdyFrame(data, size); 73 } 74 75 SpdyBuffer::~SpdyBuffer() { 76 if (GetRemainingSize() > 0) 77 ConsumeHelper(GetRemainingSize(), DISCARD); 78 } 79 80 const char* SpdyBuffer::GetRemainingData() const { 81 return shared_frame_->data->data() + offset_; 82 } 83 84 size_t SpdyBuffer::GetRemainingSize() const { 85 return shared_frame_->data->size() - offset_; 86 } 87 88 void SpdyBuffer::AddConsumeCallback(const ConsumeCallback& consume_callback) { 89 consume_callbacks_.push_back(consume_callback); 90 } 91 92 void SpdyBuffer::Consume(size_t consume_size) { 93 ConsumeHelper(consume_size, CONSUME); 94 }; 95 96 IOBuffer* SpdyBuffer::GetIOBufferForRemainingData() { 97 return new SharedFrameIOBuffer(shared_frame_, offset_); 98 } 99 100 void SpdyBuffer::ConsumeHelper(size_t consume_size, 101 ConsumeSource consume_source) { 102 DCHECK_GE(consume_size, 1u); 103 DCHECK_LE(consume_size, GetRemainingSize()); 104 offset_ += consume_size; 105 for (std::vector<ConsumeCallback>::const_iterator it = 106 consume_callbacks_.begin(); it != consume_callbacks_.end(); ++it) { 107 it->Run(consume_size, consume_source); 108 } 109 }; 110 111 } // namespace net 112