OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/spdy/buffered_spdy_framer.h" | |
6 | |
7 #include "net/spdy/spdy_test_util.h" | |
8 #include "testing/platform_test.h" | |
9 | |
10 namespace spdy { | |
11 | |
12 namespace test { | |
13 | |
14 class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface { | |
15 public: | |
16 TestBufferedSpdyVisitor() | |
17 : error_count_(0), | |
18 syn_frame_count_(0), | |
19 syn_reply_frame_count_(0), | |
20 headers_frame_count_(0), | |
21 header_stream_id_(-1) { | |
22 } | |
23 | |
24 void OnError(int error_code) { | |
25 LOG(INFO) << "SpdyFramer Error: " << error_code; | |
26 error_count_++; | |
27 } | |
28 | |
29 void OnStreamError(spdy::SpdyStreamId stream_id, | |
30 const std::string& description) { | |
31 LOG(INFO) << "SpdyFramer Error on stream: " << stream_id << " " | |
32 << description; | |
33 error_count_++; | |
34 } | |
35 | |
36 void OnSynStream(const SpdySynStreamControlFrame& frame, | |
37 const linked_ptr<SpdyHeaderBlock>& headers) { | |
38 header_stream_id_ = frame.stream_id(); | |
39 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
40 syn_frame_count_++; | |
41 headers_ = *headers; | |
42 } | |
43 | |
44 void OnSynReply(const SpdySynReplyControlFrame& frame, | |
45 const linked_ptr<SpdyHeaderBlock>& headers) { | |
46 header_stream_id_ = frame.stream_id(); | |
47 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
48 syn_reply_frame_count_++; | |
49 headers_ = *headers; | |
50 } | |
51 | |
52 void OnHeaders(const SpdyHeadersControlFrame& frame, | |
53 const linked_ptr<SpdyHeaderBlock>& headers) { | |
54 header_stream_id_ = frame.stream_id(); | |
55 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
56 headers_frame_count_++; | |
57 headers_ = *headers; | |
58 } | |
59 | |
60 void OnStreamFrameData(SpdyStreamId stream_id, | |
61 const char* data, | |
62 size_t len) { | |
63 LOG(FATAL) << "Unexpected OnStreamFrameData call."; | |
64 } | |
65 | |
66 bool OnCredentialFrameData(const char*, size_t) { | |
67 LOG(FATAL) << "Unexpected OnCredentialFrameData call."; | |
68 return false; | |
69 } | |
70 | |
71 void OnDataFrameHeader(const SpdyDataFrame* frame) { | |
72 LOG(FATAL) << "Unexpected OnDataFrameHeader call."; | |
73 } | |
74 | |
75 void OnControl(const SpdyControlFrame* frame) { | |
76 uint32 type = frame->type(); | |
77 switch (type) { | |
78 case SYN_STREAM: | |
79 case SYN_REPLY: | |
80 case HEADERS: | |
81 header_stream_id_ = SpdyFramer::GetControlFrameStreamId(frame); | |
82 EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
83 buffered_spdy_framer_.OnControl(frame); | |
84 break; | |
85 default: | |
86 LOG(FATAL) << "Unexpected frame type." << type; | |
87 } | |
88 } | |
89 | |
90 void OnRstStream(const spdy::SpdyRstStreamControlFrame& frame) {} | |
91 void OnGoAway(const spdy::SpdyGoAwayControlFrame& frame) {} | |
92 void OnPing(const spdy::SpdyPingControlFrame& frame) {} | |
93 void OnSettings(const spdy::SpdySettingsControlFrame& frame) {} | |
94 void OnWindowUpdate(const spdy::SpdyWindowUpdateControlFrame& frame) {} | |
95 void OnCredential(const spdy::SpdyCredentialControlFrame& frame) {} | |
96 | |
97 // Convenience function which runs a framer simulation with particular input. | |
98 void SimulateInFramer(const unsigned char* input, size_t size) { | |
99 buffered_spdy_framer_.set_visitor(this); | |
100 size_t input_remaining = size; | |
101 const char* input_ptr = reinterpret_cast<const char*>(input); | |
102 while (input_remaining > 0 && | |
103 buffered_spdy_framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) { | |
104 // To make the tests more interesting, we feed random (amd small) chunks | |
105 // into the framer. This simulates getting strange-sized reads from | |
106 // the socket. | |
107 const size_t kMaxReadSize = 32; | |
108 size_t bytes_read = | |
109 (rand() % std::min(input_remaining, kMaxReadSize)) + 1; | |
110 size_t bytes_processed = | |
111 buffered_spdy_framer_.ProcessInput(input_ptr, bytes_read); | |
112 input_remaining -= bytes_processed; | |
113 input_ptr += bytes_processed; | |
114 if (buffered_spdy_framer_.state() == SpdyFramer::SPDY_DONE) | |
115 buffered_spdy_framer_.Reset(); | |
116 } | |
117 } | |
118 | |
119 BufferedSpdyFramer buffered_spdy_framer_; | |
120 | |
121 // Counters from the visitor callbacks. | |
122 int error_count_; | |
123 int syn_frame_count_; | |
124 int syn_reply_frame_count_; | |
125 int headers_frame_count_; | |
126 | |
127 // Header block streaming state: | |
128 SpdyStreamId header_stream_id_; | |
129 | |
130 // Headers from OnSyn, OnSynReply and OnHeaders for verification. | |
131 SpdyHeaderBlock headers_; | |
132 }; | |
133 | |
134 } // namespace test | |
135 | |
136 } // namespace spdy | |
137 | |
138 using spdy::test::TestBufferedSpdyVisitor; | |
139 | |
140 namespace spdy { | |
141 | |
142 class BufferedSpdyFramerTest : public PlatformTest { | |
143 protected: | |
144 void EnableCompression(bool enabled) { | |
145 SpdyFramer::set_enable_compression_default(enabled); | |
146 } | |
147 | |
148 // Returns true if the two header blocks have equivalent content. | |
149 bool CompareHeaderBlocks(const SpdyHeaderBlock* expected, | |
150 const SpdyHeaderBlock* actual) { | |
151 if (expected->size() != actual->size()) { | |
152 LOG(ERROR) << "Expected " << expected->size() << " headers; actually got " | |
153 << actual->size() << "."; | |
154 return false; | |
155 } | |
156 for (SpdyHeaderBlock::const_iterator it = expected->begin(); | |
157 it != expected->end(); | |
158 ++it) { | |
159 SpdyHeaderBlock::const_iterator it2 = actual->find(it->first); | |
160 if (it2 == actual->end()) { | |
161 LOG(ERROR) << "Expected header name '" << it->first << "'."; | |
162 return false; | |
163 } | |
164 if (it->second.compare(it2->second) != 0) { | |
165 LOG(ERROR) << "Expected header named '" << it->first | |
166 << "' to have a value of '" << it->second | |
167 << "'. The actual value received was '" << it2->second | |
168 << "'."; | |
169 return false; | |
170 } | |
171 } | |
172 return true; | |
173 } | |
174 }; | |
175 | |
176 TEST_F(BufferedSpdyFramerTest, ReadSynStreamHeaderBlock) { | |
177 EnableCompression(false); | |
178 | |
179 SpdyHeaderBlock headers; | |
180 headers["aa"] = "vv"; | |
181 headers["bb"] = "ww"; | |
182 BufferedSpdyFramer framer; | |
183 scoped_ptr<SpdySynStreamControlFrame> control_frame( | |
184 framer.CreateSynStream(1, // stream_id | |
185 0, // associated_stream_id | |
186 1, // priority | |
187 CONTROL_FLAG_NONE, | |
188 true, // compress | |
189 &headers)); | |
190 EXPECT_TRUE(control_frame.get() != NULL); | |
191 | |
192 TestBufferedSpdyVisitor visitor; | |
193 visitor.SimulateInFramer( | |
194 reinterpret_cast<unsigned char*>(control_frame.get()->data()), | |
195 control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
196 EXPECT_EQ(0, visitor.error_count_); | |
197 EXPECT_EQ(1, visitor.syn_frame_count_); | |
198 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
199 EXPECT_EQ(0, visitor.headers_frame_count_); | |
200 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
201 } | |
202 | |
203 TEST_F(BufferedSpdyFramerTest, ReadSynReplyHeaderBlock) { | |
204 EnableCompression(false); | |
205 | |
206 SpdyHeaderBlock headers; | |
207 headers["alpha"] = "beta"; | |
208 headers["gamma"] = "delta"; | |
209 BufferedSpdyFramer framer; | |
210 scoped_ptr<SpdySynReplyControlFrame> control_frame( | |
211 framer.CreateSynReply(1, // stream_id | |
212 CONTROL_FLAG_NONE, | |
213 true, // compress | |
214 &headers)); | |
215 EXPECT_TRUE(control_frame.get() != NULL); | |
216 | |
217 TestBufferedSpdyVisitor visitor; | |
218 visitor.SimulateInFramer( | |
219 reinterpret_cast<unsigned char*>(control_frame.get()->data()), | |
220 control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
221 EXPECT_EQ(0, visitor.error_count_); | |
222 EXPECT_EQ(0, visitor.syn_frame_count_); | |
223 EXPECT_EQ(1, visitor.syn_reply_frame_count_); | |
224 EXPECT_EQ(0, visitor.headers_frame_count_); | |
225 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
226 } | |
227 | |
228 TEST_F(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) { | |
229 EnableCompression(false); | |
230 | |
231 SpdyHeaderBlock headers; | |
232 headers["alpha"] = "beta"; | |
233 headers["gamma"] = "delta"; | |
234 BufferedSpdyFramer framer; | |
235 scoped_ptr<SpdyHeadersControlFrame> control_frame( | |
236 framer.CreateHeaders(1, // stream_id | |
237 CONTROL_FLAG_NONE, | |
238 true, // compress | |
239 &headers)); | |
240 EXPECT_TRUE(control_frame.get() != NULL); | |
241 | |
242 TestBufferedSpdyVisitor visitor; | |
243 visitor.SimulateInFramer( | |
244 reinterpret_cast<unsigned char*>(control_frame.get()->data()), | |
245 control_frame.get()->length() + SpdyControlFrame::kHeaderSize); | |
246 EXPECT_EQ(0, visitor.error_count_); | |
247 EXPECT_EQ(0, visitor.syn_frame_count_); | |
248 EXPECT_EQ(0, visitor.syn_reply_frame_count_); | |
249 EXPECT_EQ(1, visitor.headers_frame_count_); | |
250 EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_)); | |
251 } | |
252 } // namespace spdy | |
OLD | NEW |