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.
5 #include "net/spdy/spdy_frame_builder.h"
9 #include "base/logging.h"
10 #include "net/spdy/spdy_framer.h"
11 #include "net/spdy/spdy_protocol.h"
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
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
;
35 SpdyFrameBuilder::SpdyFrameBuilder(size_t size
)
36 : buffer_(new char[size
]),
41 SpdyFrameBuilder::~SpdyFrameBuilder() {
44 char* SpdyFrameBuilder::GetWritableBuffer(size_t length
) {
45 if (!CanWrite(length
)) {
48 return buffer_
.get() + length_
;
51 bool SpdyFrameBuilder::Seek(size_t length
) {
52 if (!CanWrite(length
)) {
60 bool SpdyFrameBuilder::WriteControlFrameHeader(const SpdyFramer
& framer
,
63 DCHECK_GE(type
, FIRST_CONTROL_TYPE
);
64 DCHECK_LE(type
, LAST_CONTROL_TYPE
);
65 DCHECK_GT(4, framer
.protocol_version());
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());
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
);
82 DCHECK_EQ(0u, stream_id
& ~kStreamIdMask
);
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());
96 bool SpdyFrameBuilder::WriteFramePrefix(const SpdyFramer
& framer
,
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());
105 // Upstream DCHECK's that capacity_ is under the maximum frame size at this
106 // point. Chromium does not, because of the large additional zlib inflation
107 // factor we use. (Frame size is is still checked by OverwriteLength() below).
108 success
&= WriteUInt16(capacity_
);
109 success
&= WriteUInt8(type
);
110 success
&= WriteUInt8(flags
);
111 success
&= WriteUInt32(stream_id
);
112 DCHECK_EQ(framer
.GetDataFrameMinimumSize(), length());
116 bool SpdyFrameBuilder::WriteString(const std::string
& value
) {
117 if (value
.size() > 0xffff) {
118 DCHECK(false) << "Tried to write string with length > 16bit.";
122 if (!WriteUInt16(static_cast<int>(value
.size())))
125 return WriteBytes(value
.data(), static_cast<uint16
>(value
.size()));
128 bool SpdyFrameBuilder::WriteStringPiece32(const base::StringPiece
& value
) {
129 if (!WriteUInt32(value
.size())) {
133 return WriteBytes(value
.data(), value
.size());
136 bool SpdyFrameBuilder::WriteBytes(const void* data
, uint32 data_len
) {
137 if (!CanWrite(data_len
)) {
141 char* dest
= GetWritableBuffer(data_len
);
142 memcpy(dest
, data
, data_len
);
147 bool SpdyFrameBuilder::RewriteLength(const SpdyFramer
& framer
) {
148 if (framer
.protocol_version() < 4) {
149 return OverwriteLength(framer
,
150 length_
- framer
.GetControlFrameHeaderSize());
152 return OverwriteLength(framer
, length_
);
156 bool SpdyFrameBuilder::OverwriteLength(const SpdyFramer
& framer
,
158 if (framer
.protocol_version() < 4) {
159 DCHECK_GT(framer
.GetFrameMaximumSize() - framer
.GetFrameMinimumSize(),
162 DCHECK_GE(framer
.GetFrameMaximumSize(), length
);
164 bool success
= false;
165 const size_t old_length
= length_
;
167 if (framer
.protocol_version() < 4) {
168 FlagsAndLength flags_length
= CreateFlagsAndLength(
169 0, // We're not writing over the flags value anyway.
172 // Write into the correct location by temporarily faking the offset.
173 length_
= 5; // Offset at which the length field occurs.
174 success
= WriteBytes(reinterpret_cast<char*>(&flags_length
) + 1,
175 sizeof(flags_length
) - 1);
178 success
= WriteUInt16(length
);
181 length_
= old_length
;
185 bool SpdyFrameBuilder::CanWrite(size_t length
) const {
186 if (length
> kLengthMask
) {
191 if (length_
+ length
> capacity_
) {