| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2008 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 "base/thread.h" | |
| 6 #include "base/time.h" | |
| 7 #include "chrome/browser/url_fetcher.h" | |
| 8 #include "chrome/browser/url_fetcher_protect.h" | |
| 9 #if defined(OS_LINUX) | |
| 10 // TODO(port): ugly hack for linux | |
| 11 namespace ChromePluginLib { | |
| 12 void UnloadAllPlugins() {} | |
| 13 } | |
| 14 #else | |
| 15 #include "chrome/common/chrome_plugin_lib.h" | |
| 16 #endif | |
| 17 #include "net/base/ssl_test_util.h" | |
| 18 #include "net/url_request/url_request_unittest.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 | |
| 21 using base::Time; | |
| 22 using base::TimeDelta; | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 const wchar_t kDocRoot[] = L"chrome/test/data"; | |
| 27 | |
| 28 class URLFetcherTest : public testing::Test, public URLFetcher::Delegate { | |
| 29 public: | |
| 30 URLFetcherTest() : fetcher_(NULL) { } | |
| 31 | |
| 32 // Creates a URLFetcher, using the program's main thread to do IO. | |
| 33 virtual void CreateFetcher(const GURL& url); | |
| 34 | |
| 35 // URLFetcher::Delegate | |
| 36 virtual void OnURLFetchComplete(const URLFetcher* source, | |
| 37 const GURL& url, | |
| 38 const URLRequestStatus& status, | |
| 39 int response_code, | |
| 40 const ResponseCookies& cookies, | |
| 41 const std::string& data); | |
| 42 | |
| 43 protected: | |
| 44 virtual void SetUp() { | |
| 45 testing::Test::SetUp(); | |
| 46 | |
| 47 // Ensure that any plugin operations done by other tests are cleaned up. | |
| 48 ChromePluginLib::UnloadAllPlugins(); | |
| 49 } | |
| 50 | |
| 51 // URLFetcher is designed to run on the main UI thread, but in our tests | |
| 52 // we assume that the current thread is the IO thread where the URLFetcher | |
| 53 // dispatches its requests to. When we wish to simulate being used from | |
| 54 // a UI thread, we dispatch a worker thread to do so. | |
| 55 MessageLoopForIO io_loop_; | |
| 56 | |
| 57 URLFetcher* fetcher_; | |
| 58 }; | |
| 59 | |
| 60 // Version of URLFetcherTest that does a POST instead | |
| 61 class URLFetcherPostTest : public URLFetcherTest { | |
| 62 public: | |
| 63 virtual void CreateFetcher(const GURL& url); | |
| 64 | |
| 65 // URLFetcher::Delegate | |
| 66 virtual void OnURLFetchComplete(const URLFetcher* source, | |
| 67 const GURL& url, | |
| 68 const URLRequestStatus& status, | |
| 69 int response_code, | |
| 70 const ResponseCookies& cookies, | |
| 71 const std::string& data); | |
| 72 }; | |
| 73 | |
| 74 // Version of URLFetcherTest that tests headers. | |
| 75 class URLFetcherHeadersTest : public URLFetcherTest { | |
| 76 public: | |
| 77 // URLFetcher::Delegate | |
| 78 virtual void OnURLFetchComplete(const URLFetcher* source, | |
| 79 const GURL& url, | |
| 80 const URLRequestStatus& status, | |
| 81 int response_code, | |
| 82 const ResponseCookies& cookies, | |
| 83 const std::string& data); | |
| 84 }; | |
| 85 | |
| 86 // Version of URLFetcherTest that tests overload proctection. | |
| 87 class URLFetcherProtectTest : public URLFetcherTest { | |
| 88 public: | |
| 89 virtual void CreateFetcher(const GURL& url); | |
| 90 // URLFetcher::Delegate | |
| 91 virtual void OnURLFetchComplete(const URLFetcher* source, | |
| 92 const GURL& url, | |
| 93 const URLRequestStatus& status, | |
| 94 int response_code, | |
| 95 const ResponseCookies& cookies, | |
| 96 const std::string& data); | |
| 97 private: | |
| 98 Time start_time_; | |
| 99 }; | |
| 100 | |
| 101 // Version of URLFetcherTest that tests bad HTTPS requests. | |
| 102 class URLFetcherBadHTTPSTest : public URLFetcherTest { | |
| 103 public: | |
| 104 URLFetcherBadHTTPSTest(); | |
| 105 | |
| 106 // URLFetcher::Delegate | |
| 107 virtual void OnURLFetchComplete(const URLFetcher* source, | |
| 108 const GURL& url, | |
| 109 const URLRequestStatus& status, | |
| 110 int response_code, | |
| 111 const ResponseCookies& cookies, | |
| 112 const std::string& data); | |
| 113 | |
| 114 protected: | |
| 115 FilePath GetExpiredCertPath(); | |
| 116 SSLTestUtil util_; | |
| 117 | |
| 118 private: | |
| 119 FilePath cert_dir_; | |
| 120 }; | |
| 121 | |
| 122 // Version of URLFetcherTest that tests request cancellation on shutdown. | |
| 123 class URLFetcherCancelTest : public URLFetcherTest { | |
| 124 public: | |
| 125 virtual void CreateFetcher(const GURL& url); | |
| 126 // URLFetcher::Delegate | |
| 127 virtual void OnURLFetchComplete(const URLFetcher* source, | |
| 128 const GURL& url, | |
| 129 const URLRequestStatus& status, | |
| 130 int response_code, | |
| 131 const ResponseCookies& cookies, | |
| 132 const std::string& data); | |
| 133 | |
| 134 void CancelRequest(); | |
| 135 void TestContextReleased(); | |
| 136 | |
| 137 private: | |
| 138 base::OneShotTimer<URLFetcherCancelTest> timer_; | |
| 139 bool context_released_; | |
| 140 }; | |
| 141 | |
| 142 // Version of TestURLRequestContext that let us know if the request context | |
| 143 // is properly released. | |
| 144 class CancelTestURLRequestContext : public TestURLRequestContext { | |
| 145 public: | |
| 146 explicit CancelTestURLRequestContext(bool* destructor_called) | |
| 147 : destructor_called_(destructor_called) { | |
| 148 *destructor_called_ = false; | |
| 149 } | |
| 150 | |
| 151 virtual ~CancelTestURLRequestContext() { | |
| 152 *destructor_called_ = true; | |
| 153 } | |
| 154 | |
| 155 private: | |
| 156 bool* destructor_called_; | |
| 157 }; | |
| 158 | |
| 159 // Wrapper that lets us call CreateFetcher() on a thread of our choice. We | |
| 160 // could make URLFetcherTest refcounted and use PostTask(FROM_HERE.. ) to call | |
| 161 // CreateFetcher() directly, but the ownership of the URLFetcherTest is a bit | |
| 162 // confusing in that case because GTest doesn't know about the refcounting. | |
| 163 // It's less confusing to just do it this way. | |
| 164 class FetcherWrapperTask : public Task { | |
| 165 public: | |
| 166 FetcherWrapperTask(URLFetcherTest* test, const GURL& url) | |
| 167 : test_(test), url_(url) { } | |
| 168 virtual void Run() { | |
| 169 test_->CreateFetcher(url_); | |
| 170 }; | |
| 171 | |
| 172 private: | |
| 173 URLFetcherTest* test_; | |
| 174 GURL url_; | |
| 175 }; | |
| 176 | |
| 177 void URLFetcherTest::CreateFetcher(const GURL& url) { | |
| 178 fetcher_ = new URLFetcher(url, URLFetcher::GET, this); | |
| 179 fetcher_->set_request_context(new TestURLRequestContext()); | |
| 180 fetcher_->set_io_loop(&io_loop_); | |
| 181 fetcher_->Start(); | |
| 182 } | |
| 183 | |
| 184 void URLFetcherTest::OnURLFetchComplete(const URLFetcher* source, | |
| 185 const GURL& url, | |
| 186 const URLRequestStatus& status, | |
| 187 int response_code, | |
| 188 const ResponseCookies& cookies, | |
| 189 const std::string& data) { | |
| 190 EXPECT_TRUE(status.is_success()); | |
| 191 EXPECT_EQ(200, response_code); // HTTP OK | |
| 192 EXPECT_FALSE(data.empty()); | |
| 193 | |
| 194 delete fetcher_; // Have to delete this here and not in the destructor, | |
| 195 // because the destructor won't necessarily run on the | |
| 196 // same thread that CreateFetcher() did. | |
| 197 | |
| 198 io_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask()); | |
| 199 // If MessageLoop::current() != io_loop_, it will be shut down when the | |
| 200 // main loop returns and this thread subsequently goes out of scope. | |
| 201 } | |
| 202 | |
| 203 void URLFetcherPostTest::CreateFetcher(const GURL& url) { | |
| 204 fetcher_ = new URLFetcher(url, URLFetcher::POST, this); | |
| 205 fetcher_->set_request_context(new TestURLRequestContext()); | |
| 206 fetcher_->set_io_loop(&io_loop_); | |
| 207 fetcher_->set_upload_data("application/x-www-form-urlencoded", | |
| 208 "bobsyeruncle"); | |
| 209 fetcher_->Start(); | |
| 210 } | |
| 211 | |
| 212 void URLFetcherPostTest::OnURLFetchComplete(const URLFetcher* source, | |
| 213 const GURL& url, | |
| 214 const URLRequestStatus& status, | |
| 215 int response_code, | |
| 216 const ResponseCookies& cookies, | |
| 217 const std::string& data) { | |
| 218 EXPECT_EQ(std::string("bobsyeruncle"), data); | |
| 219 URLFetcherTest::OnURLFetchComplete(source, url, status, response_code, | |
| 220 cookies, data); | |
| 221 } | |
| 222 | |
| 223 void URLFetcherHeadersTest::OnURLFetchComplete( | |
| 224 const URLFetcher* source, | |
| 225 const GURL& url, | |
| 226 const URLRequestStatus& status, | |
| 227 int response_code, | |
| 228 const ResponseCookies& cookies, | |
| 229 const std::string& data) { | |
| 230 std::string header; | |
| 231 EXPECT_TRUE(source->response_headers()->GetNormalizedHeader("cache-control", | |
| 232 &header)); | |
| 233 EXPECT_EQ("private", header); | |
| 234 URLFetcherTest::OnURLFetchComplete(source, url, status, response_code, | |
| 235 cookies, data); | |
| 236 } | |
| 237 | |
| 238 void URLFetcherProtectTest::CreateFetcher(const GURL& url) { | |
| 239 fetcher_ = new URLFetcher(url, URLFetcher::GET, this); | |
| 240 fetcher_->set_request_context(new TestURLRequestContext()); | |
| 241 fetcher_->set_io_loop(&io_loop_); | |
| 242 start_time_ = Time::Now(); | |
| 243 fetcher_->Start(); | |
| 244 } | |
| 245 | |
| 246 void URLFetcherProtectTest::OnURLFetchComplete(const URLFetcher* source, | |
| 247 const GURL& url, | |
| 248 const URLRequestStatus& status, | |
| 249 int response_code, | |
| 250 const ResponseCookies& cookies, | |
| 251 const std::string& data) { | |
| 252 const TimeDelta one_second = TimeDelta::FromMilliseconds(1000); | |
| 253 if (response_code >= 500) { | |
| 254 // Now running ServerUnavailable test. | |
| 255 // It takes more than 1 second to finish all 11 requests. | |
| 256 EXPECT_TRUE(Time::Now() - start_time_ >= one_second); | |
| 257 EXPECT_TRUE(status.is_success()); | |
| 258 EXPECT_FALSE(data.empty()); | |
| 259 delete fetcher_; | |
| 260 io_loop_.Quit(); | |
| 261 } else { | |
| 262 // Now running Overload test. | |
| 263 static int count = 0; | |
| 264 count++; | |
| 265 if (count < 20) { | |
| 266 fetcher_->Start(); | |
| 267 } else { | |
| 268 // We have already sent 20 requests continuously. And we expect that | |
| 269 // it takes more than 1 second due to the overload pretection settings. | |
| 270 EXPECT_TRUE(Time::Now() - start_time_ >= one_second); | |
| 271 URLFetcherTest::OnURLFetchComplete(source, url, status, response_code, | |
| 272 cookies, data); | |
| 273 } | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 URLFetcherBadHTTPSTest::URLFetcherBadHTTPSTest() { | |
| 278 PathService::Get(base::DIR_SOURCE_ROOT, &cert_dir_); | |
| 279 cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("chrome")); | |
| 280 cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("test")); | |
| 281 cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("data")); | |
| 282 cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("ssl")); | |
| 283 cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("certificates")); | |
| 284 } | |
| 285 | |
| 286 // The "server certificate expired" error should result in automatic | |
| 287 // cancellation of the request by | |
| 288 // URLRequest::Delegate::OnSSLCertificateError. | |
| 289 void URLFetcherBadHTTPSTest::OnURLFetchComplete( | |
| 290 const URLFetcher* source, | |
| 291 const GURL& url, | |
| 292 const URLRequestStatus& status, | |
| 293 int response_code, | |
| 294 const ResponseCookies& cookies, | |
| 295 const std::string& data) { | |
| 296 // This part is different from URLFetcherTest::OnURLFetchComplete | |
| 297 // because this test expects the request to be cancelled. | |
| 298 EXPECT_EQ(URLRequestStatus::CANCELED, status.status()); | |
| 299 EXPECT_EQ(net::ERR_ABORTED, status.os_error()); | |
| 300 EXPECT_EQ(-1, response_code); | |
| 301 EXPECT_TRUE(cookies.empty()); | |
| 302 EXPECT_TRUE(data.empty()); | |
| 303 | |
| 304 // The rest is the same as URLFetcherTest::OnURLFetchComplete. | |
| 305 delete fetcher_; | |
| 306 io_loop_.Quit(); | |
| 307 } | |
| 308 | |
| 309 FilePath URLFetcherBadHTTPSTest::GetExpiredCertPath() { | |
| 310 return cert_dir_.Append(FILE_PATH_LITERAL("expired_cert.pem")); | |
| 311 } | |
| 312 | |
| 313 void URLFetcherCancelTest::CreateFetcher(const GURL& url) { | |
| 314 fetcher_ = new URLFetcher(url, URLFetcher::GET, this); | |
| 315 fetcher_->set_request_context( | |
| 316 new CancelTestURLRequestContext(&context_released_)); | |
| 317 fetcher_->set_io_loop(&io_loop_); | |
| 318 fetcher_->Start(); | |
| 319 // Make sure we give the IO thread a chance to run. | |
| 320 timer_.Start(TimeDelta::FromMilliseconds(100), this, | |
| 321 &URLFetcherCancelTest::CancelRequest); | |
| 322 } | |
| 323 | |
| 324 void URLFetcherCancelTest::OnURLFetchComplete(const URLFetcher* source, | |
| 325 const GURL& url, | |
| 326 const URLRequestStatus& status, | |
| 327 int response_code, | |
| 328 const ResponseCookies& cookies, | |
| 329 const std::string& data) { | |
| 330 // We should have cancelled the request before completion. | |
| 331 ADD_FAILURE(); | |
| 332 delete fetcher_; | |
| 333 io_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask()); | |
| 334 } | |
| 335 | |
| 336 void URLFetcherCancelTest::CancelRequest() { | |
| 337 delete fetcher_; | |
| 338 timer_.Stop(); | |
| 339 // Make sure we give the IO thread a chance to run. | |
| 340 timer_.Start(TimeDelta::FromMilliseconds(100), this, | |
| 341 &URLFetcherCancelTest::TestContextReleased); | |
| 342 } | |
| 343 | |
| 344 void URLFetcherCancelTest::TestContextReleased() { | |
| 345 EXPECT_TRUE(context_released_); | |
| 346 timer_.Stop(); | |
| 347 io_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask()); | |
| 348 } | |
| 349 | |
| 350 } // namespace. | |
| 351 | |
| 352 TEST_F(URLFetcherTest, SameThreadsTest) { | |
| 353 // Create the fetcher on the main thread. Since IO will happen on the main | |
| 354 // thread, this will test URLFetcher's ability to do everything on one | |
| 355 // thread. | |
| 356 scoped_refptr<HTTPTestServer> server = | |
| 357 HTTPTestServer::CreateServer(kDocRoot); | |
| 358 ASSERT_TRUE(NULL != server.get()); | |
| 359 | |
| 360 CreateFetcher(GURL(server->TestServerPage("defaultresponse"))); | |
| 361 | |
| 362 MessageLoop::current()->Run(); | |
| 363 } | |
| 364 | |
| 365 TEST_F(URLFetcherTest, DifferentThreadsTest) { | |
| 366 scoped_refptr<HTTPTestServer> server = | |
| 367 HTTPTestServer::CreateServer(kDocRoot); | |
| 368 ASSERT_TRUE(NULL != server.get()); | |
| 369 // Create a separate thread that will create the URLFetcher. The current | |
| 370 // (main) thread will do the IO, and when the fetch is complete it will | |
| 371 // terminate the main thread's message loop; then the other thread's | |
| 372 // message loop will be shut down automatically as the thread goes out of | |
| 373 // scope. | |
| 374 base::Thread t("URLFetcher test thread"); | |
| 375 t.Start(); | |
| 376 t.message_loop()->PostTask(FROM_HERE, new FetcherWrapperTask(this, | |
| 377 GURL(server->TestServerPage("defaultresponse")))); | |
| 378 | |
| 379 MessageLoop::current()->Run(); | |
| 380 } | |
| 381 | |
| 382 TEST_F(URLFetcherPostTest, Basic) { | |
| 383 scoped_refptr<HTTPTestServer> server = | |
| 384 HTTPTestServer::CreateServer(kDocRoot); | |
| 385 ASSERT_TRUE(NULL != server.get()); | |
| 386 CreateFetcher(GURL(server->TestServerPage("echo"))); | |
| 387 MessageLoop::current()->Run(); | |
| 388 } | |
| 389 | |
| 390 TEST_F(URLFetcherHeadersTest, Headers) { | |
| 391 scoped_refptr<HTTPTestServer> server = | |
| 392 HTTPTestServer::CreateServer(L"net/data/url_request_unittest"); | |
| 393 ASSERT_TRUE(NULL != server.get()); | |
| 394 CreateFetcher(GURL(server->TestServerPage("files/with-headers.html"))); | |
| 395 MessageLoop::current()->Run(); | |
| 396 // The actual tests are in the URLFetcherHeadersTest fixture. | |
| 397 } | |
| 398 | |
| 399 TEST_F(URLFetcherProtectTest, Overload) { | |
| 400 scoped_refptr<HTTPTestServer> server = | |
| 401 HTTPTestServer::CreateServer(kDocRoot); | |
| 402 ASSERT_TRUE(NULL != server.get()); | |
| 403 GURL url = GURL(server->TestServerPage("defaultresponse")); | |
| 404 | |
| 405 // Registers an entry for test url. It only allows 3 requests to be sent | |
| 406 // in 200 milliseconds. | |
| 407 URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance(); | |
| 408 URLFetcherProtectEntry* entry = | |
| 409 new URLFetcherProtectEntry(200, 3, 11, 1, 2.0, 0, 256); | |
| 410 manager->Register(url.host(), entry); | |
| 411 | |
| 412 CreateFetcher(url); | |
| 413 | |
| 414 MessageLoop::current()->Run(); | |
| 415 } | |
| 416 | |
| 417 TEST_F(URLFetcherProtectTest, ServerUnavailable) { | |
| 418 scoped_refptr<HTTPTestServer> server = | |
| 419 HTTPTestServer::CreateServer(L"chrome/test/data"); | |
| 420 ASSERT_TRUE(NULL != server.get()); | |
| 421 GURL url = GURL(server->TestServerPage("files/server-unavailable.html")); | |
| 422 | |
| 423 // Registers an entry for test url. The backoff time is calculated by: | |
| 424 // new_backoff = 2.0 * old_backoff + 0 | |
| 425 // and maximum backoff time is 256 milliseconds. | |
| 426 // Maximum retries allowed is set to 11. | |
| 427 URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance(); | |
| 428 URLFetcherProtectEntry* entry = | |
| 429 new URLFetcherProtectEntry(200, 3, 11, 1, 2.0, 0, 256); | |
| 430 manager->Register(url.host(), entry); | |
| 431 | |
| 432 CreateFetcher(url); | |
| 433 | |
| 434 MessageLoop::current()->Run(); | |
| 435 } | |
| 436 | |
| 437 #if defined(OS_WIN) | |
| 438 TEST_F(URLFetcherBadHTTPSTest, BadHTTPSTest) { | |
| 439 #else | |
| 440 // TODO(port): Enable BadHTTPSTest. Currently asserts in | |
| 441 // URLFetcherBadHTTPSTest::OnURLFetchComplete don't pass. | |
| 442 TEST_F(URLFetcherBadHTTPSTest, DISABLED_BadHTTPSTest) { | |
| 443 #endif | |
| 444 scoped_refptr<HTTPSTestServer> server = | |
| 445 HTTPSTestServer::CreateServer(util_.kHostName, util_.kBadHTTPSPort, | |
| 446 kDocRoot, util_.GetExpiredCertPath().ToWStringHack()); | |
| 447 ASSERT_TRUE(NULL != server.get()); | |
| 448 | |
| 449 CreateFetcher(GURL(server->TestServerPage("defaultresponse"))); | |
| 450 | |
| 451 MessageLoop::current()->Run(); | |
| 452 } | |
| 453 | |
| 454 TEST_F(URLFetcherCancelTest, ReleasesContext) { | |
| 455 scoped_refptr<HTTPTestServer> server = | |
| 456 HTTPTestServer::CreateServer(L"chrome/test/data"); | |
| 457 ASSERT_TRUE(NULL != server.get()); | |
| 458 GURL url = GURL(server->TestServerPage("files/server-unavailable.html")); | |
| 459 | |
| 460 // Registers an entry for test url. The backoff time is calculated by: | |
| 461 // new_backoff = 2.0 * old_backoff + 0 | |
| 462 // The initial backoff is 2 seconds and maximum backoff is 4 seconds. | |
| 463 // Maximum retries allowed is set to 2. | |
| 464 URLFetcherProtectManager* manager = URLFetcherProtectManager::GetInstance(); | |
| 465 URLFetcherProtectEntry* entry = | |
| 466 new URLFetcherProtectEntry(200, 3, 2, 2000, 2.0, 0, 4000); | |
| 467 manager->Register(url.host(), entry); | |
| 468 | |
| 469 // Create a separate thread that will create the URLFetcher. The current | |
| 470 // (main) thread will do the IO, and when the fetch is complete it will | |
| 471 // terminate the main thread's message loop; then the other thread's | |
| 472 // message loop will be shut down automatically as the thread goes out of | |
| 473 // scope. | |
| 474 base::Thread t("URLFetcher test thread"); | |
| 475 t.Start(); | |
| 476 t.message_loop()->PostTask(FROM_HERE, new FetcherWrapperTask(this, url)); | |
| 477 | |
| 478 MessageLoop::current()->Run(); | |
| 479 } | |
| OLD | NEW |