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 <limits> 8 9 #include "base/logging.h" 10 #include "net/spdy/spdy_framer.h" 11 #include "net/spdy/spdy_protocol.h" 12 13 namespace net { 14 15 namespace { 16 17 // A special structure for the 8 bit flags and 24 bit length fields. 18 union FlagsAndLength { 19 uint8 flags[4]; // 8 bits 20 uint32 length; // 24 bits 21 }; 22 23 // Creates a FlagsAndLength. 24 FlagsAndLength CreateFlagsAndLength(uint8 flags, size_t length) { 25 DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask)); 26 FlagsAndLength flags_length; 27 flags_length.length = htonl(static_cast<uint32>(length)); 28 DCHECK_EQ(0, flags & ~kControlFlagsMask); 29 flags_length.flags[0] = flags; 30 return flags_length; 31 } 32 33 } // namespace 34 35 SpdyFrameBuilder::SpdyFrameBuilder(size_t size, SpdyMajorVersion version) 36 : buffer_(new char[size]), 37 capacity_(size), 38 length_(0), 39 offset_(0), 40 version_(version) { 41 } 42 43 SpdyFrameBuilder::~SpdyFrameBuilder() { 44 } 45 46 char* SpdyFrameBuilder::GetWritableBuffer(size_t length) { 47 if (!CanWrite(length)) { 48 return NULL; 49 } 50 return buffer_.get() + offset_ + length_; 51 } 52 53 bool SpdyFrameBuilder::Seek(size_t length) { 54 if (!CanWrite(length)) { 55 return false; 56 } 57 58 length_ += length; 59 return true; 60 } 61 62 bool SpdyFrameBuilder::WriteControlFrameHeader(const SpdyFramer& framer, 63 SpdyFrameType type, 64 uint8 flags) { 65 DCHECK_GE(SPDY3, version_); 66 DCHECK_NE(-1, 67 SpdyConstants::SerializeFrameType(version_, type)); 68 bool success = true; 69 FlagsAndLength flags_length = CreateFlagsAndLength( 70 flags, capacity_ - framer.GetControlFrameHeaderSize()); 71 success &= WriteUInt16(kControlFlagMask | 72 SpdyConstants::SerializeMajorVersion(version_)); 73 success &= WriteUInt16( 74 SpdyConstants::SerializeFrameType(framer.protocol_version(), type)); 75 success &= WriteBytes(&flags_length, sizeof(flags_length)); 76 DCHECK_EQ(framer.GetControlFrameHeaderSize(), length()); 77 return success; 78 } 79 80 bool SpdyFrameBuilder::WriteDataFrameHeader(const SpdyFramer& framer, 81 SpdyStreamId stream_id, 82 uint8 flags) { 83 if (version_ > SPDY3) { 84 return BeginNewFrame(framer, DATA, flags, stream_id); 85 } 86 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); 87 bool success = true; 88 success &= WriteUInt32(stream_id); 89 size_t length_field = capacity_ - framer.GetDataFrameMinimumSize(); 90 DCHECK_EQ(0u, length_field & ~static_cast<size_t>(kLengthMask)); 91 FlagsAndLength flags_length; 92 flags_length.length = htonl(length_field); 93 DCHECK_EQ(0, flags & ~kDataFlagsMask); 94 flags_length.flags[0] = flags; 95 success &= WriteBytes(&flags_length, sizeof(flags_length)); 96 DCHECK_EQ(framer.GetDataFrameMinimumSize(), length()); 97 return success; 98 } 99 100 bool SpdyFrameBuilder::BeginNewFrame(const SpdyFramer& framer, 101 SpdyFrameType type, 102 uint8 flags, 103 SpdyStreamId stream_id) { 104 DCHECK(SpdyConstants::IsValidFrameType(version_, 105 SpdyConstants::SerializeFrameType(version_, type))); 106 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); 107 DCHECK_LT(SPDY3, framer.protocol_version()); 108 bool success = true; 109 if (length_ > 0) { 110 // Update length field for previous frame. 111 OverwriteLength(framer, length_ - framer.GetPrefixLength(type)); 112 DLOG_IF(DFATAL, SpdyConstants::GetFrameMaximumSize(version_) < length_) 113 << "Frame length " << length_ 114 << " is longer than the maximum allowed length."; 115 } 116 117 offset_ += length_; 118 length_ = 0; 119 120 // Assume all remaining capacity will be used for this frame. If not, 121 // the length will get overwritten when we begin the next frame. 122 // Don't check for length limits here because this may be larger than the 123 // actual frame length. 124 success &= WriteUInt24(capacity_ - offset_ - framer.GetPrefixLength(type)); 125 success &= WriteUInt8( 126 SpdyConstants::SerializeFrameType(version_, type)); 127 success &= WriteUInt8(flags); 128 success &= WriteUInt32(stream_id); 129 DCHECK_EQ(framer.GetDataFrameMinimumSize(), length_); 130 return success; 131 } 132 133 bool SpdyFrameBuilder::WriteString(const std::string& value) { 134 if (value.size() > 0xffff) { 135 DCHECK(false) << "Tried to write string with length > 16bit."; 136 return false; 137 } 138 139 if (!WriteUInt16(static_cast<int>(value.size()))) 140 return false; 141 142 return WriteBytes(value.data(), static_cast<uint16>(value.size())); 143 } 144 145 bool SpdyFrameBuilder::WriteStringPiece32(const base::StringPiece& value) { 146 if (!WriteUInt32(value.size())) { 147 return false; 148 } 149 150 return WriteBytes(value.data(), value.size()); 151 } 152 153 bool SpdyFrameBuilder::WriteBytes(const void* data, uint32 data_len) { 154 if (!CanWrite(data_len)) { 155 return false; 156 } 157 158 char* dest = GetWritableBuffer(data_len); 159 memcpy(dest, data, data_len); 160 Seek(data_len); 161 return true; 162 } 163 164 bool SpdyFrameBuilder::RewriteLength(const SpdyFramer& framer) { 165 return OverwriteLength(framer, 166 length_ - framer.GetControlFrameHeaderSize()); 167 } 168 169 bool SpdyFrameBuilder::OverwriteLength(const SpdyFramer& framer, 170 size_t length) { 171 if (version_ <= SPDY3) { 172 DCHECK_GE(SpdyConstants::GetFrameMaximumSize(version_) - 173 framer.GetFrameMinimumSize(), 174 length); 175 } else { 176 DCHECK_GE(SpdyConstants::GetFrameMaximumSize(version_), length); 177 } 178 bool success = false; 179 const size_t old_length = length_; 180 181 if (version_ <= SPDY3) { 182 FlagsAndLength flags_length = CreateFlagsAndLength( 183 0, // We're not writing over the flags value anyway. 184 length); 185 186 // Write into the correct location by temporarily faking the offset. 187 length_ = 5; // Offset at which the length field occurs. 188 success = WriteBytes(reinterpret_cast<char*>(&flags_length) + 1, 189 sizeof(flags_length) - 1); 190 } else { 191 length_ = 0; 192 success = WriteUInt24(length); 193 } 194 195 length_ = old_length; 196 return success; 197 } 198 199 bool SpdyFrameBuilder::OverwriteFlags(const SpdyFramer& framer, 200 uint8 flags) { 201 DCHECK_LT(SPDY3, framer.protocol_version()); 202 bool success = false; 203 const size_t old_length = length_; 204 // Flags are the fifth octet in the frame prefix. 205 length_ = 4; 206 success = WriteUInt8(flags); 207 length_ = old_length; 208 return success; 209 } 210 211 bool SpdyFrameBuilder::CanWrite(size_t length) const { 212 if (length > kLengthMask) { 213 DCHECK(false); 214 return false; 215 } 216 217 if (offset_ + length_ + length > capacity_) { 218 DCHECK(false); 219 return false; 220 } 221 222 return true; 223 } 224 225 } // namespace net 226