|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/spdy/spdy_buffer.h" | 
|  |  | 
|  | #include <cstring> | 
|  |  | 
|  | #include "base/callback.h" | 
|  | #include "base/logging.h" | 
|  | #include "net/base/io_buffer.h" | 
|  | #include "net/spdy/spdy_protocol.h" | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Bound on largest frame any SPDY version has allowed. | 
|  | const size_t kMaxSpdyFrameSize = 0x00ffffff; | 
|  |  | 
|  | // Makes a SpdyFrame with |size| bytes of data copied from | 
|  | // |data|. |data| must be non-NULL and |size| must be positive. | 
|  | scoped_ptr<SpdyFrame> MakeSpdyFrame(const char* data, size_t size) { | 
|  | DCHECK(data); | 
|  | CHECK_GT(size, 0u); | 
|  | CHECK_LE(size, kMaxSpdyFrameSize); | 
|  | scoped_ptr<char[]> frame_data(new char[size]); | 
|  | std::memcpy(frame_data.get(), data, size); | 
|  | scoped_ptr<SpdyFrame> frame( | 
|  | new SpdyFrame(frame_data.release(), size, true /* owns_buffer */)); | 
|  | return frame.Pass(); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // This class is an IOBuffer implementation that simply holds a | 
|  | // reference to a SharedFrame object and a fixed offset. Used by | 
|  | // SpdyBuffer::GetIOBufferForRemainingData(). | 
|  | class SpdyBuffer::SharedFrameIOBuffer : public IOBuffer { | 
|  | public: | 
|  | SharedFrameIOBuffer(const scoped_refptr<SharedFrame>& shared_frame, | 
|  | size_t offset) | 
|  | : IOBuffer(shared_frame->data->data() + offset), | 
|  | shared_frame_(shared_frame) {} | 
|  |  | 
|  | private: | 
|  | ~SharedFrameIOBuffer() override { | 
|  | // Prevent ~IOBuffer() from trying to delete |data_|. | 
|  | data_ = NULL; | 
|  | } | 
|  |  | 
|  | const scoped_refptr<SharedFrame> shared_frame_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(SharedFrameIOBuffer); | 
|  | }; | 
|  |  | 
|  | SpdyBuffer::SpdyBuffer(scoped_ptr<SpdyFrame> frame) | 
|  | : shared_frame_(new SharedFrame()), | 
|  | offset_(0) { | 
|  | shared_frame_->data = frame.Pass(); | 
|  | } | 
|  |  | 
|  | // The given data may not be strictly a SPDY frame; we (ab)use | 
|  | // |frame_| just as a container. | 
|  | SpdyBuffer::SpdyBuffer(const char* data, size_t size) : | 
|  | shared_frame_(new SharedFrame()), | 
|  | offset_(0) { | 
|  | CHECK_GT(size, 0u); | 
|  | CHECK_LE(size, kMaxSpdyFrameSize); | 
|  | shared_frame_->data = MakeSpdyFrame(data, size); | 
|  | } | 
|  |  | 
|  | SpdyBuffer::~SpdyBuffer() { | 
|  | if (GetRemainingSize() > 0) | 
|  | ConsumeHelper(GetRemainingSize(), DISCARD); | 
|  | } | 
|  |  | 
|  | const char* SpdyBuffer::GetRemainingData() const { | 
|  | return shared_frame_->data->data() + offset_; | 
|  | } | 
|  |  | 
|  | size_t SpdyBuffer::GetRemainingSize() const { | 
|  | return shared_frame_->data->size() - offset_; | 
|  | } | 
|  |  | 
|  | void SpdyBuffer::AddConsumeCallback(const ConsumeCallback& consume_callback) { | 
|  | consume_callbacks_.push_back(consume_callback); | 
|  | } | 
|  |  | 
|  | void SpdyBuffer::Consume(size_t consume_size) { | 
|  | ConsumeHelper(consume_size, CONSUME); | 
|  | }; | 
|  |  | 
|  | IOBuffer* SpdyBuffer::GetIOBufferForRemainingData() { | 
|  | return new SharedFrameIOBuffer(shared_frame_, offset_); | 
|  | } | 
|  |  | 
|  | void SpdyBuffer::ConsumeHelper(size_t consume_size, | 
|  | ConsumeSource consume_source) { | 
|  | DCHECK_GE(consume_size, 1u); | 
|  | DCHECK_LE(consume_size, GetRemainingSize()); | 
|  | offset_ += consume_size; | 
|  | for (std::vector<ConsumeCallback>::const_iterator it = | 
|  | consume_callbacks_.begin(); it != consume_callbacks_.end(); ++it) { | 
|  | it->Run(consume_size, consume_source); | 
|  | } | 
|  | }; | 
|  |  | 
|  | }  // namespace net |