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_spdy3.h"
8 #include "testing/platform_test.h"
10 using namespace net::test_spdy3
;
16 class TestBufferedSpdyVisitor
: public BufferedSpdyFramerVisitorInterface
{
18 TestBufferedSpdyVisitor()
19 : buffered_spdy_framer_(3),
23 syn_reply_frame_count_(0),
24 headers_frame_count_(0),
25 header_stream_id_(-1) {
28 void OnError(int 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(const SpdySynStreamControlFrame
& frame
,
41 const linked_ptr
<SpdyHeaderBlock
>& headers
) {
42 header_stream_id_
= frame
.stream_id();
43 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
48 void OnSynReply(const SpdySynReplyControlFrame
& frame
,
49 const linked_ptr
<SpdyHeaderBlock
>& headers
) {
50 header_stream_id_
= frame
.stream_id();
51 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
52 syn_reply_frame_count_
++;
56 void OnHeaders(const SpdyHeadersControlFrame
& frame
,
57 const linked_ptr
<SpdyHeaderBlock
>& headers
) {
58 header_stream_id_
= frame
.stream_id();
59 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
60 headers_frame_count_
++;
64 void OnStreamFrameData(SpdyStreamId stream_id
,
67 LOG(FATAL
) << "Unexpected OnStreamFrameData call.";
70 void OnSetting(SpdySettingsIds id
, uint8 flags
, uint32 value
) {
74 bool OnCredentialFrameData(const char*, size_t) {
75 LOG(FATAL
) << "Unexpected OnCredentialFrameData call.";
79 void OnDataFrameHeader(const SpdyDataFrame
* frame
) {
80 LOG(FATAL
) << "Unexpected OnDataFrameHeader call.";
83 void OnControl(const SpdyControlFrame
* frame
) {
84 uint32 type
= frame
->type();
89 header_stream_id_
= SpdyFramer::GetControlFrameStreamId(frame
);
90 EXPECT_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);
91 buffered_spdy_framer_
.OnControl(frame
);
94 LOG(FATAL
) << "Unexpected frame type." << type
;
98 void OnRstStream(const SpdyRstStreamControlFrame
& frame
) {}
99 void OnGoAway(const SpdyGoAwayControlFrame
& frame
) {}
100 void OnPing(const SpdyPingControlFrame
& frame
) {}
101 void OnWindowUpdate(const SpdyWindowUpdateControlFrame
& frame
) {}
102 void OnCredential(const SpdyCredentialControlFrame
& frame
) {}
104 // Convenience function which runs a framer simulation with particular input.
105 void SimulateInFramer(const unsigned char* input
, size_t size
) {
106 buffered_spdy_framer_
.set_visitor(this);
107 size_t input_remaining
= size
;
108 const char* input_ptr
= reinterpret_cast<const char*>(input
);
109 while (input_remaining
> 0 &&
110 buffered_spdy_framer_
.error_code() == SpdyFramer::SPDY_NO_ERROR
) {
111 // To make the tests more interesting, we feed random (amd small) chunks
112 // into the framer. This simulates getting strange-sized reads from
114 const size_t kMaxReadSize
= 32;
116 (rand() % std::min(input_remaining
, kMaxReadSize
)) + 1;
117 size_t bytes_processed
=
118 buffered_spdy_framer_
.ProcessInput(input_ptr
, bytes_read
);
119 input_remaining
-= bytes_processed
;
120 input_ptr
+= bytes_processed
;
121 if (buffered_spdy_framer_
.state() == SpdyFramer::SPDY_DONE
)
122 buffered_spdy_framer_
.Reset();
126 BufferedSpdyFramer buffered_spdy_framer_
;
128 // Counters from the visitor callbacks.
131 int syn_frame_count_
;
132 int syn_reply_frame_count_
;
133 int headers_frame_count_
;
135 // Header block streaming state:
136 SpdyStreamId header_stream_id_
;
138 // Headers from OnSyn, OnSynReply and OnHeaders for verification.
139 SpdyHeaderBlock headers_
;
144 class BufferedSpdyFramerSpdy3Test
: public PlatformTest
{
146 // Returns true if the two header blocks have equivalent content.
147 bool CompareHeaderBlocks(const SpdyHeaderBlock
* expected
,
148 const SpdyHeaderBlock
* actual
) {
149 if (expected
->size() != actual
->size()) {
150 LOG(ERROR
) << "Expected " << expected
->size() << " headers; actually got "
151 << actual
->size() << ".";
154 for (SpdyHeaderBlock::const_iterator it
= expected
->begin();
155 it
!= expected
->end();
157 SpdyHeaderBlock::const_iterator it2
= actual
->find(it
->first
);
158 if (it2
== actual
->end()) {
159 LOG(ERROR
) << "Expected header name '" << it
->first
<< "'.";
162 if (it
->second
.compare(it2
->second
) != 0) {
163 LOG(ERROR
) << "Expected header named '" << it
->first
164 << "' to have a value of '" << it
->second
165 << "'. The actual value received was '" << it2
->second
174 SpdyTestStateHelper spdy_state_
;
177 TEST_F(BufferedSpdyFramerSpdy3Test
, OnSetting
) {
178 SpdyFramer
framer(3);
179 SettingsMap settings
;
180 settings
[SETTINGS_UPLOAD_BANDWIDTH
] =
181 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, 0x00000002);
182 settings
[SETTINGS_DOWNLOAD_BANDWIDTH
] =
183 SettingsFlagsAndValue(SETTINGS_FLAG_NONE
, 0x00000003);
185 scoped_ptr
<SpdyFrame
> control_frame(framer
.CreateSettings(settings
));
186 TestBufferedSpdyVisitor visitor
;
188 visitor
.SimulateInFramer(
189 reinterpret_cast<unsigned char*>(control_frame
->data()),
190 control_frame
->length() + SpdyControlFrame::kHeaderSize
);
191 EXPECT_EQ(0, visitor
.error_count_
);
192 EXPECT_EQ(2, visitor
.setting_count_
);
195 TEST_F(BufferedSpdyFramerSpdy3Test
, ReadSynStreamHeaderBlock
) {
196 SpdyHeaderBlock headers
;
197 headers
["aa"] = "vv";
198 headers
["bb"] = "ww";
199 BufferedSpdyFramer
framer(3);
200 scoped_ptr
<SpdySynStreamControlFrame
> control_frame(
201 framer
.CreateSynStream(1, // stream_id
202 0, // associated_stream_id
204 0, // credential_slot
208 EXPECT_TRUE(control_frame
.get() != NULL
);
210 TestBufferedSpdyVisitor visitor
;
211 visitor
.SimulateInFramer(
212 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
213 control_frame
.get()->length() + SpdyControlFrame::kHeaderSize
);
214 EXPECT_EQ(0, visitor
.error_count_
);
215 EXPECT_EQ(1, visitor
.syn_frame_count_
);
216 EXPECT_EQ(0, visitor
.syn_reply_frame_count_
);
217 EXPECT_EQ(0, visitor
.headers_frame_count_
);
218 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));
221 TEST_F(BufferedSpdyFramerSpdy3Test
, ReadSynReplyHeaderBlock
) {
222 SpdyHeaderBlock headers
;
223 headers
["alpha"] = "beta";
224 headers
["gamma"] = "delta";
225 BufferedSpdyFramer
framer(3);
226 scoped_ptr
<SpdySynReplyControlFrame
> control_frame(
227 framer
.CreateSynReply(1, // stream_id
231 EXPECT_TRUE(control_frame
.get() != NULL
);
233 TestBufferedSpdyVisitor visitor
;
234 visitor
.SimulateInFramer(
235 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
236 control_frame
.get()->length() + SpdyControlFrame::kHeaderSize
);
237 EXPECT_EQ(0, visitor
.error_count_
);
238 EXPECT_EQ(0, visitor
.syn_frame_count_
);
239 EXPECT_EQ(1, visitor
.syn_reply_frame_count_
);
240 EXPECT_EQ(0, visitor
.headers_frame_count_
);
241 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));
244 TEST_F(BufferedSpdyFramerSpdy3Test
, ReadHeadersHeaderBlock
) {
245 SpdyHeaderBlock headers
;
246 headers
["alpha"] = "beta";
247 headers
["gamma"] = "delta";
248 BufferedSpdyFramer
framer(3);
249 scoped_ptr
<SpdyHeadersControlFrame
> control_frame(
250 framer
.CreateHeaders(1, // stream_id
254 EXPECT_TRUE(control_frame
.get() != NULL
);
256 TestBufferedSpdyVisitor visitor
;
257 visitor
.SimulateInFramer(
258 reinterpret_cast<unsigned char*>(control_frame
.get()->data()),
259 control_frame
.get()->length() + SpdyControlFrame::kHeaderSize
);
260 EXPECT_EQ(0, visitor
.error_count_
);
261 EXPECT_EQ(0, visitor
.syn_frame_count_
);
262 EXPECT_EQ(0, visitor
.syn_reply_frame_count_
);
263 EXPECT_EQ(1, visitor
.headers_frame_count_
);
264 EXPECT_TRUE(CompareHeaderBlocks(&headers
, &visitor
.headers_
));