// A special structure for the 8 bit flags and 24 bit length fields.
union FlagsAndLength {
- uint8 flags_[4]; // 8 bits
- uint32 length_; // 24 bits
+ uint8 flags[4]; // 8 bits
+ uint32 length; // 24 bits
};
// Creates a FlagsAndLength.
FlagsAndLength CreateFlagsAndLength(uint8 flags, size_t length) {
DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
FlagsAndLength flags_length;
- flags_length.length_ = htonl(static_cast<uint32>(length));
+ flags_length.length = htonl(static_cast<uint32>(length));
DCHECK_EQ(0, flags & ~kControlFlagsMask);
- flags_length.flags_[0] = flags;
+ flags_length.flags[0] = flags;
return flags_length;
}
} // namespace
-SpdyFrameBuilder::SpdyFrameBuilder(size_t size)
+SpdyFrameBuilder::SpdyFrameBuilder(size_t size, SpdyMajorVersion version)
: buffer_(new char[size]),
capacity_(size),
- length_(0) {
+ length_(0),
+ offset_(0),
+ version_(version) {
}
SpdyFrameBuilder::~SpdyFrameBuilder() {
if (!CanWrite(length)) {
return NULL;
}
- return buffer_.get() + length_;
+ return buffer_.get() + offset_ + length_;
}
bool SpdyFrameBuilder::Seek(size_t length) {
bool SpdyFrameBuilder::WriteControlFrameHeader(const SpdyFramer& framer,
SpdyFrameType type,
uint8 flags) {
- DCHECK_GE(type, FIRST_CONTROL_TYPE);
- DCHECK_LE(type, LAST_CONTROL_TYPE);
- DCHECK_GT(4, framer.protocol_version());
+ DCHECK_GE(SPDY3, version_);
+ DCHECK(SpdyConstants::IsValidFrameType(
+ version_, SpdyConstants::SerializeFrameType(version_, type)));
bool success = true;
FlagsAndLength flags_length = CreateFlagsAndLength(
flags, capacity_ - framer.GetControlFrameHeaderSize());
- success &= WriteUInt16(kControlFlagMask | framer.protocol_version());
- success &= WriteUInt16(type);
+ success &= WriteUInt16(kControlFlagMask |
+ SpdyConstants::SerializeMajorVersion(version_));
+ success &= WriteUInt16(
+ SpdyConstants::SerializeFrameType(framer.protocol_version(), type));
success &= WriteBytes(&flags_length, sizeof(flags_length));
DCHECK_EQ(framer.GetControlFrameHeaderSize(), length());
return success;
bool SpdyFrameBuilder::WriteDataFrameHeader(const SpdyFramer& framer,
SpdyStreamId stream_id,
- SpdyDataFlags flags) {
- if (framer.protocol_version() >= 4) {
- return WriteFramePrefix(framer, DATA, flags, stream_id);
+ uint8 flags) {
+ if (version_ > SPDY3) {
+ return BeginNewFrame(framer, DATA, flags, stream_id);
}
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
bool success = true;
size_t length_field = capacity_ - framer.GetDataFrameMinimumSize();
DCHECK_EQ(0u, length_field & ~static_cast<size_t>(kLengthMask));
FlagsAndLength flags_length;
- flags_length.length_ = htonl(length_field);
+ flags_length.length = htonl(length_field);
DCHECK_EQ(0, flags & ~kDataFlagsMask);
- flags_length.flags_[0] = flags;
+ flags_length.flags[0] = flags;
success &= WriteBytes(&flags_length, sizeof(flags_length));
DCHECK_EQ(framer.GetDataFrameMinimumSize(), length());
return success;
}
-bool SpdyFrameBuilder::WriteFramePrefix(const SpdyFramer& framer,
- SpdyFrameType type,
- uint8 flags,
- SpdyStreamId stream_id) {
- DCHECK_LE(DATA, type);
- DCHECK_GE(LAST_CONTROL_TYPE, type);
+bool SpdyFrameBuilder::BeginNewFrame(const SpdyFramer& framer,
+ SpdyFrameType type,
+ uint8 flags,
+ SpdyStreamId stream_id) {
+ DCHECK(SpdyConstants::IsValidFrameType(
+ version_, SpdyConstants::SerializeFrameType(version_, type)));
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
- DCHECK_LE(4, framer.protocol_version());
+ DCHECK_GT(framer.protocol_version(), SPDY3);
bool success = true;
- // Upstream DCHECK's that capacity_ is under the maximum frame size at this
- // point. Chromium does not, because of the large additional zlib inflation
- // factor we use. (Frame size is is still checked by OverwriteLength() below).
- success &= WriteUInt16(capacity_);
- success &= WriteUInt8(type);
+ if (length_ > 0) {
+ // Update length field for previous frame.
+ OverwriteLength(framer, length_ - framer.GetPrefixLength(type));
+ DLOG_IF(DFATAL, SpdyConstants::GetFrameMaximumSize(version_) < length_)
+ << "Frame length " << length_
+ << " is longer than the maximum allowed length.";
+ }
+
+ offset_ += length_;
+ length_ = 0;
+
+ // 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_ - framer.GetPrefixLength(type));
+ success &= WriteUInt8(
+ SpdyConstants::SerializeFrameType(version_, type));
success &= WriteUInt8(flags);
success &= WriteUInt32(stream_id);
- DCHECK_EQ(framer.GetDataFrameMinimumSize(), length());
+ DCHECK_EQ(framer.GetDataFrameMinimumSize(), length_);
return success;
}
return false;
}
- if (!WriteUInt16(static_cast<int>(value.size())))
+ if (!WriteUInt16(static_cast<uint16>(value.size())))
return false;
return WriteBytes(value.data(), static_cast<uint16>(value.size()));
}
bool SpdyFrameBuilder::RewriteLength(const SpdyFramer& framer) {
- if (framer.protocol_version() < 4) {
- return OverwriteLength(framer,
- length_ - framer.GetControlFrameHeaderSize());
- } else {
- return OverwriteLength(framer, length_);
- }
+ return OverwriteLength(framer,
+ length_ - framer.GetControlFrameHeaderSize());
}
bool SpdyFrameBuilder::OverwriteLength(const SpdyFramer& framer,
size_t length) {
- if (framer.protocol_version() < 4) {
- DCHECK_GT(framer.GetFrameMaximumSize() - framer.GetFrameMinimumSize(),
- length);
+ if (version_ < SPDY4) {
+ DCHECK_LE(length,
+ SpdyConstants::GetFrameMaximumSize(version_) -
+ framer.GetFrameMinimumSize());
} else {
- DCHECK_GE(framer.GetFrameMaximumSize(), length);
+ DCHECK_LE(length, SpdyConstants::GetFrameMaximumSize(version_));
}
bool success = false;
const size_t old_length = length_;
- if (framer.protocol_version() < 4) {
+ if (version_ < SPDY4) {
FlagsAndLength flags_length = CreateFlagsAndLength(
0, // We're not writing over the flags value anyway.
length);
sizeof(flags_length) - 1);
} else {
length_ = 0;
- success = WriteUInt16(length);
+ success = WriteUInt24(length);
}
length_ = old_length;
return success;
}
+bool SpdyFrameBuilder::OverwriteFlags(const SpdyFramer& framer,
+ uint8 flags) {
+ DCHECK_GT(framer.protocol_version(), SPDY3);
+ bool success = false;
+ const size_t old_length = length_;
+ // Flags are the fifth octet in the frame prefix.
+ length_ = 4;
+ success = WriteUInt8(flags);
+ length_ = old_length;
+ return success;
+}
+
bool SpdyFrameBuilder::CanWrite(size_t length) const {
if (length > kLengthMask) {
DCHECK(false);
return false;
}
- if (length_ + length > capacity_) {
+ if (offset_ + length_ + length > capacity_) {
DCHECK(false);
return false;
}