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) 36 : buffer_(new char[size]), 37 capacity_(size), 38 length_(0) { 39 } 40 41 SpdyFrameBuilder::~SpdyFrameBuilder() { 42 } 43 44 char* SpdyFrameBuilder::GetWritableBuffer(size_t length) { 45 if (!CanWrite(length)) { 46 return NULL; 47 } 48 return buffer_.get() + length_; 49 } 50 51 bool SpdyFrameBuilder::Seek(size_t length) { 52 if (!CanWrite(length)) { 53 return false; 54 } 55 56 length_ += length; 57 return true; 58 } 59 60 bool SpdyFrameBuilder::WriteControlFrameHeader(const SpdyFramer& framer, 61 SpdyFrameType type, 62 uint8 flags) { 63 DCHECK_GE(type, FIRST_CONTROL_TYPE); 64 DCHECK_LE(type, LAST_CONTROL_TYPE); 65 DCHECK_GT(4, framer.protocol_version()); 66 bool success = true; 67 FlagsAndLength flags_length = CreateFlagsAndLength( 68 flags, capacity_ - framer.GetControlFrameHeaderSize()); 69 success &= WriteUInt16(kControlFlagMask | framer.protocol_version()); 70 success &= WriteUInt16(type); 71 success &= WriteBytes(&flags_length, sizeof(flags_length)); 72 DCHECK_EQ(framer.GetControlFrameHeaderSize(), length()); 73 return success; 74 } 75 76 bool SpdyFrameBuilder::WriteDataFrameHeader(const SpdyFramer& framer, 77 SpdyStreamId stream_id, 78 SpdyDataFlags flags) { 79 if (framer.protocol_version() >= 4) { 80 return WriteFramePrefix(framer, DATA, flags, stream_id); 81 } 82 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); 83 bool success = true; 84 success &= WriteUInt32(stream_id); 85 size_t length_field = capacity_ - framer.GetDataFrameMinimumSize(); 86 DCHECK_EQ(0u, length_field & ~static_cast<size_t>(kLengthMask)); 87 FlagsAndLength flags_length; 88 flags_length.length_ = htonl(length_field); 89 DCHECK_EQ(0, flags & ~kDataFlagsMask); 90 flags_length.flags_[0] = flags; 91 success &= WriteBytes(&flags_length, sizeof(flags_length)); 92 DCHECK_EQ(framer.GetDataFrameMinimumSize(), length()); 93 return success; 94 } 95 96 bool SpdyFrameBuilder::WriteFramePrefix(const SpdyFramer& framer, 97 SpdyFrameType type, 98 uint8 flags, 99 SpdyStreamId stream_id) { 100 DCHECK_LE(DATA, type); 101 DCHECK_GE(LAST_CONTROL_TYPE, type); 102 DCHECK_EQ(0u, stream_id & ~kStreamIdMask); 103 DCHECK_LE(4, framer.protocol_version()); 104 bool success = true; 105 DCHECK_GT(1u<<16, capacity_); // Make sure length fits in 2B. 106 success &= WriteUInt16(capacity_); 107 success &= WriteUInt8(type); 108 success &= WriteUInt8(flags); 109 success &= WriteUInt32(stream_id); 110 DCHECK_EQ(framer.GetDataFrameMinimumSize(), length()); 111 return success; 112 } 113 114 bool SpdyFrameBuilder::WriteString(const std::string& value) { 115 if (value.size() > 0xffff) { 116 DCHECK(false) << "Tried to write string with length > 16bit."; 117 return false; 118 } 119 120 if (!WriteUInt16(static_cast<int>(value.size()))) 121 return false; 122 123 return WriteBytes(value.data(), static_cast<uint16>(value.size())); 124 } 125 126 bool SpdyFrameBuilder::WriteStringPiece32(const base::StringPiece& value) { 127 if (!WriteUInt32(value.size())) { 128 return false; 129 } 130 131 return WriteBytes(value.data(), value.size()); 132 } 133 134 bool SpdyFrameBuilder::WriteBytes(const void* data, uint32 data_len) { 135 if (!CanWrite(data_len)) { 136 return false; 137 } 138 139 char* dest = GetWritableBuffer(data_len); 140 memcpy(dest, data, data_len); 141 Seek(data_len); 142 return true; 143 } 144 145 bool SpdyFrameBuilder::RewriteLength(const SpdyFramer& framer) { 146 if (framer.protocol_version() < 4) { 147 return OverwriteLength(framer, 148 length_ - framer.GetControlFrameHeaderSize()); 149 } else { 150 return OverwriteLength(framer, length_); 151 } 152 } 153 154 bool SpdyFrameBuilder::OverwriteLength(const SpdyFramer& framer, 155 size_t length) { 156 bool success = false; 157 const size_t old_length = length_; 158 159 if (framer.protocol_version() < 4) { 160 FlagsAndLength flags_length = CreateFlagsAndLength( 161 0, // We're not writing over the flags value anyway. 162 length); 163 164 // Write into the correct location by temporarily faking the offset. 165 length_ = 5; // Offset at which the length field occurs. 166 success = WriteBytes(reinterpret_cast<char*>(&flags_length) + 1, 167 sizeof(flags_length) - 1); 168 } else { 169 length_ = 0; 170 success = WriteUInt16(length); 171 } 172 173 length_ = old_length; 174 return success; 175 } 176 177 bool SpdyFrameBuilder::CanWrite(size_t length) const { 178 if (length > kLengthMask) { 179 DCHECK(false); 180 return false; 181 } 182 183 if (length_ + length > capacity_) { 184 DCHECK(false); 185 return false; 186 } 187 188 return true; 189 } 190 191 } // namespace net 192