1// Copyright (c) 2011 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/message_loop_proxy.h" 6#include "base/threading/thread.h" 7#include "chrome/browser/sync/glue/http_bridge.h" 8#include "chrome/common/net/test_url_fetcher_factory.h" 9#include "chrome/test/test_url_request_context_getter.h" 10#include "content/browser/browser_thread.h" 11#include "net/url_request/url_request_test_util.h" 12#include "net/test/test_server.h" 13#include "testing/gtest/include/gtest/gtest.h" 14 15using browser_sync::HttpBridge; 16 17namespace { 18// TODO(timsteele): Should use PathService here. See Chromium Issue 3113. 19const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data"); 20} 21 22class HttpBridgeTest : public testing::Test { 23 public: 24 HttpBridgeTest() 25 : test_server_(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)), 26 fake_default_request_context_getter_(NULL), 27 io_thread_(BrowserThread::IO) { 28 } 29 30 virtual void SetUp() { 31 base::Thread::Options options; 32 options.message_loop_type = MessageLoop::TYPE_IO; 33 io_thread_.StartWithOptions(options); 34 } 35 36 virtual void TearDown() { 37 io_thread_loop()->ReleaseSoon(FROM_HERE, 38 fake_default_request_context_getter_); 39 io_thread_.Stop(); 40 fake_default_request_context_getter_ = NULL; 41 } 42 43 HttpBridge* BuildBridge() { 44 if (!fake_default_request_context_getter_) { 45 fake_default_request_context_getter_ = new TestURLRequestContextGetter(); 46 fake_default_request_context_getter_->AddRef(); 47 } 48 HttpBridge* bridge = new HttpBridge( 49 new HttpBridge::RequestContextGetter( 50 fake_default_request_context_getter_)); 51 return bridge; 52 } 53 54 static void Abort(HttpBridge* bridge) { 55 bridge->Abort(); 56 } 57 58 static void TestSameHttpNetworkSession(MessageLoop* main_message_loop, 59 HttpBridgeTest* test) { 60 scoped_refptr<HttpBridge> http_bridge(test->BuildBridge()); 61 EXPECT_TRUE(test->GetTestRequestContextGetter()); 62 net::HttpNetworkSession* test_session = 63 test->GetTestRequestContextGetter()->GetURLRequestContext()-> 64 http_transaction_factory()->GetSession(); 65 EXPECT_EQ(test_session, 66 http_bridge->GetRequestContextGetter()-> 67 GetURLRequestContext()-> 68 http_transaction_factory()->GetSession()); 69 main_message_loop->PostTask(FROM_HERE, new MessageLoop::QuitTask); 70 } 71 72 MessageLoop* io_thread_loop() { return io_thread_.message_loop(); } 73 74 // Note this is lazy created, so don't call this before your bridge. 75 TestURLRequestContextGetter* GetTestRequestContextGetter() { 76 return fake_default_request_context_getter_; 77 } 78 79 net::TestServer test_server_; 80 81 private: 82 // A make-believe "default" request context, as would be returned by 83 // Profile::GetDefaultRequestContext(). Created lazily by BuildBridge. 84 TestURLRequestContextGetter* fake_default_request_context_getter_; 85 86 // Separate thread for IO used by the HttpBridge. 87 BrowserThread io_thread_; 88 MessageLoop loop_; 89}; 90 91class DummyURLFetcher : public TestURLFetcher { 92 public: 93 DummyURLFetcher() : TestURLFetcher(0, GURL(), POST, NULL) {} 94 95 net::HttpResponseHeaders* response_headers() const { 96 return NULL; 97 } 98}; 99 100// An HttpBridge that doesn't actually make network requests and just calls 101// back with dummy response info. 102class ShuntedHttpBridge : public HttpBridge { 103 public: 104 // If |never_finishes| is true, the simulated request never actually 105 // returns. 106 ShuntedHttpBridge(net::URLRequestContextGetter* baseline_context_getter, 107 HttpBridgeTest* test, bool never_finishes) 108 : HttpBridge(new HttpBridge::RequestContextGetter( 109 baseline_context_getter)), 110 test_(test), never_finishes_(never_finishes) { } 111 protected: 112 virtual void MakeAsynchronousPost() { 113 ASSERT_TRUE(MessageLoop::current() == test_->io_thread_loop()); 114 if (never_finishes_) 115 return; 116 117 // We don't actually want to make a request for this test, so just callback 118 // as if it completed. 119 test_->io_thread_loop()->PostTask(FROM_HERE, 120 NewRunnableMethod(this, &ShuntedHttpBridge::CallOnURLFetchComplete)); 121 } 122 private: 123 ~ShuntedHttpBridge() {} 124 125 void CallOnURLFetchComplete() { 126 ASSERT_TRUE(MessageLoop::current() == test_->io_thread_loop()); 127 // We return no cookies and a dummy content response. 128 ResponseCookies cookies; 129 130 std::string response_content = "success!"; 131 DummyURLFetcher fetcher; 132 OnURLFetchComplete(&fetcher, GURL("www.google.com"), 133 net::URLRequestStatus(), 134 200, cookies, response_content); 135 } 136 HttpBridgeTest* test_; 137 bool never_finishes_; 138}; 139 140TEST_F(HttpBridgeTest, TestUsesSameHttpNetworkSession) { 141 // Run this test on the IO thread because we can only call 142 // URLRequestContextGetter::GetURLRequestContext on the IO thread. 143 BrowserThread::PostTask( 144 BrowserThread::IO, FROM_HERE, 145 NewRunnableFunction(&HttpBridgeTest::TestSameHttpNetworkSession, 146 MessageLoop::current(), this)); 147 MessageLoop::current()->Run(); 148} 149 150// Test the HttpBridge without actually making any network requests. 151TEST_F(HttpBridgeTest, TestMakeSynchronousPostShunted) { 152 scoped_refptr<net::URLRequestContextGetter> ctx_getter( 153 new TestURLRequestContextGetter()); 154 scoped_refptr<HttpBridge> http_bridge(new ShuntedHttpBridge( 155 ctx_getter, this, false)); 156 http_bridge->SetUserAgent("bob"); 157 http_bridge->SetURL("http://www.google.com", 9999); 158 http_bridge->SetPostPayload("text/plain", 2, " "); 159 160 int os_error = 0; 161 int response_code = 0; 162 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); 163 EXPECT_TRUE(success); 164 EXPECT_EQ(200, response_code); 165 EXPECT_EQ(0, os_error); 166 167 EXPECT_EQ(8, http_bridge->GetResponseContentLength()); 168 EXPECT_EQ(std::string("success!"), 169 std::string(http_bridge->GetResponseContent())); 170} 171 172// Full round-trip test of the HttpBridge, using default UA string and 173// no request cookies. 174TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) { 175 ASSERT_TRUE(test_server_.Start()); 176 177 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); 178 179 std::string payload = "this should be echoed back"; 180 GURL echo = test_server_.GetURL("echo"); 181 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort()); 182 http_bridge->SetPostPayload("application/x-www-form-urlencoded", 183 payload.length() + 1, payload.c_str()); 184 int os_error = 0; 185 int response_code = 0; 186 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); 187 EXPECT_TRUE(success); 188 EXPECT_EQ(200, response_code); 189 EXPECT_EQ(0, os_error); 190 191 EXPECT_EQ(payload.length() + 1, 192 static_cast<size_t>(http_bridge->GetResponseContentLength())); 193 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent())); 194} 195 196// Full round-trip test of the HttpBridge, using custom UA string 197TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) { 198 ASSERT_TRUE(test_server_.Start()); 199 200 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); 201 202 GURL echo_header = test_server_.GetURL("echoall"); 203 http_bridge->SetUserAgent("bob"); 204 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); 205 206 std::string test_payload = "###TEST PAYLOAD###"; 207 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, 208 test_payload.c_str()); 209 210 int os_error = 0; 211 int response_code = 0; 212 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); 213 EXPECT_TRUE(success); 214 EXPECT_EQ(200, response_code); 215 EXPECT_EQ(0, os_error); 216 217 std::string response(http_bridge->GetResponseContent(), 218 http_bridge->GetResponseContentLength()); 219 EXPECT_EQ(std::string::npos, response.find("Cookie:")); 220 EXPECT_NE(std::string::npos, response.find("User-Agent: bob")); 221 EXPECT_NE(std::string::npos, response.find(test_payload.c_str())); 222} 223 224TEST_F(HttpBridgeTest, TestExtraRequestHeaders) { 225 ASSERT_TRUE(test_server_.Start()); 226 227 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); 228 229 GURL echo_header = test_server_.GetURL("echoall"); 230 231 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); 232 http_bridge->SetExtraRequestHeaders("test:fnord"); 233 234 std::string test_payload = "###TEST PAYLOAD###"; 235 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, 236 test_payload.c_str()); 237 238 int os_error = 0; 239 int response_code = 0; 240 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); 241 EXPECT_TRUE(success); 242 EXPECT_EQ(200, response_code); 243 EXPECT_EQ(0, os_error); 244 245 std::string response(http_bridge->GetResponseContent(), 246 http_bridge->GetResponseContentLength()); 247 248 EXPECT_NE(std::string::npos, response.find("fnord")); 249 EXPECT_NE(std::string::npos, response.find(test_payload.c_str())); 250} 251 252TEST_F(HttpBridgeTest, TestResponseHeader) { 253 ASSERT_TRUE(test_server_.Start()); 254 255 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); 256 257 GURL echo_header = test_server_.GetURL("echoall"); 258 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); 259 260 std::string test_payload = "###TEST PAYLOAD###"; 261 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, 262 test_payload.c_str()); 263 264 int os_error = 0; 265 int response_code = 0; 266 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); 267 EXPECT_TRUE(success); 268 EXPECT_EQ(200, response_code); 269 EXPECT_EQ(0, os_error); 270 271 EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html"); 272 EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty()); 273} 274 275TEST_F(HttpBridgeTest, Abort) { 276 scoped_refptr<net::URLRequestContextGetter> ctx_getter( 277 new TestURLRequestContextGetter()); 278 scoped_refptr<ShuntedHttpBridge> http_bridge(new ShuntedHttpBridge( 279 ctx_getter, this, true)); 280 http_bridge->SetUserAgent("bob"); 281 http_bridge->SetURL("http://www.google.com", 9999); 282 http_bridge->SetPostPayload("text/plain", 2, " "); 283 284 int os_error = 0; 285 int response_code = 0; 286 287 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, NewRunnableFunction( 288 &HttpBridgeTest::Abort, http_bridge)); 289 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); 290 EXPECT_FALSE(success); 291 EXPECT_EQ(net::ERR_ABORTED, os_error); 292} 293 294TEST_F(HttpBridgeTest, AbortLate) { 295 scoped_refptr<net::URLRequestContextGetter> ctx_getter( 296 new TestURLRequestContextGetter()); 297 scoped_refptr<ShuntedHttpBridge> http_bridge(new ShuntedHttpBridge( 298 ctx_getter, this, false)); 299 http_bridge->SetUserAgent("bob"); 300 http_bridge->SetURL("http://www.google.com", 9999); 301 http_bridge->SetPostPayload("text/plain", 2, " "); 302 303 int os_error = 0; 304 int response_code = 0; 305 306 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); 307 ASSERT_TRUE(success); 308 http_bridge->Abort(); 309 // Ensures no double-free of URLFetcher, etc. 310} 311