OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/spdy/spdy_frame_builder.h" | |
6 | |
7 #include <algorithm> | |
8 #include <cstdint> | |
9 #include <limits> | |
10 | |
11 #include "base/logging.h" | |
12 #include "net/spdy/spdy_bug_tracker.h" | |
13 #include "net/spdy/spdy_framer.h" | |
14 #include "net/spdy/spdy_protocol.h" | |
15 #include "net/spdy/zero_copy_output_buffer.h" | |
16 | |
17 namespace net { | |
18 | |
19 SpdyFrameBuilder::SpdyFrameBuilder(size_t size) | |
20 : buffer_(new char[size]), capacity_(size), length_(0), offset_(0) {} | |
21 | |
22 SpdyFrameBuilder::SpdyFrameBuilder(size_t size, ZeroCopyOutputBuffer* output) | |
23 : buffer_(output == nullptr ? new char[size] : nullptr), | |
24 output_(output), | |
25 capacity_(size), | |
26 length_(0), | |
27 offset_(0) {} | |
28 | |
29 SpdyFrameBuilder::~SpdyFrameBuilder() { | |
30 } | |
31 | |
32 char* SpdyFrameBuilder::GetWritableBuffer(size_t length) { | |
33 if (!CanWrite(length)) { | |
34 return nullptr; | |
35 } | |
36 return buffer_.get() + offset_ + length_; | |
37 } | |
38 | |
39 char* SpdyFrameBuilder::GetWritableOutput(size_t length, | |
40 size_t* actual_length) { | |
41 char* dest = nullptr; | |
42 int size = 0; | |
43 | |
44 if (!CanWrite(length)) { | |
45 return nullptr; | |
46 } | |
47 output_->Next(&dest, &size); | |
48 *actual_length = std::min(length, (size_t)size); | |
49 return dest; | |
50 } | |
51 | |
52 bool SpdyFrameBuilder::Seek(size_t length) { | |
53 if (!CanWrite(length)) { | |
54 return false; | |
55 } | |
56 if (output_ == nullptr) { | |
57 length_ += length; | |
58 } else { | |
59 output_->AdvanceWritePtr(length); | |
60 length_ += length; | |
61 } | |
62 return true; | |
63 } | |
64 | |
65 bool SpdyFrameBuilder::BeginNewFrame(const SpdyFramer& framer, | |
66 SpdyFrameType type, | |
67 uint8_t flags, | |
68 SpdyStreamId stream_id) { | |
69 uint8_t raw_frame_type = SerializeFrameType(type); | |
70 DCHECK(IsDefinedFrameType(raw_frame_type)); | |
71 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | |
72 bool success = true; | |
73 if (length_ > 0) { | |
74 // Update length field for previous frame. | |
75 OverwriteLength(framer, length_ - kFrameHeaderSize); | |
76 SPDY_BUG_IF(framer.GetFrameMaximumSize() < length_) | |
77 << "Frame length " << length_ | |
78 << " is longer than the maximum allowed length."; | |
79 } | |
80 | |
81 offset_ += length_; | |
82 length_ = 0; | |
83 | |
84 // TODO(yasong): remove after OverwriteLength() is deleted. | |
85 bool length_written = false; | |
86 // Remember where the length field is written. Used for OverwriteLength(). | |
87 if (output_ != nullptr && CanWrite(kLengthFieldLength)) { | |
88 // Can write the length field. | |
89 char* dest = nullptr; | |
90 // |size| is the available bytes in the current memory block. | |
91 int size = 0; | |
92 output_->Next(&dest, &size); | |
93 start_of_current_frame_ = dest; | |
94 bytes_of_length_written_in_first_block_ = | |
95 size > (int)kLengthFieldLength ? kLengthFieldLength : size; | |
96 // If the current block is not enough for the length field, write the | |
97 // length field here, and remember the pointer to the next block. | |
98 if (size < (int)kLengthFieldLength) { | |
99 // Write the first portion of the length field. | |
100 int value = base::HostToNet32(capacity_ - offset_ - kFrameHeaderSize); | |
101 memcpy(dest, reinterpret_cast<char*>(&value) + 1, size); | |
102 Seek(size); | |
103 output_->Next(&dest, &size); | |
104 start_of_current_frame_in_next_block_ = dest; | |
105 int size_left = | |
106 kLengthFieldLength - bytes_of_length_written_in_first_block_; | |
107 memcpy(dest, reinterpret_cast<char*>(&value) + 1 + size, size_left); | |
108 Seek(size_left); | |
109 length_written = true; | |
110 } | |
111 } | |
112 | |
113 // Assume all remaining capacity will be used for this frame. If not, | |
114 // the length will get overwritten when we begin the next frame. | |
115 // Don't check for length limits here because this may be larger than the | |
116 // actual frame length. | |
117 if (!length_written) { | |
118 success &= WriteUInt24(capacity_ - offset_ - kFrameHeaderSize); | |
119 } | |
120 success &= WriteUInt8(raw_frame_type); | |
121 success &= WriteUInt8(flags); | |
122 success &= WriteUInt32(stream_id); | |
123 DCHECK_EQ(framer.GetDataFrameMinimumSize(), length_); | |
124 return success; | |
125 } | |
126 | |
127 bool SpdyFrameBuilder::BeginNewFrame(const SpdyFramer& framer, | |
128 SpdyFrameType type, | |
129 uint8_t flags, | |
130 SpdyStreamId stream_id, | |
131 size_t length) { | |
132 uint8_t raw_frame_type = SerializeFrameType(type); | |
133 DCHECK(IsDefinedFrameType(raw_frame_type)); | |
134 return BeginNewFrameInternal(framer, raw_frame_type, flags, stream_id, | |
135 length); | |
136 } | |
137 | |
138 bool SpdyFrameBuilder::BeginNewExtensionFrame(const SpdyFramer& framer, | |
139 uint8_t raw_frame_type, | |
140 uint8_t flags, | |
141 SpdyStreamId stream_id, | |
142 size_t length) { | |
143 DCHECK(!IsDefinedFrameType(raw_frame_type)); | |
144 return BeginNewFrameInternal(framer, raw_frame_type, flags, stream_id, | |
145 length); | |
146 } | |
147 | |
148 bool SpdyFrameBuilder::BeginNewFrameInternal(const SpdyFramer& framer, | |
149 uint8_t raw_frame_type, | |
150 uint8_t flags, | |
151 SpdyStreamId stream_id, | |
152 size_t length) { | |
153 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); | |
154 bool success = true; | |
155 SPDY_BUG_IF(framer.GetFrameMaximumSize() < length_) | |
156 << "Frame length " << length_ | |
157 << " is longer than the maximum allowed length."; | |
158 | |
159 offset_ += length_; | |
160 length_ = 0; | |
161 | |
162 success &= WriteUInt24(length); | |
163 success &= WriteUInt8(raw_frame_type); | |
164 success &= WriteUInt8(flags); | |
165 success &= WriteUInt32(stream_id); | |
166 DCHECK_EQ(framer.GetDataFrameMinimumSize(), length_); | |
167 return success; | |
168 } | |
169 | |
170 bool SpdyFrameBuilder::WriteStringPiece16(const SpdyStringPiece& value) { | |
171 if (value.size() > 0xffff) { | |
172 DCHECK(false) << "Tried to write string with length > 16bit."; | |
173 return false; | |
174 } | |
175 | |
176 if (!WriteUInt16(static_cast<uint16_t>(value.size()))) { | |
177 return false; | |
178 } | |
179 | |
180 return WriteBytes(value.data(), static_cast<uint16_t>(value.size())); | |
181 } | |
182 | |
183 bool SpdyFrameBuilder::WriteStringPiece32(const SpdyStringPiece& value) { | |
184 if (!WriteUInt32(value.size())) { | |
185 return false; | |
186 } | |
187 | |
188 return WriteBytes(value.data(), value.size()); | |
189 } | |
190 | |
191 bool SpdyFrameBuilder::WriteBytes(const void* data, uint32_t data_len) { | |
192 if (!CanWrite(data_len)) { | |
193 return false; | |
194 } | |
195 | |
196 if (output_ == nullptr) { | |
197 char* dest = GetWritableBuffer(data_len); | |
198 memcpy(dest, data, data_len); | |
199 Seek(data_len); | |
200 } else { | |
201 char* dest = nullptr; | |
202 size_t size = 0; | |
203 size_t total_written = 0; | |
204 const char* data_ptr = reinterpret_cast<const char*>(data); | |
205 while (data_len > 0) { | |
206 dest = GetWritableOutput(data_len, &size); | |
207 if (dest == nullptr || size == 0) { | |
208 // Unable to make progress. | |
209 return false; | |
210 } | |
211 uint32_t to_copy = std::min<uint32_t>(data_len, size); | |
212 const char* src = data_ptr + total_written; | |
213 memcpy(dest, src, to_copy); | |
214 Seek(to_copy); | |
215 data_len -= to_copy; | |
216 total_written += to_copy; | |
217 } | |
218 } | |
219 return true; | |
220 } | |
221 | |
222 bool SpdyFrameBuilder::OverwriteLength(const SpdyFramer& framer, | |
223 size_t length) { | |
224 if (output_ != nullptr) { | |
225 size_t value = base::HostToNet32(length); | |
226 if (start_of_current_frame_ != nullptr && | |
227 bytes_of_length_written_in_first_block_ == kLengthFieldLength) { | |
228 // Length field of the current frame is within one memory block. | |
229 memcpy(start_of_current_frame_, reinterpret_cast<char*>(&value) + 1, | |
230 kLengthFieldLength); | |
231 return true; | |
232 } else if (start_of_current_frame_ != nullptr && | |
233 start_of_current_frame_in_next_block_ != nullptr && | |
234 bytes_of_length_written_in_first_block_ < kLengthFieldLength) { | |
235 // Length field of the current frame crosses two memory blocks. | |
236 memcpy(start_of_current_frame_, reinterpret_cast<char*>(&value) + 1, | |
237 bytes_of_length_written_in_first_block_); | |
238 memcpy(start_of_current_frame_in_next_block_, | |
239 reinterpret_cast<char*>(&value) + 1 + | |
240 bytes_of_length_written_in_first_block_, | |
241 kLengthFieldLength - bytes_of_length_written_in_first_block_); | |
242 return true; | |
243 } else { | |
244 return false; | |
245 } | |
246 } | |
247 | |
248 DCHECK_GE(framer.GetFrameMaximumSize(), length); | |
249 bool success = false; | |
250 const size_t old_length = length_; | |
251 | |
252 length_ = 0; | |
253 success = WriteUInt24(length); | |
254 | |
255 length_ = old_length; | |
256 return success; | |
257 } | |
258 | |
259 bool SpdyFrameBuilder::CanWrite(size_t length) const { | |
260 if (length > kLengthMask) { | |
261 DCHECK(false); | |
262 return false; | |
263 } | |
264 | |
265 if (output_ == nullptr) { | |
266 if (offset_ + length_ + length > capacity_) { | |
267 DLOG(FATAL) << "Requested: " << length << " capacity: " << capacity_ | |
268 << " used: " << offset_ + length_; | |
269 return false; | |
270 } | |
271 } else { | |
272 if (length > output_->BytesFree()) { | |
273 return false; | |
274 } | |
275 } | |
276 | |
277 return true; | |
278 } | |
279 | |
280 } // namespace net | |
OLD | NEW |