1 // Copyright (c) 2009 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 <algorithm> 6 #include <iostream> 7 8 #include "base/scoped_ptr.h" 9 #include "flip_framer.h" // cross-google3 directory naming. 10 #include "flip_protocol.h" 11 #include "flip_frame_builder.h" 12 #include "testing/platform_test.h" 13 14 namespace flip { 15 16 namespace test { 17 18 void FramerSetEnableCompressionHelper(FlipFramer* framer, bool compress) { 19 framer->set_enable_compression(compress); 20 } 21 22 class TestFlipVisitor : public FlipFramerVisitorInterface { 23 public: 24 TestFlipVisitor() 25 : error_count_(0), 26 syn_frame_count_(0), 27 syn_reply_frame_count_(0), 28 data_bytes_(0), 29 fin_frame_count_(0), 30 fin_flag_count_(0), 31 zero_length_data_frame_count_(0) { 32 } 33 34 void OnError(FlipFramer* f) { 35 error_count_++; 36 } 37 38 void OnStreamFrameData(FlipStreamId stream_id, 39 const char* data, 40 size_t len) { 41 if (len == 0) 42 ++zero_length_data_frame_count_; 43 44 data_bytes_ += len; 45 std::cerr << "OnStreamFrameData(" << stream_id << ", \""; 46 if (len > 0) { 47 for (size_t i = 0 ; i < len; ++i) { 48 std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec; 49 } 50 } 51 std::cerr << "\", " << len << ")\n"; 52 } 53 54 void OnControl(const FlipControlFrame* frame) { 55 FlipHeaderBlock headers; 56 bool parsed_headers = false; 57 switch (frame->type()) { 58 case SYN_STREAM: 59 parsed_headers = framer_.ParseHeaderBlock(frame, &headers); 60 DCHECK(parsed_headers); 61 syn_frame_count_++; 62 break; 63 case SYN_REPLY: 64 parsed_headers = framer_.ParseHeaderBlock(frame, &headers); 65 DCHECK(parsed_headers); 66 syn_reply_frame_count_++; 67 break; 68 case FIN_STREAM: 69 fin_frame_count_++; 70 break; 71 default: 72 DCHECK(false); // Error! 73 } 74 if (frame->flags() & CONTROL_FLAG_FIN) 75 ++fin_flag_count_; 76 } 77 78 // Convenience function which runs a framer simulation with particular input. 79 void SimulateInFramer(const unsigned char* input, size_t size) { 80 framer_.set_enable_compression(false); 81 framer_.set_visitor(this); 82 size_t input_remaining = size; 83 const char* input_ptr = reinterpret_cast<const char*>(input); 84 while (input_remaining > 0 && 85 framer_.error_code() == FlipFramer::FLIP_NO_ERROR) { 86 // To make the tests more interesting, we feed random (amd small) chunks 87 // into the framer. This simulates getting strange-sized reads from 88 // the socket. 89 const size_t kMaxReadSize = 32; 90 size_t bytes_read = 91 (rand() % std::min(input_remaining, kMaxReadSize)) + 1; 92 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read); 93 input_remaining -= bytes_processed; 94 input_ptr += bytes_processed; 95 if (framer_.state() == FlipFramer::FLIP_DONE) 96 framer_.Reset(); 97 } 98 } 99 100 FlipFramer framer_; 101 // Counters from the visitor callbacks. 102 int error_count_; 103 int syn_frame_count_; 104 int syn_reply_frame_count_; 105 int data_bytes_; 106 int fin_frame_count_; // The count of FIN_STREAM type frames received. 107 int fin_flag_count_; // The count of frames with the FIN flag set. 108 int zero_length_data_frame_count_; // The count of zero-length data frames. 109 }; 110 111 } // namespace test 112 113 } // namespace flip 114 115 using flip::FlipFrame; 116 using flip::FlipFrameBuilder; 117 using flip::FlipFramer; 118 using flip::FlipHeaderBlock; 119 using flip::FlipSynStreamControlFrame; 120 using flip::kControlFlagMask; 121 using flip::CONTROL_FLAG_NONE; 122 using flip::SYN_STREAM; 123 using flip::test::FramerSetEnableCompressionHelper; 124 using flip::test::TestFlipVisitor; 125 126 namespace { 127 128 class FlipFramerTest : public PlatformTest { 129 public: 130 virtual void TearDown() {} 131 }; 132 133 // Test that we can encode and decode a FlipHeaderBlock. 134 TEST_F(FlipFramerTest, HeaderBlock) { 135 FlipHeaderBlock headers; 136 headers["alpha"] = "beta"; 137 headers["gamma"] = "charlie"; 138 FlipFramer framer; 139 140 // Encode the header block into a SynStream frame. 141 scoped_ptr<FlipSynStreamControlFrame> frame( 142 framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers)); 143 EXPECT_TRUE(frame.get() != NULL); 144 145 FlipHeaderBlock new_headers; 146 framer.ParseHeaderBlock(frame.get(), &new_headers); 147 148 EXPECT_EQ(headers.size(), new_headers.size()); 149 EXPECT_EQ(headers["alpha"], new_headers["alpha"]); 150 EXPECT_EQ(headers["gamma"], new_headers["gamma"]); 151 } 152 153 TEST_F(FlipFramerTest, OutOfOrderHeaders) { 154 FlipFrameBuilder frame; 155 156 frame.WriteUInt16(kControlFlagMask | 1); 157 frame.WriteUInt16(SYN_STREAM); 158 frame.WriteUInt32(0); // Placeholder for the length. 159 frame.WriteUInt32(3); // stream_id 160 frame.WriteUInt16(0); // Priority. 161 162 frame.WriteUInt16(2); // Number of headers. 163 FlipHeaderBlock::iterator it; 164 frame.WriteString("gamma"); 165 frame.WriteString("gamma"); 166 frame.WriteString("alpha"); 167 frame.WriteString("alpha"); 168 // write the length 169 frame.WriteUInt32ToOffset(4, frame.length() - FlipFrame::size()); 170 171 FlipHeaderBlock new_headers; 172 scoped_ptr<FlipFrame> control_frame(frame.take()); 173 FlipFramer framer; 174 FramerSetEnableCompressionHelper(&framer, false); 175 EXPECT_TRUE(framer.ParseHeaderBlock(control_frame.get(), &new_headers)); 176 } 177 178 TEST_F(FlipFramerTest, DuplicateHeader) { 179 FlipFrameBuilder frame; 180 181 frame.WriteUInt16(kControlFlagMask | 1); 182 frame.WriteUInt16(SYN_STREAM); 183 frame.WriteUInt32(0); // Placeholder for the length. 184 frame.WriteUInt32(3); // stream_id 185 frame.WriteUInt16(0); // Priority. 186 187 frame.WriteUInt16(2); // Number of headers. 188 FlipHeaderBlock::iterator it; 189 frame.WriteString("name"); 190 frame.WriteString("value1"); 191 frame.WriteString("name"); 192 frame.WriteString("value2"); 193 // write the length 194 frame.WriteUInt32ToOffset(4, frame.length() - FlipFrame::size()); 195 196 FlipHeaderBlock new_headers; 197 scoped_ptr<FlipFrame> control_frame(frame.take()); 198 FlipFramer framer; 199 FramerSetEnableCompressionHelper(&framer, false); 200 // This should fail because duplicate headers are verboten by the spec. 201 EXPECT_FALSE(framer.ParseHeaderBlock(control_frame.get(), &new_headers)); 202 } 203 204 TEST_F(FlipFramerTest, MultiValueHeader) { 205 FlipFrameBuilder frame; 206 207 frame.WriteUInt16(kControlFlagMask | 1); 208 frame.WriteUInt16(SYN_STREAM); 209 frame.WriteUInt32(0); // Placeholder for the length. 210 frame.WriteUInt32(3); // stream_id 211 frame.WriteUInt16(0); // Priority. 212 213 frame.WriteUInt16(2); // Number of headers. 214 FlipHeaderBlock::iterator it; 215 frame.WriteString("name"); 216 std::string value("value1\0value2"); 217 frame.WriteString(value); 218 // write the length 219 frame.WriteUInt32ToOffset(4, frame.length() - FlipFrame::size()); 220 221 FlipHeaderBlock new_headers; 222 scoped_ptr<FlipFrame> control_frame(frame.take()); 223 FlipFramer framer; 224 FramerSetEnableCompressionHelper(&framer, false); 225 EXPECT_TRUE(framer.ParseHeaderBlock(control_frame.get(), &new_headers)); 226 EXPECT_TRUE(new_headers.find("name") != new_headers.end()); 227 EXPECT_EQ(value, new_headers.find("name")->second); 228 } 229 230 TEST_F(FlipFramerTest, BasicCompression) { 231 FlipHeaderBlock headers; 232 headers["server"] = "FlipServer 1.0"; 233 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; 234 headers["status"] = "200"; 235 headers["version"] = "HTTP/1.1"; 236 headers["content-type"] = "text/html"; 237 headers["content-length"] = "12"; 238 239 FlipFramer framer; 240 FramerSetEnableCompressionHelper(&framer, true); 241 scoped_ptr<FlipSynStreamControlFrame> 242 frame1(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers)); 243 scoped_ptr<FlipSynStreamControlFrame> 244 frame2(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers)); 245 246 // Expect the second frame to be more compact than the first. 247 EXPECT_LE(frame2->length(), frame1->length()); 248 249 // Decompress the first frame 250 scoped_ptr<FlipFrame> frame3(framer.DecompressFrame(frame1.get())); 251 252 // Decompress the second frame 253 scoped_ptr<FlipFrame> frame4(framer.DecompressFrame(frame2.get())); 254 255 // Expect frames 3 & 4 to be the same. 256 EXPECT_EQ(0, 257 memcmp(frame3->data(), frame4->data(), 258 FlipFrame::size() + frame3->length())); 259 } 260 261 TEST_F(FlipFramerTest, DecompressUncompressedFrame) { 262 FlipHeaderBlock headers; 263 headers["server"] = "FlipServer 1.0"; 264 headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; 265 headers["status"] = "200"; 266 headers["version"] = "HTTP/1.1"; 267 headers["content-type"] = "text/html"; 268 headers["content-length"] = "12"; 269 270 FlipFramer framer; 271 FramerSetEnableCompressionHelper(&framer, true); 272 scoped_ptr<FlipSynStreamControlFrame> 273 frame1(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, false, &headers)); 274 275 // Decompress the frame 276 scoped_ptr<FlipFrame> frame2(framer.DecompressFrame(frame1.get())); 277 278 EXPECT_EQ(NULL, frame2.get()); 279 } 280 281 TEST_F(FlipFramerTest, Basic) { 282 const unsigned char input[] = { 283 0x80, 0x01, 0x00, 0x01, // SYN Stream #1 284 0x00, 0x00, 0x00, 0x10, 285 0x00, 0x00, 0x00, 0x01, 286 0x00, 0x00, 0x00, 0x01, 287 0x00, 0x02, 'h', 'h', 288 0x00, 0x02, 'v', 'v', 289 290 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 291 0x00, 0x00, 0x00, 0x0c, 292 0xde, 0xad, 0xbe, 0xef, 293 0xde, 0xad, 0xbe, 0xef, 294 0xde, 0xad, 0xbe, 0xef, 295 296 0x80, 0x01, 0x00, 0x01, // SYN Stream #3 297 0x00, 0x00, 0x00, 0x08, 298 0x00, 0x00, 0x00, 0x03, 299 0x00, 0x00, 0x00, 0x00, 300 301 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 302 0x00, 0x00, 0x00, 0x08, 303 0xde, 0xad, 0xbe, 0xef, 304 0xde, 0xad, 0xbe, 0xef, 305 306 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 307 0x00, 0x00, 0x00, 0x04, 308 0xde, 0xad, 0xbe, 0xef, 309 310 0x80, 0x01, 0x00, 0x03, // FIN on Stream #1 311 0x00, 0x00, 0x00, 0x08, 312 0x00, 0x00, 0x00, 0x01, 313 0x00, 0x00, 0x00, 0x00, 314 315 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 316 0x00, 0x00, 0x00, 0x00, 317 318 0x80, 0x01, 0x00, 0x03, // FIN on Stream #3 319 0x00, 0x00, 0x00, 0x08, 320 0x00, 0x00, 0x00, 0x03, 321 0x00, 0x00, 0x00, 0x00, 322 }; 323 324 TestFlipVisitor visitor; 325 visitor.SimulateInFramer(input, sizeof(input)); 326 327 EXPECT_EQ(0, visitor.error_count_); 328 EXPECT_EQ(2, visitor.syn_frame_count_); 329 EXPECT_EQ(0, visitor.syn_reply_frame_count_); 330 EXPECT_EQ(24, visitor.data_bytes_); 331 EXPECT_EQ(2, visitor.fin_frame_count_); 332 EXPECT_EQ(0, visitor.fin_flag_count_); 333 EXPECT_EQ(0, visitor.zero_length_data_frame_count_); 334 } 335 336 // Test that the FIN flag on a data frame signifies EOF. 337 TEST_F(FlipFramerTest, FinOnDataFrame) { 338 const unsigned char input[] = { 339 0x80, 0x01, 0x00, 0x01, // SYN Stream #1 340 0x00, 0x00, 0x00, 0x10, 341 0x00, 0x00, 0x00, 0x01, 342 0x00, 0x00, 0x00, 0x01, 343 0x00, 0x02, 'h', 'h', 344 0x00, 0x02, 'v', 'v', 345 346 0x80, 0x01, 0x00, 0x02, // SYN REPLY Stream #1 347 0x00, 0x00, 0x00, 0x10, 348 0x00, 0x00, 0x00, 0x01, 349 0x00, 0x00, 0x00, 0x01, 350 0x00, 0x02, 'a', 'a', 351 0x00, 0x02, 'b', 'b', 352 353 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 354 0x00, 0x00, 0x00, 0x0c, 355 0xde, 0xad, 0xbe, 0xef, 356 0xde, 0xad, 0xbe, 0xef, 357 0xde, 0xad, 0xbe, 0xef, 358 359 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF 360 0x01, 0x00, 0x00, 0x04, 361 0xde, 0xad, 0xbe, 0xef, 362 }; 363 364 TestFlipVisitor visitor; 365 visitor.SimulateInFramer(input, sizeof(input)); 366 367 EXPECT_EQ(0, visitor.error_count_); 368 EXPECT_EQ(1, visitor.syn_frame_count_); 369 EXPECT_EQ(1, visitor.syn_reply_frame_count_); 370 EXPECT_EQ(16, visitor.data_bytes_); 371 EXPECT_EQ(0, visitor.fin_frame_count_); 372 EXPECT_EQ(0, visitor.fin_flag_count_); 373 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); 374 } 375 376 // Test that the FIN flag on a SYN reply frame signifies EOF. 377 TEST_F(FlipFramerTest, FinOnSynReplyFrame) { 378 const unsigned char input[] = { 379 0x80, 0x01, 0x00, 0x01, // SYN Stream #1 380 0x00, 0x00, 0x00, 0x10, 381 0x00, 0x00, 0x00, 0x01, 382 0x00, 0x00, 0x00, 0x01, 383 0x00, 0x02, 'h', 'h', 384 0x00, 0x02, 'v', 'v', 385 386 0x80, 0x01, 0x00, 0x02, // SYN REPLY Stream #1 387 0x01, 0x00, 0x00, 0x10, 388 0x00, 0x00, 0x00, 0x01, 389 0x00, 0x00, 0x00, 0x01, 390 0x00, 0x02, 'a', 'a', 391 0x00, 0x02, 'b', 'b', 392 }; 393 394 TestFlipVisitor visitor; 395 visitor.SimulateInFramer(input, sizeof(input)); 396 397 EXPECT_EQ(0, visitor.error_count_); 398 EXPECT_EQ(1, visitor.syn_frame_count_); 399 EXPECT_EQ(1, visitor.syn_reply_frame_count_); 400 EXPECT_EQ(0, visitor.data_bytes_); 401 EXPECT_EQ(0, visitor.fin_frame_count_); 402 EXPECT_EQ(1, visitor.fin_flag_count_); 403 EXPECT_EQ(1, visitor.zero_length_data_frame_count_); 404 } 405 406 } // namespace 407 408