Index: net/spdy/spdy_frame_builder.cc |
diff --git a/net/spdy/spdy_frame_builder.cc b/net/spdy/spdy_frame_builder.cc |
index ee9d36c9f73d5c56cf59dbec073824b659d4e397..1f82dd9d97f2500586d5cdc861e8544644fb936c 100644 |
--- a/net/spdy/spdy_frame_builder.cc |
+++ b/net/spdy/spdy_frame_builder.cc |
@@ -80,11 +80,42 @@ bool SpdyFrameBuilder::BeginNewFrame(const SpdyFramer& framer, |
offset_ += length_; |
length_ = 0; |
+ // TODO(yasong): remove after OverwriteLength() is deleted. |
+ bool length_written = false; |
+ // Remember where the length field is written. Used for OverwriteLength(). |
+ if (output_ != nullptr && CanWrite(kLengthFieldLength)) { |
+ // Can write the length field. |
+ char* dest = nullptr; |
+ // |size| is the available bytes in the current memory block. |
+ int size = 0; |
+ output_->Next(&dest, &size); |
+ start_of_current_frame_ = dest; |
+ bytes_of_length_written_in_first_block_ = |
+ size > (int)kLengthFieldLength ? kLengthFieldLength : size; |
+ // If the current block is not enough for the length field, write the |
+ // length field here, and remember the pointer to the next block. |
+ if (size < (int)kLengthFieldLength) { |
+ // Write the first portion of the length field. |
+ int value = base::HostToNet32(capacity_ - offset_ - kFrameHeaderSize); |
+ memcpy(dest, reinterpret_cast<char*>(&value) + 1, size); |
+ Seek(size); |
+ output_->Next(&dest, &size); |
+ start_of_current_frame_in_next_block_ = dest; |
+ int size_left = |
+ kLengthFieldLength - bytes_of_length_written_in_first_block_; |
+ memcpy(dest, reinterpret_cast<char*>(&value) + 1 + size, size_left); |
+ Seek(size_left); |
+ length_written = true; |
+ } |
+ } |
+ |
// Assume all remaining capacity will be used for this frame. If not, |
// the length will get overwritten when we begin the next frame. |
// Don't check for length limits here because this may be larger than the |
// actual frame length. |
- success &= WriteUInt24(capacity_ - offset_ - kFrameHeaderSize); |
+ if (!length_written) { |
+ success &= WriteUInt24(capacity_ - offset_ - kFrameHeaderSize); |
+ } |
success &= WriteUInt8(type); |
success &= WriteUInt8(flags); |
success &= WriteUInt32(stream_id); |
@@ -169,6 +200,30 @@ bool SpdyFrameBuilder::WriteBytes(const void* data, uint32_t data_len) { |
bool SpdyFrameBuilder::OverwriteLength(const SpdyFramer& framer, |
size_t length) { |
+ if (output_ != nullptr) { |
+ size_t value = base::HostToNet32(length); |
+ if (start_of_current_frame_ != nullptr && |
+ bytes_of_length_written_in_first_block_ == kLengthFieldLength) { |
+ // Length field of the current frame is within one memory block. |
+ memcpy(start_of_current_frame_, reinterpret_cast<char*>(&value) + 1, |
+ kLengthFieldLength); |
+ return true; |
+ } else if (start_of_current_frame_ != nullptr && |
+ start_of_current_frame_in_next_block_ != nullptr && |
+ bytes_of_length_written_in_first_block_ < kLengthFieldLength) { |
+ // Length field of the current frame crosses two memory blocks. |
+ memcpy(start_of_current_frame_, reinterpret_cast<char*>(&value) + 1, |
+ bytes_of_length_written_in_first_block_); |
+ memcpy(start_of_current_frame_in_next_block_, |
+ reinterpret_cast<char*>(&value) + 1 + |
+ bytes_of_length_written_in_first_block_, |
+ kLengthFieldLength - bytes_of_length_written_in_first_block_); |
+ return true; |
+ } else { |
+ return false; |
+ } |
+ } |
+ |
DCHECK_GE(framer.GetFrameMaximumSize(), length); |
bool success = false; |
const size_t old_length = length_; |