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 |