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 void OnError(SpdyFramer::SpdyError error_code
) {
29 LOG(INFO
) << "SpdyFramer Error: " << error_code
;
33 void OnStreamError(SpdyStreamId stream_id
,
34 const std::string
& description
) {
35 LOG(INFO
) << "SpdyFramer Error on stream: " << stream_id
<< " "
40 void OnSynStream(SpdyStreamId stream_id
,
41 SpdyStreamId associated_stream_id
,
42 SpdyPriority priority
,
43 uint8 credential_slot
,
46 const SpdyHeaderBlock
& headers
) {
47 header_stream_id_
= stream_id
;
48 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
53 void OnSynReply(SpdyStreamId stream_id
,
55 const SpdyHeaderBlock
& headers
) {
56 header_stream_id_
= stream_id
;
57 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
58 syn_reply_frame_count_
++;
62 void OnHeaders(SpdyStreamId stream_id
,
64 const SpdyHeaderBlock
& headers
) {
65 header_stream_id_
= stream_id
;
66 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
67 headers_frame_count_
++;
71 void OnStreamFrameData(SpdyStreamId stream_id
,
74 SpdyDataFlags flags
) {
75 LOG(FATAL
) << "Unexpected OnStreamFrameData call.";
78 void OnSetting(SpdySettingsIds id
, uint8 flags
, uint32 value
) {
82 void OnPing(uint32 unique_id
) {}
84 void OnRstStream(SpdyStreamId stream_id
, SpdyStatusCodes status
) {}
86 void OnGoAway(SpdyStreamId last_accepted_stream_id
,
87 SpdyGoAwayStatus status
) {}
89 void OnControlFrameCompressed(
90 const SpdyControlFrame
& uncompressed_frame
,
91 const SpdyControlFrame
& compressed_frame
) {
94 bool OnCredentialFrameData(const char*, size_t) {
95 LOG(FATAL
) << "Unexpected OnCredentialFrameData call.";
99 void OnDataFrameHeader(const SpdyDataFrame
* frame
) {
100 LOG(FATAL
) << "Unexpected OnDataFrameHeader call.";
103 void OnRstStream(const SpdyRstStreamControlFrame
& frame
) {}
104 void OnGoAway(const SpdyGoAwayControlFrame
& frame
) {}
105 void OnPing(const SpdyPingControlFrame
& frame
) {}
106 void OnWindowUpdate(SpdyStreamId stream_id
, int delta_window_size
) {}
107 void OnCredential(const SpdyCredentialControlFrame
& frame
) {}
109 // Convenience function which runs a framer simulation with particular input.
110 void SimulateInFramer(const unsigned char* input
, size_t size
) {
111 buffered_spdy_framer_
.set_visitor(this);
112 size_t input_remaining
= size
;
113 const char* input_ptr
= reinterpret_cast<const char*>(input
);
114 while (input_remaining
> 0 &&
115 buffered_spdy_framer_
.error_code() == SpdyFramer::SPDY_NO_ERROR
) {
116 // To make the tests more interesting, we feed random (amd small) chunks
117 // into the framer. This simulates getting strange-sized reads from
119 const size_t kMaxReadSize
= 32;
121 (rand() % std::min(input_remaining
, kMaxReadSize
)) + 1;
122 size_t bytes_processed
=
123 buffered_spdy_framer_
.ProcessInput(input_ptr
, bytes_read
);
124 input_remaining
-= bytes_processed
;
125 input_ptr
+= bytes_processed
;
126 if (buffered_spdy_framer_
.state() == SpdyFramer::SPDY_DONE
)
127 buffered_spdy_framer_
.Reset();
131 BufferedSpdyFramer buffered_spdy_framer_
;
133 // Counters from the visitor callbacks.
136 int syn_frame_count_
;
137 int syn_reply_frame_count_
;
138 int headers_frame_count_
;
140 // Header block streaming state:
141 SpdyStreamId header_stream_id_
;
143 // Headers from OnSyn, OnSynReply and OnHeaders for verification.
144 SpdyHeaderBlock headers_
;
149 class BufferedSpdyFramerSpdy2Test
: public PlatformTest
{
151 // Returns true if the two header blocks have equivalent content.
152 bool CompareHeaderBlocks(const SpdyHeaderBlock
* expected
,
153 const SpdyHeaderBlock
* actual
) {
154 if (expected
->size() != actual
->size()) {
155 LOG(ERROR
) << "Expected " << expected
->size() << " headers; actually got "
156 << actual
->size() << ".";
159 for (SpdyHeaderBlock::const_iterator it
= expected
->begin();
160 it
!= expected
->end();
162 SpdyHeaderBlock::const_iterator it2
= actual
->find(it
->first
);
163 if (it2
== actual
->end()) {
164 LOG(ERROR
) << "Expected header name '" << it
->first
<< "'.";
167 if (it
->second
.compare(it2
->second
) != 0) {
168 LOG(ERROR
) << "Expected header named '" << it
->first
169 << "' to have a value of '" << it
->second
170 << "'. The actual value received was '" << it2
->second
179 TEST_F(BufferedSpdyFramerSpdy2Test
, OnSetting
) {
180 SpdyFramer
framer(2);
181 SettingsMap settings
;
182 settings
[SETTINGS_UPLOAD_BANDWIDTH
] =
183 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, 0x00000002);
184 settings
[SETTINGS_DOWNLOAD_BANDWIDTH
] =
185 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, 0x00000003);
187 scoped_ptr
<SpdyFrame
> control_frame(framer
.CreateSettings(settings
));
188 TestBufferedSpdyVisitor visitor
;
190 visitor
.SimulateInFramer(
191 reinterpret_cast<unsigned char*>(control_frame
->data()),
192 control_frame
->length() + SpdyControlFrame::kHeaderSize
);
193 EXPECT_EQ(0, visitor
.error_count_
);
194 EXPECT_EQ(2, visitor
.setting_count_
);
197 TEST_F(BufferedSpdyFramerSpdy2Test
, ReadSynStreamHeaderBlock
) {
198 SpdyHeaderBlock headers
;
199 headers
["aa"] = "vv";
200 headers
["bb"] = "ww";
201 BufferedSpdyFramer
framer(2, true);
202 scoped_ptr
<SpdySynStreamControlFrame
> control_frame(
203 framer
.CreateSynStream(1, // stream_id
204 0, // associated_stream_id
206 0, // credential_slot
210 EXPECT_TRUE(control_frame
.get() != NULL
);
212 TestBufferedSpdyVisitor visitor
;
213 visitor
.SimulateInFramer(
214 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
215 control_frame
.get()->length() + SpdyControlFrame::kHeaderSize
);
216 EXPECT_EQ(0, visitor
.error_count_
);
217 EXPECT_EQ(1, visitor
.syn_frame_count_
);
218 EXPECT_EQ(0, visitor
.syn_reply_frame_count_
);
219 EXPECT_EQ(0, visitor
.headers_frame_count_
);
220 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));
223 TEST_F(BufferedSpdyFramerSpdy2Test
, ReadSynReplyHeaderBlock
) {
224 SpdyHeaderBlock headers
;
225 headers
["alpha"] = "beta";
226 headers
["gamma"] = "delta";
227 BufferedSpdyFramer
framer(2, true);
228 scoped_ptr
<SpdySynReplyControlFrame
> control_frame(
229 framer
.CreateSynReply(1, // stream_id
233 EXPECT_TRUE(control_frame
.get() != NULL
);
235 TestBufferedSpdyVisitor visitor
;
236 visitor
.SimulateInFramer(
237 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
238 control_frame
.get()->length() + SpdyControlFrame::kHeaderSize
);
239 EXPECT_EQ(0, visitor
.error_count_
);
240 EXPECT_EQ(0, visitor
.syn_frame_count_
);
241 EXPECT_EQ(1, visitor
.syn_reply_frame_count_
);
242 EXPECT_EQ(0, visitor
.headers_frame_count_
);
243 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));
246 TEST_F(BufferedSpdyFramerSpdy2Test
, ReadHeadersHeaderBlock
) {
247 SpdyHeaderBlock headers
;
248 headers
["alpha"] = "beta";
249 headers
["gamma"] = "delta";
250 BufferedSpdyFramer
framer(2, true);
251 scoped_ptr
<SpdyHeadersControlFrame
> control_frame(
252 framer
.CreateHeaders(1, // stream_id
256 EXPECT_TRUE(control_frame
.get() != NULL
);
258 TestBufferedSpdyVisitor visitor
;
259 visitor
.SimulateInFramer(
260 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
261 control_frame
.get()->length() + SpdyControlFrame::kHeaderSize
);
262 EXPECT_EQ(0, visitor
.error_count_
);
263 EXPECT_EQ(0, visitor
.syn_frame_count_
);
264 EXPECT_EQ(0, visitor
.syn_reply_frame_count_
);
265 EXPECT_EQ(1, visitor
.headers_frame_count_
);
266 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));