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