// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <windows.h> #include <wininet.h> #include "base/basictypes.h" #include "base/bind.h" #include "base/path_service.h" #include "base/strings/stringprintf.h" #include "base/win/scoped_handle.h" #include "chrome_frame/test/test_server.h" #include "net/base/request_priority.h" #include "net/cookies/cookie_monster.h" #include "net/disk_cache/disk_cache.h" #include "net/dns/host_resolver_proc.h" #include "net/http/http_auth_handler_factory.h" #include "net/http/http_cache.h" #include "net/http/http_network_session.h" #include "net/proxy/proxy_service.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" class TestServerTest: public testing::Test { protected: virtual void SetUp() { PathService::Get(base::DIR_SOURCE_ROOT, &source_path_); source_path_ = source_path_.Append(FILE_PATH_LITERAL("chrome_frame")); } virtual void TearDown() { } public: const base::FilePath& source_path() const { return source_path_; } protected: base::FilePath source_path_; }; namespace { class ScopedInternet { public: explicit ScopedInternet(HINTERNET handle) : h_(handle) { } ~ScopedInternet() { if (h_) { InternetCloseHandle(h_); } } operator HINTERNET() { return h_; } protected: HINTERNET h_; }; class TestURLRequest : public net::URLRequest { public: TestURLRequest(const GURL& url, net::RequestPriority priority, Delegate* delegate, const net::TestURLRequestContext* context) : net::URLRequest(url, priority, delegate, context) {} }; class UrlTaskChain { public: UrlTaskChain(const std::string& url, UrlTaskChain* next) : url_(url), next_(next) { } void Run() { EXPECT_EQ(0, delegate_.response_started_count()); base::MessageLoopForIO loop; net::TestURLRequestContext context; TestURLRequest r(GURL(url_), net::DEFAULT_PRIORITY, &delegate_, &context); r.Start(); EXPECT_TRUE(r.is_pending()); base::MessageLoop::current()->Run(); EXPECT_EQ(1, delegate_.response_started_count()); EXPECT_FALSE(delegate_.received_data_before_response()); EXPECT_NE(0, delegate_.bytes_received()); } UrlTaskChain* next() const { return next_; } const std::string& response() const { return delegate_.data_received(); } protected: std::string url_; net::TestDelegate delegate_; UrlTaskChain* next_; }; DWORD WINAPI FetchUrl(void* param) { UrlTaskChain* task = reinterpret_cast<UrlTaskChain*>(param); while (task != NULL) { task->Run(); task = task->next(); } return 0; } struct QuitMessageHit { explicit QuitMessageHit(base::MessageLoopForUI* loop) : loop_(loop), hit_(false) {} base::MessageLoopForUI* loop_; bool hit_; }; void QuitMessageLoop(QuitMessageHit* msg) { msg->hit_ = true; msg->loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); } } // end namespace TEST_F(TestServerTest, TestServer) { // The web server needs a loop to exist on this thread during construction // the loop must be created before we construct the server. base::MessageLoopForUI loop; test_server::SimpleWebServer server(1337); test_server::SimpleWebServer redirected_server(server.host(), 1338); test_server::SimpleResponse person("/person", "Guthrie Govan!"); server.AddResponse(&person); test_server::FileResponse file("/file", source_path().Append( FILE_PATH_LITERAL("CFInstance.js"))); server.AddResponse(&file); test_server::RedirectResponse redir( "/redir", base::StringPrintf("http://%s:1338/dest", redirected_server.host().c_str())); server.AddResponse(&redir); test_server::SimpleResponse dest("/dest", "Destination"); redirected_server.AddResponse(&dest); // We should never hit this, but it's our way to break out of the test if // things start hanging. QuitMessageHit quit_msg(&loop); loop.PostDelayedTask(FROM_HERE, base::Bind(QuitMessageLoop, &quit_msg), base::TimeDelta::FromSeconds(10)); UrlTaskChain quit_task( base::StringPrintf("http://%s:1337/quit", server.host().c_str()), NULL); UrlTaskChain fnf_task( base::StringPrintf("http://%s:1337/404", server.host().c_str()), &quit_task); UrlTaskChain person_task( base::StringPrintf("http://%s:1337/person", server.host().c_str()), &fnf_task); UrlTaskChain file_task( base::StringPrintf("http://%s:1337/file", server.host().c_str()), &person_task); UrlTaskChain redir_task( base::StringPrintf("http://%s:1337/redir", server.host().c_str()), &file_task); DWORD tid = 0; base::win::ScopedHandle worker(::CreateThread( NULL, 0, FetchUrl, &redir_task, 0, &tid)); loop.base::MessageLoop::Run(); EXPECT_FALSE(quit_msg.hit_); if (!quit_msg.hit_) { EXPECT_EQ(::WaitForSingleObject(worker, 10 * 1000), WAIT_OBJECT_0); EXPECT_EQ(person.accessed(), 1); EXPECT_EQ(file.accessed(), 1); EXPECT_EQ(redir.accessed(), 1); EXPECT_TRUE(person_task.response().find("Guthrie") != std::string::npos); EXPECT_TRUE(file_task.response().find("function") != std::string::npos); EXPECT_TRUE(redir_task.response().find("Destination") != std::string::npos); } else { ::TerminateThread(worker, ~0); } }