// Copyright (c) 2009 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 <limits> #include "net/spdy/spdy_frame_builder.h" #include "net/spdy/spdy_protocol.h" namespace spdy { // We mark a read only SpdyFrameBuilder with a special capacity_. static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max(); SpdyFrameBuilder::SpdyFrameBuilder() : buffer_(NULL), capacity_(0), length_(0), variable_buffer_offset_(0) { Resize(kInitialPayload); } SpdyFrameBuilder::SpdyFrameBuilder(const char* data, int data_len) : buffer_(const_cast<char*>(data)), capacity_(kCapacityReadOnly), length_(data_len), variable_buffer_offset_(0) { } SpdyFrameBuilder::~SpdyFrameBuilder() { if (capacity_ != kCapacityReadOnly) delete[] buffer_; } bool SpdyFrameBuilder::ReadUInt16(void** iter, uint16* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(buffer_); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; *result = ntohs(*(reinterpret_cast<uint16*>(*iter))); UpdateIter(iter, sizeof(*result)); return true; } bool SpdyFrameBuilder::ReadUInt32(void** iter, uint32* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(buffer_); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; *result = ntohl(*(reinterpret_cast<uint32*>(*iter))); UpdateIter(iter, sizeof(*result)); return true; } bool SpdyFrameBuilder::ReadString(void** iter, std::string* result) const { DCHECK(iter); uint16 len; if (!ReadUInt16(iter, &len)) return false; if (!IteratorHasRoomFor(*iter, len)) return false; char* chars = reinterpret_cast<char*>(*iter); result->assign(chars, len); UpdateIter(iter, len); return true; } bool SpdyFrameBuilder::ReadBytes(void** iter, const char** data, uint16 length) const { DCHECK(iter); DCHECK(data); if (!IteratorHasRoomFor(*iter, length)) return false; *data = reinterpret_cast<const char*>(*iter); UpdateIter(iter, length); return true; } bool SpdyFrameBuilder::ReadData(void** iter, const char** data, uint16* length) const { DCHECK(iter); DCHECK(data); DCHECK(length); if (!ReadUInt16(iter, length)) return false; return ReadBytes(iter, data, *length); } bool SpdyFrameBuilder::WriteString(const std::string& value) { if (value.size() > 0xffff) return false; if (!WriteUInt16(static_cast<int>(value.size()))) return false; return WriteBytes(value.data(), static_cast<uint16>(value.size())); } bool SpdyFrameBuilder::WriteBytes(const void* data, uint16 data_len) { DCHECK(capacity_ != kCapacityReadOnly); char* dest = BeginWrite(data_len); if (!dest) return false; memcpy(dest, data, data_len); EndWrite(dest, data_len); length_ += data_len; return true; } char* SpdyFrameBuilder::BeginWriteData(uint16 length) { DCHECK_EQ(variable_buffer_offset_, 0U) << "There can only be one variable buffer in a SpdyFrameBuilder"; if (!WriteUInt16(length)) return NULL; char *data_ptr = BeginWrite(length); if (!data_ptr) return NULL; variable_buffer_offset_ = data_ptr - buffer_ - sizeof(int); // EndWrite doesn't necessarily have to be called after the write operation, // so we call it here to pad out what the caller will eventually write. EndWrite(data_ptr, length); return data_ptr; } char* SpdyFrameBuilder::BeginWrite(size_t length) { size_t needed_size = length_ + length; if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) return NULL; #ifdef ARCH_CPU_64_BITS DCHECK_LE(length, std::numeric_limits<uint32>::max()); #endif return buffer_ + length_; } void SpdyFrameBuilder::EndWrite(char* dest, int length) { } bool SpdyFrameBuilder::Resize(size_t new_capacity) { if (new_capacity <= capacity_) return true; char* p = new char[new_capacity]; if (!p) return false; if (buffer_) { memcpy(p, buffer_, capacity_); delete[] buffer_; } buffer_ = p; capacity_ = new_capacity; return true; } } // namespace spdy