| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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/tools/flip_server/http_interface.h" | |
| 6 | |
| 7 #include <list> | |
| 8 #include <memory> | |
| 9 | |
| 10 #include "base/stl_util.h" | |
| 11 #include "base/strings/string_piece.h" | |
| 12 #include "net/tools/balsa/balsa_enums.h" | |
| 13 #include "net/tools/balsa/balsa_frame.h" | |
| 14 #include "net/tools/balsa/balsa_headers.h" | |
| 15 #include "net/tools/flip_server/flip_config.h" | |
| 16 #include "net/tools/flip_server/flip_test_utils.h" | |
| 17 #include "net/tools/flip_server/mem_cache.h" | |
| 18 #include "testing/gmock/include/gmock/gmock.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 | |
| 21 namespace net { | |
| 22 | |
| 23 using ::base::StringPiece; | |
| 24 using ::testing::_; | |
| 25 using ::testing::InSequence; | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 class MockSMConnection : public SMConnection { | |
| 30 public: | |
| 31 MockSMConnection(EpollServer* epoll_server, | |
| 32 SSLState* ssl_state, | |
| 33 MemoryCache* memory_cache, | |
| 34 FlipAcceptor* acceptor, | |
| 35 std::string log_prefix) | |
| 36 : SMConnection(epoll_server, | |
| 37 ssl_state, | |
| 38 memory_cache, | |
| 39 acceptor, | |
| 40 log_prefix) {} | |
| 41 | |
| 42 MOCK_METHOD0(Cleanup, void()); | |
| 43 MOCK_METHOD8(InitSMConnection, | |
| 44 void(SMConnectionPoolInterface*, | |
| 45 SMInterface*, | |
| 46 EpollServer*, | |
| 47 int, | |
| 48 std::string, | |
| 49 std::string, | |
| 50 std::string, | |
| 51 bool)); | |
| 52 }; | |
| 53 | |
| 54 class FlipHttpSMTest : public ::testing::Test { | |
| 55 public: | |
| 56 explicit FlipHttpSMTest(FlipHandlerType type = FLIP_HANDLER_PROXY) { | |
| 57 SSLState* ssl_state = NULL; | |
| 58 mock_another_interface_.reset(new MockSMInterface); | |
| 59 memory_cache_.reset(new MemoryCache); | |
| 60 acceptor_.reset(new FlipAcceptor(type, | |
| 61 "127.0.0.1", | |
| 62 "8941", | |
| 63 "ssl_cert_filename", | |
| 64 "ssl_key_filename", | |
| 65 "127.0.0.1", | |
| 66 "8942", | |
| 67 "127.0.0.1", | |
| 68 "8943", | |
| 69 1, | |
| 70 0, | |
| 71 true, | |
| 72 1, | |
| 73 false, | |
| 74 true, | |
| 75 NULL)); | |
| 76 epoll_server_.reset(new EpollServer); | |
| 77 connection_.reset(new MockSMConnection(epoll_server_.get(), | |
| 78 ssl_state, | |
| 79 memory_cache_.get(), | |
| 80 acceptor_.get(), | |
| 81 "log_prefix")); | |
| 82 | |
| 83 interface_.reset(new HttpSM(connection_.get(), | |
| 84 mock_another_interface_.get(), | |
| 85 memory_cache_.get(), | |
| 86 acceptor_.get())); | |
| 87 } | |
| 88 | |
| 89 void TearDown() override { | |
| 90 if (acceptor_->listen_fd_ >= 0) { | |
| 91 epoll_server_->UnregisterFD(acceptor_->listen_fd_); | |
| 92 close(acceptor_->listen_fd_); | |
| 93 acceptor_->listen_fd_ = -1; | |
| 94 } | |
| 95 STLDeleteElements(connection_->output_list()); | |
| 96 } | |
| 97 | |
| 98 bool HasStream(uint32_t stream_id) { | |
| 99 return interface_->output_ordering().ExistsInPriorityMaps(stream_id); | |
| 100 } | |
| 101 | |
| 102 protected: | |
| 103 std::unique_ptr<MockSMInterface> mock_another_interface_; | |
| 104 std::unique_ptr<MemoryCache> memory_cache_; | |
| 105 std::unique_ptr<FlipAcceptor> acceptor_; | |
| 106 std::unique_ptr<EpollServer> epoll_server_; | |
| 107 std::unique_ptr<MockSMConnection> connection_; | |
| 108 std::unique_ptr<HttpSM> interface_; | |
| 109 }; | |
| 110 | |
| 111 class FlipHttpSMProxyTest : public FlipHttpSMTest { | |
| 112 public: | |
| 113 FlipHttpSMProxyTest() : FlipHttpSMTest(FLIP_HANDLER_PROXY) {} | |
| 114 ~FlipHttpSMProxyTest() override {} | |
| 115 }; | |
| 116 | |
| 117 class FlipHttpSMHttpTest : public FlipHttpSMTest { | |
| 118 public: | |
| 119 FlipHttpSMHttpTest() : FlipHttpSMTest(FLIP_HANDLER_HTTP_SERVER) {} | |
| 120 ~FlipHttpSMHttpTest() override {} | |
| 121 }; | |
| 122 | |
| 123 class FlipHttpSMSpdyTest : public FlipHttpSMTest { | |
| 124 public: | |
| 125 FlipHttpSMSpdyTest() : FlipHttpSMTest(FLIP_HANDLER_SPDY_SERVER) {} | |
| 126 ~FlipHttpSMSpdyTest() override {} | |
| 127 }; | |
| 128 | |
| 129 TEST_F(FlipHttpSMTest, Construct) { | |
| 130 ASSERT_FALSE(interface_->spdy_framer()->is_request()); | |
| 131 } | |
| 132 | |
| 133 TEST_F(FlipHttpSMTest, AddToOutputOrder) { | |
| 134 uint32_t stream_id = 13; | |
| 135 MemCacheIter mci; | |
| 136 mci.stream_id = stream_id; | |
| 137 | |
| 138 { | |
| 139 BalsaHeaders headers; | |
| 140 std::string filename = "foobar"; | |
| 141 memory_cache_->InsertFile(&headers, filename, ""); | |
| 142 mci.file_data = memory_cache_->GetFileData(filename); | |
| 143 } | |
| 144 | |
| 145 interface_->AddToOutputOrder(mci); | |
| 146 ASSERT_TRUE(HasStream(stream_id)); | |
| 147 } | |
| 148 | |
| 149 TEST_F(FlipHttpSMTest, InitSMInterface) { | |
| 150 std::unique_ptr<MockSMInterface> mock(new MockSMInterface); | |
| 151 { | |
| 152 InSequence s; | |
| 153 EXPECT_CALL(*mock_another_interface_, SendEOF(_)); | |
| 154 EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)); | |
| 155 EXPECT_CALL(*mock, SendEOF(_)); | |
| 156 EXPECT_CALL(*mock, ResetForNewInterface(_)); | |
| 157 } | |
| 158 | |
| 159 interface_->ResetForNewConnection(); | |
| 160 interface_->InitSMInterface(mock.get(), 0); | |
| 161 interface_->ResetForNewConnection(); | |
| 162 } | |
| 163 | |
| 164 TEST_F(FlipHttpSMTest, InitSMConnection) { | |
| 165 EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _)); | |
| 166 | |
| 167 interface_->InitSMConnection(NULL, NULL, NULL, 0, "", "", "", false); | |
| 168 } | |
| 169 | |
| 170 TEST_F(FlipHttpSMTest, ProcessReadInput) { | |
| 171 std::string data = | |
| 172 "HTTP/1.1 200 OK\r\n" | |
| 173 "Content-Length: 14\r\n\r\n" | |
| 174 "hello, world\r\n"; | |
| 175 testing::MockFunction<void(int)> checkpoint; // NOLINT | |
| 176 { | |
| 177 InSequence s; | |
| 178 EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _)); | |
| 179 EXPECT_CALL(checkpoint, Call(0)); | |
| 180 EXPECT_CALL(*mock_another_interface_, SendDataFrame(_, _, _, _, _)); | |
| 181 EXPECT_CALL(*mock_another_interface_, SendEOF(_)); | |
| 182 } | |
| 183 | |
| 184 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE, | |
| 185 interface_->spdy_framer()->ParseState()); | |
| 186 | |
| 187 size_t read = interface_->ProcessReadInput(data.data(), data.size()); | |
| 188 ASSERT_EQ(39u, read); | |
| 189 checkpoint.Call(0); | |
| 190 read += interface_->ProcessReadInput(&data.data()[read], data.size() - read); | |
| 191 ASSERT_EQ(data.size(), read); | |
| 192 ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ, | |
| 193 interface_->spdy_framer()->ParseState()); | |
| 194 ASSERT_TRUE(interface_->MessageFullyRead()); | |
| 195 } | |
| 196 | |
| 197 TEST_F(FlipHttpSMTest, ProcessWriteInput) { | |
| 198 std::string data = "hello, world"; | |
| 199 interface_->ProcessWriteInput(data.data(), data.size()); | |
| 200 | |
| 201 ASSERT_EQ(1u, connection_->output_list()->size()); | |
| 202 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin(); | |
| 203 DataFrame* df = *i++; | |
| 204 ASSERT_EQ(data, StringPiece(df->data, df->size)); | |
| 205 ASSERT_EQ(connection_->output_list()->end(), i); | |
| 206 } | |
| 207 | |
| 208 TEST_F(FlipHttpSMTest, Reset) { | |
| 209 std::string data = "HTTP/1.1 200 OK\r\n\r\n"; | |
| 210 testing::MockFunction<void(int)> checkpoint; // NOLINT | |
| 211 { | |
| 212 InSequence s; | |
| 213 EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _)); | |
| 214 EXPECT_CALL(checkpoint, Call(0)); | |
| 215 } | |
| 216 | |
| 217 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE, | |
| 218 interface_->spdy_framer()->ParseState()); | |
| 219 | |
| 220 interface_->ProcessReadInput(data.data(), data.size()); | |
| 221 checkpoint.Call(0); | |
| 222 ASSERT_FALSE(interface_->MessageFullyRead()); | |
| 223 ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE, | |
| 224 interface_->spdy_framer()->ParseState()); | |
| 225 | |
| 226 interface_->Reset(); | |
| 227 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE, | |
| 228 interface_->spdy_framer()->ParseState()); | |
| 229 } | |
| 230 | |
| 231 TEST_F(FlipHttpSMTest, ResetForNewConnection) { | |
| 232 std::string data = "HTTP/1.1 200 OK\r\n\r\n"; | |
| 233 testing::MockFunction<void(int)> checkpoint; // NOLINT | |
| 234 { | |
| 235 InSequence s; | |
| 236 EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _)); | |
| 237 EXPECT_CALL(checkpoint, Call(0)); | |
| 238 EXPECT_CALL(*mock_another_interface_, SendEOF(_)); | |
| 239 EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)); | |
| 240 } | |
| 241 | |
| 242 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE, | |
| 243 interface_->spdy_framer()->ParseState()); | |
| 244 | |
| 245 interface_->ProcessReadInput(data.data(), data.size()); | |
| 246 checkpoint.Call(0); | |
| 247 ASSERT_FALSE(interface_->MessageFullyRead()); | |
| 248 ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE, | |
| 249 interface_->spdy_framer()->ParseState()); | |
| 250 | |
| 251 interface_->ResetForNewConnection(); | |
| 252 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE, | |
| 253 interface_->spdy_framer()->ParseState()); | |
| 254 } | |
| 255 | |
| 256 TEST_F(FlipHttpSMTest, NewStream) { | |
| 257 uint32_t stream_id = 4; | |
| 258 { | |
| 259 BalsaHeaders headers; | |
| 260 std::string filename = "foobar"; | |
| 261 memory_cache_->InsertFile(&headers, filename, ""); | |
| 262 } | |
| 263 | |
| 264 interface_->NewStream(stream_id, 1, "foobar"); | |
| 265 ASSERT_TRUE(HasStream(stream_id)); | |
| 266 } | |
| 267 | |
| 268 TEST_F(FlipHttpSMTest, NewStreamError) { | |
| 269 std::string syn_reply = | |
| 270 "HTTP/1.1 404 Not Found\r\n" | |
| 271 "transfer-encoding: chunked\r\n\r\n"; | |
| 272 std::string body = "e\r\npage not found\r\n"; | |
| 273 uint32_t stream_id = 4; | |
| 274 | |
| 275 ASSERT_FALSE(HasStream(stream_id)); | |
| 276 interface_->NewStream(stream_id, 1, "foobar"); | |
| 277 | |
| 278 ASSERT_EQ(3u, connection_->output_list()->size()); | |
| 279 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin(); | |
| 280 DataFrame* df = *i++; | |
| 281 ASSERT_EQ(syn_reply, StringPiece(df->data, df->size)); | |
| 282 df = *i++; | |
| 283 ASSERT_EQ(body, StringPiece(df->data, df->size)); | |
| 284 df = *i++; | |
| 285 ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size)); | |
| 286 ASSERT_FALSE(HasStream(stream_id)); | |
| 287 } | |
| 288 | |
| 289 TEST_F(FlipHttpSMTest, SendErrorNotFound) { | |
| 290 std::string syn_reply = | |
| 291 "HTTP/1.1 404 Not Found\r\n" | |
| 292 "transfer-encoding: chunked\r\n\r\n"; | |
| 293 std::string body = "e\r\npage not found\r\n"; | |
| 294 uint32_t stream_id = 13; | |
| 295 MemCacheIter mci; | |
| 296 mci.stream_id = stream_id; | |
| 297 | |
| 298 { | |
| 299 BalsaHeaders headers; | |
| 300 std::string filename = "foobar"; | |
| 301 memory_cache_->InsertFile(&headers, filename, ""); | |
| 302 mci.file_data = memory_cache_->GetFileData(filename); | |
| 303 } | |
| 304 | |
| 305 interface_->AddToOutputOrder(mci); | |
| 306 ASSERT_TRUE(HasStream(stream_id)); | |
| 307 interface_->SendErrorNotFound(stream_id); | |
| 308 | |
| 309 ASSERT_EQ(3u, connection_->output_list()->size()); | |
| 310 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin(); | |
| 311 DataFrame* df = *i++; | |
| 312 ASSERT_EQ(syn_reply, StringPiece(df->data, df->size)); | |
| 313 df = *i++; | |
| 314 ASSERT_EQ(body, StringPiece(df->data, df->size)); | |
| 315 df = *i++; | |
| 316 ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size)); | |
| 317 ASSERT_FALSE(HasStream(stream_id)); | |
| 318 } | |
| 319 | |
| 320 TEST_F(FlipHttpSMTest, SendSynStream) { | |
| 321 std::string expected = | |
| 322 "GET / HTTP/1.0\r\n" | |
| 323 "key1: value1\r\n\r\n"; | |
| 324 BalsaHeaders headers; | |
| 325 headers.SetResponseFirstlineFromStringPieces("GET", "/path", "HTTP/1.0"); | |
| 326 headers.AppendHeader("key1", "value1"); | |
| 327 interface_->SendSynStream(18, headers); | |
| 328 | |
| 329 // TODO(yhirano): Is this behavior correct? | |
| 330 ASSERT_EQ(0u, connection_->output_list()->size()); | |
| 331 } | |
| 332 | |
| 333 TEST_F(FlipHttpSMTest, SendSynReply) { | |
| 334 std::string expected = | |
| 335 "HTTP/1.1 200 OK\r\n" | |
| 336 "key1: value1\r\n\r\n"; | |
| 337 BalsaHeaders headers; | |
| 338 headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK"); | |
| 339 headers.AppendHeader("key1", "value1"); | |
| 340 interface_->SendSynReply(18, headers); | |
| 341 | |
| 342 ASSERT_EQ(1u, connection_->output_list()->size()); | |
| 343 DataFrame* df = connection_->output_list()->front(); | |
| 344 ASSERT_EQ(expected, StringPiece(df->data, df->size)); | |
| 345 } | |
| 346 | |
| 347 TEST_F(FlipHttpSMTest, SendDataFrame) { | |
| 348 std::string data = "foo bar baz"; | |
| 349 interface_->SendDataFrame(12, data.data(), data.size(), 0, false); | |
| 350 | |
| 351 ASSERT_EQ(1u, connection_->output_list()->size()); | |
| 352 DataFrame* df = connection_->output_list()->front(); | |
| 353 ASSERT_EQ("b\r\nfoo bar baz\r\n", StringPiece(df->data, df->size)); | |
| 354 } | |
| 355 | |
| 356 TEST_F(FlipHttpSMProxyTest, ProcessBodyData) { | |
| 357 BalsaVisitorInterface* visitor = interface_.get(); | |
| 358 std::string data = "hello, world"; | |
| 359 { | |
| 360 InSequence s; | |
| 361 EXPECT_CALL(*mock_another_interface_, | |
| 362 SendDataFrame(0, data.data(), data.size(), 0, false)); | |
| 363 } | |
| 364 visitor->ProcessBodyData(data.data(), data.size()); | |
| 365 } | |
| 366 | |
| 367 // -- | |
| 368 // FlipHttpSMProxyTest | |
| 369 | |
| 370 TEST_F(FlipHttpSMProxyTest, ProcessHeaders) { | |
| 371 BalsaVisitorInterface* visitor = interface_.get(); | |
| 372 { | |
| 373 InSequence s; | |
| 374 EXPECT_CALL(*mock_another_interface_, SendSynReply(0, _)); | |
| 375 } | |
| 376 BalsaHeaders headers; | |
| 377 visitor->ProcessHeaders(headers); | |
| 378 } | |
| 379 | |
| 380 TEST_F(FlipHttpSMProxyTest, MessageDone) { | |
| 381 BalsaVisitorInterface* visitor = interface_.get(); | |
| 382 { | |
| 383 InSequence s; | |
| 384 EXPECT_CALL(*mock_another_interface_, SendEOF(0)); | |
| 385 } | |
| 386 visitor->MessageDone(); | |
| 387 } | |
| 388 | |
| 389 TEST_F(FlipHttpSMProxyTest, Cleanup) { | |
| 390 EXPECT_CALL(*connection_, Cleanup()).Times(0); | |
| 391 interface_->Cleanup(); | |
| 392 } | |
| 393 | |
| 394 TEST_F(FlipHttpSMProxyTest, SendEOF) { | |
| 395 { | |
| 396 InSequence s; | |
| 397 EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)); | |
| 398 } | |
| 399 interface_->SendEOF(32); | |
| 400 ASSERT_EQ(1u, connection_->output_list()->size()); | |
| 401 DataFrame* df = connection_->output_list()->front(); | |
| 402 ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size)); | |
| 403 } | |
| 404 | |
| 405 // -- | |
| 406 // FlipHttpSMHttpTest | |
| 407 | |
| 408 TEST_F(FlipHttpSMHttpTest, ProcessHeaders) { | |
| 409 BalsaVisitorInterface* visitor = interface_.get(); | |
| 410 { | |
| 411 BalsaHeaders headers; | |
| 412 std::string filename = "GET_/path/file"; | |
| 413 memory_cache_->InsertFile(&headers, filename, ""); | |
| 414 } | |
| 415 | |
| 416 BalsaHeaders headers; | |
| 417 headers.AppendHeader("Host", "example.com"); | |
| 418 headers.SetRequestFirstlineFromStringPieces("GET", "/path/file", "HTTP/1.0"); | |
| 419 uint32_t stream_id = 133; | |
| 420 interface_->SetStreamID(stream_id); | |
| 421 ASSERT_FALSE(HasStream(stream_id)); | |
| 422 visitor->ProcessHeaders(headers); | |
| 423 ASSERT_TRUE(HasStream(stream_id)); | |
| 424 } | |
| 425 | |
| 426 TEST_F(FlipHttpSMHttpTest, MessageDone) { | |
| 427 BalsaVisitorInterface* visitor = interface_.get(); | |
| 428 { | |
| 429 InSequence s; | |
| 430 EXPECT_CALL(*mock_another_interface_, SendEOF(0)).Times(0); | |
| 431 } | |
| 432 visitor->MessageDone(); | |
| 433 } | |
| 434 | |
| 435 TEST_F(FlipHttpSMHttpTest, Cleanup) { | |
| 436 EXPECT_CALL(*connection_, Cleanup()).Times(0); | |
| 437 interface_->Cleanup(); | |
| 438 } | |
| 439 | |
| 440 TEST_F(FlipHttpSMHttpTest, SendEOF) { | |
| 441 { | |
| 442 InSequence s; | |
| 443 EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)).Times(0); | |
| 444 } | |
| 445 interface_->SendEOF(32); | |
| 446 ASSERT_EQ(1u, connection_->output_list()->size()); | |
| 447 DataFrame* df = connection_->output_list()->front(); | |
| 448 ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size)); | |
| 449 } | |
| 450 | |
| 451 // -- | |
| 452 // FlipHttpSMSpdyTest | |
| 453 | |
| 454 TEST_F(FlipHttpSMSpdyTest, ProcessHeaders) { | |
| 455 BalsaVisitorInterface* visitor = interface_.get(); | |
| 456 { | |
| 457 InSequence s; | |
| 458 EXPECT_CALL(*mock_another_interface_, SendSynReply(0, _)); | |
| 459 } | |
| 460 BalsaHeaders headers; | |
| 461 visitor->ProcessHeaders(headers); | |
| 462 } | |
| 463 | |
| 464 TEST_F(FlipHttpSMSpdyTest, MessageDone) { | |
| 465 BalsaVisitorInterface* visitor = interface_.get(); | |
| 466 { | |
| 467 InSequence s; | |
| 468 EXPECT_CALL(*mock_another_interface_, SendEOF(0)).Times(0); | |
| 469 } | |
| 470 visitor->MessageDone(); | |
| 471 } | |
| 472 | |
| 473 TEST_F(FlipHttpSMSpdyTest, Cleanup) { | |
| 474 EXPECT_CALL(*connection_, Cleanup()).Times(0); | |
| 475 interface_->Cleanup(); | |
| 476 } | |
| 477 | |
| 478 TEST_F(FlipHttpSMSpdyTest, SendEOF) { | |
| 479 { | |
| 480 InSequence s; | |
| 481 EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)).Times(0); | |
| 482 } | |
| 483 interface_->SendEOF(32); | |
| 484 ASSERT_EQ(1u, connection_->output_list()->size()); | |
| 485 DataFrame* df = connection_->output_list()->front(); | |
| 486 ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size)); | |
| 487 } | |
| 488 | |
| 489 } // namespace | |
| 490 | |
| 491 } // namespace net | |
| OLD | NEW |