• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SpdyFrameBuilder()15 SpdyFrameBuilder::SpdyFrameBuilder()
16     : buffer_(NULL),
17       capacity_(0),
18       length_(0),
19       variable_buffer_offset_(0) {
20   Resize(kInitialPayload);
21 }
22 
SpdyFrameBuilder(const char * data,int data_len)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 
~SpdyFrameBuilder()30 SpdyFrameBuilder::~SpdyFrameBuilder() {
31   if (capacity_ != kCapacityReadOnly)
32     delete[] buffer_;
33 }
34 
ReadUInt16(void ** iter,uint16 * result) const35 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 
ReadUInt32(void ** iter,uint32 * result) const49 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 
ReadString(void ** iter,std::string * result) const63 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 
ReadBytes(void ** iter,const char ** data,uint16 length) const80 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 
ReadData(void ** iter,const char ** data,uint16 * length) const94 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 
WriteString(const std::string & value)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 
WriteBytes(const void * data,uint16 data_len)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 
BeginWriteData(uint16 length)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 
BeginWrite(size_t length)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 
EndWrite(char * dest,int length)161 void SpdyFrameBuilder::EndWrite(char* dest, int length) {
162 }
163 
Resize(size_t new_capacity)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