summaryrefslogtreecommitdiffstats
path: root/net/spdy
diff options
context:
space:
mode:
authorrjshade <rjshade@chromium.org>2016-03-11 12:42:17 -0800
committerCommit bot <commit-bot@chromium.org>2016-03-11 20:43:47 +0000
commitd069aaee0b3affb6004d8cf3a276c32e248a2a3d (patch)
treece0e89ab98a7ca09ac5df43122928a1f5aebf44b /net/spdy
parentab26b6681dde41b4141fef09decf9c4e930aee85 (diff)
downloadchromium_src-d069aaee0b3affb6004d8cf3a276c32e248a2a3d.zip
chromium_src-d069aaee0b3affb6004d8cf3a276c32e248a2a3d.tar.gz
chromium_src-d069aaee0b3affb6004d8cf3a276c32e248a2a3d.tar.bz2
Landing Recent QUIC changes until 2016-03-07 19:39 UTC
Up to, and including internal change 116570346 Add a new QUIC Ack Decimation mode that is reordering tolerant. Protected by FLAG_quic_ack_decimation2. Merge internal change: 115853846 https://codereview.chromium.org/1777293002/ Deprecating FLAG_quic_batch_writes Merge internal change: 115880164 https://codereview.chromium.org/1780913002/ Deprecate FLAG_quic_validate_stk_without_scid Merge internal change: 115885351 https://codereview.chromium.org/1780923002/ Deprecate FLAG_quic_use_new_tcp_sender Merge internal change: 115890504 https://codereview.chromium.org/1785663003/ Deprecate FLAG_quic_use_new_idle_timeout Merge internal change: 115904466 https://codereview.chromium.org/1785693003/ Deprecate FLAG_quic_block_unencrypted_writes Merge internal change: 115909446 https://codereview.chromium.org/1784643006/ Clang formatting net/quic. Merge internal change: 115992556 https://codereview.chromium.org/1780783003/ Optionally defer responding to a QUIC ACK until all ACK processing has completed for an EpollServer iteration. Guarded by FLAG_quic_connection_defer_ack_response Merge internal change: 114770052 https://codereview.chromium.org/1782053003/ Deprecate FLAG_require_strike_register_or_server_nonce Merge internal change: 115891009 https://codereview.chromium.org/1785613005/ Add a boolean use_stateless_rejects_if_peer_supported argument to the QuicCryptoServerStream constructor instead of consulting FLAG_enable_quic_stateless_reject_support directly. No behavior change expected. Merge internal change: 115844136 https://codereview.chromium.org/1783713003/ Remove FEC from send path. Merge internal change: 115997404 https://codereview.chromium.org/1784903003/ Remove FEC code from receive path. Drop received FEC packet. Merge internal change: 116134765 https://codereview.chromium.org/1782143003/ Only cancel QUIC alarms if they have been set. Protected behind FLAG_quic_only_cancel_set_alarms Merge internal change: 116142833 https://codereview.chromium.org/1781073002/ Call QuicAlarm::IsSet instead of looking at deadline_ directly, rename some variables for readability. Merge internal change: 116146641 https://codereview.chromium.org/1778243005/ Add whether QUIC's unencrypted stream data was received or about to be sent in the error log. Logging only change. Merge internal change: 116152506 https://codereview.chromium.org/1782193002/ Temporarily store the raw QUIC packet in QuicConnection. Merge internal change: 116180343 https://codereview.chromium.org/1779313002/ Deprecate FLAG_quic_no_unencrypted_fec. Merge internal change: 116244697 https://codereview.chromium.org/1780573006/ Make ShouldCreateOutgoingDynamicStream a virtual method. Merge internal change: 116249386 https://codereview.chromium.org/1784933003/ Correctly handle EINTR during sendmsg in QuicSocketUtils::WritePacket. Merge internal change: 116261116 https://codereview.chromium.org/1780323002/ Simplify QUIC's encryption path now that FEC is gone. Protected by FLAG_quic_inplace_encryption. Merge internal change: 116266391 https://codereview.chromium.org/1785513003/ Remove the force param from QuicPacketGenerator::SetMaxPacketLength because path MTU packets should not be sent if the MTU cannot be changed. Not flag protected. Merge internal change: 116273065 https://codereview.chromium.org/1781043004/ Remove lastest_revived_packet from QuicAckFrame since FEC is gone. No functional change expected. Wire format is not changed yet. Merge internal change: 116411121 https://codereview.chromium.org/1787443002/ Remove is_fec_packet from TransmissionInfo and SerializedPacket. No functional change. Merge internal change: 116555910 https://codereview.chromium.org/1785853002/ Remove FEC related connection options and update FEC related comment in code base. Merge internal change: 116566297 https://codereview.chromium.org/1785863002/ Switch "const StringPiece&" to just "StringPiece" in QUIC code. No functional change. Not flag protected. Merge internal change: 116570346 https://codereview.chromium.org/1787453002/ Add a QuicCompressedCertsCache instance to QuicDispatcher, plumbing to QuicServerSessionBase but not used. No behavior change. Merge internal change: 116277134 https://codereview.chromium.org/1783783003/ Add more detailed logging to QUIC's ack validation. No functional change. Merge internal change: 116277228 https://codereview.chromium.org/1784963002/ Remove max_packet_length from QuicPacketGenerator, because it is no longer necessary with FEC gone. Not flag protected. Merge internal change: 116387934 https://codereview.chromium.org/1777423002/ Add QuicCompressedCertsCache* to QuicCrytoServerStream plumbed from QuicServerSessionBase. No behavior change. Merge internal change: 116388439 https://codereview.chromium.org/1782743005/ Remove unused return value from QuicAlarm::Delegate::OnAlarm. No behavior change, not protected. The only place in the codebase that returns something other than QuicTime::Zero() is the DelayAlarm in PacketDroppingTestWriter. I've the implementation of OnAlarm in there to set the alarm directly to the new time, rather than relying on the return value. Merge internal change: 116389752 https://codereview.chromium.org/1779883005/ Add a QUIC ScopedPacketBundler to send an ack when the ack alarm goes off. No functional change. Not flag protected. Merge internal change: 116391846 https://codereview.chromium.org/1786493003/ OnStreamEnd is now called instead of the sentinel call of OnStreamFrameData(stream_id, nullptr, 0, true). Protected by the flag FLAGS_spdy_on_stream_end. Merge internal change: 116272960 https://codereview.chromium.org/1777163003/ R=rch@chromium.org BUG= Review URL: https://codereview.chromium.org/1781123002 Cr-Commit-Position: refs/heads/master@{#380718}
Diffstat (limited to 'net/spdy')
-rw-r--r--net/spdy/buffered_spdy_framer.cc2
-rw-r--r--net/spdy/spdy_framer.cc18
-rw-r--r--net/spdy/spdy_framer.h5
-rw-r--r--net/spdy/spdy_framer_test.cc341
4 files changed, 341 insertions, 25 deletions
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc
index e76b83d..e7e3d3d 100644
--- a/net/spdy/buffered_spdy_framer.cc
+++ b/net/spdy/buffered_spdy_framer.cc
@@ -202,7 +202,7 @@ void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id,
}
void BufferedSpdyFramer::OnStreamEnd(SpdyStreamId stream_id) {
- LOG(DFATAL) << "Unimplemented";
+ visitor_->OnStreamFrameData(stream_id, nullptr, 0, true);
}
void BufferedSpdyFramer::OnStreamPadding(SpdyStreamId stream_id, size_t len) {
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index e34345a..5c8d011 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -14,6 +14,7 @@
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_macros.h"
+#include "net/quic/quic_flags.h"
#include "net/spdy/hpack/hpack_constants.h"
#include "net/spdy/spdy_frame_builder.h"
#include "net/spdy/spdy_frame_reader.h"
@@ -171,7 +172,8 @@ SpdyFramer::SpdyFramer(SpdyMajorVersion version)
enable_compression_(true),
syn_frame_processed_(false),
probable_http_response_(false),
- end_stream_when_done_(false) {
+ end_stream_when_done_(false),
+ spdy_on_stream_end_(FLAGS_spdy_on_stream_end) {
DCHECK(protocol_version_ == SPDY3 || protocol_version_ == HTTP2);
DCHECK_LE(kMaxControlFrameSize,
SpdyConstants::GetFrameMaximumSize(protocol_version_) +
@@ -830,8 +832,12 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
} else {
// Empty data frame.
if (current_frame_flags_ & DATA_FLAG_FIN) {
- visitor_->OnStreamFrameData(
- current_frame_stream_id_, NULL, 0, true);
+ if (spdy_on_stream_end_) {
+ visitor_->OnStreamEnd(current_frame_stream_id_);
+ } else {
+ visitor_->OnStreamFrameData(current_frame_stream_id_, nullptr, 0,
+ true);
+ }
}
CHANGE_STATE(SPDY_FRAME_COMPLETE);
}
@@ -2099,7 +2105,11 @@ size_t SpdyFramer::ProcessFramePadding(const char* data, size_t len) {
((current_frame_flags_ & CONTROL_FLAG_FIN) != 0 ||
end_stream_when_done_)) {
end_stream_when_done_ = false;
- visitor_->OnStreamFrameData(current_frame_stream_id_, NULL, 0, true);
+ if (spdy_on_stream_end_) {
+ visitor_->OnStreamEnd(current_frame_stream_id_);
+ } else {
+ visitor_->OnStreamFrameData(current_frame_stream_id_, nullptr, 0, true);
+ }
}
CHANGE_STATE(SPDY_FRAME_COMPLETE);
}
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index 30e7899..6261777 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -795,6 +795,11 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// If true, then ProcessInput returns after processing a full frame,
// rather than reading all available input.
bool process_single_input_frame_ = false;
+
+ // Latched value of --FLAGS_spdy_on_stream_end.
+ // If true, OnStreamEnd will be called instead of the sentinel call of
+ // OnStreamFrameData(stream_id, nullptr, 0, true)
+ bool spdy_on_stream_end_;
};
} // namespace net
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 2dcc855..5e41327 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -16,6 +16,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "net/quic/quic_flags.h"
#include "net/spdy/hpack/hpack_constants.h"
#include "net/spdy/mock_spdy_framer_visitor.h"
#include "net/spdy/spdy_frame_builder.h"
@@ -281,7 +282,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
fin_frame_count_(0),
fin_opaque_data_(),
fin_flag_count_(0),
- zero_length_data_frame_count_(0),
+ end_of_stream_count_(0),
control_frame_header_data_count_(0),
zero_length_control_frame_header_data_count_(0),
data_frame_count_(0),
@@ -312,8 +313,10 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
size_t len,
bool fin) override {
EXPECT_EQ(header_stream_id_, stream_id);
- if (len == 0) {
- ++zero_length_data_frame_count_;
+ if (!FLAGS_spdy_on_stream_end) {
+ if (len == 0) {
+ ++end_of_stream_count_;
+ }
}
data_bytes_ += len;
@@ -328,7 +331,9 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
}
void OnStreamEnd(SpdyStreamId stream_id) override {
- LOG(DFATAL) << "Unimplemented.";
+ LOG(INFO) << "OnStreamEnd(" << stream_id << ")";
+ EXPECT_EQ(header_stream_id_, stream_id);
+ ++end_of_stream_count_;
}
void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
@@ -587,7 +592,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
int fin_frame_count_; // The count of RST_STREAM type frames received.
string fin_opaque_data_;
int fin_flag_count_; // The count of frames with the FIN flag set.
- int zero_length_data_frame_count_; // The count of zero-length data frames.
+ int end_of_stream_count_; // The count of zero-length data frames.
int control_frame_header_data_count_; // The count of chunks received.
// The count of zero-length control frame header data chunks received.
int zero_length_control_frame_header_data_count_;
@@ -1207,7 +1212,7 @@ TEST_P(SpdyFramerTest, Basic) {
}
EXPECT_EQ(0, visitor.fin_flag_count_);
- EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(0, visitor.end_of_stream_count_);
EXPECT_EQ(4, visitor.data_frame_count_);
visitor.fin_opaque_data_.clear();
}
@@ -1289,7 +1294,7 @@ TEST_P(SpdyFramerTest, FinOnDataFrame) {
EXPECT_EQ(16, visitor.data_bytes_);
EXPECT_EQ(0, visitor.fin_frame_count_);
EXPECT_EQ(0, visitor.fin_flag_count_);
- EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(1, visitor.end_of_stream_count_);
EXPECT_EQ(2, visitor.data_frame_count_);
}
@@ -1348,7 +1353,7 @@ TEST_P(SpdyFramerTest, FinOnSynReplyFrame) {
EXPECT_EQ(0, visitor.data_bytes_);
EXPECT_EQ(0, visitor.fin_frame_count_);
EXPECT_EQ(1, visitor.fin_flag_count_);
- EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(1, visitor.end_of_stream_count_);
EXPECT_EQ(0, visitor.data_frame_count_);
}
@@ -1466,7 +1471,7 @@ TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
EXPECT_EQ(0, visitor.fin_frame_count_);
EXPECT_EQ(0, visitor.fin_flag_count_);
- EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(1, visitor.end_of_stream_count_);
EXPECT_EQ(1, visitor.data_frame_count_);
}
@@ -3196,7 +3201,7 @@ TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) {
// at least twice.
EXPECT_LE(2, visitor.control_frame_header_data_count_);
EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(0, visitor.end_of_stream_count_);
EXPECT_EQ(headers, visitor.headers_);
}
@@ -3221,7 +3226,7 @@ TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {
// at least twice.
EXPECT_LE(2, visitor.control_frame_header_data_count_);
EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(1, visitor.end_of_stream_count_);
EXPECT_EQ(headers, visitor.headers_);
}
@@ -3258,7 +3263,7 @@ TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) {
EXPECT_EQ(0, visitor.error_count_);
EXPECT_EQ(1, visitor.syn_frame_count_);
EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(0, visitor.end_of_stream_count_);
EXPECT_LT(kBigValueSize, visitor.header_buffer_length_);
}
@@ -3403,7 +3408,7 @@ TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
// The framer should not have sent half-close to the visitor.
- EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(0, visitor.end_of_stream_count_);
}
TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) {
@@ -3860,7 +3865,7 @@ TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) {
EXPECT_EQ(2, visitor.continuation_count_);
EXPECT_EQ(1, visitor.fin_flag_count_);
EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(1, visitor.end_of_stream_count_);
EXPECT_THAT(visitor.headers_,
testing::ElementsAre(
@@ -3910,7 +3915,7 @@ TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) {
EXPECT_EQ(42u, visitor.last_push_promise_promised_stream_);
EXPECT_EQ(2, visitor.continuation_count_);
EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
- EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
+ EXPECT_EQ(0, visitor.end_of_stream_count_);
EXPECT_THAT(visitor.headers_,
testing::ElementsAre(
@@ -4384,6 +4389,50 @@ TEST_P(SpdyFramerTest, CatchProbableHttpResponse) {
}
TEST_P(SpdyFramerTest, DataFrameFlagsV2V3) {
+ FLAGS_spdy_on_stream_end = true;
+
+ if (!IsSpdy3()) {
+ return;
+ }
+
+ uint8_t flags = 0;
+ do {
+ SCOPED_TRACE(testing::Message() << "Flags " << flags);
+
+ testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
+ SpdyFramer framer(spdy_version_);
+ framer.set_visitor(&visitor);
+
+ SpdyDataIR data_ir(1, "hello");
+ scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
+ SetFrameFlags(frame.get(), flags, spdy_version_);
+
+ if (flags & ~DATA_FLAG_FIN) {
+ EXPECT_CALL(visitor, OnError(_));
+ } else {
+ EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN));
+ EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false));
+ if (flags & DATA_FLAG_FIN) {
+ EXPECT_CALL(visitor, OnStreamEnd(_));
+ }
+ }
+
+ framer.ProcessInput(frame->data(), frame->size());
+ if (flags & ~DATA_FLAG_FIN) {
+ EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ } else {
+ EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ }
+ } while (++flags != 0);
+}
+
+TEST_P(SpdyFramerTest, DataFrameFlagsV2V3disabled) {
+ FLAGS_spdy_on_stream_end = false;
+
if (!IsSpdy3()) {
return;
}
@@ -4425,6 +4474,60 @@ TEST_P(SpdyFramerTest, DataFrameFlagsV2V3) {
}
TEST_P(SpdyFramerTest, DataFrameFlagsV4) {
+ FLAGS_spdy_on_stream_end = true;
+
+ if (!IsHttp2()) {
+ return;
+ }
+
+ uint8_t valid_data_flags =
+ DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT | DATA_FLAG_PADDED;
+
+ uint8_t flags = 0;
+ do {
+ SCOPED_TRACE(testing::Message() << "Flags " << flags);
+
+ testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
+ SpdyFramer framer(spdy_version_);
+ framer.set_visitor(&visitor);
+
+ SpdyDataIR data_ir(1, "hello");
+ scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
+ SetFrameFlags(frame.get(), flags, spdy_version_);
+
+ if (flags & ~valid_data_flags) {
+ EXPECT_CALL(visitor, OnError(_));
+ } else {
+ EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN));
+ if (flags & DATA_FLAG_PADDED) {
+ // The first byte of payload is parsed as padding length.
+ EXPECT_CALL(visitor, OnStreamPadding(_, 1));
+ // Expect Error since the frame ends prematurely.
+ EXPECT_CALL(visitor, OnError(_));
+ } else {
+ EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false));
+ if (flags & DATA_FLAG_FIN) {
+ EXPECT_CALL(visitor, OnStreamEnd(_));
+ }
+ }
+ }
+
+ framer.ProcessInput(frame->data(), frame->size());
+ if ((flags & ~valid_data_flags) || (flags & DATA_FLAG_PADDED)) {
+ EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ } else {
+ EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ }
+ } while (++flags != 0);
+}
+
+TEST_P(SpdyFramerTest, DataFrameFlagsV4disabled) {
+ FLAGS_spdy_on_stream_end = false;
+
if (!IsHttp2()) {
return;
}
@@ -4475,6 +4578,64 @@ TEST_P(SpdyFramerTest, DataFrameFlagsV4) {
}
TEST_P(SpdyFramerTest, SynStreamFrameFlags) {
+ FLAGS_spdy_on_stream_end = true;
+
+ if (!IsSpdy3()) {
+ return;
+ }
+
+ uint8_t flags = 0;
+ do {
+ SCOPED_TRACE(testing::Message() << "Flags " << flags);
+
+ testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
+ testing::StrictMock<test::MockDebugVisitor> debug_visitor;
+ SpdyFramer framer(spdy_version_);
+ framer.set_visitor(&visitor);
+ framer.set_debug_visitor(&debug_visitor);
+
+ EXPECT_CALL(debug_visitor, OnSendCompressedFrame(8, SYN_STREAM, _, _));
+
+ SpdySynStreamIR syn_stream(8);
+ syn_stream.set_associated_to_stream_id(3);
+ syn_stream.set_priority(1);
+ syn_stream.SetHeader("foo", "bar");
+ scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
+ SetFrameFlags(frame.get(), flags, spdy_version_);
+
+ if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
+ EXPECT_CALL(visitor, OnError(_));
+ } else {
+ EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(8, SYN_STREAM, _));
+ EXPECT_CALL(visitor, OnSynStream(8, 3, 1, flags & CONTROL_FLAG_FIN,
+ flags & CONTROL_FLAG_UNIDIRECTIONAL));
+ EXPECT_CALL(visitor, OnControlFrameHeaderData(8, _, _))
+ .WillRepeatedly(testing::Return(true));
+ if (flags & DATA_FLAG_FIN) {
+ EXPECT_CALL(visitor, OnStreamEnd(_));
+ } else {
+ // Do not close the stream if we are expecting a CONTINUATION frame.
+ EXPECT_CALL(visitor, OnStreamEnd(_)).Times(0);
+ }
+ }
+
+ framer.ProcessInput(frame->data(), frame->size());
+ if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
+ EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
+ framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ } else {
+ EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ }
+ } while (++flags != 0);
+}
+
+TEST_P(SpdyFramerTest, SynStreamFrameFlagsDisabled) {
+ FLAGS_spdy_on_stream_end = false;
+
if (!IsSpdy3()) {
return;
}
@@ -4529,6 +4690,53 @@ TEST_P(SpdyFramerTest, SynStreamFrameFlags) {
}
TEST_P(SpdyFramerTest, SynReplyFrameFlags) {
+ FLAGS_spdy_on_stream_end = true;
+
+ if (!IsSpdy3()) {
+ return;
+ }
+
+ uint8_t flags = 0;
+ do {
+ SCOPED_TRACE(testing::Message() << "Flags " << flags);
+
+ testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
+ SpdyFramer framer(spdy_version_);
+ framer.set_visitor(&visitor);
+
+ SpdySynReplyIR syn_reply(37);
+ syn_reply.SetHeader("foo", "bar");
+ scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply));
+ SetFrameFlags(frame.get(), flags, spdy_version_);
+
+ if (flags & ~CONTROL_FLAG_FIN) {
+ EXPECT_CALL(visitor, OnError(_));
+ } else {
+ EXPECT_CALL(visitor, OnSynReply(37, flags & CONTROL_FLAG_FIN));
+ EXPECT_CALL(visitor, OnControlFrameHeaderData(37, _, _))
+ .WillRepeatedly(testing::Return(true));
+ if (flags & DATA_FLAG_FIN) {
+ EXPECT_CALL(visitor, OnStreamEnd(_));
+ }
+ }
+
+ framer.ProcessInput(frame->data(), frame->size());
+ if (flags & ~CONTROL_FLAG_FIN) {
+ EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
+ framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ } else {
+ EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ }
+ } while (++flags != 0);
+}
+
+TEST_P(SpdyFramerTest, SynReplyFrameFlagsDisabled) {
+ FLAGS_spdy_on_stream_end = false;
+
if (!IsSpdy3()) {
return;
}
@@ -4729,6 +4937,99 @@ TEST_P(SpdyFramerTest, GoawayFrameFlags) {
}
TEST_P(SpdyFramerTest, HeadersFrameFlags) {
+ FLAGS_spdy_on_stream_end = true;
+
+ uint8_t flags = 0;
+ do {
+ SCOPED_TRACE(testing::Message() << "Flags " << flags);
+
+ testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
+ SpdyFramer framer(spdy_version_);
+ framer.set_visitor(&visitor);
+
+ SpdyHeadersIR headers_ir(57);
+ if (IsHttp2() && (flags & HEADERS_FLAG_PRIORITY)) {
+ headers_ir.set_priority(3);
+ headers_ir.set_has_priority(true);
+ headers_ir.set_parent_stream_id(5);
+ headers_ir.set_exclusive(true);
+ }
+ headers_ir.SetHeader("foo", "bar");
+ std::unique_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
+ uint8_t set_flags = flags;
+ if (IsHttp2()) {
+ // TODO(jgraettinger): Add padding to SpdyHeadersIR,
+ // and implement framing.
+ set_flags &= ~HEADERS_FLAG_PADDED;
+ }
+ SetFrameFlags(frame.get(), set_flags, spdy_version_);
+
+ if (!IsHttp2() && flags & ~CONTROL_FLAG_FIN) {
+ EXPECT_CALL(visitor, OnError(_));
+ } else if (IsHttp2() &&
+ flags &
+ ~(CONTROL_FLAG_FIN | HEADERS_FLAG_END_HEADERS |
+ HEADERS_FLAG_END_SEGMENT | HEADERS_FLAG_PADDED |
+ HEADERS_FLAG_PRIORITY)) {
+ EXPECT_CALL(visitor, OnError(_));
+ } else {
+ // Expected callback values
+ SpdyStreamId stream_id = 57;
+ bool has_priority = false;
+ SpdyPriority priority = 0;
+ SpdyStreamId parent_stream_id = 0;
+ bool exclusive = false;
+ bool fin = flags & CONTROL_FLAG_FIN;
+ bool end = IsSpdy3() || (flags & HEADERS_FLAG_END_HEADERS);
+ if (IsHttp2() && flags & HEADERS_FLAG_PRIORITY) {
+ has_priority = true;
+ priority = 3;
+ parent_stream_id = 5;
+ exclusive = true;
+ }
+ EXPECT_CALL(visitor, OnHeaders(stream_id, has_priority, priority,
+ parent_stream_id, exclusive, fin, end));
+ EXPECT_CALL(visitor, OnControlFrameHeaderData(57, _, _))
+ .WillRepeatedly(testing::Return(true));
+ if (flags & DATA_FLAG_FIN &&
+ (IsSpdy3() || flags & HEADERS_FLAG_END_HEADERS)) {
+ EXPECT_CALL(visitor, OnStreamEnd(_));
+ } else {
+ // Do not close the stream if we are expecting a CONTINUATION frame.
+ EXPECT_CALL(visitor, OnStreamEnd(_)).Times(0);
+ }
+ }
+
+ framer.ProcessInput(frame->data(), frame->size());
+ if (IsSpdy3() && flags & ~CONTROL_FLAG_FIN) {
+ EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
+ framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ } else if (IsHttp2() &&
+ flags &
+ ~(CONTROL_FLAG_FIN | HEADERS_FLAG_END_HEADERS |
+ HEADERS_FLAG_END_SEGMENT | HEADERS_FLAG_PADDED |
+ HEADERS_FLAG_PRIORITY)) {
+ EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
+ framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ } else if (IsHttp2() && ~(flags & HEADERS_FLAG_END_HEADERS)) {
+ EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ } else {
+ EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state());
+ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
+ << SpdyFramer::ErrorCodeToString(framer.error_code());
+ }
+ } while (++flags != 0);
+}
+
+TEST_P(SpdyFramerTest, HeadersFrameFlagsDisabled) {
+ FLAGS_spdy_on_stream_end = false;
+
uint8_t flags = 0;
do {
SCOPED_TRACE(testing::Message() << "Flags " << flags);
@@ -4756,11 +5057,11 @@ TEST_P(SpdyFramerTest, HeadersFrameFlags) {
if (!IsHttp2() && flags & ~CONTROL_FLAG_FIN) {
EXPECT_CALL(visitor, OnError(_));
- } else if (IsHttp2() && flags & ~(CONTROL_FLAG_FIN |
- HEADERS_FLAG_END_HEADERS |
- HEADERS_FLAG_END_SEGMENT |
- HEADERS_FLAG_PADDED |
- HEADERS_FLAG_PRIORITY)) {
+ } else if (IsHttp2() &&
+ flags &
+ ~(CONTROL_FLAG_FIN | HEADERS_FLAG_END_HEADERS |
+ HEADERS_FLAG_END_SEGMENT | HEADERS_FLAG_PADDED |
+ HEADERS_FLAG_PRIORITY)) {
EXPECT_CALL(visitor, OnError(_));
} else {
// Expected callback values