| 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 |