summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-12 23:07:39 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-12 23:07:39 +0000
commit339489a3c74ee37dd9818f127e285dcf81d2d1fb (patch)
tree12d5c58973814b8e62d4b10ede1ebe08a1d29c6a
parentf5a2775922b5b54f6b226b3280724df811003e14 (diff)
downloadchromium_src-339489a3c74ee37dd9818f127e285dcf81d2d1fb.zip
chromium_src-339489a3c74ee37dd9818f127e285dcf81d2d1fb.tar.gz
chromium_src-339489a3c74ee37dd9818f127e285dcf81d2d1fb.tar.bz2
Refactor in preparation for SPDY 4, part 1.
Zero behavioral change to the on-the-wire format nor protocol semantics. This lands server change 40997047. Also create spdy_protocol.cc and move some functions to it to avoid clang warnings. Review URL: https://chromiumcodereview.appspot.com/12220116 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182053 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/net.gyp1
-rw-r--r--net/spdy/spdy_frame_builder.cc4
-rw-r--r--net/spdy/spdy_frame_builder.h4
-rw-r--r--net/spdy/spdy_framer.cc472
-rw-r--r--net/spdy/spdy_framer.h27
-rw-r--r--net/spdy/spdy_protocol.cc24
-rw-r--r--net/spdy/spdy_protocol.h304
7 files changed, 684 insertions, 152 deletions
diff --git a/net/net.gyp b/net/net.gyp
index 51cdaf6..9fad87b 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -826,6 +826,7 @@
'spdy/spdy_http_utils.h',
'spdy/spdy_io_buffer.cc',
'spdy/spdy_io_buffer.h',
+ 'spdy/spdy_protocol.cc',
'spdy/spdy_protocol.h',
'spdy/spdy_proxy_client_socket.cc',
'spdy/spdy_proxy_client_socket.h',
diff --git a/net/spdy/spdy_frame_builder.cc b/net/spdy/spdy_frame_builder.cc
index 314dd12..ead527c 100644
--- a/net/spdy/spdy_frame_builder.cc
+++ b/net/spdy/spdy_frame_builder.cc
@@ -12,7 +12,7 @@ namespace net {
namespace {
// Creates a FlagsAndLength.
-FlagsAndLength CreateFlagsAndLength(SpdyControlFlags flags, size_t length) {
+FlagsAndLength CreateFlagsAndLength(uint8 flags, size_t length) {
DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
FlagsAndLength flags_length;
flags_length.length_ = htonl(static_cast<uint32>(length));
@@ -30,7 +30,7 @@ SpdyFrameBuilder::SpdyFrameBuilder(size_t size)
}
SpdyFrameBuilder::SpdyFrameBuilder(SpdyControlType type,
- SpdyControlFlags flags,
+ uint8 flags,
int spdy_version,
size_t size)
: buffer_(new char[size]),
diff --git a/net/spdy/spdy_frame_builder.h b/net/spdy/spdy_frame_builder.h
index 8f3b0cd..0a2410c 100644
--- a/net/spdy/spdy_frame_builder.h
+++ b/net/spdy/spdy_frame_builder.h
@@ -31,7 +31,9 @@ class NET_EXPORT_PRIVATE SpdyFrameBuilder {
// Initializes a SpdyFrameBuilder with a buffer of given size,
// populate with a SPDY control frame header based on
// |type|, |flags|, and |spdy_version|.
- SpdyFrameBuilder(SpdyControlType type, SpdyControlFlags flags,
+ //
+ // TODO(akalin): Add a typedef for this uint8.
+ SpdyFrameBuilder(SpdyControlType type, uint8 flags,
int spdy_version, size_t size);
// Initiailizes a SpdyFrameBuilder with a buffer of given size,
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index 21615a0..96ccf9a 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -46,6 +46,9 @@ struct DictionaryIds {
// initialized lazily to avoid static initializers.
base::LazyInstance<DictionaryIds>::Leaky g_dictionary_ids;
+// Used to indicate no flags in a SPDY flags field.
+const uint8 kNoFlags = 0;
+
} // namespace
const int SpdyFramer::kMinSpdyVersion = 2;
@@ -677,15 +680,13 @@ void SpdyFramer::WriteHeaderBlock(SpdyFrameBuilder* frame,
}
SpdyHeaderBlock::const_iterator it;
for (it = headers->begin(); it != headers->end(); ++it) {
- bool wrote_header;
if (spdy_version < 3) {
- wrote_header = frame->WriteString(it->first);
- wrote_header &= frame->WriteString(it->second);
+ frame->WriteString(it->first);
+ frame->WriteString(it->second);
} else {
- wrote_header = frame->WriteStringPiece32(it->first);
- wrote_header &= frame->WriteStringPiece32(it->second);
+ frame->WriteStringPiece32(it->first);
+ frame->WriteStringPiece32(it->second);
}
- DCHECK(wrote_header);
}
}
@@ -1291,29 +1292,20 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
SpdyControlFlags flags,
bool compressed,
const SpdyHeaderBlock* headers) {
- DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
- DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask);
-
- // Find our length.
- size_t frame_size = SpdySynStreamControlFrame::size() +
- GetSerializedLength(spdy_version_, headers);
+ DCHECK_EQ(0, flags & ~CONTROL_FLAG_FIN & ~CONTROL_FLAG_UNIDIRECTIONAL);
- SpdyFrameBuilder frame(SYN_STREAM, flags, spdy_version_, frame_size);
- frame.WriteUInt32(stream_id);
- frame.WriteUInt32(associated_stream_id);
- // Cap as appropriate.
- if (priority > GetLowestPriority()) {
- DLOG(DFATAL) << "Priority out-of-bounds.";
- priority = GetLowestPriority();
- }
- // Priority is 2 bits for <spdy3, 3 bits otherwise.
- frame.WriteUInt8(priority << ((spdy_version_ < 3) ? 6 : 5));
- frame.WriteUInt8((spdy_version_ < 3) ? 0 : credential_slot);
- WriteHeaderBlock(&frame, spdy_version_, headers);
- DCHECK_EQ(frame.length(), frame_size);
+ SpdySynStreamIR syn_stream(stream_id);
+ syn_stream.set_associated_to_stream_id(associated_stream_id);
+ syn_stream.set_priority(priority);
+ syn_stream.set_slot(credential_slot);
+ syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
+ syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
+ // TODO(hkhalil): Avoid copy here.
+ *(syn_stream.GetMutableNameValueBlock()) = *headers;
scoped_ptr<SpdySynStreamControlFrame> syn_frame(
- reinterpret_cast<SpdySynStreamControlFrame*>(frame.take()));
+ reinterpret_cast<SpdySynStreamControlFrame*>(
+ SerializeSynStream(syn_stream)));
if (compressed) {
return reinterpret_cast<SpdySynStreamControlFrame*>(
CompressControlFrame(*syn_frame.get(), headers));
@@ -1321,32 +1313,57 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
return syn_frame.release();
}
+SpdySerializedFrame* SpdyFramer::SerializeSynStream(
+ const SpdySynStreamIR& syn_stream) {
+ uint8 flags = 0;
+ if (syn_stream.fin()) {
+ flags |= CONTROL_FLAG_FIN;
+ }
+ if (syn_stream.unidirectional()) {
+ flags |= CONTROL_FLAG_UNIDIRECTIONAL;
+ }
+
+ // The size, in bytes, of this frame not including the variable-length
+ // name-value block. Calculated as:
+ // 8 (control frame header) + 2 * 4 (stream IDs) + 1 (priority) + 1 (slot)
+ const size_t kSynStreamSizeBeforeNameValueBlock = 18;
+
+ // The size of this frame, including variable-length name-value block.
+ const size_t size = kSynStreamSizeBeforeNameValueBlock
+ + GetSerializedLength(protocol_version(),
+ &(syn_stream.name_value_block()));
+
+ SpdyFrameBuilder builder(SYN_STREAM, flags, protocol_version(), size);
+ builder.WriteUInt32(syn_stream.stream_id());
+ 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(kSynStreamSizeBeforeNameValueBlock, builder.length());
+ SerializeNameValueBlock(&builder, syn_stream);
+
+ return builder.take();
+}
+
SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(
SpdyStreamId stream_id,
SpdyControlFlags flags,
bool compressed,
const SpdyHeaderBlock* headers) {
- DCHECK_GT(stream_id, 0u);
- DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
+ DCHECK_EQ(0, flags & ~CONTROL_FLAG_FIN);
- // Find our length.
- size_t frame_size = SpdySynReplyControlFrame::size() +
- GetSerializedLength(spdy_version_, headers);
- // In SPDY 2, there were 2 unused bytes before payload.
- if (spdy_version_ < 3) {
- frame_size += 2;
- }
-
- SpdyFrameBuilder frame(SYN_REPLY, flags, spdy_version_, frame_size);
- frame.WriteUInt32(stream_id);
- if (spdy_version_ < 3) {
- frame.WriteUInt16(0); // Unused
- }
- WriteHeaderBlock(&frame, spdy_version_, headers);
- DCHECK_EQ(frame.length(), frame_size);
+ SpdySynReplyIR syn_reply(stream_id);
+ syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
+ // TODO(hkhalil): Avoid copy here.
+ *(syn_reply.GetMutableNameValueBlock()) = *headers;
scoped_ptr<SpdySynReplyControlFrame> reply_frame(
- reinterpret_cast<SpdySynReplyControlFrame*>(frame.take()));
+ reinterpret_cast<SpdySynReplyControlFrame*>(SerializeSynReply(
+ syn_reply)));
if (compressed) {
return reinterpret_cast<SpdySynReplyControlFrame*>(
CompressControlFrame(*reply_frame.get(), headers));
@@ -1354,159 +1371,298 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(
return reply_frame.release();
}
+SpdySerializedFrame* SpdyFramer::SerializeSynReply(
+ const SpdySynReplyIR& syn_reply) {
+ uint8 flags = 0;
+ if (syn_reply.fin()) {
+ flags |= CONTROL_FLAG_FIN;
+ }
+
+ // The size, in bytes, of this frame not including the variable-length
+ // name-value block. Calculated as:
+ // 8 (control frame header) + 4 (stream ID)
+ size_t syn_reply_size_before_name_value_block = 12;
+ // In SPDY 2, there were 2 unused bytes before payload.
+ if (protocol_version() < 3) {
+ syn_reply_size_before_name_value_block += 2;
+ }
+
+ // The size of this frame, including variable-length name-value block.
+ size_t size = syn_reply_size_before_name_value_block
+ + GetSerializedLength(protocol_version(),
+ &(syn_reply.name_value_block()));
+
+ SpdyFrameBuilder builder(SYN_REPLY, flags, protocol_version(), size);
+ builder.WriteUInt32(syn_reply.stream_id());
+ if (protocol_version() < 3) {
+ builder.WriteUInt16(0); // Unused.
+ }
+ DCHECK_EQ(syn_reply_size_before_name_value_block, builder.length());
+ SerializeNameValueBlock(&builder, syn_reply);
+
+ return builder.take();
+}
+
SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(
SpdyStreamId stream_id,
SpdyRstStreamStatus status) const {
- DCHECK_GT(stream_id, 0u);
- DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
- DCHECK_NE(status, RST_STREAM_INVALID);
- DCHECK_LT(status, RST_STREAM_NUM_STATUS_CODES);
-
- size_t frame_size = SpdyRstStreamControlFrame::size();
- SpdyFrameBuilder frame(RST_STREAM, CONTROL_FLAG_NONE, spdy_version_,
- frame_size);
- frame.WriteUInt32(stream_id);
- frame.WriteUInt32(status);
- DCHECK_EQ(frame.length(), frame_size);
- return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take());
+ SpdyRstStreamIR rst_stream(stream_id, status);
+ return reinterpret_cast<SpdyRstStreamControlFrame*>(
+ SerializeRstStream(rst_stream));
+}
+
+SpdySerializedFrame* SpdyFramer::SerializeRstStream(
+ const SpdyRstStreamIR& rst_stream) const {
+ // Size of our RST_STREAM frame. Calculated as:
+ // 8 (control frame header) + 4 (stream id) + 4 (status code)
+ const size_t kRstStreamFrameSize = 16;
+
+ SpdyFrameBuilder builder(RST_STREAM,
+ kNoFlags,
+ protocol_version(),
+ kRstStreamFrameSize);
+ builder.WriteUInt32(rst_stream.stream_id());
+ builder.WriteUInt32(rst_stream.status());
+ DCHECK_EQ(kRstStreamFrameSize, builder.length());
+ return builder.take();
}
SpdySettingsControlFrame* SpdyFramer::CreateSettings(
const SettingsMap& values) const {
- size_t frame_size = SpdySettingsControlFrame::size() + 8 * values.size();
- SpdyFrameBuilder frame(SETTINGS, CONTROL_FLAG_NONE, spdy_version_,
- frame_size);
- frame.WriteUInt32(values.size());
+ SpdySettingsIR settings;
for (SettingsMap::const_iterator it = values.begin();
it != values.end();
- it++) {
- SettingsFlagsAndId flags_and_id(it->second.first, it->first);
- uint32 id_and_flags_wire = flags_and_id.GetWireFormat(spdy_version_);
- frame.WriteBytes(&id_and_flags_wire, 4);
- frame.WriteUInt32(it->second.second);
- }
- DCHECK_EQ(frame.length(), frame_size);
- return reinterpret_cast<SpdySettingsControlFrame*>(frame.take());
+ ++it) {
+ settings.AddSetting(it->first,
+ (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0,
+ (it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
+ it->second.second);
+ }
+ return reinterpret_cast<SpdySettingsControlFrame*>(
+ SerializeSettings(settings));
+}
+
+SpdySerializedFrame* SpdyFramer::SerializeSettings(
+ const SpdySettingsIR& settings) const {
+ uint8 flags = 0;
+ if (settings.clear_settings()) {
+ flags |= SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS;
+ }
+ const SpdySettingsIR::ValueMap* values = &(settings.values());
+
+ // Size, in bytes, of this SETTINGS frame not including the IDs and values
+ // from the variable-length value block. Calculated as:
+ // 8 (control frame header) + 4 (number of ID/value pairs)
+ const size_t kSettingsSizeWithoutValues = 12;
+ // Size, in bytes, of this SETTINGS frame.
+ const size_t size = kSettingsSizeWithoutValues + (values->size() * 8);
+
+ SpdyFrameBuilder builder(SETTINGS, flags, protocol_version(), size);
+ builder.WriteUInt32(values->size());
+ DCHECK_EQ(kSettingsSizeWithoutValues, 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;
+ }
+ 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());
+ return builder.take();
}
SpdyPingControlFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) const {
- size_t frame_size = SpdyPingControlFrame::size();
- SpdyFrameBuilder frame(PING, CONTROL_FLAG_NONE, spdy_version_, frame_size);
- frame.WriteUInt32(unique_id);
- DCHECK_EQ(frame.length(), frame_size);
- return reinterpret_cast<SpdyPingControlFrame*>(frame.take());
+ SpdyPingIR ping(unique_id);
+ return reinterpret_cast<SpdyPingControlFrame*>(SerializePing(ping));
+}
+
+SpdySerializedFrame* SpdyFramer::SerializePing(const SpdyPingIR& ping) const {
+ // Size, in bytes, of this PING frame. Calculated as:
+ // 8 (control frame header) + 4 (id)
+ const size_t kPingSize = 12;
+ SpdyFrameBuilder builder(PING, 0, protocol_version(), kPingSize);
+ builder.WriteUInt32(ping.id());
+ DCHECK_EQ(kPingSize, builder.length());
+ return builder.take();
}
SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway(
SpdyStreamId last_accepted_stream_id,
SpdyGoAwayStatus status) const {
- DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask);
-
- // SPDY 2 GOAWAY frames are 4 bytes smaller than in SPDY 3. We account for
- // this difference via a separate offset variable, since
- // SpdyGoAwayControlFrame::size() returns the SPDY 3 size.
- const size_t goaway_offset = (protocol_version() < 3) ? 4 : 0;
- size_t frame_size = SpdyGoAwayControlFrame::size() - goaway_offset;
- SpdyFrameBuilder frame(GOAWAY, CONTROL_FLAG_NONE, spdy_version_, frame_size);
- frame.WriteUInt32(last_accepted_stream_id);
+ SpdyGoAwayIR goaway(last_accepted_stream_id, status);
+ return reinterpret_cast<SpdyGoAwayControlFrame*>(SerializeGoAway(goaway));
+}
+
+SpdySerializedFrame* SpdyFramer::SerializeGoAway(
+ const SpdyGoAwayIR& goaway) const {
+ // Size, in bytes, of this GOAWAY frame. Calculated as:
+ // 8 (control frame header) + 4 (last good stream id)
+ size_t size = 12;
+ // SPDY 3+ GOAWAY frames also contain a status.
+ if (protocol_version() >= 3) {
+ size += 4;
+ }
+ SpdyFrameBuilder builder(GOAWAY, 0, protocol_version(), size);
+ builder.WriteUInt32(goaway.last_good_stream_id());
if (protocol_version() >= 3) {
- frame.WriteUInt32(status);
+ builder.WriteUInt32(goaway.status());
}
- DCHECK_EQ(frame.length(), frame_size);
- return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take());
+ DCHECK_EQ(size, builder.length());
+ return builder.take();
}
SpdyHeadersControlFrame* SpdyFramer::CreateHeaders(
SpdyStreamId stream_id,
SpdyControlFlags flags,
bool compressed,
- const SpdyHeaderBlock* headers) {
+ const SpdyHeaderBlock* header_block) {
// Basically the same as CreateSynReply().
- DCHECK_GT(stream_id, 0u);
- DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
-
- // Find our length.
- size_t frame_size = SpdyHeadersControlFrame::size() +
- GetSerializedLength(spdy_version_, headers);
- // In SPDY 2, there were 2 unused bytes before payload.
- if (spdy_version_ < 3) {
- frame_size += 2;
- }
+ DCHECK_EQ(0, flags & (!CONTROL_FLAG_FIN));
- SpdyFrameBuilder frame(HEADERS, flags, spdy_version_, frame_size);
- frame.WriteUInt32(stream_id);
- if (spdy_version_ < 3) {
- frame.WriteUInt16(0); // Unused
- }
- WriteHeaderBlock(&frame, spdy_version_, headers);
- DCHECK_EQ(frame.length(), frame_size);
+ SpdyHeadersIR headers(stream_id);
+ headers.set_fin(flags & CONTROL_FLAG_FIN);
+ // TODO(hkhalil): Avoid copy here.
+ *(headers.GetMutableNameValueBlock()) = *header_block;
scoped_ptr<SpdyHeadersControlFrame> headers_frame(
- reinterpret_cast<SpdyHeadersControlFrame*>(frame.take()));
+ reinterpret_cast<SpdyHeadersControlFrame*>(SerializeHeaders(headers)));
if (compressed) {
return reinterpret_cast<SpdyHeadersControlFrame*>(
- CompressControlFrame(*headers_frame.get(), headers));
+ CompressControlFrame(*headers_frame.get(),
+ headers.GetMutableNameValueBlock()));
}
return headers_frame.release();
}
+SpdySerializedFrame* SpdyFramer::SerializeHeaders(
+ const SpdyHeadersIR& headers) {
+ uint8 flags = 0;
+ if (headers.fin()) {
+ flags |= CONTROL_FLAG_FIN;
+ }
+
+ // The size, in bytes, of this frame not including the variable-length
+ // name-value block. Calculated as:
+ // 8 (control frame header) + 4 (stream ID)
+ size_t headers_size_before_name_value_block = 12;
+ // In SPDY 2, there were 2 unused bytes before payload.
+ if (protocol_version() < 3) {
+ headers_size_before_name_value_block += 2;
+ }
+
+ // The size of this frame, including variable-length name-value block.
+ size_t size = headers_size_before_name_value_block
+ + GetSerializedLength(protocol_version(),
+ &(headers.name_value_block()));
+
+ SpdyFrameBuilder builder(HEADERS, flags, protocol_version(), size);
+ builder.WriteUInt32(headers.stream_id());
+ if (protocol_version() < 3) {
+ builder.WriteUInt16(0); // Unused.
+ }
+ DCHECK_EQ(headers_size_before_name_value_block, builder.length());
+
+ SerializeNameValueBlock(&builder, headers);
+ DCHECK_EQ(size, builder.length());
+
+ return builder.take();
+}
+
SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
SpdyStreamId stream_id,
uint32 delta_window_size) const {
- DCHECK_GT(stream_id, 0u);
- DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
- DCHECK_GT(delta_window_size, 0u);
- DCHECK_LE(delta_window_size,
- static_cast<uint32>(kSpdyStreamMaximumWindowSize));
-
- size_t frame_size = SpdyWindowUpdateControlFrame::size();
- SpdyFrameBuilder frame(WINDOW_UPDATE, CONTROL_FLAG_NONE, spdy_version_,
- frame_size);
- frame.WriteUInt32(stream_id);
- frame.WriteUInt32(delta_window_size);
- DCHECK_EQ(frame.length(), frame_size);
- return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take());
+ SpdyWindowUpdateIR window_update(stream_id, delta_window_size);
+ return reinterpret_cast<SpdyWindowUpdateControlFrame*>(
+ SerializeWindowUpdate(window_update));
+}
+
+SpdySerializedFrame* SpdyFramer::SerializeWindowUpdate(
+ const SpdyWindowUpdateIR& window_update) const {
+ // Size, in bytes, of this WINDOW_UPDATE frame. Calculated as:
+ // 8 (control frame header) + 4 (stream id) + 4 (delta)
+ const size_t kWindowUpdateSize = 16;
+
+ SpdyFrameBuilder builder(WINDOW_UPDATE,
+ kNoFlags,
+ protocol_version(),
+ kWindowUpdateSize);
+ builder.WriteUInt32(window_update.stream_id());
+ builder.WriteUInt32(window_update.delta());
+ DCHECK_EQ(kWindowUpdateSize, builder.length());
+ return builder.take();
}
+// TODO(hkhalil): Gut with SpdyCredential removal.
SpdyCredentialControlFrame* SpdyFramer::CreateCredentialFrame(
const SpdyCredential& credential) const {
- // Calculate the size of the frame by adding the size of the
- // variable length data to the size of the fixed length data.
- size_t frame_size = SpdyCredentialControlFrame::size() +
- credential.proof.length();
- DCHECK_EQ(SpdyCredentialControlFrame::size(), 14u);
+ SpdyCredentialIR credential_ir(credential.slot);
+ credential_ir.set_proof(credential.proof);
for (std::vector<std::string>::const_iterator cert = credential.certs.begin();
cert != credential.certs.end();
++cert) {
- frame_size += sizeof(uint32); // size of the cert_length field
- frame_size += cert->length(); // size of the cert_data field
+ credential_ir.AddCertificate(*cert);
}
+ return reinterpret_cast<SpdyCredentialControlFrame*>(
+ SerializeCredential(credential_ir));
+}
- SpdyFrameBuilder frame(CREDENTIAL, CONTROL_FLAG_NONE, spdy_version_,
- frame_size);
- frame.WriteUInt16(credential.slot);
- frame.WriteUInt32(credential.proof.size());
- frame.WriteBytes(credential.proof.c_str(), credential.proof.size());
- for (std::vector<std::string>::const_iterator cert = credential.certs.begin();
- cert != credential.certs.end();
- ++cert) {
- frame.WriteUInt32(cert->length());
- frame.WriteBytes(cert->c_str(), cert->length());
+SpdySerializedFrame* SpdyFramer::SerializeCredential(
+ const SpdyCredentialIR& credential) const {
+ size_t size = 8; // Room for frame header.
+ size += 2; // Room for slot.
+ size += 4 + credential.proof().length(); // Room for proof.
+ for (SpdyCredentialIR::CertificateList::const_iterator it =
+ credential.certificates()->begin();
+ it != credential.certificates()->end();
+ ++it) {
+ size += 4 + it->length(); // Room for certificate.
+ }
+
+ SpdyFrameBuilder builder(CREDENTIAL, 0, protocol_version(), size);
+ builder.WriteUInt16(credential.slot());
+ builder.WriteStringPiece32(credential.proof());
+ for (SpdyCredentialIR::CertificateList::const_iterator it =
+ credential.certificates()->begin();
+ it != credential.certificates()->end();
+ ++it) {
+ builder.WriteStringPiece32(*it);
}
- DCHECK_EQ(frame.length(), frame_size);
- return reinterpret_cast<SpdyCredentialControlFrame*>(frame.take());
+ DCHECK_EQ(size, builder.length());
+ return builder.take();
}
SpdyDataFrame* SpdyFramer::CreateDataFrame(
- SpdyStreamId stream_id,
- const char* data,
+ SpdyStreamId stream_id, const char* data,
uint32 len, SpdyDataFlags flags) const {
- DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
- size_t frame_size = SpdyDataFrame::size() + len;
- SpdyFrameBuilder frame(stream_id, flags, frame_size);
- frame.WriteBytes(data, len);
- DCHECK_EQ(frame.length(), frame_size);
- return reinterpret_cast<SpdyDataFrame*>(frame.take());
+ DCHECK_EQ(0, flags & (!DATA_FLAG_FIN));
+
+ SpdyDataIR data_ir(stream_id, base::StringPiece(data, len));
+ data_ir.set_fin(flags & DATA_FLAG_FIN);
+ return reinterpret_cast<SpdyDataFrame*>(SerializeData(data_ir));
+}
+
+SpdySerializedFrame* SpdyFramer::SerializeData(const SpdyDataIR& data) const {
+ // Size, in bytes, of this DATA frame. Calculated as:
+ // 4 (stream id) + 1 (flags) + 3 (length) + payload length
+ const size_t size = 8 + data.data().length();
+
+ SpdyDataFlags flags = DATA_FLAG_NONE;
+ if (data.fin()) {
+ flags = DATA_FLAG_FIN;
+ }
+
+ SpdyFrameBuilder builder(data.stream_id(), flags, size);
+ builder.WriteBytes(data.data().data(), data.data().length());
+ DCHECK_EQ(size, builder.length());
+ return builder.take();
}
// The following compression setting are based on Brian Olson's analysis. See
@@ -1912,8 +2068,30 @@ SpdyStreamId SpdyFramer::GetControlFrameStreamId(
return stream_id;
}
-void SpdyFramer::set_enable_compression(bool value) {
- enable_compression_ = value;
+void SpdyFramer::SerializeNameValueBlock(
+ SpdyFrameBuilder* builder,
+ const SpdyFrameWithNameValueBlockIR& frame) const {
+ const SpdyNameValueBlock* name_value_block = &(frame.name_value_block());
+
+ // Serialize number of headers.
+ if (protocol_version() < 3) {
+ builder->WriteUInt16(name_value_block->size());
+ } else {
+ builder->WriteUInt32(name_value_block->size());
+ }
+
+ // Serialize each header.
+ for (SpdyHeaderBlock::const_iterator it = name_value_block->begin();
+ it != name_value_block->end();
+ ++it) {
+ if (protocol_version() < 3) {
+ builder->WriteString(it->first);
+ builder->WriteString(it->second);
+ } else {
+ builder->WriteStringPiece32(it->first);
+ builder->WriteStringPiece32(it->second);
+ }
+ }
}
} // namespace net
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index a97eddb..436ee6c 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -44,6 +44,10 @@ class TestSpdyVisitor;
} // namespace test
+// A datastructure for holding a set of headers from either a
+// SYN_STREAM or SYN_REPLY frame.
+typedef std::map<std::string, std::string> SpdyHeaderBlock;
+
// A datastructure for holding the ID and flag fields for SETTINGS.
// Conveniently handles converstion to/from wire format.
class NET_EXPORT_PRIVATE SettingsFlagsAndId {
@@ -72,6 +76,7 @@ typedef std::pair<SpdySettingsFlags, uint32> SettingsFlagsAndValue;
typedef std::map<SpdySettingsIds, SettingsFlagsAndValue> SettingsMap;
// A datastrcture for holding the contents of a CREDENTIAL frame.
+// TODO(hkhalil): Remove, use SpdyCredentialIR instead.
struct NET_EXPORT_PRIVATE SpdyCredential {
SpdyCredential();
~SpdyCredential();
@@ -299,6 +304,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
const SpdyHeaderBlock* headers);
// Retrieve serialized length of SpdyHeaderBlock.
+ // TODO(hkhalil): Change to const reference instead of const pointer.
static size_t GetSerializedLength(const int spdy_version,
const SpdyHeaderBlock* headers);
@@ -360,6 +366,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
SpdyControlFlags flags,
bool compressed,
const SpdyHeaderBlock* headers);
+ SpdySerializedFrame* SerializeSynStream(const SpdySynStreamIR& syn_stream);
// Create a SpdySynReplyControlFrame.
// |stream_id| is the stream for this frame.
@@ -371,17 +378,22 @@ class NET_EXPORT_PRIVATE SpdyFramer {
SpdyControlFlags flags,
bool compressed,
const SpdyHeaderBlock* headers);
+ SpdySerializedFrame* SerializeSynReply(const SpdySynReplyIR& syn_reply);
SpdyRstStreamControlFrame* CreateRstStream(SpdyStreamId stream_id,
SpdyRstStreamStatus status) const;
+ SpdySerializedFrame* SerializeRstStream(
+ const SpdyRstStreamIR& rst_stream) const;
// Creates an instance of SpdySettingsControlFrame. The SETTINGS frame is
// used to communicate name/value pairs relevant to the communication channel.
SpdySettingsControlFrame* CreateSettings(const SettingsMap& values) const;
+ SpdySerializedFrame* SerializeSettings(const SpdySettingsIR& settings) const;
// Creates an instance of SpdyPingControlFrame. The unique_id is used to
// identify the ping request/response.
SpdyPingControlFrame* CreatePingFrame(uint32 unique_id) const;
+ SpdySerializedFrame* SerializePing(const SpdyPingIR& ping) const;
// Creates an instance of SpdyGoAwayControlFrame. The GOAWAY frame is used
// prior to the shutting down of the TCP connection, and includes the
@@ -389,6 +401,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// to completion.
SpdyGoAwayControlFrame* CreateGoAway(SpdyStreamId last_accepted_stream_id,
SpdyGoAwayStatus status) const;
+ SpdySerializedFrame* SerializeGoAway(const SpdyGoAwayIR& goaway) const;
// Creates an instance of SpdyHeadersControlFrame. The HEADERS frame is used
// for sending additional headers outside of a SYN_STREAM/SYN_REPLY. The
@@ -397,18 +410,23 @@ class NET_EXPORT_PRIVATE SpdyFramer {
SpdyControlFlags flags,
bool compressed,
const SpdyHeaderBlock* headers);
+ SpdySerializedFrame* SerializeHeaders(const SpdyHeadersIR& headers);
// Creates an instance of SpdyWindowUpdateControlFrame. The WINDOW_UPDATE
// frame is used to implement per stream flow control in SPDY.
SpdyWindowUpdateControlFrame* CreateWindowUpdate(
SpdyStreamId stream_id,
uint32 delta_window_size) const;
+ SpdySerializedFrame* SerializeWindowUpdate(
+ const SpdyWindowUpdateIR& window_update) const;
// Creates an instance of SpdyCredentialControlFrame. The CREDENTIAL
// frame is used to send a client certificate to the server when
// request more than one origin are sent over the same SPDY session.
SpdyCredentialControlFrame* CreateCredentialFrame(
const SpdyCredential& credential) const;
+ SpdySerializedFrame* SerializeCredential(
+ const SpdyCredentialIR& credential) const;
// Given a SpdySettingsControlFrame, extract the settings.
// Returns true on successful parse, false otherwise.
@@ -430,6 +448,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// To mark this frame as the last data frame, enable DATA_FLAG_FIN.
SpdyDataFrame* CreateDataFrame(SpdyStreamId stream_id, const char* data,
uint32 len, SpdyDataFlags flags) const;
+ SpdySerializedFrame* SerializeData(const SpdyDataIR& data) const;
// NOTES about frame compression.
// We want spdy to compress headers across the entire session. As long as
@@ -467,7 +486,9 @@ class NET_EXPORT_PRIVATE SpdyFramer {
const SpdyControlFrame* control_frame);
// For ease of testing and experimentation we can tweak compression on/off.
- void set_enable_compression(bool value);
+ void set_enable_compression(bool value) {
+ enable_compression_ = value;
+ }
// Used only in log messages.
void set_display_protocol(const std::string& protocol) {
@@ -560,6 +581,10 @@ class NET_EXPORT_PRIVATE SpdyFramer {
void WriteHeaderBlockToZ(const SpdyHeaderBlock* headers,
z_stream* out) const;
+ void SerializeNameValueBlock(
+ SpdyFrameBuilder* builder,
+ const SpdyFrameWithNameValueBlockIR& frame) const;
+
// Set the error code and moves the framer into the error state.
void set_error(SpdyError error);
diff --git a/net/spdy/spdy_protocol.cc b/net/spdy/spdy_protocol.cc
new file mode 100644
index 0000000..9a43c0d
--- /dev/null
+++ b/net/spdy/spdy_protocol.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/spdy/spdy_protocol.h"
+
+namespace net {
+
+SpdyFrameWithNameValueBlockIR::SpdyFrameWithNameValueBlockIR(
+ SpdyStreamId stream_id) : SpdyFrameWithFinIR(stream_id) {}
+
+SpdyFrameWithNameValueBlockIR::~SpdyFrameWithNameValueBlockIR() {}
+
+SpdySettingsIR::SpdySettingsIR() : clear_settings_(false) {}
+
+SpdySettingsIR::~SpdySettingsIR() {}
+
+SpdyCredentialIR::SpdyCredentialIR(int16 slot) {
+ set_slot(slot);
+}
+
+SpdyCredentialIR::~SpdyCredentialIR() {}
+
+} // namespace
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h
index 0647ea1..e9faa24 100644
--- a/net/spdy/spdy_protocol.h
+++ b/net/spdy/spdy_protocol.h
@@ -8,9 +8,12 @@
#define NET_SPDY_SPDY_PROTOCOL_H_
#include <limits>
+#include <map>
+#include <vector>
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/string_piece.h"
#include "base/sys_byteorder.h"
#include "net/spdy/spdy_bitmasks.h"
@@ -355,6 +358,7 @@ const int kV3DictionarySize = arraysize(kV3Dictionary);
// Note: all protocol data structures are on-the-wire format. That means that
// data is stored in network-normalized order. Readers must use the
// accessors provided or call ntohX() functions.
+// TODO(hkhalil): remove above note.
// Types of Spdy Control Frames.
enum SpdyControlType {
@@ -445,6 +449,12 @@ typedef uint32 SpdyStreamId;
// number between 0 and 3.
typedef uint8 SpdyPriority;
+typedef uint8 SpdyCredentialSlot;
+
+typedef std::map<std::string, std::string> SpdyNameValueBlock;
+
+typedef uint32 SpdyPingId;
+
// -------------------------------------------------------------------------
// These structures mirror the protocol structure definitions.
@@ -532,6 +542,298 @@ struct SpdyWindowUpdateControlFrameBlock : SpdyFrameBlock {
#pragma pack(pop)
+class SpdyFrame;
+typedef SpdyFrame SpdySerializedFrame;
+
+class SpdyFramer;
+class SpdyFrameBuilder;
+
+// Intermediate representation for SPDY frames.
+// TODO(hkhalil): Rename this class to SpdyFrame when the existing SpdyFrame is
+// gone.
+class SpdyFrameIR {
+ public:
+ virtual ~SpdyFrameIR() {}
+
+ protected:
+ SpdyFrameIR() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SpdyFrameIR);
+};
+
+// Abstract class intended to be inherited by IRs that have a stream associated
+// to them.
+class SpdyFrameWithStreamIdIR : public SpdyFrameIR {
+ public:
+ virtual ~SpdyFrameWithStreamIdIR() {}
+ SpdyStreamId stream_id() const { return stream_id_; }
+ void set_stream_id(SpdyStreamId stream_id) {
+ // TODO(hkhalil): DCHECK_LT(0u, stream_id);
+ DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
+ stream_id_ = stream_id;
+ }
+
+ protected:
+ explicit SpdyFrameWithStreamIdIR(SpdyStreamId stream_id) {
+ set_stream_id(stream_id);
+ }
+
+ private:
+ SpdyStreamId stream_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithStreamIdIR);
+};
+
+// Abstract class intended to be inherited by IRs that have the option of a FIN
+// flag. Implies SpdyFrameWithStreamIdIR.
+class SpdyFrameWithFinIR : public SpdyFrameWithStreamIdIR {
+ public:
+ virtual ~SpdyFrameWithFinIR() {}
+ bool fin() const { return fin_; }
+ void set_fin(bool fin) { fin_ = fin; }
+
+ protected:
+ explicit SpdyFrameWithFinIR(SpdyStreamId stream_id)
+ : SpdyFrameWithStreamIdIR(stream_id),
+ fin_(false) {}
+
+ private:
+ bool fin_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithFinIR);
+};
+
+// Abstract class intended to be inherited by IRs that contain a name-value
+// block. Implies SpdyFrameWithFinIR.
+class SpdyFrameWithNameValueBlockIR : public SpdyFrameWithFinIR {
+ public:
+ const SpdyNameValueBlock& name_value_block() const {
+ return name_value_block_;
+ }
+ SpdyNameValueBlock* GetMutableNameValueBlock() { return &name_value_block_; }
+
+ protected:
+ explicit SpdyFrameWithNameValueBlockIR(SpdyStreamId stream_id);
+ virtual ~SpdyFrameWithNameValueBlockIR();
+
+ private:
+ SpdyNameValueBlock name_value_block_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithNameValueBlockIR);
+};
+
+class SpdyDataIR : public SpdyFrameWithFinIR {
+ public:
+ SpdyDataIR(SpdyStreamId stream_id, const base::StringPiece& data)
+ : SpdyFrameWithFinIR(stream_id) {
+ set_data(data);
+ }
+ base::StringPiece data() const { return data_; }
+ void set_data(const base::StringPiece& data) { data.CopyToString(&data_); }
+
+ private:
+ std::string data_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyDataIR);
+};
+
+class SpdySynStreamIR : public SpdyFrameWithNameValueBlockIR {
+ public:
+ explicit SpdySynStreamIR(SpdyStreamId stream_id)
+ : SpdyFrameWithNameValueBlockIR(stream_id),
+ associated_to_stream_id_(0),
+ priority_(0),
+ slot_(0),
+ unidirectional_(false) {}
+ SpdyStreamId associated_to_stream_id() const {
+ return associated_to_stream_id_;
+ }
+ void set_associated_to_stream_id(SpdyStreamId stream_id) {
+ associated_to_stream_id_ = stream_id;
+ }
+ SpdyPriority priority() const { return priority_; }
+ void set_priority(SpdyPriority priority) { priority_ = priority; }
+ SpdyCredentialSlot slot() const { return slot_; }
+ void set_slot(SpdyCredentialSlot slot) { slot_ = slot; }
+ bool unidirectional() const { return unidirectional_; }
+ void set_unidirectional(bool unidirectional) {
+ unidirectional_ = unidirectional;
+ }
+
+ private:
+ SpdyStreamId associated_to_stream_id_;
+ SpdyPriority priority_;
+ SpdyCredentialSlot slot_;
+ bool unidirectional_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdySynStreamIR);
+};
+
+class SpdySynReplyIR : public SpdyFrameWithNameValueBlockIR {
+ public:
+ explicit SpdySynReplyIR(SpdyStreamId stream_id)
+ : SpdyFrameWithNameValueBlockIR(stream_id) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SpdySynReplyIR);
+};
+
+class SpdyRstStreamIR : public SpdyFrameWithStreamIdIR {
+ public:
+ SpdyRstStreamIR(SpdyStreamId stream_id, SpdyRstStreamStatus status)
+ : SpdyFrameWithStreamIdIR(stream_id) {
+ set_status(status);
+ }
+ SpdyRstStreamStatus status() const {
+ return status_;
+ }
+ void set_status(SpdyRstStreamStatus status) {
+ DCHECK_NE(status, RST_STREAM_INVALID);
+ DCHECK_LT(status, RST_STREAM_NUM_STATUS_CODES);
+ status_ = status;
+ }
+
+ private:
+ SpdyRstStreamStatus status_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyRstStreamIR);
+};
+
+class SpdySettingsIR : public SpdyFrameIR {
+ public:
+ // Associates flags with a value.
+ struct Value {
+ Value() : persist_value(false),
+ persisted(false),
+ value(0) {}
+ bool persist_value;
+ bool persisted;
+ int32 value;
+ };
+ typedef std::map<SpdySettingsIds, Value> ValueMap;
+
+ SpdySettingsIR();
+
+ virtual ~SpdySettingsIR();
+
+ // Overwrites as appropriate.
+ const ValueMap& values() const { return values_; }
+ void AddSetting(SpdySettingsIds id,
+ bool persist_value,
+ bool persisted,
+ int32 value) {
+ // TODO(hkhalil): DCHECK_LE(SETTINGS_UPLOAD_BANDWIDTH, id);
+ // TODO(hkhalil): DCHECK_GE(SETTINGS_INITIAL_WINDOW_SIZE, id);
+ values_[id].persist_value = persist_value;
+ values_[id].persisted = persisted;
+ values_[id].value = value;
+ }
+ bool clear_settings() const { return clear_settings_; }
+ void set_clear_settings(bool clear_settings) {
+ clear_settings_ = clear_settings;
+ }
+
+ private:
+ ValueMap values_;
+ bool clear_settings_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdySettingsIR);
+};
+
+class SpdyPingIR : public SpdyFrameIR {
+ public:
+ explicit SpdyPingIR(SpdyPingId id) : id_(id) {}
+ SpdyPingId id() const { return id_; }
+
+ private:
+ SpdyPingId id_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyPingIR);
+};
+
+class SpdyGoAwayIR : public SpdyFrameIR {
+ public:
+ SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyGoAwayStatus status) {
+ set_last_good_stream_id(last_good_stream_id);
+ set_status(status);
+ }
+ SpdyStreamId last_good_stream_id() const { return last_good_stream_id_; }
+ void set_last_good_stream_id(SpdyStreamId last_good_stream_id) {
+ DCHECK_LE(0u, last_good_stream_id);
+ DCHECK_EQ(0u, last_good_stream_id & ~kStreamIdMask);
+ last_good_stream_id_ = last_good_stream_id;
+ }
+ SpdyGoAwayStatus status() const { return status_; }
+ void set_status(SpdyGoAwayStatus status) {
+ // TODO(hkhalil): Check valid ranges of status?
+ status_ = status;
+ }
+
+ private:
+ SpdyStreamId last_good_stream_id_;
+ SpdyGoAwayStatus status_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyGoAwayIR);
+};
+
+class SpdyHeadersIR : public SpdyFrameWithNameValueBlockIR {
+ public:
+ explicit SpdyHeadersIR(SpdyStreamId stream_id)
+ : SpdyFrameWithNameValueBlockIR(stream_id) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SpdyHeadersIR);
+};
+
+class SpdyWindowUpdateIR : public SpdyFrameWithStreamIdIR {
+ public:
+ SpdyWindowUpdateIR(SpdyStreamId stream_id, int32 delta)
+ : SpdyFrameWithStreamIdIR(stream_id) {
+ set_delta(delta);
+ }
+ int32 delta() const { return delta_; }
+ void set_delta(int32 delta) {
+ DCHECK_LT(0, delta);
+ DCHECK_LE(delta, kSpdyStreamMaximumWindowSize);
+ delta_ = delta;
+ }
+
+ private:
+ int32 delta_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyWindowUpdateIR);
+};
+
+class SpdyCredentialIR : public SpdyFrameIR {
+ public:
+ typedef std::vector<std::string> CertificateList;
+
+ explicit SpdyCredentialIR(int16 slot);
+ virtual ~SpdyCredentialIR();
+
+ int16 slot() const { return slot_; }
+ void set_slot(int16 slot) {
+ // TODO(hkhalil): Verify valid slot range?
+ slot_ = slot;
+ }
+ base::StringPiece proof() const { return proof_; }
+ void set_proof(const base::StringPiece& proof) {
+ proof.CopyToString(&proof_);
+ }
+ const CertificateList* certificates() const { return &certificates_; }
+ void AddCertificate(const base::StringPiece& certificate) {
+ certificates_.push_back(certificate.as_string());
+ }
+
+ private:
+ int16 slot_;
+ std::string proof_;
+ CertificateList certificates_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyCredentialIR);
+};
+
// -------------------------------------------------------------------------
// Wrapper classes for various SPDY frames.
@@ -731,7 +1033,7 @@ class SpdySynStreamControlFrame : public SpdyControlFrame {
}
void set_credential_slot(uint8 credential_slot) {
- DCHECK(version() >= 3);
+ DCHECK_LE(3, version());
mutable_block()->credential_slot_ = credential_slot;
}