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

Unified Diff: net/spdy/spdy_framer.cc

Issue 288373004: Add handling + parsing for HTTP/2 ALTSVC frame. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Non-static initializer fixes. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/spdy/spdy_framer.h ('k') | net/spdy/spdy_framer_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_framer.cc
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index 33942b971add3922804b04c7f26e5be453679be8..ebc523b06156981bd371077d1d3b2dd9d0332af4 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -13,6 +13,7 @@
#include "net/spdy/spdy_bitmasks.h"
#include "third_party/zlib/zlib.h"
+using base::StringPiece;
using std::string;
using std::vector;
@@ -50,7 +51,6 @@ const uint8 kNoFlags = 0;
const SpdyStreamId SpdyFramer::kInvalidStream = -1;
const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024;
-// The size of the control frame buffer. Must be >= the minimum size of the
// largest control frame, which is SYN_STREAM. See GetSynStreamMinimumSize() for
// calculation details.
const size_t SpdyFramer::kControlFrameBufferSize = 18;
@@ -109,6 +109,9 @@ void SettingsFlagsAndId::ConvertFlagsAndIdForSpdy2(uint32* val) {
std::swap(wire_array[1], wire_array[2]);
}
+SpdyAltSvcScratch::SpdyAltSvcScratch() { Reset(); }
+SpdyAltSvcScratch::~SpdyAltSvcScratch() {}
+
bool SpdyFramerVisitorInterface::OnGoAwayFrameData(const char* goaway_data,
size_t len) {
return true;
@@ -157,6 +160,7 @@ void SpdyFramer::Reset() {
current_frame_length_ = 0;
current_frame_stream_id_ = kInvalidStream;
settings_scratch_.Reset();
+ altsvc_scratch_.Reset();
remaining_padding_payload_length_ = 0;
remaining_padding_length_fields_ = 0;
}
@@ -307,6 +311,16 @@ size_t SpdyFramer::GetContinuationMinimumSize() const {
return GetControlFrameHeaderSize();
}
+size_t SpdyFramer::GetAltSvcMinimumSize() const {
+ // Size, in bytes, of an ALTSVC frame not including the Protocol-ID, Host, and
+ // (optional) Origin fields, all of which can vary in length.
+ // Note that this gives a lower bound on the frame size rather than a true
+ // minimum; the actual frame should always be larger than this.
+ // Calculated as frame prefix + 4 (max-age) + 2 (port) + 1 (reserved byte)
+ // + 1 (pid_len) + 1 (host_len).
+ return GetControlFrameHeaderSize() + 9;
+}
+
size_t SpdyFramer::GetFrameMinimumSize() const {
return std::min(GetDataFrameMinimumSize(), GetControlFrameHeaderSize());
}
@@ -353,6 +367,8 @@ const char* SpdyFramer::StateToString(int state) {
return "SPDY_RST_STREAM_FRAME_PAYLOAD";
case SPDY_SETTINGS_FRAME_PAYLOAD:
return "SPDY_SETTINGS_FRAME_PAYLOAD";
+ case SPDY_ALTSVC_FRAME_PAYLOAD:
+ return "SPDY_ALTSVC_FRAME_PAYLOAD";
}
return "UNKNOWN_STATE";
}
@@ -460,6 +476,8 @@ const char* SpdyFramer::FrameTypeToString(SpdyFrameType type) {
return "PUSH_PROMISE";
case CONTINUATION:
return "CONTINUATION";
+ case ALTSVC:
+ return "ALTSVC";
}
return "UNKNOWN_CONTROL_TYPE";
}
@@ -539,6 +557,13 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
break;
}
+ case SPDY_ALTSVC_FRAME_PAYLOAD: {
+ size_t bytes_read = ProcessAltSvcFramePayload(data, len);
+ len -= bytes_read;
+ data += bytes_read;
+ break;
+ }
+
case SPDY_CONTROL_FRAME_PAYLOAD: {
size_t bytes_read = ProcessControlFramePayload(data, len);
len -= bytes_read;
@@ -911,7 +936,9 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
}
break;
case BLOCKED:
- if (current_frame_length_ != GetBlockedSize()) {
+ if (current_frame_length_ != GetBlockedSize() ||
+ protocol_version() <= SPDY3) {
+ // TODO(mlavan): BLOCKED frames are no longer part of SPDY4.
set_error(SPDY_INVALID_CONTROL_FRAME);
} else if (current_frame_flags_ != 0) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
@@ -935,6 +962,13 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
}
break;
+ case ALTSVC:
+ if (current_frame_length_ <= GetAltSvcMinimumSize()) {
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ } else if (current_frame_flags_ != 0) {
+ set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS);
+ }
+ break;
default:
LOG(WARNING) << "Valid " << display_protocol_
<< " control frame with unhandled type: "
@@ -969,6 +1003,10 @@ void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) {
return;
}
+ if (current_frame_type_ == ALTSVC) {
+ CHANGE_STATE(SPDY_ALTSVC_FRAME_PAYLOAD);
+ return;
+ }
// Determine the frame size without variable-length data.
int32 frame_size_without_variable_data;
switch (current_frame_type_) {
@@ -1856,6 +1894,133 @@ size_t SpdyFramer::ProcessRstStreamFramePayload(const char* data, size_t len) {
return original_len;
}
+size_t SpdyFramer::ProcessAltSvcFramePayload(const char* data, size_t len) {
+ if (len == 0) {
+ return 0;
+ }
+
+ // Clamp to the actual remaining payload.
+ len = std::min(len, remaining_data_length_);
+
+ size_t processed_bytes = 0;
+ size_t processing = 0;
+ size_t bytes_remaining;
+ char* buffer;
+ size_t* buffer_len;
+
+ while (len > 0) {
+ if (altsvc_scratch_.pid_len == 0) {
+ // The size of the frame up to the PID_LEN field.
+ size_t fixed_len_portion = GetAltSvcMinimumSize() - 1;
+ bytes_remaining = fixed_len_portion - current_frame_buffer_length_;
+ processing = std::min(len, bytes_remaining);
+ // Buffer the new ALTSVC bytes we got.
+ UpdateCurrentFrameBuffer(&data, &len, processing);
+
+ // Do we have enough to parse the length of the protocol id?
+ if (current_frame_buffer_length_ == fixed_len_portion) {
+ // Parse out the max age, port, and pid_len.
+ SpdyFrameReader reader(current_frame_buffer_.get(),
+ current_frame_buffer_length_);
+ reader.Seek(GetControlFrameHeaderSize()); // Seek past frame header.
+ bool successful_read = reader.ReadUInt32(&altsvc_scratch_.max_age);
+ reader.ReadUInt16(&altsvc_scratch_.port);
+ reader.Seek(1); // Reserved byte.
+ successful_read = successful_read &&
+ reader.ReadUInt8(&altsvc_scratch_.pid_len);
+ DCHECK(successful_read);
+ // Sanity check length value.
+ if (GetAltSvcMinimumSize() + altsvc_scratch_.pid_len >=
+ current_frame_length_) {
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ return 0;
+ }
+ altsvc_scratch_.protocol_id.reset(
+ new char[size_t(altsvc_scratch_.pid_len)]);
+ }
+ processed_bytes += processing;
+ continue;
+ } else if (altsvc_scratch_.pid_buf_len < altsvc_scratch_.pid_len) {
+ // Buffer protocol id field as in comes in.
+ buffer = altsvc_scratch_.protocol_id.get();
+ buffer_len = &altsvc_scratch_.pid_buf_len;
+ bytes_remaining = altsvc_scratch_.pid_len - altsvc_scratch_.pid_buf_len;
+ } else if (altsvc_scratch_.host_len == 0) {
+ // Parse out the host length.
+ processing = 1;
+ altsvc_scratch_.host_len = *reinterpret_cast<const uint8*>(data);
+ // Sanity check length value.
+ if (GetAltSvcMinimumSize() + altsvc_scratch_.pid_len +
+ altsvc_scratch_.host_len > current_frame_length_) {
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ return 0;
+ }
+ altsvc_scratch_.host.reset(new char[altsvc_scratch_.host_len]);
+ // Once we have host length, we can also determine the origin length
+ // by process of elimination.
+ altsvc_scratch_.origin_len = current_frame_length_ -
+ GetAltSvcMinimumSize() -
+ altsvc_scratch_.pid_len -
+ altsvc_scratch_.host_len;
+ if (altsvc_scratch_.origin_len > 0) {
+ altsvc_scratch_.origin.reset(new char[altsvc_scratch_.origin_len]);
+ }
+ data += processing;
+ processed_bytes += processing;
+ len -= processing;
+ continue;
+ } else if (altsvc_scratch_.host_buf_len < altsvc_scratch_.host_len) {
+ // Buffer host field as it comes in.
+ // TODO(mlavan): check formatting for host and origin
+ buffer = altsvc_scratch_.host.get();
+ buffer_len = &altsvc_scratch_.host_buf_len;
+ bytes_remaining = altsvc_scratch_.host_len - altsvc_scratch_.host_buf_len;
+ } else {
+ // Buffer (optional) origin field as it comes in.
+ if (altsvc_scratch_.origin_len <= 0) {
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ return 0;
+ }
+ buffer = altsvc_scratch_.origin.get();
+ buffer_len = &altsvc_scratch_.origin_buf_len;
+ bytes_remaining = remaining_data_length_ -
+ processed_bytes -
+ altsvc_scratch_.origin_buf_len;
+ if (len > bytes_remaining) {
+ // This is our last field; there shouldn't be any more bytes.
+ set_error(SPDY_INVALID_CONTROL_FRAME);
+ return 0;
+ }
+ }
+
+ // Copy data bytes into the appropriate field.
+ processing = std::min(len, bytes_remaining);
+ memcpy(buffer + *buffer_len,
+ data,
+ processing);
+ *buffer_len += processing;
+ data += processing;
+ processed_bytes += processing;
+ len -= processing;
+ }
+
+ remaining_data_length_ -= processed_bytes;
+ if (remaining_data_length_ == 0) {
+ visitor_->OnAltSvc(current_frame_stream_id_,
+ altsvc_scratch_.max_age,
+ altsvc_scratch_.port,
+ StringPiece(altsvc_scratch_.protocol_id.get(),
+ altsvc_scratch_.pid_len),
+ StringPiece(altsvc_scratch_.host.get(),
+ altsvc_scratch_.host_len),
+ StringPiece(altsvc_scratch_.origin.get(),
+ altsvc_scratch_.origin_len));
+ CHANGE_STATE(SPDY_AUTO_RESET);
+ }
+
+ return processed_bytes;
+}
+
size_t SpdyFramer::ProcessFramePaddingLength(const char* data, size_t len) {
DCHECK_EQ(SPDY_READ_PADDING_LENGTH, state_);
@@ -2603,6 +2768,29 @@ SpdyFrame* SpdyFramer::SerializeContinuation(
return builder.take();
}
+SpdyFrame* SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc) {
+ DCHECK_LT(SPDY3, protocol_version());
+ size_t size = GetAltSvcMinimumSize();
+ size += altsvc.protocol_id().length();
+ size += altsvc.host().length();
+ size += altsvc.origin().length();
+
+ SpdyFrameBuilder builder(size, protocol_version());
+ builder.BeginNewFrame(*this, ALTSVC, kNoFlags, altsvc.stream_id());
+
+ builder.WriteUInt32(altsvc.max_age());
+ builder.WriteUInt16(altsvc.port());
+ builder.WriteUInt8(0); // Reserved.
+ builder.WriteUInt8(altsvc.protocol_id().length());
+ builder.WriteBytes(altsvc.protocol_id().data(),
+ altsvc.protocol_id().length());
+ builder.WriteUInt8(altsvc.host().length());
+ builder.WriteBytes(altsvc.host().data(), altsvc.host().length());
+ builder.WriteBytes(altsvc.origin().data(), altsvc.origin().length());
+ DCHECK_LT(GetAltSvcMinimumSize(), builder.length());
+ return builder.take();
+}
+
namespace {
class FrameSerializationVisitor : public SpdyFrameVisitor {
@@ -2651,6 +2839,9 @@ class FrameSerializationVisitor : public SpdyFrameVisitor {
const SpdyContinuationIR& continuation) OVERRIDE {
frame_.reset(framer_->SerializeContinuation(continuation));
}
+ virtual void VisitAltSvc(const SpdyAltSvcIR& altsvc) OVERRIDE {
+ frame_.reset(framer_->SerializeAltSvc(altsvc));
+ }
private:
SpdyFramer* framer_;
« no previous file with comments | « net/spdy/spdy_framer.h ('k') | net/spdy/spdy_framer_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698