Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/spdy/buffered_spdy_framer.h" | 5 #include "net/spdy/buffered_spdy_framer.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 | 8 |
| 9 namespace net { | 9 namespace net { |
| 10 | 10 |
| 11 namespace { | 11 namespace { |
| 12 | 12 |
| 13 // GOAWAY frame debug data is only buffered up to this many bytes. | 13 // GOAWAY frame debug data is only buffered up to this many bytes. |
| 14 size_t kGoAwayDebugDataMaxSize = 1024; | 14 size_t kGoAwayDebugDataMaxSize = 1024; |
| 15 | 15 |
| 16 // Initial and maximum sizes for header block buffer. | |
| 17 size_t kHeaderBufferInitialSize = 8 * 1024; | |
| 18 size_t kHeaderBufferMaxSize = 256 * 1024; | |
| 19 | |
| 16 } // namespace | 20 } // namespace |
| 17 | 21 |
| 18 SpdyMajorVersion NextProtoToSpdyMajorVersion(NextProto next_proto) { | 22 SpdyMajorVersion NextProtoToSpdyMajorVersion(NextProto next_proto) { |
| 19 switch (next_proto) { | 23 switch (next_proto) { |
| 20 case kProtoDeprecatedSPDY2: | 24 case kProtoDeprecatedSPDY2: |
| 21 return SPDY2; | 25 return SPDY2; |
| 22 case kProtoSPDY3: | 26 case kProtoSPDY3: |
| 23 case kProtoSPDY31: | 27 case kProtoSPDY31: |
| 24 return SPDY3; | 28 return SPDY3; |
| 25 case kProtoHTTP2: | 29 case kProtoHTTP2: |
| 26 return HTTP2; | 30 return HTTP2; |
| 27 case kProtoUnknown: | 31 case kProtoUnknown: |
| 28 case kProtoHTTP11: | 32 case kProtoHTTP11: |
| 29 case kProtoQUIC1SPDY3: | 33 case kProtoQUIC1SPDY3: |
| 30 break; | 34 break; |
| 31 } | 35 } |
| 32 NOTREACHED(); | 36 NOTREACHED(); |
| 33 return SPDY2; | 37 return SPDY2; |
| 34 } | 38 } |
| 35 | 39 |
| 36 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version, | 40 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version, |
| 37 bool enable_compression) | 41 bool enable_compression) |
| 38 : spdy_framer_(version), | 42 : spdy_framer_(version), |
| 39 visitor_(NULL), | 43 visitor_(NULL), |
| 40 header_buffer_used_(0), | |
| 41 header_buffer_valid_(false), | 44 header_buffer_valid_(false), |
| 42 header_stream_id_(SpdyFramer::kInvalidStream), | 45 header_stream_id_(SpdyFramer::kInvalidStream), |
| 43 frames_received_(0) { | 46 frames_received_(0) { |
| 44 spdy_framer_.set_enable_compression(enable_compression); | 47 spdy_framer_.set_enable_compression(enable_compression); |
| 45 memset(header_buffer_, 0, sizeof(header_buffer_)); | 48 header_buffer_.clear(); |
|
Ryan Hamilton
2016/01/08 00:16:29
Does this do anything since the buffer was newly c
Bence
2016/01/08 18:58:24
Hm, I guess not. Thanks for catching it.
| |
| 46 } | 49 } |
| 47 | 50 |
| 48 BufferedSpdyFramer::~BufferedSpdyFramer() { | 51 BufferedSpdyFramer::~BufferedSpdyFramer() { |
| 49 } | 52 } |
| 50 | 53 |
| 51 void BufferedSpdyFramer::set_visitor( | 54 void BufferedSpdyFramer::set_visitor( |
| 52 BufferedSpdyFramerVisitorInterface* visitor) { | 55 BufferedSpdyFramerVisitorInterface* visitor) { |
| 53 visitor_ = visitor; | 56 visitor_ = visitor; |
| 54 spdy_framer_.set_visitor(this); | 57 spdy_framer_.set_visitor(this); |
| 55 } | 58 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 120 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id, | 123 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id, |
| 121 const char* header_data, | 124 const char* header_data, |
| 122 size_t len) { | 125 size_t len) { |
| 123 CHECK_EQ(header_stream_id_, stream_id); | 126 CHECK_EQ(header_stream_id_, stream_id); |
| 124 | 127 |
| 125 if (len == 0) { | 128 if (len == 0) { |
| 126 // Indicates end-of-header-block. | 129 // Indicates end-of-header-block. |
| 127 CHECK(header_buffer_valid_); | 130 CHECK(header_buffer_valid_); |
| 128 | 131 |
| 129 SpdyHeaderBlock headers; | 132 SpdyHeaderBlock headers; |
| 130 if (!spdy_framer_.ParseHeaderBlockInBuffer(header_buffer_, | 133 if (!spdy_framer_.ParseHeaderBlockInBuffer( |
| 131 header_buffer_used_, &headers)) { | 134 header_buffer_.data(), header_buffer_.size(), &headers)) { |
| 132 visitor_->OnStreamError( | 135 visitor_->OnStreamError( |
| 133 stream_id, "Could not parse Spdy Control Frame Header."); | 136 stream_id, "Could not parse Spdy Control Frame Header."); |
| 134 return false; | 137 return false; |
| 135 } | 138 } |
| 136 DCHECK(control_frame_fields_.get()); | 139 DCHECK(control_frame_fields_.get()); |
| 137 switch (control_frame_fields_->type) { | 140 switch (control_frame_fields_->type) { |
| 138 case SYN_STREAM: | 141 case SYN_STREAM: |
| 139 visitor_->OnSynStream(control_frame_fields_->stream_id, | 142 visitor_->OnSynStream(control_frame_fields_->stream_id, |
| 140 control_frame_fields_->associated_stream_id, | 143 control_frame_fields_->associated_stream_id, |
| 141 control_frame_fields_->priority, | 144 control_frame_fields_->priority, |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 164 break; | 167 break; |
| 165 default: | 168 default: |
| 166 DCHECK(false) << "Unexpect control frame type: " | 169 DCHECK(false) << "Unexpect control frame type: " |
| 167 << control_frame_fields_->type; | 170 << control_frame_fields_->type; |
| 168 break; | 171 break; |
| 169 } | 172 } |
| 170 control_frame_fields_.reset(NULL); | 173 control_frame_fields_.reset(NULL); |
| 171 return true; | 174 return true; |
| 172 } | 175 } |
| 173 | 176 |
| 174 const size_t available = kHeaderBufferSize - header_buffer_used_; | 177 const size_t new_size = header_buffer_.size() + len; |
| 175 if (len > available) { | 178 if (new_size > kHeaderBufferMaxSize) { |
| 176 header_buffer_valid_ = false; | 179 header_buffer_valid_ = false; |
| 177 visitor_->OnStreamError( | 180 visitor_->OnStreamError(stream_id, "Received too much header data."); |
| 178 stream_id, "Received more data than the allocated size."); | |
| 179 return false; | 181 return false; |
| 180 } | 182 } |
| 181 memcpy(header_buffer_ + header_buffer_used_, header_data, len); | 183 |
| 182 header_buffer_used_ += len; | 184 if (new_size > header_buffer_.capacity()) { |
| 185 // Grow |header_buffer_| exponentially to reduce memory allocations and | |
| 186 // copies. | |
| 187 size_t new_capacity = std::max(new_size, kHeaderBufferInitialSize); | |
|
Ryan Hamilton
2016/01/08 00:16:29
Can new_size ever be < kHeaderBufferInitialSize, s
Bence
2016/01/08 18:58:24
Yes, new_size can be smaller. This is the only pl
Ryan Hamilton
2016/01/08 21:20:46
Hah, I missed that. Good point :>
| |
| 188 new_capacity = std::max(new_capacity, 2 * header_buffer_.capacity()); | |
| 189 new_capacity = std::min(new_capacity, kHeaderBufferMaxSize); | |
| 190 header_buffer_.reserve(new_capacity); | |
| 191 } | |
| 192 header_buffer_.append(header_data, len); | |
| 183 return true; | 193 return true; |
|
Ryan Hamilton
2016/01/08 00:16:29
Should we have a unit test of this new behavior?
Bence
2016/01/08 18:58:24
The behavior of larger buffer limit? There is one
| |
| 184 } | 194 } |
| 185 | 195 |
| 186 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id, | 196 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id, |
| 187 size_t length, | 197 size_t length, |
| 188 bool fin) { | 198 bool fin) { |
| 189 frames_received_++; | 199 frames_received_++; |
| 190 header_stream_id_ = stream_id; | 200 header_stream_id_ = stream_id; |
| 191 visitor_->OnDataFrameHeader(stream_id, length, fin); | 201 visitor_->OnDataFrameHeader(stream_id, length, fin); |
| 192 } | 202 } |
| 193 | 203 |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 435 SpdyPushPromiseIR push_promise_ir(stream_id, promised_stream_id); | 445 SpdyPushPromiseIR push_promise_ir(stream_id, promised_stream_id); |
| 436 push_promise_ir.set_header_block(*headers); | 446 push_promise_ir.set_header_block(*headers); |
| 437 return spdy_framer_.SerializePushPromise(push_promise_ir); | 447 return spdy_framer_.SerializePushPromise(push_promise_ir); |
| 438 } | 448 } |
| 439 | 449 |
| 440 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const { | 450 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const { |
| 441 return spdy_framer_.GetHighestPriority(); | 451 return spdy_framer_.GetHighestPriority(); |
| 442 } | 452 } |
| 443 | 453 |
| 444 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) { | 454 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) { |
| 445 memset(header_buffer_, 0, kHeaderBufferSize); | 455 header_buffer_.clear(); |
| 446 header_buffer_used_ = 0; | |
| 447 header_buffer_valid_ = true; | 456 header_buffer_valid_ = true; |
| 448 header_stream_id_ = stream_id; | 457 header_stream_id_ = stream_id; |
| 449 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); | 458 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); |
| 450 } | 459 } |
| 451 | 460 |
| 452 } // namespace net | 461 } // namespace net |
| OLD | NEW |