summaryrefslogtreecommitdiff
path: root/chromium/net/spdy/buffered_spdy_framer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/spdy/buffered_spdy_framer.cc')
-rw-r--r--chromium/net/spdy/buffered_spdy_framer.cc331
1 files changed, 331 insertions, 0 deletions
diff --git a/chromium/net/spdy/buffered_spdy_framer.cc b/chromium/net/spdy/buffered_spdy_framer.cc
new file mode 100644
index 00000000000..46d028404fe
--- /dev/null
+++ b/chromium/net/spdy/buffered_spdy_framer.cc
@@ -0,0 +1,331 @@
+// 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/buffered_spdy_framer.h"
+
+#include "base/logging.h"
+
+namespace net {
+
+SpdyMajorVersion NextProtoToSpdyMajorVersion(NextProto next_proto) {
+ switch (next_proto) {
+ case kProtoSPDY2:
+ case kProtoSPDY21:
+ return SPDY2;
+ case kProtoSPDY3:
+ case kProtoSPDY31:
+ return SPDY3;
+ // SPDY/4 and HTTP/2 share the same framing for now.
+ case kProtoSPDY4a2:
+ case kProtoHTTP2Draft04:
+ return SPDY4;
+ case kProtoUnknown:
+ case kProtoHTTP11:
+ case kProtoSPDY1:
+ case kProtoQUIC1SPDY3:
+ break;
+ }
+ NOTREACHED();
+ return SPDY2;
+}
+
+BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version,
+ bool enable_compression)
+ : spdy_framer_(version),
+ visitor_(NULL),
+ header_buffer_used_(0),
+ header_buffer_valid_(false),
+ header_stream_id_(SpdyFramer::kInvalidStream),
+ frames_received_(0) {
+ spdy_framer_.set_enable_compression(enable_compression);
+ memset(header_buffer_, 0, sizeof(header_buffer_));
+}
+
+BufferedSpdyFramer::~BufferedSpdyFramer() {
+}
+
+void BufferedSpdyFramer::set_visitor(
+ BufferedSpdyFramerVisitorInterface* visitor) {
+ visitor_ = visitor;
+ spdy_framer_.set_visitor(this);
+}
+
+void BufferedSpdyFramer::set_debug_visitor(
+ SpdyFramerDebugVisitorInterface* debug_visitor) {
+ spdy_framer_.set_debug_visitor(debug_visitor);
+}
+
+void BufferedSpdyFramer::OnError(SpdyFramer* spdy_framer) {
+ DCHECK(spdy_framer);
+ visitor_->OnError(spdy_framer->error_code());
+}
+
+void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id,
+ SpdyStreamId associated_stream_id,
+ SpdyPriority priority,
+ uint8 credential_slot,
+ bool fin,
+ bool unidirectional) {
+ frames_received_++;
+ DCHECK(!control_frame_fields_.get());
+ control_frame_fields_.reset(new ControlFrameFields());
+ control_frame_fields_->type = SYN_STREAM;
+ control_frame_fields_->stream_id = stream_id;
+ control_frame_fields_->associated_stream_id = associated_stream_id;
+ control_frame_fields_->priority = priority;
+ control_frame_fields_->credential_slot = credential_slot;
+ control_frame_fields_->fin = fin;
+ control_frame_fields_->unidirectional = unidirectional;
+
+ InitHeaderStreaming(stream_id);
+}
+
+void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id,
+ bool fin) {
+ frames_received_++;
+ DCHECK(!control_frame_fields_.get());
+ control_frame_fields_.reset(new ControlFrameFields());
+ control_frame_fields_->type = HEADERS;
+ control_frame_fields_->stream_id = stream_id;
+ control_frame_fields_->fin = fin;
+
+ InitHeaderStreaming(stream_id);
+}
+
+void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id,
+ bool fin) {
+ frames_received_++;
+ DCHECK(!control_frame_fields_.get());
+ control_frame_fields_.reset(new ControlFrameFields());
+ control_frame_fields_->type = SYN_REPLY;
+ control_frame_fields_->stream_id = stream_id;
+ control_frame_fields_->fin = fin;
+
+ InitHeaderStreaming(stream_id);
+}
+
+bool BufferedSpdyFramer::OnCredentialFrameData(const char* frame_data,
+ size_t len) {
+ DCHECK(false);
+ return false;
+}
+
+bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t len) {
+ CHECK_EQ(header_stream_id_, stream_id);
+
+ if (len == 0) {
+ // Indicates end-of-header-block.
+ CHECK(header_buffer_valid_);
+
+ SpdyHeaderBlock headers;
+ size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer(
+ header_buffer_, header_buffer_used_, &headers);
+ // TODO(rch): this really should be checking parsed_len != len,
+ // but a bunch of tests fail. Need to figure out why.
+ if (parsed_len == 0) {
+ visitor_->OnStreamError(
+ stream_id, "Could not parse Spdy Control Frame Header.");
+ return false;
+ }
+ DCHECK(control_frame_fields_.get());
+ switch (control_frame_fields_->type) {
+ case SYN_STREAM:
+ visitor_->OnSynStream(control_frame_fields_->stream_id,
+ control_frame_fields_->associated_stream_id,
+ control_frame_fields_->priority,
+ control_frame_fields_->credential_slot,
+ control_frame_fields_->fin,
+ control_frame_fields_->unidirectional,
+ headers);
+ break;
+ case SYN_REPLY:
+ visitor_->OnSynReply(control_frame_fields_->stream_id,
+ control_frame_fields_->fin,
+ headers);
+ break;
+ case HEADERS:
+ visitor_->OnHeaders(control_frame_fields_->stream_id,
+ control_frame_fields_->fin,
+ headers);
+ break;
+ default:
+ DCHECK(false) << "Unexpect control frame type: "
+ << control_frame_fields_->type;
+ break;
+ }
+ control_frame_fields_.reset(NULL);
+ return true;
+ }
+
+ const size_t available = kHeaderBufferSize - header_buffer_used_;
+ if (len > available) {
+ header_buffer_valid_ = false;
+ visitor_->OnStreamError(
+ stream_id, "Received more data than the allocated size.");
+ return false;
+ }
+ memcpy(header_buffer_ + header_buffer_used_, header_data, len);
+ header_buffer_used_ += len;
+ return true;
+}
+
+void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id,
+ size_t length,
+ bool fin) {
+ frames_received_++;
+ header_stream_id_ = stream_id;
+}
+
+void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id,
+ const char* data,
+ size_t len,
+ bool fin) {
+ visitor_->OnStreamFrameData(stream_id, data, len, fin);
+}
+
+void BufferedSpdyFramer::OnSettings(bool clear_persisted) {
+ visitor_->OnSettings(clear_persisted);
+}
+
+void BufferedSpdyFramer::OnSetting(SpdySettingsIds id,
+ uint8 flags,
+ uint32 value) {
+ visitor_->OnSetting(id, flags, value);
+}
+
+void BufferedSpdyFramer::OnPing(uint32 unique_id) {
+ visitor_->OnPing(unique_id);
+}
+
+void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id,
+ SpdyRstStreamStatus status) {
+ visitor_->OnRstStream(stream_id, status);
+}
+void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id,
+ SpdyGoAwayStatus status) {
+ visitor_->OnGoAway(last_accepted_stream_id, status);
+}
+
+void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
+ uint32 delta_window_size) {
+ visitor_->OnWindowUpdate(stream_id, delta_window_size);
+}
+
+void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id) {
+ visitor_->OnPushPromise(stream_id, promised_stream_id);
+}
+
+int BufferedSpdyFramer::protocol_version() {
+ return spdy_framer_.protocol_version();
+}
+
+size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
+ return spdy_framer_.ProcessInput(data, len);
+}
+
+void BufferedSpdyFramer::Reset() {
+ spdy_framer_.Reset();
+}
+
+SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const {
+ return spdy_framer_.error_code();
+}
+
+SpdyFramer::SpdyState BufferedSpdyFramer::state() const {
+ return spdy_framer_.state();
+}
+
+bool BufferedSpdyFramer::MessageFullyRead() {
+ return state() == SpdyFramer::SPDY_AUTO_RESET;
+}
+
+bool BufferedSpdyFramer::HasError() {
+ return spdy_framer_.HasError();
+}
+
+SpdyFrame* BufferedSpdyFramer::CreateSynStream(
+ SpdyStreamId stream_id,
+ SpdyStreamId associated_stream_id,
+ SpdyPriority priority,
+ uint8 credential_slot,
+ SpdyControlFlags flags,
+ bool compressed,
+ const SpdyHeaderBlock* headers) {
+ return spdy_framer_.CreateSynStream(stream_id, associated_stream_id, priority,
+ credential_slot, flags, compressed,
+ headers);
+}
+
+SpdyFrame* BufferedSpdyFramer::CreateSynReply(
+ SpdyStreamId stream_id,
+ SpdyControlFlags flags,
+ bool compressed,
+ const SpdyHeaderBlock* headers) {
+ return spdy_framer_.CreateSynReply(stream_id, flags, compressed, headers);
+}
+
+SpdyFrame* BufferedSpdyFramer::CreateRstStream(
+ SpdyStreamId stream_id,
+ SpdyRstStreamStatus status) const {
+ return spdy_framer_.CreateRstStream(stream_id, status);
+}
+
+SpdyFrame* BufferedSpdyFramer::CreateSettings(
+ const SettingsMap& values) const {
+ return spdy_framer_.CreateSettings(values);
+}
+
+SpdyFrame* BufferedSpdyFramer::CreatePingFrame(
+ uint32 unique_id) const {
+ return spdy_framer_.CreatePingFrame(unique_id);
+}
+
+SpdyFrame* BufferedSpdyFramer::CreateGoAway(
+ SpdyStreamId last_accepted_stream_id,
+ SpdyGoAwayStatus status) const {
+ return spdy_framer_.CreateGoAway(last_accepted_stream_id, status);
+}
+
+SpdyFrame* BufferedSpdyFramer::CreateHeaders(
+ SpdyStreamId stream_id,
+ SpdyControlFlags flags,
+ bool compressed,
+ const SpdyHeaderBlock* headers) {
+ return spdy_framer_.CreateHeaders(stream_id, flags, compressed, headers);
+}
+
+SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate(
+ SpdyStreamId stream_id,
+ uint32 delta_window_size) const {
+ return spdy_framer_.CreateWindowUpdate(stream_id, delta_window_size);
+}
+
+SpdyFrame* BufferedSpdyFramer::CreateCredentialFrame(
+ const SpdyCredential& credential) const {
+ return spdy_framer_.CreateCredentialFrame(credential);
+}
+
+SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
+ const char* data,
+ uint32 len,
+ SpdyDataFlags flags) {
+ return spdy_framer_.CreateDataFrame(stream_id, data, len, flags);
+}
+
+SpdyPriority BufferedSpdyFramer::GetHighestPriority() const {
+ return spdy_framer_.GetHighestPriority();
+}
+
+void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) {
+ memset(header_buffer_, 0, kHeaderBufferSize);
+ header_buffer_used_ = 0;
+ header_buffer_valid_ = true;
+ header_stream_id_ = stream_id;
+ DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
+}
+
+} // namespace net