| 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 |