Commit 339489a3 authored by akalin@chromium.org's avatar akalin@chromium.org

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
parent f5a27759
...@@ -826,6 +826,7 @@ ...@@ -826,6 +826,7 @@
'spdy/spdy_http_utils.h', 'spdy/spdy_http_utils.h',
'spdy/spdy_io_buffer.cc', 'spdy/spdy_io_buffer.cc',
'spdy/spdy_io_buffer.h', 'spdy/spdy_io_buffer.h',
'spdy/spdy_protocol.cc',
'spdy/spdy_protocol.h', 'spdy/spdy_protocol.h',
'spdy/spdy_proxy_client_socket.cc', 'spdy/spdy_proxy_client_socket.cc',
'spdy/spdy_proxy_client_socket.h', 'spdy/spdy_proxy_client_socket.h',
......
...@@ -12,7 +12,7 @@ namespace net { ...@@ -12,7 +12,7 @@ namespace net {
namespace { namespace {
// Creates a FlagsAndLength. // 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)); DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
FlagsAndLength flags_length; FlagsAndLength flags_length;
flags_length.length_ = htonl(static_cast<uint32>(length)); flags_length.length_ = htonl(static_cast<uint32>(length));
...@@ -30,7 +30,7 @@ SpdyFrameBuilder::SpdyFrameBuilder(size_t size) ...@@ -30,7 +30,7 @@ SpdyFrameBuilder::SpdyFrameBuilder(size_t size)
} }
SpdyFrameBuilder::SpdyFrameBuilder(SpdyControlType type, SpdyFrameBuilder::SpdyFrameBuilder(SpdyControlType type,
SpdyControlFlags flags, uint8 flags,
int spdy_version, int spdy_version,
size_t size) size_t size)
: buffer_(new char[size]), : buffer_(new char[size]),
......
...@@ -31,7 +31,9 @@ class NET_EXPORT_PRIVATE SpdyFrameBuilder { ...@@ -31,7 +31,9 @@ class NET_EXPORT_PRIVATE SpdyFrameBuilder {
// Initializes a SpdyFrameBuilder with a buffer of given size, // Initializes a SpdyFrameBuilder with a buffer of given size,
// populate with a SPDY control frame header based on // populate with a SPDY control frame header based on
// |type|, |flags|, and |spdy_version|. // |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); int spdy_version, size_t size);
// Initiailizes a SpdyFrameBuilder with a buffer of given size, // Initiailizes a SpdyFrameBuilder with a buffer of given size,
......
...@@ -46,6 +46,9 @@ struct DictionaryIds { ...@@ -46,6 +46,9 @@ struct DictionaryIds {
// initialized lazily to avoid static initializers. // initialized lazily to avoid static initializers.
base::LazyInstance<DictionaryIds>::Leaky g_dictionary_ids; base::LazyInstance<DictionaryIds>::Leaky g_dictionary_ids;
// Used to indicate no flags in a SPDY flags field.
const uint8 kNoFlags = 0;
} // namespace } // namespace
const int SpdyFramer::kMinSpdyVersion = 2; const int SpdyFramer::kMinSpdyVersion = 2;
...@@ -677,15 +680,13 @@ void SpdyFramer::WriteHeaderBlock(SpdyFrameBuilder* frame, ...@@ -677,15 +680,13 @@ void SpdyFramer::WriteHeaderBlock(SpdyFrameBuilder* frame,
} }
SpdyHeaderBlock::const_iterator it; SpdyHeaderBlock::const_iterator it;
for (it = headers->begin(); it != headers->end(); ++it) { for (it = headers->begin(); it != headers->end(); ++it) {
bool wrote_header;
if (spdy_version < 3) { if (spdy_version < 3) {
wrote_header = frame->WriteString(it->first); frame->WriteString(it->first);
wrote_header &= frame->WriteString(it->second); frame->WriteString(it->second);
} else { } else {
wrote_header = frame->WriteStringPiece32(it->first); frame->WriteStringPiece32(it->first);
wrote_header &= frame->WriteStringPiece32(it->second); frame->WriteStringPiece32(it->second);
} }
DCHECK(wrote_header);
} }
} }
...@@ -1291,29 +1292,20 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( ...@@ -1291,29 +1292,20 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
SpdyControlFlags flags, SpdyControlFlags flags,
bool compressed, bool compressed,
const SpdyHeaderBlock* headers) { const SpdyHeaderBlock* headers) {
DCHECK_EQ(0u, stream_id & ~kStreamIdMask); DCHECK_EQ(0, flags & ~CONTROL_FLAG_FIN & ~CONTROL_FLAG_UNIDIRECTIONAL);
DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask);
// Find our length.
size_t frame_size = SpdySynStreamControlFrame::size() +
GetSerializedLength(spdy_version_, headers);
SpdyFrameBuilder frame(SYN_STREAM, flags, spdy_version_, frame_size); SpdySynStreamIR syn_stream(stream_id);
frame.WriteUInt32(stream_id); syn_stream.set_associated_to_stream_id(associated_stream_id);
frame.WriteUInt32(associated_stream_id); syn_stream.set_priority(priority);
// Cap as appropriate. syn_stream.set_slot(credential_slot);
if (priority > GetLowestPriority()) { syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
DLOG(DFATAL) << "Priority out-of-bounds."; syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
priority = GetLowestPriority(); // TODO(hkhalil): Avoid copy here.
} *(syn_stream.GetMutableNameValueBlock()) = *headers;
// 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);
scoped_ptr<SpdySynStreamControlFrame> syn_frame( scoped_ptr<SpdySynStreamControlFrame> syn_frame(
reinterpret_cast<SpdySynStreamControlFrame*>(frame.take())); reinterpret_cast<SpdySynStreamControlFrame*>(
SerializeSynStream(syn_stream)));
if (compressed) { if (compressed) {
return reinterpret_cast<SpdySynStreamControlFrame*>( return reinterpret_cast<SpdySynStreamControlFrame*>(
CompressControlFrame(*syn_frame.get(), headers)); CompressControlFrame(*syn_frame.get(), headers));
...@@ -1321,32 +1313,57 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream( ...@@ -1321,32 +1313,57 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
return syn_frame.release(); 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( SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(
SpdyStreamId stream_id, SpdyStreamId stream_id,
SpdyControlFlags flags, SpdyControlFlags flags,
bool compressed, bool compressed,
const SpdyHeaderBlock* headers) { const SpdyHeaderBlock* headers) {
DCHECK_GT(stream_id, 0u); DCHECK_EQ(0, flags & ~CONTROL_FLAG_FIN);
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
// Find our length. SpdySynReplyIR syn_reply(stream_id);
size_t frame_size = SpdySynReplyControlFrame::size() + syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
GetSerializedLength(spdy_version_, headers); // TODO(hkhalil): Avoid copy here.
// In SPDY 2, there were 2 unused bytes before payload. *(syn_reply.GetMutableNameValueBlock()) = *headers;
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);
scoped_ptr<SpdySynReplyControlFrame> reply_frame( scoped_ptr<SpdySynReplyControlFrame> reply_frame(
reinterpret_cast<SpdySynReplyControlFrame*>(frame.take())); reinterpret_cast<SpdySynReplyControlFrame*>(SerializeSynReply(
syn_reply)));
if (compressed) { if (compressed) {
return reinterpret_cast<SpdySynReplyControlFrame*>( return reinterpret_cast<SpdySynReplyControlFrame*>(
CompressControlFrame(*reply_frame.get(), headers)); CompressControlFrame(*reply_frame.get(), headers));
...@@ -1354,159 +1371,298 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply( ...@@ -1354,159 +1371,298 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(
return reply_frame.release(); 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( SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(
SpdyStreamId stream_id, SpdyStreamId stream_id,
SpdyRstStreamStatus status) const { SpdyRstStreamStatus status) const {
DCHECK_GT(stream_id, 0u); SpdyRstStreamIR rst_stream(stream_id, status);
DCHECK_EQ(0u, stream_id & ~kStreamIdMask); return reinterpret_cast<SpdyRstStreamControlFrame*>(
DCHECK_NE(status, RST_STREAM_INVALID); SerializeRstStream(rst_stream));
DCHECK_LT(status, RST_STREAM_NUM_STATUS_CODES); }
size_t frame_size = SpdyRstStreamControlFrame::size(); SpdySerializedFrame* SpdyFramer::SerializeRstStream(
SpdyFrameBuilder frame(RST_STREAM, CONTROL_FLAG_NONE, spdy_version_, const SpdyRstStreamIR& rst_stream) const {
frame_size); // Size of our RST_STREAM frame. Calculated as:
frame.WriteUInt32(stream_id); // 8 (control frame header) + 4 (stream id) + 4 (status code)
frame.WriteUInt32(status); const size_t kRstStreamFrameSize = 16;
DCHECK_EQ(frame.length(), frame_size);
return reinterpret_cast<SpdyRstStreamControlFrame*>(frame.take()); 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( SpdySettingsControlFrame* SpdyFramer::CreateSettings(
const SettingsMap& values) const { const SettingsMap& values) const {
size_t frame_size = SpdySettingsControlFrame::size() + 8 * values.size(); SpdySettingsIR settings;
SpdyFrameBuilder frame(SETTINGS, CONTROL_FLAG_NONE, spdy_version_,
frame_size);
frame.WriteUInt32(values.size());
for (SettingsMap::const_iterator it = values.begin(); for (SettingsMap::const_iterator it = values.begin();
it != values.end(); it != values.end();
it++) { ++it) {
SettingsFlagsAndId flags_and_id(it->second.first, it->first); settings.AddSetting(it->first,
uint32 id_and_flags_wire = flags_and_id.GetWireFormat(spdy_version_); (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0,
frame.WriteBytes(&id_and_flags_wire, 4); (it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
frame.WriteUInt32(it->second.second); it->second.second);
} }
DCHECK_EQ(frame.length(), frame_size); return reinterpret_cast<SpdySettingsControlFrame*>(
return reinterpret_cast<SpdySettingsControlFrame*>(frame.take()); 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 { SpdyPingControlFrame* SpdyFramer::CreatePingFrame(uint32 unique_id) const {
size_t frame_size = SpdyPingControlFrame::size(); SpdyPingIR ping(unique_id);
SpdyFrameBuilder frame(PING, CONTROL_FLAG_NONE, spdy_version_, frame_size); return reinterpret_cast<SpdyPingControlFrame*>(SerializePing(ping));
frame.WriteUInt32(unique_id); }
DCHECK_EQ(frame.length(), frame_size);
return reinterpret_cast<SpdyPingControlFrame*>(frame.take()); 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( SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway(
SpdyStreamId last_accepted_stream_id, SpdyStreamId last_accepted_stream_id,
SpdyGoAwayStatus status) const { SpdyGoAwayStatus status) const {
DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask); SpdyGoAwayIR goaway(last_accepted_stream_id, status);
return reinterpret_cast<SpdyGoAwayControlFrame*>(SerializeGoAway(goaway));
// 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. SpdySerializedFrame* SpdyFramer::SerializeGoAway(
const size_t goaway_offset = (protocol_version() < 3) ? 4 : 0; const SpdyGoAwayIR& goaway) const {
size_t frame_size = SpdyGoAwayControlFrame::size() - goaway_offset; // Size, in bytes, of this GOAWAY frame. Calculated as:
SpdyFrameBuilder frame(GOAWAY, CONTROL_FLAG_NONE, spdy_version_, frame_size); // 8 (control frame header) + 4 (last good stream id)
frame.WriteUInt32(last_accepted_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) { if (protocol_version() >= 3) {
frame.WriteUInt32(status); builder.WriteUInt32(goaway.status());
} }
DCHECK_EQ(frame.length(), frame_size); DCHECK_EQ(size, builder.length());
return reinterpret_cast<SpdyGoAwayControlFrame*>(frame.take()); return builder.take();
} }
SpdyHeadersControlFrame* SpdyFramer::CreateHeaders( SpdyHeadersControlFrame* SpdyFramer::CreateHeaders(
SpdyStreamId stream_id, SpdyStreamId stream_id,
SpdyControlFlags flags, SpdyControlFlags flags,
bool compressed, bool compressed,
const SpdyHeaderBlock* headers) { const SpdyHeaderBlock* header_block) {
// Basically the same as CreateSynReply(). // Basically the same as CreateSynReply().
DCHECK_GT(stream_id, 0u); DCHECK_EQ(0, flags & (!CONTROL_FLAG_FIN));
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;
}
SpdyFrameBuilder frame(HEADERS, flags, spdy_version_, frame_size); SpdyHeadersIR headers(stream_id);
frame.WriteUInt32(stream_id); headers.set_fin(flags & CONTROL_FLAG_FIN);
if (spdy_version_ < 3) { // TODO(hkhalil): Avoid copy here.
frame.WriteUInt16(0); // Unused *(headers.GetMutableNameValueBlock()) = *header_block;
}
WriteHeaderBlock(&frame, spdy_version_, headers);
DCHECK_EQ(frame.length(), frame_size);
scoped_ptr<SpdyHeadersControlFrame> headers_frame( scoped_ptr<SpdyHeadersControlFrame> headers_frame(
reinterpret_cast<SpdyHeadersControlFrame*>(frame.take())); reinterpret_cast<SpdyHeadersControlFrame*>(SerializeHeaders(headers)));
if (compressed) { if (compressed) {
return reinterpret_cast<SpdyHeadersControlFrame*>( return reinterpret_cast<SpdyHeadersControlFrame*>(
CompressControlFrame(*headers_frame.get(), headers)); CompressControlFrame(*headers_frame.get(),
headers.GetMutableNameValueBlock()));
} }
return headers_frame.release(); 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( SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
SpdyStreamId stream_id, SpdyStreamId stream_id,
uint32 delta_window_size) const { uint32 delta_window_size) const {
DCHECK_GT(stream_id, 0u); SpdyWindowUpdateIR window_update(stream_id, delta_window_size);
DCHECK_EQ(0u, stream_id & ~kStreamIdMask); return reinterpret_cast<SpdyWindowUpdateControlFrame*>(
DCHECK_GT(delta_window_size, 0u); SerializeWindowUpdate(window_update));
DCHECK_LE(delta_window_size, }
static_cast<uint32>(kSpdyStreamMaximumWindowSize));
SpdySerializedFrame* SpdyFramer::SerializeWindowUpdate(
size_t frame_size = SpdyWindowUpdateControlFrame::size(); const SpdyWindowUpdateIR& window_update) const {
SpdyFrameBuilder frame(WINDOW_UPDATE, CONTROL_FLAG_NONE, spdy_version_, // Size, in bytes, of this WINDOW_UPDATE frame. Calculated as:
frame_size); // 8 (control frame header) + 4 (stream id) + 4 (delta)
frame.WriteUInt32(stream_id); const size_t kWindowUpdateSize = 16;
frame.WriteUInt32(delta_window_size);
DCHECK_EQ(frame.length(), frame_size); SpdyFrameBuilder builder(WINDOW_UPDATE,
return reinterpret_cast<SpdyWindowUpdateControlFrame*>(frame.take()); 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( SpdyCredentialControlFrame* SpdyFramer::CreateCredentialFrame(
const SpdyCredential& credential) const { const SpdyCredential& credential) const {
// Calculate the size of the frame by adding the size of the SpdyCredentialIR credential_ir(credential.slot);
// variable length data to the size of the fixed length data. credential_ir.set_proof(credential.proof);
size_t frame_size = SpdyCredentialControlFrame::size() +
credential.proof.length();
DCHECK_EQ(SpdyCredentialControlFrame::size(), 14u);
for (std::vector<std::string>::const_iterator cert = credential.certs.begin(); for (std::vector<std::string>::const_iterator cert = credential.certs.begin();
cert != credential.certs.end(); cert != credential.certs.end();
++cert) { ++cert) {
frame_size += sizeof(uint32); // size of the cert_length field credential_ir.AddCertificate(*cert);
frame_size += cert->length(); // size of the cert_data field
} }
return reinterpret_cast<SpdyCredentialControlFrame*>(
SerializeCredential(credential_ir));
}
SpdyFrameBuilder frame(CREDENTIAL, CONTROL_FLAG_NONE, spdy_version_, SpdySerializedFrame* SpdyFramer::SerializeCredential(
frame_size); const SpdyCredentialIR& credential) const {
frame.WriteUInt16(credential.slot); size_t size = 8; // Room for frame header.
frame.WriteUInt32(credential.proof.size()); size += 2; // Room for slot.
frame.WriteBytes(credential.proof.c_str(), credential.proof.size()); size += 4 + credential.proof().length(); // Room for proof.
for (std::vector<std::string>::const_iterator cert = credential.certs.begin(); for (SpdyCredentialIR::CertificateList::const_iterator it =
cert != credential.certs.end(); credential.certificates()->begin();
++cert) { it != credential.certificates()->end();
frame.WriteUInt32(cert->length()); ++it) {
frame.WriteBytes(cert->c_str(), cert->length()); 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); DCHECK_EQ(size, builder.length());
return reinterpret_cast<SpdyCredentialControlFrame*>(frame.take()); return builder.take();
} }
SpdyDataFrame* SpdyFramer::CreateDataFrame( SpdyDataFrame* SpdyFramer::CreateDataFrame(
SpdyStreamId stream_id, SpdyStreamId stream_id, const char* data,
const char* data,
uint32 len, SpdyDataFlags flags) const { uint32 len, SpdyDataFlags flags) const {
DCHECK_EQ(0u, stream_id & ~kStreamIdMask); DCHECK_EQ(0, flags & (!DATA_FLAG_FIN));
size_t frame_size = SpdyDataFrame::size() + len;
SpdyFrameBuilder frame(stream_id, flags, frame_size); SpdyDataIR data_ir(stream_id, base::StringPiece(data, len));
frame.WriteBytes(data, len); data_ir.set_fin(flags & DATA_FLAG_FIN);
DCHECK_EQ(frame.length(), frame_size); return reinterpret_cast<SpdyDataFrame*>(SerializeData(data_ir));
return reinterpret_cast<SpdyDataFrame*>(frame.take()); }
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 // The following compression setting are based on Brian Olson's analysis. See
...@@ -1912,8 +2068,30 @@ SpdyStreamId SpdyFramer::GetControlFrameStreamId( ...@@ -1912,8 +2068,30 @@ SpdyStreamId SpdyFramer::GetControlFrameStreamId(
return stream_id; return stream_id;
} }
void SpdyFramer::set_enable_compression(bool value) { void SpdyFramer::SerializeNameValueBlock(
enable_compression_ = value; 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 } // namespace net
...@@ -44,6 +44,10 @@ class TestSpdyVisitor; ...@@ -44,6 +44,10 @@ class TestSpdyVisitor;
} // namespace test } // 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. // A datastructure for holding the ID and flag fields for SETTINGS.
// Conveniently handles converstion to/from wire format. // Conveniently handles converstion to/from wire format.
class NET_EXPORT_PRIVATE SettingsFlagsAndId { class NET_EXPORT_PRIVATE SettingsFlagsAndId {
...@@ -72,6 +76,7 @@ typedef std::pair<SpdySettingsFlags, uint32> SettingsFlagsAndValue; ...@@ -72,6 +76,7 @@ typedef std::pair<SpdySettingsFlags, uint32> SettingsFlagsAndValue;
typedef std::map<SpdySettingsIds, SettingsFlagsAndValue> SettingsMap; typedef std::map<SpdySettingsIds, SettingsFlagsAndValue> SettingsMap;
// A datastrcture for holding the contents of a CREDENTIAL frame. // A datastrcture for holding the contents of a CREDENTIAL frame.
// TODO(hkhalil): Remove, use SpdyCredentialIR instead.
struct NET_EXPORT_PRIVATE SpdyCredential { struct NET_EXPORT_PRIVATE SpdyCredential {
SpdyCredential(); SpdyCredential();
~SpdyCredential(); ~SpdyCredential();
...@@ -299,6 +304,7 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -299,6 +304,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
const SpdyHeaderBlock* headers); const SpdyHeaderBlock* headers);
// Retrieve serialized length of SpdyHeaderBlock. // Retrieve serialized length of SpdyHeaderBlock.
// TODO(hkhalil): Change to const reference instead of const pointer.
static size_t GetSerializedLength(const int spdy_version, static size_t GetSerializedLength(const int spdy_version,
const SpdyHeaderBlock* headers); const SpdyHeaderBlock* headers);
...@@ -360,6 +366,7 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -360,6 +366,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
SpdyControlFlags flags, SpdyControlFlags flags,
bool compressed, bool compressed,
const SpdyHeaderBlock* headers); const SpdyHeaderBlock* headers);
SpdySerializedFrame* SerializeSynStream(const SpdySynStreamIR& syn_stream);
// Create a SpdySynReplyControlFrame. // Create a SpdySynReplyControlFrame.
// |stream_id| is the stream for this frame. // |stream_id| is the stream for this frame.
...@@ -371,17 +378,22 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -371,17 +378,22 @@ class NET_EXPORT_PRIVATE SpdyFramer {
SpdyControlFlags flags, SpdyControlFlags flags,
bool compressed, bool compressed,
const SpdyHeaderBlock* headers); const SpdyHeaderBlock* headers);
SpdySerializedFrame* SerializeSynReply(const SpdySynReplyIR& syn_reply);
SpdyRstStreamControlFrame* CreateRstStream(SpdyStreamId stream_id, SpdyRstStreamControlFrame* CreateRstStream(SpdyStreamId stream_id,
SpdyRstStreamStatus status) const; SpdyRstStreamStatus status) const;
SpdySerializedFrame* SerializeRstStream(
const SpdyRstStreamIR& rst_stream) const;
// Creates an instance of SpdySettingsControlFrame. The SETTINGS frame is // Creates an instance of SpdySettingsControlFrame. The SETTINGS frame is
// used to communicate name/value pairs relevant to the communication channel. // used to communicate name/value pairs relevant to the communication channel.
SpdySettingsControlFrame* CreateSettings(const SettingsMap& values) const; SpdySettingsControlFrame* CreateSettings(const SettingsMap& values) const;
SpdySerializedFrame* SerializeSettings(const SpdySettingsIR& settings) const;
// Creates an instance of SpdyPingControlFrame. The unique_id is used to // Creates an instance of SpdyPingControlFrame. The unique_id is used to
// identify the ping request/response. // identify the ping request/response.
SpdyPingControlFrame* CreatePingFrame(uint32 unique_id) const; SpdyPingControlFrame* CreatePingFrame(uint32 unique_id) const;
SpdySerializedFrame* SerializePing(const SpdyPingIR& ping) const;
// Creates an instance of SpdyGoAwayControlFrame. The GOAWAY frame is used // Creates an instance of SpdyGoAwayControlFrame. The GOAWAY frame is used
// prior to the shutting down of the TCP connection, and includes the // prior to the shutting down of the TCP connection, and includes the
...@@ -389,6 +401,7 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -389,6 +401,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// to completion. // to completion.
SpdyGoAwayControlFrame* CreateGoAway(SpdyStreamId last_accepted_stream_id, SpdyGoAwayControlFrame* CreateGoAway(SpdyStreamId last_accepted_stream_id,
SpdyGoAwayStatus status) const; SpdyGoAwayStatus status) const;
SpdySerializedFrame* SerializeGoAway(const SpdyGoAwayIR& goaway) const;
// Creates an instance of SpdyHeadersControlFrame. The HEADERS frame is used // Creates an instance of SpdyHeadersControlFrame. The HEADERS frame is used
// for sending additional headers outside of a SYN_STREAM/SYN_REPLY. The // for sending additional headers outside of a SYN_STREAM/SYN_REPLY. The
...@@ -397,18 +410,23 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -397,18 +410,23 @@ class NET_EXPORT_PRIVATE SpdyFramer {
SpdyControlFlags flags, SpdyControlFlags flags,
bool compressed, bool compressed,
const SpdyHeaderBlock* headers); const SpdyHeaderBlock* headers);
SpdySerializedFrame* SerializeHeaders(const SpdyHeadersIR& headers);
// Creates an instance of SpdyWindowUpdateControlFrame. The WINDOW_UPDATE // Creates an instance of SpdyWindowUpdateControlFrame. The WINDOW_UPDATE
// frame is used to implement per stream flow control in SPDY. // frame is used to implement per stream flow control in SPDY.
SpdyWindowUpdateControlFrame* CreateWindowUpdate( SpdyWindowUpdateControlFrame* CreateWindowUpdate(
SpdyStreamId stream_id, SpdyStreamId stream_id,
uint32 delta_window_size) const; uint32 delta_window_size) const;
SpdySerializedFrame* SerializeWindowUpdate(
const SpdyWindowUpdateIR& window_update) const;
// Creates an instance of SpdyCredentialControlFrame. The CREDENTIAL // Creates an instance of SpdyCredentialControlFrame. The CREDENTIAL
// frame is used to send a client certificate to the server when // frame is used to send a client certificate to the server when
// request more than one origin are sent over the same SPDY session. // request more than one origin are sent over the same SPDY session.
SpdyCredentialControlFrame* CreateCredentialFrame( SpdyCredentialControlFrame* CreateCredentialFrame(
const SpdyCredential& credential) const; const SpdyCredential& credential) const;
SpdySerializedFrame* SerializeCredential(
const SpdyCredentialIR& credential) const;
// Given a SpdySettingsControlFrame, extract the settings. // Given a SpdySettingsControlFrame, extract the settings.
// Returns true on successful parse, false otherwise. // Returns true on successful parse, false otherwise.
...@@ -430,6 +448,7 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -430,6 +448,7 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// To mark this frame as the last data frame, enable DATA_FLAG_FIN. // To mark this frame as the last data frame, enable DATA_FLAG_FIN.
SpdyDataFrame* CreateDataFrame(SpdyStreamId stream_id, const char* data, SpdyDataFrame* CreateDataFrame(SpdyStreamId stream_id, const char* data,
uint32 len, SpdyDataFlags flags) const; uint32 len, SpdyDataFlags flags) const;
SpdySerializedFrame* SerializeData(const SpdyDataIR& data) const;
// NOTES about frame compression. // NOTES about frame compression.
// We want spdy to compress headers across the entire session. As long as // We want spdy to compress headers across the entire session. As long as
...@@ -467,7 +486,9 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -467,7 +486,9 @@ class NET_EXPORT_PRIVATE SpdyFramer {
const SpdyControlFrame* control_frame); const SpdyControlFrame* control_frame);
// For ease of testing and experimentation we can tweak compression on/off. // 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. // Used only in log messages.
void set_display_protocol(const std::string& protocol) { void set_display_protocol(const std::string& protocol) {
...@@ -560,6 +581,10 @@ class NET_EXPORT_PRIVATE SpdyFramer { ...@@ -560,6 +581,10 @@ class NET_EXPORT_PRIVATE SpdyFramer {
void WriteHeaderBlockToZ(const SpdyHeaderBlock* headers, void WriteHeaderBlockToZ(const SpdyHeaderBlock* headers,
z_stream* out) const; z_stream* out) const;
void SerializeNameValueBlock(
SpdyFrameBuilder* builder,
const SpdyFrameWithNameValueBlockIR& frame) const;
// Set the error code and moves the framer into the error state. // Set the error code and moves the framer into the error state.
void set_error(SpdyError error); void set_error(SpdyError error);
......
// 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
...@@ -8,9 +8,12 @@ ...@@ -8,9 +8,12 @@
#define NET_SPDY_SPDY_PROTOCOL_H_ #define NET_SPDY_SPDY_PROTOCOL_H_
#include <limits> #include <limits>
#include <map>
#include <vector>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/string_piece.h"
#include "base/sys_byteorder.h" #include "base/sys_byteorder.h"
#include "net/spdy/spdy_bitmasks.h" #include "net/spdy/spdy_bitmasks.h"
...@@ -355,6 +358,7 @@ const int kV3DictionarySize = arraysize(kV3Dictionary); ...@@ -355,6 +358,7 @@ const int kV3DictionarySize = arraysize(kV3Dictionary);
// Note: all protocol data structures are on-the-wire format. That means that // Note: all protocol data structures are on-the-wire format. That means that
// data is stored in network-normalized order. Readers must use the // data is stored in network-normalized order. Readers must use the
// accessors provided or call ntohX() functions. // accessors provided or call ntohX() functions.
// TODO(hkhalil): remove above note.
// Types of Spdy Control Frames. // Types of Spdy Control Frames.
enum SpdyControlType { enum SpdyControlType {
...@@ -445,6 +449,12 @@ typedef uint32 SpdyStreamId; ...@@ -445,6 +449,12 @@ typedef uint32 SpdyStreamId;
// number between 0 and 3. // number between 0 and 3.
typedef uint8 SpdyPriority; typedef uint8 SpdyPriority;
typedef uint8 SpdyCredentialSlot;
typedef std::map<std::string, std::string> SpdyNameValueBlock;
typedef uint32 SpdyPingId;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// These structures mirror the protocol structure definitions. // These structures mirror the protocol structure definitions.
...@@ -532,6 +542,298 @@ struct SpdyWindowUpdateControlFrameBlock : SpdyFrameBlock { ...@@ -532,6 +542,298 @@ struct SpdyWindowUpdateControlFrameBlock : SpdyFrameBlock {
#pragma pack(pop) #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. // Wrapper classes for various SPDY frames.
...@@ -731,7 +1033,7 @@ class SpdySynStreamControlFrame : public SpdyControlFrame { ...@@ -731,7 +1033,7 @@ class SpdySynStreamControlFrame : public SpdyControlFrame {
} }
void set_credential_slot(uint8 credential_slot) { void set_credential_slot(uint8 credential_slot) {
DCHECK(version() >= 3); DCHECK_LE(3, version());
mutable_block()->credential_slot_ = credential_slot; mutable_block()->credential_slot_ = credential_slot;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment