1 // Copyright (c) 2009 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 <limits> 6 7 #include "net/spdy/spdy_frame_builder.h" 8 #include "net/spdy/spdy_protocol.h" 9 10 namespace spdy { 11 12 // We mark a read only SpdyFrameBuilder with a special capacity_. 13 static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max(); 14 15 SpdyFrameBuilder::SpdyFrameBuilder() 16 : buffer_(NULL), 17 capacity_(0), 18 length_(0), 19 variable_buffer_offset_(0) { 20 Resize(kInitialPayload); 21 } 22 23 SpdyFrameBuilder::SpdyFrameBuilder(const char* data, int data_len) 24 : buffer_(const_cast<char*>(data)), 25 capacity_(kCapacityReadOnly), 26 length_(data_len), 27 variable_buffer_offset_(0) { 28 } 29 30 SpdyFrameBuilder::~SpdyFrameBuilder() { 31 if (capacity_ != kCapacityReadOnly) 32 delete[] buffer_; 33 } 34 35 bool SpdyFrameBuilder::ReadUInt16(void** iter, uint16* result) const { 36 DCHECK(iter); 37 if (!*iter) 38 *iter = const_cast<char*>(buffer_); 39 40 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 41 return false; 42 43 *result = ntohs(*(reinterpret_cast<uint16*>(*iter))); 44 45 UpdateIter(iter, sizeof(*result)); 46 return true; 47 } 48 49 bool SpdyFrameBuilder::ReadUInt32(void** iter, uint32* result) const { 50 DCHECK(iter); 51 if (!*iter) 52 *iter = const_cast<char*>(buffer_); 53 54 if (!IteratorHasRoomFor(*iter, sizeof(*result))) 55 return false; 56 57 *result = ntohl(*(reinterpret_cast<uint32*>(*iter))); 58 59 UpdateIter(iter, sizeof(*result)); 60 return true; 61 } 62 63 bool SpdyFrameBuilder::ReadString(void** iter, std::string* result) const { 64 DCHECK(iter); 65 66 uint16 len; 67 if (!ReadUInt16(iter, &len)) 68 return false; 69 70 if (!IteratorHasRoomFor(*iter, len)) 71 return false; 72 73 char* chars = reinterpret_cast<char*>(*iter); 74 result->assign(chars, len); 75 76 UpdateIter(iter, len); 77 return true; 78 } 79 80 bool SpdyFrameBuilder::ReadBytes(void** iter, const char** data, 81 uint16 length) const { 82 DCHECK(iter); 83 DCHECK(data); 84 85 if (!IteratorHasRoomFor(*iter, length)) 86 return false; 87 88 *data = reinterpret_cast<const char*>(*iter); 89 90 UpdateIter(iter, length); 91 return true; 92 } 93 94 bool SpdyFrameBuilder::ReadData(void** iter, const char** data, 95 uint16* length) const { 96 DCHECK(iter); 97 DCHECK(data); 98 DCHECK(length); 99 100 if (!ReadUInt16(iter, length)) 101 return false; 102 103 return ReadBytes(iter, data, *length); 104 } 105 106 bool SpdyFrameBuilder::WriteString(const std::string& value) { 107 if (value.size() > 0xffff) 108 return false; 109 110 if (!WriteUInt16(static_cast<int>(value.size()))) 111 return false; 112 113 return WriteBytes(value.data(), static_cast<uint16>(value.size())); 114 } 115 116 bool SpdyFrameBuilder::WriteBytes(const void* data, uint16 data_len) { 117 DCHECK(capacity_ != kCapacityReadOnly); 118 119 char* dest = BeginWrite(data_len); 120 if (!dest) 121 return false; 122 123 memcpy(dest, data, data_len); 124 125 EndWrite(dest, data_len); 126 length_ += data_len; 127 return true; 128 } 129 130 char* SpdyFrameBuilder::BeginWriteData(uint16 length) { 131 DCHECK_EQ(variable_buffer_offset_, 0U) << 132 "There can only be one variable buffer in a SpdyFrameBuilder"; 133 134 if (!WriteUInt16(length)) 135 return NULL; 136 137 char *data_ptr = BeginWrite(length); 138 if (!data_ptr) 139 return NULL; 140 141 variable_buffer_offset_ = data_ptr - buffer_ - sizeof(int); 142 143 // EndWrite doesn't necessarily have to be called after the write operation, 144 // so we call it here to pad out what the caller will eventually write. 145 EndWrite(data_ptr, length); 146 return data_ptr; 147 } 148 149 char* SpdyFrameBuilder::BeginWrite(size_t length) { 150 size_t needed_size = length_ + length; 151 if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) 152 return NULL; 153 154 #ifdef ARCH_CPU_64_BITS 155 DCHECK_LE(length, std::numeric_limits<uint32>::max()); 156 #endif 157 158 return buffer_ + length_; 159 } 160 161 void SpdyFrameBuilder::EndWrite(char* dest, int length) { 162 } 163 164 bool SpdyFrameBuilder::Resize(size_t new_capacity) { 165 if (new_capacity <= capacity_) 166 return true; 167 168 char* p = new char[new_capacity]; 169 if (!p) 170 return false; 171 if (buffer_) { 172 memcpy(p, buffer_, capacity_); 173 delete[] buffer_; 174 } 175 buffer_ = p; 176 capacity_ = new_capacity; 177 return true; 178 } 179 180 } // namespace spdy 181