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
3 // found in the LICENSE file.
5 #include "net/spdy/buffered_spdy_framer.h"
7 #include "net/spdy/spdy_test_util_common.h"
8 #include "testing/platform_test.h"
14 class TestBufferedSpdyVisitor
: public BufferedSpdyFramerVisitorInterface
{
16 explicit TestBufferedSpdyVisitor(SpdyMajorVersion spdy_version
)
17 : buffered_spdy_framer_(spdy_version
, true),
21 syn_reply_frame_count_(0),
22 headers_frame_count_(0),
23 header_stream_id_(-1) {
26 virtual void OnError(SpdyFramer::SpdyError error_code
) OVERRIDE
{
27 LOG(INFO
) << "SpdyFramer Error: " << error_code
;
31 virtual void OnStreamError(
32 SpdyStreamId stream_id
,
33 const std::string
& description
) OVERRIDE
{
34 LOG(INFO
) << "SpdyFramer Error on stream: " << stream_id
<< " "
39 virtual void OnSynStream(SpdyStreamId stream_id
,
40 SpdyStreamId associated_stream_id
,
41 SpdyPriority priority
,
44 const SpdyHeaderBlock
& headers
) OVERRIDE
{
45 header_stream_id_
= stream_id
;
46 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
51 virtual void OnSynReply(SpdyStreamId stream_id
,
53 const SpdyHeaderBlock
& headers
) OVERRIDE
{
54 header_stream_id_
= stream_id
;
55 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
56 syn_reply_frame_count_
++;
60 virtual void OnHeaders(SpdyStreamId stream_id
,
62 const SpdyHeaderBlock
& headers
) OVERRIDE
{
63 header_stream_id_
= stream_id
;
64 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
65 headers_frame_count_
++;
69 virtual void OnDataFrameHeader(SpdyStreamId stream_id
,
72 ADD_FAILURE() << "Unexpected OnDataFrameHeader call.";
75 virtual void OnStreamFrameData(SpdyStreamId stream_id
,
79 LOG(FATAL
) << "Unexpected OnStreamFrameData call.";
82 virtual void OnSettings(bool clear_persisted
) OVERRIDE
{}
84 virtual void OnSetting(SpdySettingsIds id
,
86 uint32 value
) OVERRIDE
{
90 virtual void OnPing(SpdyPingId unique_id
, bool is_ack
) OVERRIDE
{}
92 virtual void OnRstStream(SpdyStreamId stream_id
,
93 SpdyRstStreamStatus status
) OVERRIDE
{
96 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id
,
97 SpdyGoAwayStatus status
) OVERRIDE
{
100 bool OnCredentialFrameData(const char*, size_t) {
101 LOG(FATAL
) << "Unexpected OnCredentialFrameData call.";
105 void OnDataFrameHeader(const SpdyFrame
* frame
) {
106 LOG(FATAL
) << "Unexpected OnDataFrameHeader call.";
109 void OnRstStream(const SpdyFrame
& frame
) {}
110 void OnGoAway(const SpdyFrame
& frame
) {}
111 void OnPing(const SpdyFrame
& frame
) {}
112 virtual void OnWindowUpdate(SpdyStreamId stream_id
,
113 uint32 delta_window_size
) OVERRIDE
{}
114 virtual void OnPushPromise(SpdyStreamId stream_id
,
115 SpdyStreamId promised_stream_id
) OVERRIDE
{}
116 void OnCredential(const SpdyFrame
& frame
) {}
118 // Convenience function which runs a framer simulation with particular input.
119 void SimulateInFramer(const unsigned char* input
, size_t size
) {
120 buffered_spdy_framer_
.set_visitor(this);
121 size_t input_remaining
= size
;
122 const char* input_ptr
= reinterpret_cast<const char*>(input
);
123 while (input_remaining
> 0 &&
124 buffered_spdy_framer_
.error_code() == SpdyFramer::SPDY_NO_ERROR
) {
125 // To make the tests more interesting, we feed random (amd small) chunks
126 // into the framer. This simulates getting strange-sized reads from
128 const size_t kMaxReadSize
= 32;
130 (rand() % std::min(input_remaining
, kMaxReadSize
)) + 1;
131 size_t bytes_processed
=
132 buffered_spdy_framer_
.ProcessInput(input_ptr
, bytes_read
);
133 input_remaining
-= bytes_processed
;
134 input_ptr
+= bytes_processed
;
138 BufferedSpdyFramer buffered_spdy_framer_
;
140 // Counters from the visitor callbacks.
143 int syn_frame_count_
;
144 int syn_reply_frame_count_
;
145 int headers_frame_count_
;
147 // Header block streaming state:
148 SpdyStreamId header_stream_id_
;
150 // Headers from OnSyn, OnSynReply and OnHeaders for verification.
151 SpdyHeaderBlock headers_
;
156 class BufferedSpdyFramerTest
157 : public PlatformTest
,
158 public ::testing::WithParamInterface
<NextProto
> {
160 // Returns true if the two header blocks have equivalent content.
161 bool CompareHeaderBlocks(const SpdyHeaderBlock
* expected
,
162 const SpdyHeaderBlock
* actual
) {
163 if (expected
->size() != actual
->size()) {
164 LOG(ERROR
) << "Expected " << expected
->size() << " headers; actually got "
165 << actual
->size() << ".";
168 for (SpdyHeaderBlock::const_iterator it
= expected
->begin();
169 it
!= expected
->end();
171 SpdyHeaderBlock::const_iterator it2
= actual
->find(it
->first
);
172 if (it2
== actual
->end()) {
173 LOG(ERROR
) << "Expected header name '" << it
->first
<< "'.";
176 if (it
->second
.compare(it2
->second
) != 0) {
177 LOG(ERROR
) << "Expected header named '" << it
->first
178 << "' to have a value of '" << it
->second
179 << "'. The actual value received was '" << it2
->second
187 SpdyMajorVersion
spdy_version() {
188 return NextProtoToSpdyMajorVersion(GetParam());
192 INSTANTIATE_TEST_CASE_P(
194 BufferedSpdyFramerTest
,
195 testing::Values(kProtoDeprecatedSPDY2
,
196 kProtoSPDY3
, kProtoSPDY31
, kProtoSPDY4a2
,
197 kProtoHTTP2Draft04
));
199 TEST_P(BufferedSpdyFramerTest
, OnSetting
) {
200 SpdyFramer
framer(spdy_version());
201 SpdySettingsIR settings_ir
;
202 settings_ir
.AddSetting(SETTINGS_UPLOAD_BANDWIDTH
, false, false, 0x00000002);
203 settings_ir
.AddSetting(SETTINGS_DOWNLOAD_BANDWIDTH
, false, false, 0x00000003);
204 scoped_ptr
<SpdyFrame
> control_frame(framer
.SerializeSettings(settings_ir
));
205 TestBufferedSpdyVisitor
visitor(spdy_version());
207 visitor
.SimulateInFramer(
208 reinterpret_cast<unsigned char*>(control_frame
->data()),
209 control_frame
->size());
210 EXPECT_EQ(0, visitor
.error_count_
);
211 EXPECT_EQ(2, visitor
.setting_count_
);
214 TEST_P(BufferedSpdyFramerTest
, ReadSynStreamHeaderBlock
) {
215 SpdyHeaderBlock headers
;
216 headers
["aa"] = "vv";
217 headers
["bb"] = "ww";
218 BufferedSpdyFramer
framer(spdy_version(), true);
219 scoped_ptr
<SpdyFrame
> control_frame(
220 framer
.CreateSynStream(1, // stream_id
221 0, // associated_stream_id
225 EXPECT_TRUE(control_frame
.get() != NULL
);
227 TestBufferedSpdyVisitor
visitor(spdy_version());
228 visitor
.SimulateInFramer(
229 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
230 control_frame
.get()->size());
231 EXPECT_EQ(0, visitor
.error_count_
);
232 EXPECT_EQ(1, visitor
.syn_frame_count_
);
233 EXPECT_EQ(0, visitor
.syn_reply_frame_count_
);
234 EXPECT_EQ(0, visitor
.headers_frame_count_
);
235 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));
238 TEST_P(BufferedSpdyFramerTest
, ReadSynReplyHeaderBlock
) {
239 SpdyHeaderBlock headers
;
240 headers
["alpha"] = "beta";
241 headers
["gamma"] = "delta";
242 BufferedSpdyFramer
framer(spdy_version(), true);
243 scoped_ptr
<SpdyFrame
> control_frame(
244 framer
.CreateSynReply(1, // stream_id
247 EXPECT_TRUE(control_frame
.get() != NULL
);
249 TestBufferedSpdyVisitor
visitor(spdy_version());
250 visitor
.SimulateInFramer(
251 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
252 control_frame
.get()->size());
253 EXPECT_EQ(0, visitor
.error_count_
);
254 EXPECT_EQ(0, visitor
.syn_frame_count_
);
255 if(spdy_version() < SPDY4
) {
256 EXPECT_EQ(1, visitor
.syn_reply_frame_count_
);
257 EXPECT_EQ(0, visitor
.headers_frame_count_
);
259 EXPECT_EQ(0, visitor
.syn_reply_frame_count_
);
260 EXPECT_EQ(1, visitor
.headers_frame_count_
);
262 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));
265 TEST_P(BufferedSpdyFramerTest
, ReadHeadersHeaderBlock
) {
266 SpdyHeaderBlock headers
;
267 headers
["alpha"] = "beta";
268 headers
["gamma"] = "delta";
269 BufferedSpdyFramer
framer(spdy_version(), true);
270 scoped_ptr
<SpdyFrame
> control_frame(
271 framer
.CreateHeaders(1, // stream_id
274 EXPECT_TRUE(control_frame
.get() != NULL
);
276 TestBufferedSpdyVisitor
visitor(spdy_version());
277 visitor
.SimulateInFramer(
278 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
279 control_frame
.get()->size());
280 EXPECT_EQ(0, visitor
.error_count_
);
281 EXPECT_EQ(0, visitor
.syn_frame_count_
);
282 EXPECT_EQ(0, visitor
.syn_reply_frame_count_
);
283 EXPECT_EQ(1, visitor
.headers_frame_count_
);
284 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));