Index: net/spdy/spdy_framer.cc |
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc |
index 1483962b95b588228c88e65bb734c3a25cb00d5a..bfe45968c5987fe7cd98e4a7fe14c74f4f738609 100644 |
--- a/net/spdy/spdy_framer.cc |
+++ b/net/spdy/spdy_framer.cc |
@@ -113,6 +113,7 @@ const size_t SpdyFramer::kMaxDataPayloadSendSize = 1 << 14; |
// The size of the control frame buffer. Must be >= the minimum size of the |
// largest control frame. |
const size_t SpdyFramer::kControlFrameBufferSize = 19; |
+const size_t SpdyFramer::kOneSettingParameterSize = 6; |
#ifdef DEBUG_SPDY_STATE_CHANGES |
#define CHANGE_STATE(newstate) \ |
@@ -778,9 +779,10 @@ void SpdyFramer::ProcessControlFrameHeader() { |
{ |
// Make sure that we have an integral number of 8-byte key/value pairs, |
// Size of each key/value pair in bytes. |
- int setting_size = 6; |
if (current_frame_length_ < GetSettingsMinimumSize() || |
- (current_frame_length_ - GetFrameHeaderSize()) % setting_size != 0) { |
+ (current_frame_length_ - GetFrameHeaderSize()) % |
+ kOneSettingParameterSize != |
+ 0) { |
DLOG(WARNING) << "Invalid length for SETTINGS frame: " |
<< current_frame_length_; |
set_error(SPDY_INVALID_CONTROL_FRAME_SIZE); |
@@ -1262,16 +1264,15 @@ size_t SpdyFramer::ProcessSettingsFramePayload(const char* data, |
size_t unprocessed_bytes = std::min(data_len, remaining_data_length_); |
size_t processed_bytes = 0; |
- size_t setting_size = 6; |
- |
// Loop over our incoming data. |
while (unprocessed_bytes > 0) { |
// Process up to one setting at a time. |
- size_t processing = std::min(unprocessed_bytes, |
- setting_size - settings_scratch_.buffer.len()); |
+ size_t processing = |
+ std::min(unprocessed_bytes, |
+ kOneSettingParameterSize - settings_scratch_.buffer.len()); |
// Check if we have a complete setting in our input. |
- if (processing == setting_size) { |
+ if (processing == kOneSettingParameterSize) { |
// Parse the setting directly out of the input without buffering. |
if (!ProcessSetting(data + processed_bytes)) { |
set_error(SPDY_INVALID_CONTROL_FRAME); |
@@ -1282,7 +1283,7 @@ size_t SpdyFramer::ProcessSettingsFramePayload(const char* data, |
settings_scratch_.buffer.CopyFrom(data + processed_bytes, processing); |
// Check if we have a complete setting buffered. |
- if (settings_scratch_.buffer.len() == setting_size) { |
+ if (settings_scratch_.buffer.len() == kOneSettingParameterSize) { |
if (!ProcessSetting(settings_scratch_.buffer.data())) { |
set_error(SPDY_INVALID_CONTROL_FRAME); |
return processed_bytes; |
@@ -1744,21 +1745,31 @@ SpdySerializedFrame SpdyFramer::SpdyHeaderFrameIterator::NextFrame() { |
} |
} |
-SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) const { |
- uint8_t flags = DATA_FLAG_NONE; |
+void SpdyFramer::SerializeDataBuilderHelper(const SpdyDataIR& data_ir, |
+ uint8_t* flags, |
+ int* num_padding_fields, |
+ size_t* size_with_padding) const { |
if (data_ir.fin()) { |
- flags = DATA_FLAG_FIN; |
+ *flags = DATA_FLAG_FIN; |
} |
- int num_padding_fields = 0; |
if (data_ir.padded()) { |
- flags |= DATA_FLAG_PADDED; |
- ++num_padding_fields; |
+ *flags = *flags | DATA_FLAG_PADDED; |
+ ++*num_padding_fields; |
} |
- const size_t size_with_padding = num_padding_fields + data_ir.data_len() + |
- data_ir.padding_payload_len() + |
- GetDataFrameMinimumSize(); |
+ *size_with_padding = *num_padding_fields + data_ir.data_len() + |
+ data_ir.padding_payload_len() + |
+ GetDataFrameMinimumSize(); |
+} |
+ |
+SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) const { |
+ uint8_t flags = DATA_FLAG_NONE; |
+ int num_padding_fields = 0; |
+ size_t size_with_padding = 0; |
+ SerializeDataBuilderHelper(data_ir, &flags, &num_padding_fields, |
+ &size_with_padding); |
+ |
SpdyFrameBuilder builder(size_with_padding); |
builder.BeginNewFrame(*this, DATA, flags, data_ir.stream_id()); |
if (data_ir.padded()) { |
@@ -1773,20 +1784,31 @@ SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) const { |
return builder.take(); |
} |
-SpdySerializedFrame SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField( |
- const SpdyDataIR& data_ir) const { |
- uint8_t flags = DATA_FLAG_NONE; |
+void SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper( |
+ const SpdyDataIR& data_ir, |
+ uint8_t* flags, |
+ size_t* frame_size, |
+ size_t* num_padding_fields) const { |
+ *flags = DATA_FLAG_NONE; |
if (data_ir.fin()) { |
- flags = DATA_FLAG_FIN; |
+ *flags = DATA_FLAG_FIN; |
} |
- size_t frame_size = GetDataFrameMinimumSize(); |
- size_t num_padding_fields = 0; |
+ *frame_size = GetDataFrameMinimumSize(); |
if (data_ir.padded()) { |
- flags |= DATA_FLAG_PADDED; |
- ++num_padding_fields; |
- frame_size += num_padding_fields; |
+ *flags = *flags | DATA_FLAG_PADDED; |
+ ++(*num_padding_fields); |
+ *frame_size = *frame_size + *num_padding_fields; |
} |
+} |
+ |
+SpdySerializedFrame SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField( |
+ const SpdyDataIR& data_ir) const { |
+ uint8_t flags = DATA_FLAG_NONE; |
+ size_t frame_size = 0; |
+ size_t num_padding_fields = 0; |
+ SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper( |
+ data_ir, &flags, &frame_size, &num_padding_fields); |
SpdyFrameBuilder builder(frame_size); |
if (!skip_rewritelength_) { |
@@ -1821,19 +1843,24 @@ SpdySerializedFrame SpdyFramer::SerializeRstStream( |
return builder.take(); |
} |
-SpdySerializedFrame SpdyFramer::SerializeSettings( |
- const SpdySettingsIR& settings) const { |
- uint8_t flags = 0; |
- |
+void SpdyFramer::SerializeSettingsBuilderHelper(const SpdySettingsIR& settings, |
+ uint8_t* flags, |
+ const SettingsMap* values, |
+ size_t* size) const { |
if (settings.is_ack()) { |
- flags |= SETTINGS_FLAG_ACK; |
+ *flags = *flags | SETTINGS_FLAG_ACK; |
} |
- const SettingsMap* values = &(settings.values()); |
+ *size = |
+ GetSettingsMinimumSize() + (values->size() * kOneSettingParameterSize); |
+} |
- int setting_size = 6; |
+SpdySerializedFrame SpdyFramer::SerializeSettings( |
+ const SpdySettingsIR& settings) const { |
+ uint8_t flags = 0; |
// Size, in bytes, of this SETTINGS frame. |
- const size_t size = GetSettingsMinimumSize() + |
- (values->size() * setting_size); |
+ size_t size = 0; |
+ const SettingsMap* values = &(settings.values()); |
+ SerializeSettingsBuilderHelper(settings, &flags, values, &size); |
SpdyFrameBuilder builder(size); |
builder.BeginNewFrame(*this, SETTINGS, flags, 0); |
@@ -1892,65 +1919,76 @@ SpdySerializedFrame SpdyFramer::SerializeGoAway( |
return builder.take(); |
} |
-SpdySerializedFrame SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers) { |
- uint8_t flags = 0; |
+void SpdyFramer::SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers, |
+ uint8_t* flags, |
+ size_t* size, |
+ string* hpack_encoding, |
+ int* weight, |
+ size_t* length_field) { |
if (headers.fin()) { |
- flags |= CONTROL_FLAG_FIN; |
+ *flags = *flags | CONTROL_FLAG_FIN; |
} |
// This will get overwritten if we overflow into a CONTINUATION frame. |
- flags |= HEADERS_FLAG_END_HEADERS; |
+ *flags = *flags | HEADERS_FLAG_END_HEADERS; |
if (headers.has_priority()) { |
- flags |= HEADERS_FLAG_PRIORITY; |
+ *flags = *flags | HEADERS_FLAG_PRIORITY; |
} |
if (headers.padded()) { |
- flags |= HEADERS_FLAG_PADDED; |
+ *flags = *flags | HEADERS_FLAG_PADDED; |
} |
- // The size of this frame, including padding (if there is any) and |
- // variable-length header block. |
- size_t size = GetHeadersMinimumSize(); |
+ *size = GetHeadersMinimumSize(); |
if (headers.padded()) { |
- size += kPadLengthFieldSize; |
- size += headers.padding_payload_len(); |
+ *size = *size + kPadLengthFieldSize; |
+ *size = *size + headers.padding_payload_len(); |
} |
- int weight = 0; |
if (headers.has_priority()) { |
- weight = ClampHttp2Weight(headers.weight()); |
- size += 5; |
+ *weight = ClampHttp2Weight(headers.weight()); |
+ *size = *size + 5; |
} |
- string hpack_encoding; |
- GetHpackEncoder()->EncodeHeaderSet(headers.header_block(), &hpack_encoding); |
- size += hpack_encoding.size(); |
- if (size > kMaxControlFrameSize) { |
- size += GetNumberRequiredContinuationFrames(size) * |
- GetContinuationMinimumSize(); |
- flags &= ~HEADERS_FLAG_END_HEADERS; |
+ GetHpackEncoder()->EncodeHeaderSet(headers.header_block(), hpack_encoding); |
+ *size = *size + hpack_encoding->size(); |
+ if (*size > kMaxControlFrameSize) { |
+ *size = *size + GetNumberRequiredContinuationFrames(*size) * |
+ GetContinuationMinimumSize(); |
+ *flags = *flags & ~HEADERS_FLAG_END_HEADERS; |
+ } |
+ // Compute frame length field. |
+ if (headers.padded()) { |
+ *length_field = *length_field + 1; // Padding length field. |
+ } |
+ if (headers.has_priority()) { |
+ *length_field = *length_field + 4; // Dependency field. |
+ *length_field = *length_field + 1; // Weight field. |
} |
+ *length_field = *length_field + headers.padding_payload_len(); |
+ *length_field = *length_field + hpack_encoding->size(); |
+ // If the HEADERS frame with payload would exceed the max frame size, then |
+ // WritePayloadWithContinuation() will serialize CONTINUATION frames as |
+ // necessary. |
+ *length_field = |
+ std::min(*length_field, kMaxControlFrameSize - GetFrameHeaderSize()); |
+} |
+ |
+SpdySerializedFrame SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers) { |
+ uint8_t flags = 0; |
+ // The size of this frame, including padding (if there is any) and |
+ // variable-length header block. |
+ size_t size = 0; |
+ string hpack_encoding; |
+ int weight = 0; |
+ size_t length_field = 0; |
+ SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding, |
+ &weight, &length_field); |
SpdyFrameBuilder builder(size); |
if (!skip_rewritelength_) { |
builder.BeginNewFrame(*this, HEADERS, flags, headers.stream_id()); |
} else { |
- // Compute frame length field. |
- size_t length_field = 0; |
- if (headers.padded()) { |
- length_field += 1; // Padding length field. |
- } |
- if (headers.has_priority()) { |
- length_field += 4; // Dependency field. |
- length_field += 1; // Weight field. |
- } |
- length_field += headers.padding_payload_len(); |
- length_field += hpack_encoding.size(); |
- // If the HEADERS frame with payload would exceed the max frame size, then |
- // WritePayloadWithContinuation() will serialize CONTINUATION frames as |
- // necessary. |
- length_field = |
- std::min(length_field, kMaxControlFrameSize - GetFrameHeaderSize()); |
builder.BeginNewFrame(*this, HEADERS, flags, headers.stream_id(), |
length_field); |
} |
@@ -2001,29 +2039,40 @@ SpdySerializedFrame SpdyFramer::SerializeBlocked( |
return builder.take(); |
} |
-SpdySerializedFrame SpdyFramer::SerializePushPromise( |
- const SpdyPushPromiseIR& push_promise) { |
- uint8_t flags = 0; |
+void SpdyFramer::SerializePushPromiseBuilderHelper( |
+ const SpdyPushPromiseIR& push_promise, |
+ uint8_t* flags, |
+ string* hpack_encoding, |
+ size_t* size) { |
+ *flags = 0; |
// This will get overwritten if we overflow into a CONTINUATION frame. |
- flags |= PUSH_PROMISE_FLAG_END_PUSH_PROMISE; |
+ *flags = *flags | PUSH_PROMISE_FLAG_END_PUSH_PROMISE; |
// The size of this frame, including variable-length name-value block. |
- size_t size = GetPushPromiseMinimumSize(); |
+ *size = GetPushPromiseMinimumSize(); |
if (push_promise.padded()) { |
- flags |= PUSH_PROMISE_FLAG_PADDED; |
- size += kPadLengthFieldSize; |
- size += push_promise.padding_payload_len(); |
+ *flags = *flags | PUSH_PROMISE_FLAG_PADDED; |
+ *size = *size + kPadLengthFieldSize; |
+ *size = *size + push_promise.padding_payload_len(); |
} |
- string hpack_encoding; |
GetHpackEncoder()->EncodeHeaderSet(push_promise.header_block(), |
- &hpack_encoding); |
- size += hpack_encoding.size(); |
- if (size > kMaxControlFrameSize) { |
- size += GetNumberRequiredContinuationFrames(size) * |
- GetContinuationMinimumSize(); |
- flags &= ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE; |
+ hpack_encoding); |
+ *size = *size + hpack_encoding->size(); |
+ if (*size > kMaxControlFrameSize) { |
+ *size = *size + GetNumberRequiredContinuationFrames(*size) * |
+ GetContinuationMinimumSize(); |
+ *flags = *flags & ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE; |
} |
+} |
+ |
+SpdySerializedFrame SpdyFramer::SerializePushPromise( |
+ const SpdyPushPromiseIR& push_promise) { |
+ uint8_t flags = 0; |
+ size_t size = 0; |
+ string hpack_encoding; |
+ SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding, |
+ &size); |
SpdyFrameBuilder builder(size); |
if (!skip_rewritelength_) { |
@@ -2106,17 +2155,24 @@ SpdySerializedFrame SpdyFramer::SerializeContinuation( |
builder.BeginNewFrame(*this, CONTINUATION, flags, continuation.stream_id()); |
DCHECK_EQ(GetFrameHeaderSize(), builder.length()); |
- builder.WriteBytes(&encoding[0], encoding.size()); |
+ builder.WriteBytes(encoding.data(), encoding.size()); |
return builder.take(); |
} |
-SpdySerializedFrame SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir) { |
- size_t size = GetAltSvcMinimumSize(); |
- size += altsvc_ir.origin().length(); |
- string value = SpdyAltSvcWireFormat::SerializeHeaderFieldValue( |
+void SpdyFramer::SerializeAltSvcBuilderHelper(const SpdyAltSvcIR& altsvc_ir, |
+ string* value, |
+ size_t* size) const { |
+ *size = GetAltSvcMinimumSize(); |
+ *size = *size + altsvc_ir.origin().length(); |
+ *value = SpdyAltSvcWireFormat::SerializeHeaderFieldValue( |
altsvc_ir.altsvc_vector()); |
- size += value.length(); |
+ *size = *size + value->length(); |
+} |
+SpdySerializedFrame SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir) { |
+ string value; |
+ size_t size = 0; |
+ SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size); |
SpdyFrameBuilder builder(size); |
builder.BeginNewFrame(*this, ALTSVC, kNoFlags, altsvc_ir.stream_id()); |
@@ -2291,6 +2347,362 @@ uint8_t SpdyFramer::GetSerializedFlags(const SpdyFrameIR& frame) { |
return visitor.flags(); |
} |
+bool SpdyFramer::SerializeData(const SpdyDataIR& data_ir, |
+ ZeroCopyOutputBuffer* output) const { |
+ uint8_t flags = DATA_FLAG_NONE; |
+ int num_padding_fields = 0; |
+ size_t size_with_padding = 0; |
+ SerializeDataBuilderHelper(data_ir, &flags, &num_padding_fields, |
+ &size_with_padding); |
+ SpdyFrameBuilder builder(size_with_padding, output); |
+ |
+ bool ok = builder.BeginNewFrame(*this, DATA, flags, data_ir.stream_id()); |
+ |
+ if (data_ir.padded()) { |
+ ok = ok && builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); |
+ } |
+ |
+ ok = ok && builder.WriteBytes(data_ir.data(), data_ir.data_len()); |
+ if (data_ir.padding_payload_len() > 0) { |
+ string padding; |
+ padding = string(data_ir.padding_payload_len(), 0); |
+ ok = ok && builder.WriteBytes(padding.data(), padding.length()); |
+ } |
+ DCHECK_EQ(size_with_padding, builder.length()); |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField( |
+ const SpdyDataIR& data_ir, |
+ ZeroCopyOutputBuffer* output) const { |
+ uint8_t flags = DATA_FLAG_NONE; |
+ size_t frame_size = 0; |
+ size_t num_padding_fields = 0; |
+ SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper( |
+ data_ir, &flags, &frame_size, &num_padding_fields); |
+ |
+ SpdyFrameBuilder builder(frame_size, output); |
+ bool ok = true; |
+ if (!skip_rewritelength_) { |
+ ok = builder.BeginNewFrame(*this, DATA, flags, data_ir.stream_id()); |
+ if (data_ir.padded()) { |
+ ok = ok && builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); |
+ } |
+ ok = ok && builder.OverwriteLength(*this, |
+ num_padding_fields + data_ir.data_len() + |
+ data_ir.padding_payload_len()); |
+ } else { |
+ ok = ok && builder.BeginNewFrame(*this, DATA, flags, data_ir.stream_id(), |
+ num_padding_fields + data_ir.data_len() + |
+ data_ir.padding_payload_len()); |
+ if (data_ir.padded()) { |
+ ok = ok && builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); |
+ } |
+ } |
+ DCHECK_EQ(frame_size, builder.length()); |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializeRstStream(const SpdyRstStreamIR& rst_stream, |
+ ZeroCopyOutputBuffer* output) const { |
+ size_t expected_length = GetRstStreamSize(); |
+ SpdyFrameBuilder builder(expected_length, output); |
+ bool ok = builder.BeginNewFrame(*this, RST_STREAM, 0, rst_stream.stream_id()); |
+ ok = ok && builder.WriteUInt32(rst_stream.error_code()); |
+ |
+ DCHECK_EQ(expected_length, builder.length()); |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializeSettings(const SpdySettingsIR& settings, |
+ ZeroCopyOutputBuffer* output) const { |
+ uint8_t flags = 0; |
+ // Size, in bytes, of this SETTINGS frame. |
+ size_t size = 0; |
+ const SettingsMap* values = &(settings.values()); |
+ SerializeSettingsBuilderHelper(settings, &flags, values, &size); |
+ SpdyFrameBuilder builder(size, output); |
+ bool ok = builder.BeginNewFrame(*this, SETTINGS, flags, 0); |
+ |
+ // If this is an ACK, payload should be empty. |
+ if (settings.is_ack()) { |
+ return ok; |
+ } |
+ |
+ DCHECK_EQ(GetSettingsMinimumSize(), builder.length()); |
+ for (SettingsMap::const_iterator it = values->begin(); it != values->end(); |
+ ++it) { |
+ int setting_id = it->first; |
+ DCHECK_GE(setting_id, 0); |
+ ok = ok && builder.WriteUInt16(static_cast<uint16_t>(setting_id)) && |
+ builder.WriteUInt32(it->second); |
+ } |
+ DCHECK_EQ(size, builder.length()); |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializePing(const SpdyPingIR& ping, |
+ ZeroCopyOutputBuffer* output) const { |
+ SpdyFrameBuilder builder(GetPingSize(), output); |
+ uint8_t flags = 0; |
+ if (ping.is_ack()) { |
+ flags |= PING_FLAG_ACK; |
+ } |
+ bool ok = builder.BeginNewFrame(*this, PING, flags, 0); |
+ ok = ok && builder.WriteUInt64(ping.id()); |
+ DCHECK_EQ(GetPingSize(), builder.length()); |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializeGoAway(const SpdyGoAwayIR& goaway, |
+ ZeroCopyOutputBuffer* output) const { |
+ // Compute the output buffer size, take opaque data into account. |
+ size_t expected_length = GetGoAwayMinimumSize(); |
+ expected_length += goaway.description().size(); |
+ SpdyFrameBuilder builder(expected_length, output); |
+ |
+ // Serialize the GOAWAY frame. |
+ bool ok = builder.BeginNewFrame(*this, GOAWAY, 0, 0); |
+ |
+ // GOAWAY frames specify the last good stream id. |
+ ok = ok && builder.WriteUInt32(goaway.last_good_stream_id()) && |
+ // GOAWAY frames also specify the error status code. |
+ builder.WriteUInt32(goaway.error_code()); |
+ |
+ // GOAWAY frames may also specify opaque data. |
+ if (!goaway.description().empty()) { |
+ ok = ok && builder.WriteBytes(goaway.description().data(), |
+ goaway.description().size()); |
+ } |
+ |
+ DCHECK_EQ(expected_length, builder.length()); |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers, |
+ ZeroCopyOutputBuffer* output) { |
+ uint8_t flags = 0; |
+ // The size of this frame, including padding (if there is any) and |
+ // variable-length header block. |
+ size_t size = 0; |
+ string hpack_encoding; |
+ int weight = 0; |
+ size_t length_field = 0; |
+ SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding, |
+ &weight, &length_field); |
+ |
+ bool ok = true; |
+ SpdyFrameBuilder builder(size, output); |
+ if (!skip_rewritelength_) { |
+ ok = builder.BeginNewFrame(*this, HEADERS, flags, headers.stream_id()); |
+ } else { |
+ ok = ok && builder.BeginNewFrame(*this, HEADERS, flags, headers.stream_id(), |
+ length_field); |
+ } |
+ DCHECK_EQ(GetHeadersMinimumSize(), builder.length()); |
+ |
+ int padding_payload_len = 0; |
+ if (headers.padded()) { |
+ ok = ok && builder.WriteUInt8(headers.padding_payload_len()); |
+ padding_payload_len = headers.padding_payload_len(); |
+ } |
+ if (headers.has_priority()) { |
+ ok = ok && |
+ builder.WriteUInt32(PackStreamDependencyValues( |
+ headers.exclusive(), headers.parent_stream_id())) && |
+ // Per RFC 7540 section 6.3, serialized weight value is weight - 1. |
+ builder.WriteUInt8(weight - 1); |
+ } |
+ ok = ok && WritePayloadWithContinuation(&builder, hpack_encoding, |
+ headers.stream_id(), HEADERS, |
+ padding_payload_len); |
+ |
+ if (debug_visitor_) { |
+ // HTTP2 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(&(headers.header_block())); |
+ debug_visitor_->OnSendCompressedFrame(headers.stream_id(), HEADERS, |
+ payload_len, builder.length()); |
+ } |
+ |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update, |
+ ZeroCopyOutputBuffer* output) const { |
+ SpdyFrameBuilder builder(GetWindowUpdateSize(), output); |
+ bool ok = builder.BeginNewFrame(*this, WINDOW_UPDATE, kNoFlags, |
+ window_update.stream_id()); |
+ ok = ok && builder.WriteUInt32(window_update.delta()); |
+ DCHECK_EQ(GetWindowUpdateSize(), builder.length()); |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializeBlocked(const SpdyBlockedIR& blocked, |
+ ZeroCopyOutputBuffer* output) const { |
+ SpdyFrameBuilder builder(GetBlockedSize(), output); |
+ return builder.BeginNewFrame(*this, BLOCKED, kNoFlags, blocked.stream_id()); |
+} |
+ |
+bool SpdyFramer::SerializePushPromise(const SpdyPushPromiseIR& push_promise, |
+ ZeroCopyOutputBuffer* output) { |
+ uint8_t flags = 0; |
+ size_t size = 0; |
+ string hpack_encoding; |
+ SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding, |
+ &size); |
+ |
+ bool ok = true; |
+ SpdyFrameBuilder builder(size, output); |
+ if (!skip_rewritelength_) { |
+ ok = builder.BeginNewFrame(*this, PUSH_PROMISE, flags, |
+ push_promise.stream_id()); |
+ } else { |
+ size_t length = std::min(size, kMaxControlFrameSize) - GetFrameHeaderSize(); |
+ ok = builder.BeginNewFrame(*this, PUSH_PROMISE, flags, |
+ push_promise.stream_id(), length); |
+ } |
+ |
+ int padding_payload_len = 0; |
+ if (push_promise.padded()) { |
+ ok = ok && builder.WriteUInt8(push_promise.padding_payload_len()) && |
+ builder.WriteUInt32(push_promise.promised_stream_id()); |
+ DCHECK_EQ(GetPushPromiseMinimumSize() + kPadLengthFieldSize, |
+ builder.length()); |
+ |
+ padding_payload_len = push_promise.padding_payload_len(); |
+ } else { |
+ ok = ok && builder.WriteUInt32(push_promise.promised_stream_id()); |
+ DCHECK_EQ(GetPushPromiseMinimumSize(), builder.length()); |
+ } |
+ |
+ ok = ok && WritePayloadWithContinuation(&builder, hpack_encoding, |
+ push_promise.stream_id(), |
+ PUSH_PROMISE, padding_payload_len); |
+ |
+ if (debug_visitor_) { |
+ // HTTP2 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(&(push_promise.header_block())); |
+ debug_visitor_->OnSendCompressedFrame( |
+ push_promise.stream_id(), PUSH_PROMISE, payload_len, builder.length()); |
+ } |
+ |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializeContinuation(const SpdyContinuationIR& continuation, |
+ ZeroCopyOutputBuffer* output) const { |
+ const string& encoding = continuation.encoding(); |
+ size_t frame_size = GetContinuationMinimumSize() + encoding.size(); |
+ SpdyFrameBuilder builder(frame_size, output); |
+ uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0; |
+ bool ok = builder.BeginNewFrame(*this, CONTINUATION, flags, |
+ continuation.stream_id()); |
+ DCHECK_EQ(GetFrameHeaderSize(), builder.length()); |
+ |
+ ok = ok && builder.WriteBytes(encoding.data(), encoding.size()); |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir, |
+ ZeroCopyOutputBuffer* output) { |
+ string value; |
+ size_t size = 0; |
+ SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size); |
+ SpdyFrameBuilder builder(size, output); |
+ bool ok = |
+ builder.BeginNewFrame(*this, ALTSVC, kNoFlags, altsvc_ir.stream_id()) && |
+ builder.WriteUInt16(altsvc_ir.origin().length()) && |
+ builder.WriteBytes(altsvc_ir.origin().data(), |
+ altsvc_ir.origin().length()) && |
+ builder.WriteBytes(value.data(), value.length()); |
+ DCHECK_LT(GetAltSvcMinimumSize(), builder.length()); |
+ return ok; |
+} |
+ |
+bool SpdyFramer::SerializePriority(const SpdyPriorityIR& priority, |
+ ZeroCopyOutputBuffer* output) const { |
+ size_t size = GetPrioritySize(); |
+ |
+ SpdyFrameBuilder builder(size, output); |
+ bool ok = |
+ builder.BeginNewFrame(*this, PRIORITY, kNoFlags, priority.stream_id()); |
+ ok = ok && |
+ builder.WriteUInt32(PackStreamDependencyValues( |
+ priority.exclusive(), priority.parent_stream_id())) && |
+ // Per RFC 7540 section 6.3, serialized weight value is actual value - 1. |
+ builder.WriteUInt8(priority.weight() - 1); |
+ DCHECK_EQ(GetPrioritySize(), builder.length()); |
+ return ok; |
+} |
+ |
+namespace { |
+ |
+class FrameSerializationVisitorWithOutput : public SpdyFrameVisitor { |
+ public: |
+ explicit FrameSerializationVisitorWithOutput(SpdyFramer* framer, |
+ ZeroCopyOutputBuffer* output) |
+ : framer_(framer), output_(output), result_(false) {} |
+ ~FrameSerializationVisitorWithOutput() override {} |
+ |
+ bool Result() { return result_; } |
+ |
+ void VisitData(const SpdyDataIR& data) override { |
+ result_ = framer_->SerializeData(data, output_); |
+ } |
+ void VisitRstStream(const SpdyRstStreamIR& rst_stream) override { |
+ result_ = framer_->SerializeRstStream(rst_stream, output_); |
+ } |
+ void VisitSettings(const SpdySettingsIR& settings) override { |
+ result_ = framer_->SerializeSettings(settings, output_); |
+ } |
+ void VisitPing(const SpdyPingIR& ping) override { |
+ result_ = framer_->SerializePing(ping, output_); |
+ } |
+ void VisitGoAway(const SpdyGoAwayIR& goaway) override { |
+ result_ = framer_->SerializeGoAway(goaway, output_); |
+ } |
+ void VisitHeaders(const SpdyHeadersIR& headers) override { |
+ result_ = framer_->SerializeHeaders(headers, output_); |
+ } |
+ void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) override { |
+ result_ = framer_->SerializeWindowUpdate(window_update, output_); |
+ } |
+ void VisitBlocked(const SpdyBlockedIR& blocked) override { |
+ result_ = framer_->SerializeBlocked(blocked, output_); |
+ } |
+ void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override { |
+ result_ = framer_->SerializePushPromise(push_promise, output_); |
+ } |
+ void VisitContinuation(const SpdyContinuationIR& continuation) override { |
+ result_ = framer_->SerializeContinuation(continuation, output_); |
+ } |
+ void VisitAltSvc(const SpdyAltSvcIR& altsvc) override { |
+ result_ = framer_->SerializeAltSvc(altsvc, output_); |
+ } |
+ void VisitPriority(const SpdyPriorityIR& priority) override { |
+ result_ = framer_->SerializePriority(priority, output_); |
+ } |
+ |
+ private: |
+ SpdyFramer* framer_; |
+ ZeroCopyOutputBuffer* output_; |
+ bool result_; |
+}; |
+ |
+} // namespace |
+ |
+bool SpdyFramer::SerializeFrame(const SpdyFrameIR& frame, |
+ ZeroCopyOutputBuffer* output) { |
+ FrameSerializationVisitorWithOutput visitor(this, output); |
+ frame.Visit(&visitor); |
+ return visitor.Result(); |
+} |
+ |
size_t SpdyFramer::GetNumberRequiredContinuationFrames(size_t size) { |
DCHECK_GT(size, kMaxControlFrameSize); |
size_t overflow = size - kMaxControlFrameSize; |
@@ -2333,7 +2745,7 @@ uint8_t SpdyFramer::SerializeHeaderFrameFlags( |
return flags; |
} |
-void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder, |
+bool SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder, |
const string& hpack_encoding, |
SpdyStreamId stream_id, |
SpdyFrameType type, |
@@ -2356,19 +2768,19 @@ void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder, |
hpack_encoding.size() - |
std::min(hpack_encoding.size(), |
kMaxControlFrameSize - builder->length() - padding_payload_len); |
- builder->WriteBytes(&hpack_encoding[0], |
- hpack_encoding.size() - bytes_remaining); |
+ bool ret = builder->WriteBytes(&hpack_encoding[0], |
+ hpack_encoding.size() - bytes_remaining); |
if (padding_payload_len > 0) { |
string padding = string(padding_payload_len, 0); |
- builder->WriteBytes(padding.data(), padding.length()); |
+ ret &= builder->WriteBytes(padding.data(), padding.length()); |
} |
if (bytes_remaining > 0 && !skip_rewritelength_) { |
- builder->OverwriteLength(*this, |
- kMaxControlFrameSize - GetFrameHeaderSize()); |
+ ret &= builder->OverwriteLength( |
+ *this, kMaxControlFrameSize - GetFrameHeaderSize()); |
} |
// Tack on CONTINUATION frames for the overflow. |
- while (bytes_remaining > 0) { |
+ while (bytes_remaining > 0 && ret) { |
size_t bytes_to_write = std::min( |
bytes_remaining, kMaxControlFrameSize - GetContinuationMinimumSize()); |
// Write CONTINUATION frame prefix. |
@@ -2376,17 +2788,18 @@ void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder, |
flags |= end_flag; |
} |
if (!skip_rewritelength_) { |
- builder->BeginNewFrame(*this, CONTINUATION, flags, stream_id); |
+ ret &= builder->BeginNewFrame(*this, CONTINUATION, flags, stream_id); |
} else { |
- builder->BeginNewFrame(*this, CONTINUATION, flags, stream_id, |
- bytes_to_write); |
+ ret &= builder->BeginNewFrame(*this, CONTINUATION, flags, stream_id, |
+ bytes_to_write); |
} |
// Write payload fragment. |
- builder->WriteBytes( |
+ ret &= builder->WriteBytes( |
&hpack_encoding[hpack_encoding.size() - bytes_remaining], |
bytes_to_write); |
bytes_remaining -= bytes_to_write; |
} |
+ return ret; |
} |
HpackEncoder* SpdyFramer::GetHpackEncoder() { |