dictionary_size);
}
+// Check to see if the name and value of a cookie are both empty.
+bool IsCookieEmpty(const base::StringPiece& cookie) {
+ if (cookie.size() == 0) {
+ return true;
+ }
+ size_t pos = cookie.find('=');
+ if (pos == base::StringPiece::npos) {
+ return false;
+ }
+ // Ignore leading whitespaces of cookie value.
+ size_t value_start = pos + 1;
+ for (; value_start < cookie.size(); value_start++) {
+ if (!(cookie[value_start] == ' ' || cookie[value_start] == '\t')) {
+ break;
+ }
+ }
+ return (pos == 0) && ((cookie.size() - value_start) == 0);
+}
+
struct DictionaryIds {
DictionaryIds()
: v2_dictionary_id(CalculateDictionaryId(kV2Dictionary, kV2DictionarySize)),
} // namespace
-const SpdyStreamId SpdyFramer::kInvalidStream = -1;
+const SpdyStreamId SpdyFramer::kInvalidStream = static_cast<SpdyStreamId>(-1);
const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024;
+// The size of the control frame buffer. Must be >= the minimum size of the
// largest control frame, which is SYN_STREAM. See GetSynStreamMinimumSize() for
// calculation details.
-const size_t SpdyFramer::kControlFrameBufferSize = 18;
+const size_t SpdyFramer::kControlFrameBufferSize = 19;
#ifdef DEBUG_SPDY_STATE_CHANGES
#define CHANGE_STATE(newstate) \
settings_scratch_.Reset();
altsvc_scratch_.Reset();
remaining_padding_payload_length_ = 0;
- remaining_padding_length_fields_ = 0;
}
size_t SpdyFramer::GetDataFrameMinimumSize() const {
- return SpdyConstants::GetDataFrameMinimumSize();
+ return SpdyConstants::GetDataFrameMinimumSize(protocol_version());
}
// Size, in bytes, of the control frame header.
return "RST_STREAM";
case SETTINGS:
return "SETTINGS";
- case NOOP:
- return "NOOP";
case PING:
return "PING";
case GOAWAY:
return "WINDOW_UPDATE";
case CREDENTIAL:
return "CREDENTIAL";
- case BLOCKED:
- return "BLOCKED";
case PUSH_PROMISE:
return "PUSH_PROMISE";
case CONTINUATION:
return "CONTINUATION";
- case ALTSVC:
- return "ALTSVC";
case PRIORITY:
return "PRIORITY";
+ case ALTSVC:
+ return "ALTSVC";
+ case BLOCKED:
+ return "BLOCKED";
}
return "UNKNOWN_CONTROL_TYPE";
}
uint16 version = 0;
bool is_control_frame = false;
- uint16 control_frame_type_field = DATA;
+ uint16 control_frame_type_field =
+ SpdyConstants::DataFrameType(protocol_version());
// ProcessControlFrameHeader() will set current_frame_type_ to the
// correct value if this is a valid control frame.
current_frame_type_ = DATA;
current_frame_length_ = remaining_data_length_ + reader->GetBytesConsumed();
} else {
version = protocol_version();
- uint16 length_field = 0;
- bool successful_read = reader->ReadUInt16(&length_field);
+ uint32 length_field = 0;
+ bool successful_read = reader->ReadUInt24(&length_field);
DCHECK(successful_read);
- uint8 control_frame_type_field_uint8 = DATA;
+ uint8 control_frame_type_field_uint8 =
+ SpdyConstants::DataFrameType(protocol_version());
successful_read = reader->ReadUInt8(&control_frame_type_field_uint8);
DCHECK(successful_read);
// We check control_frame_type_field's validity in
// ProcessControlFrameHeader().
control_frame_type_field = control_frame_type_field_uint8;
- is_control_frame = (control_frame_type_field != DATA);
+ is_control_frame = (protocol_version() > SPDY3) ?
+ control_frame_type_field !=
+ SpdyConstants::SerializeFrameType(protocol_version(), DATA) :
+ control_frame_type_field != 0;
if (is_control_frame) {
current_frame_length_ = length_field + GetControlFrameHeaderSize();
uint8 valid_data_flags = 0;
if (protocol_version() > SPDY3) {
- valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT |
- DATA_FLAG_PAD_LOW | DATA_FLAG_PAD_HIGH;
+ valid_data_flags =
+ DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT | DATA_FLAG_PADDED;
} else {
valid_data_flags = DATA_FLAG_FIN;
}
DCHECK_EQ(SPDY_NO_ERROR, error_code_);
DCHECK_LE(GetControlFrameHeaderSize(), current_frame_buffer_length_);
+ // TODO(mlavan): Either remove credential frames from the code entirely,
+ // or add them to parsing + serialization methods for SPDY3.
// Early detection of deprecated frames that we ignore.
if (protocol_version() <= SPDY3) {
- if (control_frame_type_field == NOOP) {
- current_frame_type_ = NOOP;
- DVLOG(1) << "NOOP control frame found. Ignoring.";
- CHANGE_STATE(SPDY_AUTO_RESET);
- return;
- }
-
if (control_frame_type_field == CREDENTIAL) {
current_frame_type_ = CREDENTIAL;
DCHECK_EQ(SPDY3, protocol_version());
if (!SpdyConstants::IsValidFrameType(protocol_version(),
control_frame_type_field)) {
- DLOG(WARNING) << "Invalid control frame type " << control_frame_type_field
- << " (protocol version: " << protocol_version() << ")";
- set_error(SPDY_INVALID_CONTROL_FRAME);
- return;
+ if (protocol_version() <= SPDY3) {
+ DLOG(WARNING) << "Invalid control frame type " << control_frame_type_field
+ << " (protocol version: " << protocol_version() << ")";
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ return;
+ } else {
+ // In HTTP2 we ignore unknown frame types for extensibility, as long as
+ // the rest of the control frame header is valid.
+ // We rely on the visitor to check validity of current_frame_stream_id_.
+ bool valid_stream = visitor_->OnUnknownFrame(current_frame_stream_id_,
+ control_frame_type_field);
+ if (valid_stream) {
+ DVLOG(1) << "Ignoring unknown frame type.";
+ CHANGE_STATE(SPDY_IGNORE_REMAINING_PAYLOAD);
+ } else {
+ // Report an invalid frame error and close the stream if the
+ // stream_id is not valid.
+ DLOG(WARNING) << "Unknown control frame type "
+ << control_frame_type_field
+ << " received on invalid stream "
+ << current_frame_stream_id_;
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ }
+ return;
+ }
}
current_frame_type_ = SpdyConstants::ParseFrameType(protocol_version(),
// plus a 4-byte length field in SPDY3 and below.
size_t values_prefix_size = (protocol_version() <= SPDY3 ? 4 : 0);
// Size of each key/value pair in bytes.
- size_t setting_size = (protocol_version() <= SPDY3 ? 8 : 5);
+ size_t setting_size = SpdyConstants::GetSettingSize(protocol_version());
if (current_frame_length_ < GetSettingsMinimumSize() ||
(current_frame_length_ - GetControlFrameHeaderSize())
% setting_size != values_prefix_size) {
min_size += 4;
}
if (current_frame_length_ < min_size) {
+ // TODO(mlavan): check here for HEADERS with no payload?
+ // (not allowed in SPDY4)
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (protocol_version() <= SPDY3 &&
current_frame_flags_ & ~CONTROL_FLAG_FIN) {
current_frame_flags_ &
~(CONTROL_FLAG_FIN | HEADERS_FLAG_PRIORITY |
HEADERS_FLAG_END_HEADERS | HEADERS_FLAG_END_SEGMENT |
- HEADERS_FLAG_PAD_LOW | HEADERS_FLAG_PAD_HIGH)) {
+ HEADERS_FLAG_PADDED)) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
}
case BLOCKED:
if (current_frame_length_ != GetBlockedSize() ||
protocol_version() <= SPDY3) {
- // TODO(mlavan): BLOCKED frames are no longer part of SPDY4.
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ != 0) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
} else if (protocol_version() > SPDY3 &&
current_frame_flags_ &
~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE |
- HEADERS_FLAG_PAD_LOW | HEADERS_FLAG_PAD_HIGH)) {
+ HEADERS_FLAG_PADDED)) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
break;
if (current_frame_length_ < GetContinuationMinimumSize() ||
protocol_version() <= SPDY3) {
set_error(SPDY_INVALID_CONTROL_FRAME);
- } else if (current_frame_flags_ &
- ~(HEADERS_FLAG_END_HEADERS | HEADERS_FLAG_PAD_LOW |
- HEADERS_FLAG_PAD_HIGH)) {
+ } else if (current_frame_flags_ & ~HEADERS_FLAG_END_HEADERS) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
break;
break;
}
if (i < cookie_data.size()) {
- cookie_values.push_back(cookie_data.substr(0, i));
- cookie_length += i + 2 /* semicolon and space */;
+ if (!IsCookieEmpty(cookie_data.substr(0, i))) {
+ cookie_values.push_back(cookie_data.substr(0, i));
+ cookie_length += i + 2 /* semicolon and space */;
+ }
cookie_data.remove_prefix(i + 1);
} else {
- cookie_values.push_back(cookie_data);
- cookie_length += cookie_data.size();
+ if (!IsCookieEmpty(cookie_data)) {
+ cookie_values.push_back(cookie_data);
+ cookie_length += cookie_data.size();
+ } else if (cookie_length > 2) {
+ cookie_length -= 2 /* compensate for previously added length */;
+ }
cookie_data.remove_prefix(i);
}
}
DCHECK_EQ(Z_OK, rv);
z->clas = kZStandardData;
}
+
#endif // !defined(USE_SYSTEM_ZLIB)
size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
(current_frame_flags_ &
HEADERS_FLAG_END_HEADERS) != 0);
}
- CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
+ CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
break;
default:
DCHECK(false);
size_t unprocessed_bytes = std::min(data_len, remaining_data_length_);
size_t processed_bytes = 0;
- size_t setting_size = protocol_version() <= SPDY3 ? 8 : 5;
+ size_t setting_size = SpdyConstants::GetSettingSize(protocol_version());
// Loop over our incoming data.
while (unprocessed_bytes > 0) {
flags = id_and_flags.flags();
value = ntohl(*(reinterpret_cast<const uint32*>(data + 4)));
} else {
- id_field = *(reinterpret_cast<const uint8*>(data));
- value = ntohl(*(reinterpret_cast<const uint32*>(data + 1)));
+ id_field = ntohs(*(reinterpret_cast<const uint16*>(data)));
+ value = ntohl(*(reinterpret_cast<const uint32*>(data + 2)));
}
// Validate id.
if (!SpdyConstants::IsValidSettingId(protocol_version(), id_field)) {
DLOG(WARNING) << "Unknown SETTINGS ID: " << id_field;
- return false;
+ if (protocol_version() <= SPDY3) {
+ return false;
+ } else {
+ // In HTTP2 we ignore unknown settings for extensibility.
+ return true;
+ }
}
id = SpdyConstants::ParseSettingId(protocol_version(), id_field);
break;
case PRIORITY: {
DCHECK_LT(SPDY3, protocol_version());
- // TODO(hkhalil): Process PRIORITY frames rather than ignore them.
- reader.Seek(5);
+ uint32 parent_stream_id;
+ uint8 weight;
+ bool exclusive;
+ bool successful_read = true;
+ successful_read = reader.ReadUInt32(&parent_stream_id);
+ DCHECK(successful_read);
+ // Exclusivity is indicated by a single bit flag.
+ exclusive = (parent_stream_id >> 31) != 0;
+ // Zero out the highest-order bit to get the parent stream id.
+ parent_stream_id &= 0x7fffffff;
+ successful_read = reader.ReadUInt8(&weight);
+ DCHECK(successful_read);
DCHECK(reader.IsDoneReading());
+ visitor_->OnPriority(
+ current_frame_stream_id_, parent_stream_id, weight, exclusive);
}
break;
default:
status = SpdyConstants::ParseGoAwayStatus(protocol_version(),
status_raw);
} else {
- DCHECK(false);
- // Throw an error for SPDY4+, keep liberal behavior
- // for earlier versions.
if (protocol_version() > SPDY3) {
- DLOG(WARNING) << "Invalid GO_AWAY status " << status_raw;
- set_error(SPDY_INVALID_CONTROL_FRAME);
- return 0;
+ // Treat unrecognized status codes as INTERNAL_ERROR as
+ // recommended by the HTTP/2 spec.
+ status = GOAWAY_INTERNAL_ERROR;
}
}
}
status_raw)) {
status = static_cast<SpdyRstStreamStatus>(status_raw);
} else {
- // Throw an error for SPDY4+, keep liberal behavior
- // for earlier versions.
if (protocol_version() > SPDY3) {
- DLOG(WARNING) << "Invalid RST_STREAM status " << status_raw;
- set_error(SPDY_INVALID_CONTROL_FRAME);
- return 0;
+ // Treat unrecognized status codes as INTERNAL_ERROR as
+ // recommended by the HTTP/2 spec.
+ status = RST_STREAM_INTERNAL_ERROR;
}
}
// Finished parsing the RST_STREAM header, call frame handler.
return processed_bytes;
}
+// TODO(raullenchai): ProcessFramePaddingLength should be able to deal with
+// HEADERS_FLAG_PADDED and PUSH_PROMISE_FLAG_PADDED as well (see b/15777051).
size_t SpdyFramer::ProcessFramePaddingLength(const char* data, size_t len) {
DCHECK_EQ(SPDY_READ_PADDING_LENGTH, state_);
+ DCHECK_EQ(remaining_padding_payload_length_, 0u);
size_t original_len = len;
- if (remaining_padding_length_fields_ == 0) {
- DCHECK_EQ(remaining_padding_payload_length_, 0u);
- bool pad_low = false;
- bool pad_high = false;
- if (current_frame_flags_ & DATA_FLAG_PAD_LOW) {
- pad_low = true;
- ++remaining_padding_length_fields_;
- }
- if (current_frame_flags_ & DATA_FLAG_PAD_HIGH) {
- pad_high = true;
- ++remaining_padding_length_fields_;
- }
- if ((pad_high && !pad_low) ||
- remaining_data_length_ < remaining_padding_length_fields_) {
- set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
+ if (current_frame_flags_ & DATA_FLAG_PADDED) {
+ if (len != 0) {
+ if (remaining_data_length_ < 1) {
+ set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
+ return 0;
+ }
+
+ remaining_padding_payload_length_ = *reinterpret_cast<const uint8*>(data);
+ ++data;
+ --len;
+ --remaining_data_length_;
+ } else {
+ // We don't have the data available for parsing the pad length field. Keep
+ // waiting.
return 0;
}
}
- // Parse the padding length.
- while (len != 0 && remaining_padding_length_fields_ != 0) {
- remaining_padding_payload_length_ =
- (remaining_padding_payload_length_ << 8) +
- *reinterpret_cast<const uint8*>(data);
- ++data;
- --len;
- --remaining_padding_length_fields_;
- --remaining_data_length_;
+ if (remaining_padding_payload_length_ > remaining_data_length_) {
+ set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
+ return 0;
}
-
- if (remaining_padding_length_fields_ == 0) {
- if (remaining_padding_payload_length_ > remaining_data_length_) {
- set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
- return 0;
- }
- if (current_frame_type_ == DATA) {
- CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
- } else {
- DCHECK(current_frame_type_ == HEADERS ||
- current_frame_type_ == PUSH_PROMISE ||
- current_frame_type_ == CONTINUATION ||
- current_frame_type_ == SYN_STREAM ||
- current_frame_type_ == SYN_REPLY)
- << current_frame_type_;
- CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
- }
+ if (current_frame_type_ == DATA) {
+ CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
+ } else {
+ DCHECK(current_frame_type_ == HEADERS ||
+ current_frame_type_ == PUSH_PROMISE ||
+ current_frame_type_ == SYN_STREAM ||
+ current_frame_type_ == SYN_REPLY)
+ << current_frame_type_;
+ CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
}
return original_len - len;
}
if (protocol_version() > SPDY3) {
int num_padding_fields = 0;
- if (data_ir.pad_low()) {
- flags |= DATA_FLAG_PAD_LOW;
- ++num_padding_fields;
- }
- if (data_ir.pad_high()) {
- flags |= DATA_FLAG_PAD_HIGH;
+ if (data_ir.padded()) {
+ flags |= DATA_FLAG_PADDED;
++num_padding_fields;
}
GetDataFrameMinimumSize();
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);
- }
- if (data_ir.pad_low()) {
+ if (data_ir.padded()) {
builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
}
builder.WriteBytes(data_ir.data().data(), data_ir.data().length());
size_t frame_size = GetDataFrameMinimumSize();
size_t num_padding_fields = 0;
if (protocol_version() > SPDY3) {
- if (data_ir.pad_low()) {
- flags |= DATA_FLAG_PAD_LOW;
- ++num_padding_fields;
- }
- if (data_ir.pad_high()) {
- flags |= DATA_FLAG_PAD_HIGH;
+ if (data_ir.padded()) {
+ flags |= DATA_FLAG_PADDED;
++num_padding_fields;
}
frame_size += num_padding_fields;
SpdyFrameBuilder builder(frame_size, protocol_version());
builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags);
if (protocol_version() > SPDY3) {
- if (data_ir.pad_high()) {
- builder.WriteUInt8(data_ir.padding_payload_len() >> 8);
- }
- if (data_ir.pad_low()) {
+ if (data_ir.padded()) {
builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
}
builder.OverwriteLength(*this, num_padding_fields +
SpdySerializedFrame* SpdyFramer::SerializeSynStream(
const SpdySynStreamIR& syn_stream) {
+ DCHECK_GE(SPDY3, protocol_version());
uint8 flags = 0;
if (syn_stream.fin()) {
flags |= CONTROL_FLAG_FIN;
// TODO(hkhalil): invalid for HTTP2.
flags |= CONTROL_FLAG_UNIDIRECTIONAL;
}
- // In SPDY >= 4, SYN_STREAM frames are HEADERS frames, but for now
- // we never expect to have to overflow into a CONTINUATION frame.
- if (protocol_version() > SPDY3) {
- flags |= HEADERS_FLAG_PRIORITY;
- flags |= HEADERS_FLAG_END_HEADERS;
- }
// Sanitize priority.
uint8 priority = syn_stream.priority();
}
// The size of this frame, including variable-length name-value block.
- size_t size = GetSynStreamMinimumSize();
-
- string hpack_encoding;
- if (protocol_version() > SPDY3) {
- if (enable_compression_) {
- GetHpackEncoder()->EncodeHeaderSet(
- syn_stream.name_value_block(), &hpack_encoding);
- } else {
- GetHpackEncoder()->EncodeHeaderSetWithoutCompression(
- syn_stream.name_value_block(), &hpack_encoding);
- }
- size += hpack_encoding.size();
- } else {
- size += GetSerializedLength(syn_stream.name_value_block());
- }
+ size_t size = GetSynStreamMinimumSize() +
+ GetSerializedLength(syn_stream.name_value_block());
SpdyFrameBuilder builder(size, protocol_version());
- if (protocol_version() <= SPDY3) {
- builder.WriteControlFrameHeader(*this, SYN_STREAM, flags);
- builder.WriteUInt32(syn_stream.stream_id());
- builder.WriteUInt32(syn_stream.associated_to_stream_id());
- builder.WriteUInt8(priority << ((protocol_version() <= SPDY2) ? 6 : 5));
- builder.WriteUInt8(0); // Unused byte where credential slot used to be.
- } else {
- builder.BeginNewFrame(*this,
- HEADERS,
- flags,
- syn_stream.stream_id());
- // TODO(jgraettinger): Plumb priorities and stream dependencies.
- builder.WriteUInt32(0); // Non-exclusive bit and root stream ID.
- builder.WriteUInt8(MapPriorityToWeight(priority));
- }
+ builder.WriteControlFrameHeader(*this, SYN_STREAM, flags);
+ builder.WriteUInt32(syn_stream.stream_id());
+ builder.WriteUInt32(syn_stream.associated_to_stream_id());
+ builder.WriteUInt8(priority << ((protocol_version() <= SPDY2) ? 6 : 5));
+ builder.WriteUInt8(0); // Unused byte where credential slot used to be.
DCHECK_EQ(GetSynStreamMinimumSize(), builder.length());
- if (protocol_version() > SPDY3) {
- builder.WriteBytes(&hpack_encoding[0], hpack_encoding.size());
- } else {
- SerializeNameValueBlock(&builder, syn_stream);
- }
+ SerializeNameValueBlock(&builder, syn_stream);
if (debug_visitor_) {
- const size_t payload_len = protocol_version() > SPDY3 ?
- hpack_encoding.size() :
+ const size_t payload_len =
GetSerializedLength(protocol_version(),
&(syn_stream.name_value_block()));
- // SPDY 4 reports this compression as a SYN_STREAM compression.
debug_visitor_->OnSendCompressedFrame(syn_stream.stream_id(),
SYN_STREAM,
payload_len,
SpdySerializedFrame* SpdyFramer::SerializeSynReply(
const SpdySynReplyIR& syn_reply) {
+ DCHECK_GE(SPDY3, protocol_version());
uint8 flags = 0;
if (syn_reply.fin()) {
flags |= CONTROL_FLAG_FIN;
}
- // In SPDY >= 4, SYN_REPLY frames are HEADERS frames, but for now
- // we never expect to have to overflow into a CONTINUATION frame.
- if (protocol_version() > SPDY3) {
- flags |= HEADERS_FLAG_END_HEADERS;
- }
// The size of this frame, including variable-length name-value block.
- size_t size = GetSynReplyMinimumSize();
-
- string hpack_encoding;
- if (protocol_version() > SPDY3) {
- if (enable_compression_) {
- GetHpackEncoder()->EncodeHeaderSet(
- syn_reply.name_value_block(), &hpack_encoding);
- } else {
- GetHpackEncoder()->EncodeHeaderSetWithoutCompression(
- syn_reply.name_value_block(), &hpack_encoding);
- }
- size += hpack_encoding.size();
- } else {
- size += GetSerializedLength(syn_reply.name_value_block());
- }
+ const size_t size = GetSynReplyMinimumSize() +
+ GetSerializedLength(syn_reply.name_value_block());
SpdyFrameBuilder builder(size, protocol_version());
if (protocol_version() <= SPDY3) {
builder.WriteUInt16(0); // Unused.
}
DCHECK_EQ(GetSynReplyMinimumSize(), builder.length());
- if (protocol_version() > SPDY3) {
- builder.WriteBytes(&hpack_encoding[0], hpack_encoding.size());
- } else {
- SerializeNameValueBlock(&builder, syn_reply);
- }
+ SerializeNameValueBlock(&builder, syn_reply);
if (debug_visitor_) {
- const size_t payload_len = protocol_version() > SPDY3 ?
- hpack_encoding.size() :
- GetSerializedLength(protocol_version(),
- &(syn_reply.name_value_block()));
+ const size_t payload_len = GetSerializedLength(
+ protocol_version(), &(syn_reply.name_value_block()));
debug_visitor_->OnSendCompressedFrame(syn_reply.stream_id(),
SYN_REPLY,
payload_len,
}
const SpdySettingsIR::ValueMap* values = &(settings.values());
- size_t setting_size = (protocol_version() <= SPDY3 ? 8 : 5);
+ size_t setting_size = SpdyConstants::GetSettingSize(protocol_version());
// Size, in bytes, of this SETTINGS frame.
const size_t size = GetSettingsMinimumSize() +
(values->size() * setting_size);
uint32 id_and_flags_wire = flags_and_id.GetWireFormat(protocol_version());
builder.WriteBytes(&id_and_flags_wire, 4);
} else {
- builder.WriteUInt8(SpdyConstants::SerializeSettingId(protocol_version(),
- it->first));
+ builder.WriteUInt16(SpdyConstants::SerializeSettingId(protocol_version(),
+ it->first));
}
builder.WriteUInt32(it->second.value);
}
DLOG(DFATAL) << "Priority out-of-bounds.";
priority = GetLowestPriority();
}
- size += 4;
+ size += 5;
}
string hpack_encoding;
headers.name_value_block(), &hpack_encoding);
}
size += hpack_encoding.size();
- if (size > GetControlFrameBufferMaxSize()) {
+ if (size > GetHeaderFragmentMaxSize()) {
size += GetNumberRequiredContinuationFrames(size) *
GetContinuationMinimumSize();
flags &= ~HEADERS_FLAG_END_HEADERS;
HEADERS,
flags,
headers.stream_id());
- if (headers.has_priority()) {
- // TODO(jgraettinger): Plumb priorities and stream dependencies.
- builder.WriteUInt32(0); // Non-exclusive bit and root stream ID.
- builder.WriteUInt8(MapPriorityToWeight(priority));
- }
}
if (protocol_version() <= SPDY2) {
builder.WriteUInt16(0); // Unused.
DCHECK_EQ(GetHeadersMinimumSize(), builder.length());
if (protocol_version() > SPDY3) {
+ if (headers.has_priority()) {
+ // TODO(jgraettinger): Plumb priorities and stream dependencies.
+ builder.WriteUInt32(0); // Non-exclusive bit and root stream ID.
+ builder.WriteUInt8(MapPriorityToWeight(priority));
+ }
WritePayloadWithContinuation(&builder,
hpack_encoding,
headers.stream_id(),
}
if (debug_visitor_) {
- const size_t payload_len = protocol_version() > SPDY3 ?
- hpack_encoding.size() :
+ // SPDY4 uses HPACK for header compression. However, continue to
+ // use GetSerializedLength() for an apples-to-apples comparision of
+ // compression performance between HPACK and SPDY w/ deflate.
+ const size_t payload_len =
GetSerializedLength(protocol_version(),
&(headers.name_value_block()));
debug_visitor_->OnSendCompressedFrame(headers.stream_id(),
size_t size = GetPushPromiseMinimumSize();
string hpack_encoding;
- if (protocol_version() > SPDY3) {
- if (enable_compression_) {
- GetHpackEncoder()->EncodeHeaderSet(
- push_promise.name_value_block(), &hpack_encoding);
- } else {
- GetHpackEncoder()->EncodeHeaderSetWithoutCompression(
- 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;
- }
+ if (enable_compression_) {
+ GetHpackEncoder()->EncodeHeaderSet(
+ push_promise.name_value_block(), &hpack_encoding);
} else {
- size += GetSerializedLength(push_promise.name_value_block());
+ GetHpackEncoder()->EncodeHeaderSetWithoutCompression(
+ push_promise.name_value_block(), &hpack_encoding);
+ }
+ size += hpack_encoding.size();
+ if (size > GetHeaderFragmentMaxSize()) {
+ size += GetNumberRequiredContinuationFrames(size) *
+ GetContinuationMinimumSize();
+ flags &= ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
}
SpdyFrameBuilder builder(size, protocol_version());
builder.WriteUInt32(push_promise.promised_stream_id());
DCHECK_EQ(GetPushPromiseMinimumSize(), builder.length());
- if (protocol_version() > SPDY3) {
- WritePayloadWithContinuation(&builder,
- hpack_encoding,
- push_promise.stream_id(),
- PUSH_PROMISE);
- } else {
- SerializeNameValueBlock(&builder, push_promise);
- }
+ WritePayloadWithContinuation(&builder,
+ hpack_encoding,
+ push_promise.stream_id(),
+ PUSH_PROMISE);
if (debug_visitor_) {
- const size_t payload_len = protocol_version() > SPDY3 ?
- hpack_encoding.size() :
+ // SPDY4 uses HPACK for header compression. However, continue to
+ // use GetSerializedLength() for an apples-to-apples comparision of
+ // compression performance between HPACK and SPDY w/ deflate.
+ const size_t payload_len =
GetSerializedLength(protocol_version(),
&(push_promise.name_value_block()));
debug_visitor_->OnSendCompressedFrame(push_promise.stream_id(),
- PUSH_PROMISE, payload_len, builder.length());
+ PUSH_PROMISE,
+ payload_len,
+ builder.length());
}
return builder.take();
DCHECK_EQ(GetContinuationMinimumSize(), builder.length());
builder.WriteBytes(&hpack_encoding[0], hpack_encoding.size());
-
- if (debug_visitor_) {
- const size_t payload_len = hpack_encoding.size();
- debug_visitor_->OnSendCompressedFrame(continuation.stream_id(),
- CONTINUATION, payload_len, builder.length());
- }
-
return builder.take();
}
return builder.take();
}
+SpdyFrame* SpdyFramer::SerializePriority(const SpdyPriorityIR& priority) {
+ DCHECK_LT(SPDY3, protocol_version());
+ size_t size = GetPrioritySize();
+
+ SpdyFrameBuilder builder(size, protocol_version());
+ builder.BeginNewFrame(*this, PRIORITY, kNoFlags, priority.stream_id());
+
+ // Make sure the highest-order bit in the parent stream id is zeroed out.
+ uint32 parent_stream_id = priority.parent_stream_id() & 0x7fffffff;
+ uint32 exclusive = priority.exclusive() ? 0x80000000 : 0;
+ // Set the one-bit exclusivity flag.
+ uint32 flag_and_parent_id = parent_stream_id | exclusive;
+ builder.WriteUInt32(flag_and_parent_id);
+ builder.WriteUInt8(priority.weight());
+ DCHECK_EQ(GetPrioritySize(), builder.length());
+ return builder.take();
+}
+
namespace {
class FrameSerializationVisitor : public SpdyFrameVisitor {
virtual void VisitAltSvc(const SpdyAltSvcIR& altsvc) OVERRIDE {
frame_.reset(framer_->SerializeAltSvc(altsvc));
}
+ virtual void VisitPriority(const SpdyPriorityIR& priority) OVERRIDE {
+ frame_.reset(framer_->SerializePriority(priority));
+ }
private:
SpdyFramer* framer_;
}
size_t SpdyFramer::GetNumberRequiredContinuationFrames(size_t size) {
- const size_t kMaxControlFrameSize = GetControlFrameBufferMaxSize();
+ const size_t kMaxControlFrameSize = GetHeaderFragmentMaxSize();
DCHECK_GT(protocol_version(), SPDY3);
DCHECK_GT(size, kMaxControlFrameSize);
size_t overflow = size - kMaxControlFrameSize;
const string& hpack_encoding,
SpdyStreamId stream_id,
SpdyFrameType type) {
- const size_t kMaxControlFrameSize = GetControlFrameBufferMaxSize();
+ const size_t kMaxControlFrameSize = GetHeaderFragmentMaxSize();
// In addition to the prefix, fixed_field_size includes the size of
// any fields that come before the variable-length name/value block.