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