Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(940)

Unified Diff: net/spdy/spdy_framer.cc

Issue 246013002: SPDY: Headers & Push-Promise now use Continuations (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase only Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/spdy/spdy_framer.h ('k') | net/spdy/spdy_framer_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_framer.cc
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index 6d57aa9563d54b38299c186abbff6d8883e15c8f..0b0c9619ae1da3c7ae7e48fe504794f2257622e2 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -166,22 +166,12 @@ void SpdyFramer::Reset() {
}
size_t SpdyFramer::GetDataFrameMinimumSize() const {
- // Size, in bytes, of the data frame header. Future versions of SPDY
- // will likely vary this, so we allow for the flexibility of a function call
- // for this value as opposed to a constant.
- return 8;
+ return SpdyConstants::GetDataFrameMinimumSize();
}
// Size, in bytes, of the control frame header.
size_t SpdyFramer::GetControlFrameHeaderSize() const {
- switch (protocol_version()) {
- case SPDY2:
- case SPDY3:
- case SPDY4:
- return 8;
- }
- LOG(DFATAL) << "Unhandled SPDY version.";
- return 0;
+ return SpdyConstants::GetControlFrameHeaderSize(protocol_version());
}
size_t SpdyFramer::GetSynStreamMinimumSize() const {
@@ -326,19 +316,17 @@ size_t SpdyFramer::GetFrameMinimumSize() const {
}
size_t SpdyFramer::GetFrameMaximumSize() const {
- if (protocol_version() <= SPDY3) {
- // 24-bit length field plus eight-byte frame header.
- return ((1<<24) - 1) + 8;
- } else {
- // 14-bit length field.
- return (1<<14) - 1;
- }
+ return SpdyConstants::GetFrameMaximumSize(protocol_version());
}
size_t SpdyFramer::GetDataFrameMaximumPayload() const {
return GetFrameMaximumSize() - GetDataFrameMinimumSize();
}
+size_t SpdyFramer::GetPrefixLength(SpdyFrameType type) const {
+ return SpdyConstants::GetPrefixLength(type, protocol_version());
+}
+
const char* SpdyFramer::StateToString(int state) {
switch (state) {
case SPDY_ERROR:
@@ -1601,7 +1589,8 @@ void SpdyFramer::DeliverHpackBlockAsSpdy3Block() {
return;
}
SpdyFrameBuilder builder(
- GetSerializedLength(protocol_version(), &block));
+ GetSerializedLength(protocol_version(), &block),
+ SPDY3);
SerializeNameValueBlockWithoutCompression(&builder, block);
scoped_ptr<SpdyFrame> frame(builder.take());
@@ -2031,7 +2020,7 @@ SpdySerializedFrame* SpdyFramer::SerializeData(
const size_t size_with_padding = num_padding_fields +
data_ir.data().length() + data_ir.padding_payload_len() +
GetDataFrameMinimumSize();
- SpdyFrameBuilder builder(size_with_padding);
+ SpdyFrameBuilder builder(size_with_padding, protocol_version());
builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags);
if (data_ir.pad_high()) {
builder.WriteUInt8(data_ir.padding_payload_len() >> 8);
@@ -2048,7 +2037,7 @@ SpdySerializedFrame* SpdyFramer::SerializeData(
return builder.take();
} else {
const size_t size = GetDataFrameMinimumSize() + data_ir.data().length();
- SpdyFrameBuilder builder(size);
+ SpdyFrameBuilder builder(size, protocol_version());
builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags);
builder.WriteBytes(data_ir.data().data(), data_ir.data().length());
DCHECK_EQ(size, builder.length());
@@ -2077,7 +2066,7 @@ SpdySerializedFrame* SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField(
frame_size += num_padding_fields;
}
- SpdyFrameBuilder builder(frame_size);
+ SpdyFrameBuilder builder(frame_size, protocol_version());
builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags);
if (protocol_version() > SPDY3) {
if (data_ir.pad_high()) {
@@ -2131,7 +2120,7 @@ SpdySerializedFrame* SpdyFramer::SerializeSynStream(
size += GetSerializedLength(syn_stream.name_value_block());
}
- SpdyFrameBuilder builder(size);
+ SpdyFrameBuilder builder(size, protocol_version());
if (protocol_version() <= SPDY3) {
builder.WriteControlFrameHeader(*this, SYN_STREAM, flags);
builder.WriteUInt32(syn_stream.stream_id());
@@ -2139,10 +2128,10 @@ SpdySerializedFrame* SpdyFramer::SerializeSynStream(
builder.WriteUInt8(priority << ((protocol_version() <= SPDY2) ? 6 : 5));
builder.WriteUInt8(0); // Unused byte where credential slot used to be.
} else {
- builder.WriteFramePrefix(*this,
- HEADERS,
- flags,
- syn_stream.stream_id());
+ builder.BeginNewFrame(*this,
+ HEADERS,
+ flags,
+ syn_stream.stream_id());
builder.WriteUInt32(priority);
}
DCHECK_EQ(GetSynStreamMinimumSize(), builder.length());
@@ -2191,15 +2180,15 @@ SpdySerializedFrame* SpdyFramer::SerializeSynReply(
size += GetSerializedLength(syn_reply.name_value_block());
}
- SpdyFrameBuilder builder(size);
+ SpdyFrameBuilder builder(size, protocol_version());
if (protocol_version() <= SPDY3) {
builder.WriteControlFrameHeader(*this, SYN_REPLY, flags);
builder.WriteUInt32(syn_reply.stream_id());
} else {
- builder.WriteFramePrefix(*this,
- HEADERS,
- flags,
- syn_reply.stream_id());
+ builder.BeginNewFrame(*this,
+ HEADERS,
+ flags,
+ syn_reply.stream_id());
}
if (protocol_version() < SPDY3) {
builder.WriteUInt16(0); // Unused.
@@ -2236,14 +2225,14 @@ SpdySerializedFrame* SpdyFramer::SerializeRstStream(
if (protocol_version() > SPDY3) {
expected_length += rst_stream.description().size();
}
- SpdyFrameBuilder builder(expected_length);
+ SpdyFrameBuilder builder(expected_length, protocol_version());
// Serialize the RST_STREAM frame.
if (protocol_version() <= SPDY3) {
builder.WriteControlFrameHeader(*this, RST_STREAM, 0);
builder.WriteUInt32(rst_stream.stream_id());
} else {
- builder.WriteFramePrefix(*this, RST_STREAM, 0, rst_stream.stream_id());
+ builder.BeginNewFrame(*this, RST_STREAM, 0, rst_stream.stream_id());
}
builder.WriteUInt32(rst_stream.status());
@@ -2277,11 +2266,11 @@ SpdySerializedFrame* SpdyFramer::SerializeSettings(
// Size, in bytes, of this SETTINGS frame.
const size_t size = GetSettingsMinimumSize() +
(values->size() * setting_size);
- SpdyFrameBuilder builder(size);
+ SpdyFrameBuilder builder(size, protocol_version());
if (protocol_version() <= SPDY3) {
builder.WriteControlFrameHeader(*this, SETTINGS, flags);
} else {
- builder.WriteFramePrefix(*this, SETTINGS, flags, 0);
+ builder.BeginNewFrame(*this, SETTINGS, flags, 0);
}
// If this is an ACK, payload should be empty.
@@ -2319,15 +2308,8 @@ SpdySerializedFrame* SpdyFramer::SerializeSettings(
return builder.take();
}
-SpdyFrame* SpdyFramer::SerializeBlocked(const SpdyBlockedIR& blocked) const {
- DCHECK_LT(SPDY3, protocol_version());
- SpdyFrameBuilder builder(GetBlockedSize());
- builder.WriteFramePrefix(*this, BLOCKED, kNoFlags, blocked.stream_id());
- return builder.take();
-}
-
SpdySerializedFrame* SpdyFramer::SerializePing(const SpdyPingIR& ping) const {
- SpdyFrameBuilder builder(GetPingSize());
+ SpdyFrameBuilder builder(GetPingSize(), protocol_version());
if (protocol_version() <= SPDY3) {
builder.WriteControlFrameHeader(*this, PING, kNoFlags);
builder.WriteUInt32(static_cast<uint32>(ping.id()));
@@ -2336,7 +2318,7 @@ SpdySerializedFrame* SpdyFramer::SerializePing(const SpdyPingIR& ping) const {
if (ping.is_ack()) {
flags |= PING_FLAG_ACK;
}
- builder.WriteFramePrefix(*this, PING, flags, 0);
+ builder.BeginNewFrame(*this, PING, flags, 0);
builder.WriteUInt64(ping.id());
}
DCHECK_EQ(GetPingSize(), builder.length());
@@ -2351,13 +2333,13 @@ SpdySerializedFrame* SpdyFramer::SerializeGoAway(
if (protocol_version() > SPDY3) {
expected_length += goaway.description().size();
}
- SpdyFrameBuilder builder(expected_length);
+ SpdyFrameBuilder builder(expected_length, protocol_version());
// Serialize the GOAWAY frame.
if (protocol_version() <= SPDY3) {
builder.WriteControlFrameHeader(*this, GOAWAY, kNoFlags);
} else {
- builder.WriteFramePrefix(*this, GOAWAY, 0, 0);
+ builder.BeginNewFrame(*this, GOAWAY, 0, 0);
}
// GOAWAY frames specify the last good stream id for all SPDY versions.
@@ -2385,6 +2367,9 @@ SpdySerializedFrame* SpdyFramer::SerializeHeaders(
flags |= CONTROL_FLAG_FIN;
}
if (protocol_version() > SPDY3) {
+ // TODO(mlavan): If we overflow into a CONTINUATION frame, this will
+ // get overwritten below, so we should probably just get rid of the
+ // end_headers field.
if (headers.end_headers()) {
flags |= HEADERS_FLAG_END_HEADERS;
}
@@ -2409,19 +2394,24 @@ SpdySerializedFrame* SpdyFramer::SerializeHeaders(
if (protocol_version() > SPDY3) {
hpack_encoder_.EncodeHeaderSet(headers.name_value_block(), &hpack_encoding);
size += hpack_encoding.size();
+ if (size > GetControlFrameBufferMaxSize()) {
+ size += GetNumberRequiredContinuationFrames(size) *
+ GetContinuationMinimumSize();
+ flags &= ~HEADERS_FLAG_END_HEADERS;
+ }
} else {
size += GetSerializedLength(headers.name_value_block());
}
- SpdyFrameBuilder builder(size);
+ SpdyFrameBuilder builder(size, protocol_version());
if (protocol_version() <= SPDY3) {
builder.WriteControlFrameHeader(*this, HEADERS, flags);
builder.WriteUInt32(headers.stream_id());
} else {
- builder.WriteFramePrefix(*this,
- HEADERS,
- flags,
- headers.stream_id());
+ builder.BeginNewFrame(*this,
+ HEADERS,
+ flags,
+ headers.stream_id());
if (headers.has_priority()) {
builder.WriteUInt32(priority);
}
@@ -2432,7 +2422,10 @@ SpdySerializedFrame* SpdyFramer::SerializeHeaders(
DCHECK_EQ(GetHeadersMinimumSize(), builder.length());
if (protocol_version() > SPDY3) {
- builder.WriteBytes(&hpack_encoding[0], hpack_encoding.size());
+ WritePayloadWithContinuation(&builder,
+ hpack_encoding,
+ headers.stream_id(),
+ HEADERS);
} else {
SerializeNameValueBlock(&builder, headers);
}
@@ -2453,25 +2446,35 @@ SpdySerializedFrame* SpdyFramer::SerializeHeaders(
SpdySerializedFrame* SpdyFramer::SerializeWindowUpdate(
const SpdyWindowUpdateIR& window_update) const {
- SpdyFrameBuilder builder(GetWindowUpdateSize());
+ SpdyFrameBuilder builder(GetWindowUpdateSize(), protocol_version());
if (protocol_version() <= SPDY3) {
builder.WriteControlFrameHeader(*this, WINDOW_UPDATE, kNoFlags);
builder.WriteUInt32(window_update.stream_id());
} else {
- builder.WriteFramePrefix(*this,
- WINDOW_UPDATE,
- kNoFlags,
- window_update.stream_id());
+ builder.BeginNewFrame(*this,
+ WINDOW_UPDATE,
+ kNoFlags,
+ window_update.stream_id());
}
builder.WriteUInt32(window_update.delta());
DCHECK_EQ(GetWindowUpdateSize(), builder.length());
return builder.take();
}
+SpdyFrame* SpdyFramer::SerializeBlocked(const SpdyBlockedIR& blocked) const {
+ DCHECK_LT(SPDY3, protocol_version());
+ SpdyFrameBuilder builder(GetBlockedSize(), protocol_version());
+ builder.BeginNewFrame(*this, BLOCKED, kNoFlags, blocked.stream_id());
+ return builder.take();
+}
+
SpdyFrame* SpdyFramer::SerializePushPromise(
const SpdyPushPromiseIR& push_promise) {
DCHECK_LT(SPDY3, protocol_version());
uint8 flags = 0;
+ // TODO(mlavan): If we overflow into a CONTINUATION frame, this will
+ // get overwritten below, so we should probably just get rid of the
+ // end_push_promise field.
if (push_promise.end_push_promise()) {
flags |= PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
}
@@ -2483,18 +2486,28 @@ SpdyFrame* SpdyFramer::SerializePushPromise(
hpack_encoder_.EncodeHeaderSet(push_promise.name_value_block(),
&hpack_encoding);
size += hpack_encoding.size();
+ if (size > GetControlFrameBufferMaxSize()) {
+ size += GetNumberRequiredContinuationFrames(size) *
+ GetContinuationMinimumSize();
+ flags &= ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
+ }
} else {
size += GetSerializedLength(push_promise.name_value_block());
}
- SpdyFrameBuilder builder(size);
- builder.WriteFramePrefix(*this, PUSH_PROMISE, flags,
- push_promise.stream_id());
+ SpdyFrameBuilder builder(size, protocol_version());
+ builder.BeginNewFrame(*this,
+ PUSH_PROMISE,
+ flags,
+ push_promise.stream_id());
builder.WriteUInt32(push_promise.promised_stream_id());
DCHECK_EQ(GetPushPromiseMinimumSize(), builder.length());
if (protocol_version() > SPDY3) {
- builder.WriteBytes(&hpack_encoding[0], hpack_encoding.size());
+ WritePayloadWithContinuation(&builder,
+ hpack_encoding,
+ push_promise.stream_id(),
+ PUSH_PROMISE);
} else {
SerializeNameValueBlock(&builder, push_promise);
}
@@ -2529,8 +2542,8 @@ SpdyFrame* SpdyFramer::SerializeContinuation(
&hpack_encoding);
size += hpack_encoding.size();
- SpdyFrameBuilder builder(size);
- builder.WriteFramePrefix(*this, CONTINUATION, flags,
+ SpdyFrameBuilder builder(size, protocol_version());
+ builder.BeginNewFrame(*this, CONTINUATION, flags,
continuation.stream_id());
DCHECK_EQ(GetContinuationMinimumSize(), builder.length());
@@ -2620,6 +2633,69 @@ size_t SpdyFramer::GetSerializedLength(const SpdyHeaderBlock& headers) {
return 2 * deflateBound(compressor, uncompressed_length);
}
+size_t SpdyFramer::GetNumberRequiredContinuationFrames(size_t size) {
+ const size_t kMaxControlFrameSize = GetControlFrameBufferMaxSize();
+ DCHECK_GT(protocol_version(), net::SPDY3);
+ DCHECK_GT(size, kMaxControlFrameSize);
+ size_t overflow = size - kMaxControlFrameSize;
+ return overflow / (kMaxControlFrameSize - GetContinuationMinimumSize()) + 1;
+}
+
+void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder,
+ const string& hpack_encoding,
+ SpdyStreamId stream_id,
+ SpdyFrameType type) {
+ const size_t kMaxControlFrameSize = GetControlFrameBufferMaxSize();
+
+ // In addition to the prefix, fixed_field_size includes the size of
+ // any fields that come before the variable-length name/value block.
+ size_t fixed_field_size = 0;
+ uint8 end_flag = 0;
+ uint8 flags = 0;
+ if (type == HEADERS) {
+ fixed_field_size = GetHeadersMinimumSize();
+ end_flag = HEADERS_FLAG_END_HEADERS;
+ } else if (type == PUSH_PROMISE) {
+ fixed_field_size = GetPushPromiseMinimumSize();
+ end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
+ } else {
+ DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type "
+ << FrameTypeToString(type);
+ }
+
+ // Write as much of the payload as possible into the initial frame.
+ size_t bytes_remaining = hpack_encoding.size() -
+ std::min(hpack_encoding.size(),
+ kMaxControlFrameSize - fixed_field_size);
+ builder->WriteBytes(&hpack_encoding[0],
+ hpack_encoding.size() - bytes_remaining);
+
+ if (bytes_remaining > 0) {
+ builder->OverwriteLength(*this,
+ kMaxControlFrameSize - GetControlFrameHeaderSize());
+ }
+
+ // Tack on CONTINUATION frames for the overflow.
+ while (bytes_remaining > 0) {
+ size_t bytes_to_write = std::min(bytes_remaining,
+ kMaxControlFrameSize -
+ GetContinuationMinimumSize());
+ // Write CONTINUATION frame prefix.
+ if (bytes_remaining == bytes_to_write) {
+ flags |= end_flag;
+ }
+ builder->BeginNewFrame(*this,
+ CONTINUATION,
+ flags,
+ stream_id);
+ // Write payload fragment.
+ builder->WriteBytes(&hpack_encoding[hpack_encoding.size() -
+ bytes_remaining],
+ bytes_to_write);
+ bytes_remaining -= bytes_to_write;
+ }
+}
+
// The following compression setting are based on Brian Olson's analysis. See
// https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac792
// for more details.
@@ -2807,7 +2883,7 @@ void SpdyFramer::SerializeNameValueBlock(
// First build an uncompressed version to be fed into the compressor.
const size_t uncompressed_len = GetSerializedLength(
protocol_version(), &(frame.name_value_block()));
- SpdyFrameBuilder uncompressed_builder(uncompressed_len);
+ SpdyFrameBuilder uncompressed_builder(uncompressed_len, protocol_version());
SerializeNameValueBlockWithoutCompression(&uncompressed_builder,
frame.name_value_block());
scoped_ptr<SpdyFrame> uncompressed_payload(uncompressed_builder.take());
« no previous file with comments | « net/spdy/spdy_framer.h ('k') | net/spdy/spdy_framer_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698