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_spdy2.h"
8 #include "testing/platform_test.h"
10 using namespace net::test_spdy2
;
16 class TestBufferedSpdyVisitor
: public BufferedSpdyFramerVisitorInterface
{
18 TestBufferedSpdyVisitor()
19 : buffered_spdy_framer_(2, true),
23 syn_reply_frame_count_(0),
24 headers_frame_count_(0),
25 header_stream_id_(-1) {
28 virtual void OnError(SpdyFramer::SpdyError error_code
) OVERRIDE
{
29 LOG(INFO
) << "SpdyFramer Error: " << error_code
;
33 virtual void OnStreamError(
34 SpdyStreamId stream_id
,
35 const std::string
& description
) OVERRIDE
{
36 LOG(INFO
) << "SpdyFramer Error on stream: " << stream_id
<< " "
41 virtual void OnSynStream(SpdyStreamId stream_id
,
42 SpdyStreamId associated_stream_id
,
43 SpdyPriority priority
,
44 uint8 credential_slot
,
47 const SpdyHeaderBlock
& headers
) OVERRIDE
{
48 header_stream_id_
= stream_id
;
49 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
54 virtual void OnSynReply(SpdyStreamId stream_id
,
56 const SpdyHeaderBlock
& headers
) OVERRIDE
{
57 header_stream_id_
= stream_id
;
58 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
59 syn_reply_frame_count_
++;
63 virtual void OnHeaders(SpdyStreamId stream_id
,
65 const SpdyHeaderBlock
& headers
) OVERRIDE
{
66 header_stream_id_
= stream_id
;
67 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
68 headers_frame_count_
++;
72 virtual void OnStreamFrameData(SpdyStreamId stream_id
,
76 LOG(FATAL
) << "Unexpected OnStreamFrameData call.";
79 virtual void OnSetting(SpdySettingsIds id
,
81 uint32 value
) OVERRIDE
{
85 virtual void OnPing(uint32 unique_id
) OVERRIDE
{}
87 virtual void OnRstStream(SpdyStreamId stream_id
,
88 SpdyRstStreamStatus status
) OVERRIDE
{
91 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id
,
92 SpdyGoAwayStatus status
) OVERRIDE
{
95 virtual void OnSynStreamCompressed(
96 size_t uncompressed_size
,
97 size_t compressed_size
) 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
{
115 void OnCredential(const SpdyFrame
& frame
) {}
117 // Convenience function which runs a framer simulation with particular input.
118 void SimulateInFramer(const unsigned char* input
, size_t size
) {
119 buffered_spdy_framer_
.set_visitor(this);
120 size_t input_remaining
= size
;
121 const char* input_ptr
= reinterpret_cast<const char*>(input
);
122 while (input_remaining
> 0 &&
123 buffered_spdy_framer_
.error_code() == SpdyFramer::SPDY_NO_ERROR
) {
124 // To make the tests more interesting, we feed random (amd small) chunks
125 // into the framer. This simulates getting strange-sized reads from
127 const size_t kMaxReadSize
= 32;
129 (rand() % std::min(input_remaining
, kMaxReadSize
)) + 1;
130 size_t bytes_processed
=
131 buffered_spdy_framer_
.ProcessInput(input_ptr
, bytes_read
);
132 input_remaining
-= bytes_processed
;
133 input_ptr
+= bytes_processed
;
137 BufferedSpdyFramer buffered_spdy_framer_
;
139 // Counters from the visitor callbacks.
142 int syn_frame_count_
;
143 int syn_reply_frame_count_
;
144 int headers_frame_count_
;
146 // Header block streaming state:
147 SpdyStreamId header_stream_id_
;
149 // Headers from OnSyn, OnSynReply and OnHeaders for verification.
150 SpdyHeaderBlock headers_
;
155 class BufferedSpdyFramerSpdy2Test
: public PlatformTest
{
157 // Returns true if the two header blocks have equivalent content.
158 bool CompareHeaderBlocks(const SpdyHeaderBlock
* expected
,
159 const SpdyHeaderBlock
* actual
) {
160 if (expected
->size() != actual
->size()) {
161 LOG(ERROR
) << "Expected " << expected
->size() << " headers; actually got "
162 << actual
->size() << ".";
165 for (SpdyHeaderBlock::const_iterator it
= expected
->begin();
166 it
!= expected
->end();
168 SpdyHeaderBlock::const_iterator it2
= actual
->find(it
->first
);
169 if (it2
== actual
->end()) {
170 LOG(ERROR
) << "Expected header name '" << it
->first
<< "'.";
173 if (it
->second
.compare(it2
->second
) != 0) {
174 LOG(ERROR
) << "Expected header named '" << it
->first
175 << "' to have a value of '" << it
->second
176 << "'. The actual value received was '" << it2
->second
185 TEST_F(BufferedSpdyFramerSpdy2Test
, OnSetting
) {
186 SpdyFramer
framer(2);
187 SettingsMap settings
;
188 settings
[SETTINGS_UPLOAD_BANDWIDTH
] =
189 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, 0x00000002);
190 settings
[SETTINGS_DOWNLOAD_BANDWIDTH
] =
191 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, 0x00000003);
193 scoped_ptr
<SpdyFrame
> control_frame(framer
.CreateSettings(settings
));
194 TestBufferedSpdyVisitor visitor
;
196 visitor
.SimulateInFramer(
197 reinterpret_cast<unsigned char*>(control_frame
->data()),
198 control_frame
->size());
199 EXPECT_EQ(0, visitor
.error_count_
);
200 EXPECT_EQ(2, visitor
.setting_count_
);
203 TEST_F(BufferedSpdyFramerSpdy2Test
, ReadSynStreamHeaderBlock
) {
204 SpdyHeaderBlock headers
;
205 headers
["aa"] = "vv";
206 headers
["bb"] = "ww";
207 BufferedSpdyFramer
framer(2, true);
208 scoped_ptr
<SpdyFrame
> control_frame(
209 framer
.CreateSynStream(1, // stream_id
210 0, // associated_stream_id
212 0, // credential_slot
216 EXPECT_TRUE(control_frame
.get() != NULL
);
218 TestBufferedSpdyVisitor visitor
;
219 visitor
.SimulateInFramer(
220 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
221 control_frame
.get()->size());
222 EXPECT_EQ(0, visitor
.error_count_
);
223 EXPECT_EQ(1, visitor
.syn_frame_count_
);
224 EXPECT_EQ(0, visitor
.syn_reply_frame_count_
);
225 EXPECT_EQ(0, visitor
.headers_frame_count_
);
226 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));
229 TEST_F(BufferedSpdyFramerSpdy2Test
, ReadSynReplyHeaderBlock
) {
230 SpdyHeaderBlock headers
;
231 headers
["alpha"] = "beta";
232 headers
["gamma"] = "delta";
233 BufferedSpdyFramer
framer(2, true);
234 scoped_ptr
<SpdyFrame
> control_frame(
235 framer
.CreateSynReply(1, // stream_id
239 EXPECT_TRUE(control_frame
.get() != NULL
);
241 TestBufferedSpdyVisitor visitor
;
242 visitor
.SimulateInFramer(
243 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
244 control_frame
.get()->size());
245 EXPECT_EQ(0, visitor
.error_count_
);
246 EXPECT_EQ(0, visitor
.syn_frame_count_
);
247 EXPECT_EQ(1, visitor
.syn_reply_frame_count_
);
248 EXPECT_EQ(0, visitor
.headers_frame_count_
);
249 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));
252 TEST_F(BufferedSpdyFramerSpdy2Test
, ReadHeadersHeaderBlock
) {
253 SpdyHeaderBlock headers
;
254 headers
["alpha"] = "beta";
255 headers
["gamma"] = "delta";
256 BufferedSpdyFramer
framer(2, true);
257 scoped_ptr
<SpdyFrame
> control_frame(
258 framer
.CreateHeaders(1, // stream_id
262 EXPECT_TRUE(control_frame
.get() != NULL
);
264 TestBufferedSpdyVisitor visitor
;
265 visitor
.SimulateInFramer(
266 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
267 control_frame
.get()->size());
268 EXPECT_EQ(0, visitor
.error_count_
);
269 EXPECT_EQ(0, visitor
.syn_frame_count_
);
270 EXPECT_EQ(0, visitor
.syn_reply_frame_count_
);
271 EXPECT_EQ(1, visitor
.headers_frame_count_
);
272 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));