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

Unified Diff: net/spdy/spdy_framer.cc

Issue 21820003: DO NOT COMMIT: SPDY 4: Hack SpdyFramer to turn SYN_STREAM and SYN_REPLY into HEADERS semi-transpare… Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase for draft 06 Created 7 years, 2 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_frame_builder.cc ('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 89a8309ea44c22aa0d19e927f8551b0106fdcb3e..f48a46c307c813676e169d281ea311be581c1c13 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -171,17 +171,15 @@ size_t SpdyFramer::GetControlFrameHeaderSize() const {
}
size_t SpdyFramer::GetSynStreamMinimumSize() const {
+ if (spdy_version_ >= SPDY4)
+ return GetSynReplyMinimumSize();
+
+ DCHECK_LT(spdy_version_, SPDY4);
// Size, in bytes, of a SYN_STREAM frame not including the variable-length
// name-value block.
- if (spdy_version_ < 4) {
- // Calculated as:
- // control frame header + 2 * 4 (stream IDs) + 1 (priority) + 1 (slot)
- return GetControlFrameHeaderSize() + 10;
- } else {
- // Calculated as:
- // frame prefix + 4 (associated stream ID) + 1 (priority) + 1 (slot)
- return GetControlFrameHeaderSize() + 6;
- }
+ // Calculated as:
+ // control frame header + 2 * 4 (stream IDs) + 1 (priority) + 1 (slot)
+ return GetControlFrameHeaderSize() + 10;
}
size_t SpdyFramer::GetSynReplyMinimumSize() const {
@@ -216,16 +214,24 @@ size_t SpdyFramer::GetRstStreamSize() const {
}
size_t SpdyFramer::GetSettingsMinimumSize() const {
- // Size, in bytes, of a SETTINGS frame not including the IDs and values
- // from the variable-length value block. Calculated as:
- // control frame header + 4 (number of ID/value pairs)
- return GetControlFrameHeaderSize() + 4;
+ if (spdy_version_ < 4) {
+ // Size, in bytes, of a SETTINGS frame not including the IDs and values
+ // from the variable-length value block. Calculated as:
+ // control frame header + 4 (number of ID/value pairs)
+ return GetControlFrameHeaderSize() + 4;
+ } else {
+ return GetControlFrameHeaderSize();
+ }
}
size_t SpdyFramer::GetPingSize() const {
// Size, in bytes, of this PING frame. Calculated as:
- // control frame header + 4 (id)
- return GetControlFrameHeaderSize() + 4;
+ // control frame header + 4 (id) (or 8 for SPDY4)
+ if (spdy_version_ < SPDY4) {
+ return GetControlFrameHeaderSize() + 4;
+ } else {
+ return GetControlFrameHeaderSize() + 8;
+ }
}
size_t SpdyFramer::GetGoAwaySize() const {
@@ -591,7 +597,6 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
uint16 length_field = 0;
bool successful_read = reader->ReadUInt16(&length_field);
DCHECK(successful_read);
- current_frame_length_ = length_field;
uint8 control_frame_type_field_uint8 = DATA;
successful_read = reader->ReadUInt8(&control_frame_type_field_uint8);
@@ -607,7 +612,8 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
successful_read = reader->ReadUInt31(&current_frame_stream_id_);
DCHECK(successful_read);
- remaining_data_length_ = current_frame_length_ - reader->GetBytesConsumed();
+ remaining_data_length_ = length_field;
+ current_frame_length_ = remaining_data_length_ + reader->GetBytesConsumed();
}
DCHECK_EQ(is_control_frame ? GetControlFrameHeaderSize()
: GetDataFrameMinimumSize(),
@@ -674,6 +680,10 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
current_frame_type_ = static_cast<SpdyFrameType>(control_frame_type_field);
+ if (spdy_version_ >= SPDY4 && current_frame_type_ == SYN_STREAM) {
+ current_frame_type_ = HEADERS;
+ }
+
if (current_frame_type_ == NOOP) {
DLOG(INFO) << "NOOP control frame found. Ignoring.";
CHANGE_STATE(SPDY_AUTO_RESET);
@@ -685,7 +695,7 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
case SYN_STREAM:
if (current_frame_length_ < GetSynStreamMinimumSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
- } else if (current_frame_flags_ &
+ } else if (spdy_version_ < SPDY4 && current_frame_flags_ &
~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
@@ -693,7 +703,8 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
case SYN_REPLY:
if (current_frame_length_ < GetSynReplyMinimumSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
- } else if (current_frame_flags_ & ~CONTROL_FLAG_FIN) {
+ } else if (spdy_version_ < SPDY4 && current_frame_flags_ &
+ ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
break;
@@ -708,7 +719,9 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
// Make sure that we have an integral number of 8-byte key/value pairs,
// plus a 4-byte length field.
if (current_frame_length_ < GetSettingsMinimumSize() ||
- (current_frame_length_ - GetControlFrameHeaderSize()) % 8 != 4) {
+ ((spdy_version_ < SPDY4) &&
+ ((current_frame_length_ - GetControlFrameHeaderSize()) % 8 != 4)) ||
+ ((spdy_version_ >= SPDY4) && (current_frame_length_ % 8 != 0))) {
DLOG(WARNING) << "Invalid length for SETTINGS frame: "
<< current_frame_length_;
set_error(SPDY_INVALID_CONTROL_FRAME);
@@ -720,8 +733,11 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
case PING:
if (current_frame_length_ != GetPingSize()) {
set_error(SPDY_INVALID_CONTROL_FRAME);
- } else if (current_frame_flags_ != 0) {
+ } else if (spdy_version_ < SPDY4 && current_frame_flags_ != 0) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
+ } else if (spdy_version_ >= SPDY4 && (current_frame_flags_ & ~0x1) != 0) {
+ // TODO(akalin): Unignore this.
+ // set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
break;
case GOAWAY:
@@ -734,10 +750,21 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
break;
}
case HEADERS:
- if (current_frame_length_ < GetHeadersMinimumSize()) {
- set_error(SPDY_INVALID_CONTROL_FRAME);
- } else if (current_frame_flags_ & ~CONTROL_FLAG_FIN) {
- set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
+ {
+ size_t min_size = GetHeadersMinimumSize();
+ if (spdy_version_ > 3 && current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
+ min_size += 4;
+ }
+ if (current_frame_length_ < min_size) {
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ } else if (spdy_version_ < 4 &&
+ current_frame_flags_ & ~CONTROL_FLAG_FIN) {
+ set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
+ } else if (spdy_version_ > 3 && current_frame_flags_ &
+ ~(CONTROL_FLAG_FIN | HEADERS_FLAG_PRIORITY |
+ HEADERS_FLAG_END_HEADERS)) {
+ set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
+ }
}
break;
case WINDOW_UPDATE:
@@ -813,6 +840,9 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
break;
case HEADERS:
frame_size_without_variable_data = GetHeadersMinimumSize();
+ if (spdy_version_ > 3 && current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
+ frame_size_without_variable_data += 4; // priority
+ }
break;
case PUSH_PROMISE:
frame_size_without_variable_data = GetPushPromiseMinimumSize();
@@ -1075,7 +1105,7 @@ void SpdyFramer::WriteHeaderBlockToZ(const SpdyHeaderBlock* headers,
size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
size_t len) {
DCHECK_EQ(SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, state_);
- size_t original_len = len;
+ const size_t original_len = len;
if (remaining_control_header_ > 0) {
size_t bytes_read = UpdateCurrentFrameBuffer(&data, &len,
@@ -1092,6 +1122,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
switch (current_frame_type_) {
case SYN_STREAM:
{
+ DCHECK_GT(4, spdy_version_);
bool successful_read = true;
if (spdy_version_ < 4) {
successful_read = reader.ReadUInt31(&current_frame_stream_id_);
@@ -1163,17 +1194,42 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
// SPDY 2 had two unused bytes here. Seek past them.
reader.Seek(2);
}
+ const bool has_priority =
+ (current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0;
+ uint32 priority = 0;
+ if (protocol_version() > 3 && has_priority) {
+ successful_read = reader.ReadUInt31(&priority);
+ DCHECK(successful_read);
+ }
DCHECK(reader.IsDoneReading());
if (debug_visitor_) {
+ // SPDY 4 reports HEADERS with PRIORITY as SYN_STREAM.
+ SpdyFrameType reported_type = current_frame_type_;
+ if (protocol_version() > 3 && has_priority) {
+ reported_type = SYN_STREAM;
+ }
debug_visitor_->OnReceiveCompressedFrame(
current_frame_stream_id_,
- current_frame_type_,
+ reported_type,
current_frame_length_);
}
- if (current_frame_type_ == SYN_REPLY) {
+ // TODO(akalin): Fix this hack.
+ if (current_frame_type_ == SYN_REPLY ||
+ (spdy_version_ >= SPDY4 && current_frame_type_ == HEADERS)) {
visitor_->OnSynReply(
current_frame_stream_id_,
(current_frame_flags_ & CONTROL_FLAG_FIN) != 0);
+ } else if (spdy_version_ > 3 &&
+ current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
+ // SPDY 4+ is missing SYN_STREAM. Simulate it so that API changes
+ // can be made independent of wire changes.
+ visitor_->OnSynStream(
+ current_frame_stream_id_,
+ 0, // associated_to_stream_id
+ priority,
+ 0, // TODO(hkhalil): handle slot for SPDY 4+?
+ current_frame_flags_ & CONTROL_FLAG_FIN,
+ false); // unidirectional
} else {
visitor_->OnHeaders(
current_frame_stream_id_,
@@ -1403,10 +1459,18 @@ size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
break;
case PING: {
SpdyPingId id = 0;
- bool successful_read = reader.ReadUInt32(&id);
- DCHECK(successful_read);
- DCHECK(reader.IsDoneReading());
- visitor_->OnPing(id);
+ uint32 zero_expected = 0x01;
+ bool successful_read =
+ reader.ReadUInt32(&id) && reader.ReadUInt32(&zero_expected);
+ if (successful_read && reader.IsDoneReading() && zero_expected == 0) {
+ visitor_->OnPing(id);
+ } else {
+ // Can't set_error() here, so just warn, I guess. But this
+ // breaks spec.
+ //
+ // TODO(akalin): Fix this.
+ LOG(WARNING) << "Dropping invalid ping frame";
+ }
}
break;
case GOAWAY: {
@@ -1662,33 +1726,44 @@ SpdySerializedFrame* SpdyFramer::SerializeSynStream(
if (syn_stream.fin()) {
flags |= CONTROL_FLAG_FIN;
}
- if (syn_stream.unidirectional()) {
+ if (spdy_version_ <= SPDY4 && syn_stream.unidirectional()) {
flags |= CONTROL_FLAG_UNIDIRECTIONAL;
}
+ if (spdy_version_ >= SPDY4) {
+ flags |= HEADERS_FLAG_END_HEADERS;
+ flags |= HEADERS_FLAG_PRIORITY;
+ }
+
+ // Sanitize priority.
+ uint8 priority = syn_stream.priority();
+ if (priority > GetLowestPriority()) {
+ DLOG(DFATAL) << "Priority out-of-bounds.";
+ priority = GetLowestPriority();
+ }
// The size of this frame, including variable-length name-value block.
- const size_t size = GetSynStreamMinimumSize()
+ size_t size = GetSynStreamMinimumSize()
+ GetSerializedLength(syn_stream.name_value_block());
+ if (spdy_version_ >= SPDY4 && (flags & HEADERS_FLAG_PRIORITY)) {
+ size += 4;
+ }
+
SpdyFrameBuilder builder(size);
if (spdy_version_ < 4) {
builder.WriteControlFrameHeader(*this, SYN_STREAM, flags);
builder.WriteUInt32(syn_stream.stream_id());
+ builder.WriteUInt32(syn_stream.associated_to_stream_id());
+ builder.WriteUInt8(priority << ((spdy_version_ < 3) ? 6 : 5));
+ builder.WriteUInt8(syn_stream.slot());
+ DCHECK_EQ(GetSynStreamMinimumSize(), builder.length());
} else {
builder.WriteFramePrefix(*this,
- SYN_STREAM,
+ HTTP2_HEADERS,
flags,
syn_stream.stream_id());
+ builder.WriteUInt32(priority);
}
- builder.WriteUInt32(syn_stream.associated_to_stream_id());
- uint8 priority = syn_stream.priority();
- if (priority > GetLowestPriority()) {
- DLOG(DFATAL) << "Priority out-of-bounds.";
- priority = GetLowestPriority();
- }
- builder.WriteUInt8(priority << ((spdy_version_ < 3) ? 6 : 5));
- builder.WriteUInt8(syn_stream.slot());
- DCHECK_EQ(GetSynStreamMinimumSize(), builder.length());
SerializeNameValueBlock(&builder, syn_stream);
if (debug_visitor_) {
@@ -1736,7 +1811,7 @@ SpdySerializedFrame* SpdyFramer::SerializeSynReply(
builder.WriteUInt32(syn_reply.stream_id());
} else {
builder.WriteFramePrefix(*this,
- SYN_REPLY,
+ HEADERS,
flags,
syn_reply.stream_id());
}
@@ -1810,24 +1885,29 @@ SpdySerializedFrame* SpdyFramer::SerializeSettings(
SpdyFrameBuilder builder(size);
if (spdy_version_ < 4) {
builder.WriteControlFrameHeader(*this, SETTINGS, flags);
+ builder.WriteUInt32(values->size());
} else {
builder.WriteFramePrefix(*this, SETTINGS, flags, 0);
}
- builder.WriteUInt32(values->size());
DCHECK_EQ(GetSettingsMinimumSize(), builder.length());
for (SpdySettingsIR::ValueMap::const_iterator it = values->begin();
it != values->end();
++it) {
uint8 setting_flags = 0;
- if (it->second.persist_value) {
- setting_flags |= SETTINGS_FLAG_PLEASE_PERSIST;
- }
- if (it->second.persisted) {
- setting_flags |= SETTINGS_FLAG_PERSISTED;
+ if (spdy_version_ < SPDY4) {
+ if (it->second.persist_value) {
+ setting_flags |= SETTINGS_FLAG_PLEASE_PERSIST;
+ }
+ if (it->second.persisted) {
+ setting_flags |= SETTINGS_FLAG_PERSISTED;
+ }
+ SettingsFlagsAndId flags_and_id(setting_flags, it->first);
+ uint32 id_and_flags_wire = flags_and_id.GetWireFormat(protocol_version());
+ builder.WriteBytes(&id_and_flags_wire, 4);
+ } else {
+ builder.WriteUInt8(0);
+ builder.WriteUInt24(it->first);
}
- SettingsFlagsAndId flags_and_id(setting_flags, it->first);
- uint32 id_and_flags_wire = flags_and_id.GetWireFormat(protocol_version());
- builder.WriteBytes(&id_and_flags_wire, 4);
builder.WriteUInt32(it->second.value);
}
DCHECK_EQ(size, builder.length());
@@ -1848,12 +1928,15 @@ SpdyFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) const {
SpdySerializedFrame* SpdyFramer::SerializePing(const SpdyPingIR& ping) const {
SpdyFrameBuilder builder(GetPingSize());
- if (spdy_version_ < 4) {
+ if (spdy_version_ < SPDY4) {
builder.WriteControlFrameHeader(*this, PING, kNoFlags);
} else {
builder.WriteFramePrefix(*this, PING, 0, 0);
}
builder.WriteUInt32(ping.id());
+ if (spdy_version_ >= SPDY4) {
+ builder.WriteUInt32(0);
+ }
DCHECK_EQ(GetPingSize(), builder.length());
return builder.take();
}
« no previous file with comments | « net/spdy/spdy_frame_builder.cc ('k') | net/spdy/spdy_framer_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698