// 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);
}
}