1 // Copyright (c) 2012 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 <atlbase.h> 6 #include <atlcom.h> 7 8 #include "base/bind.h" 9 #include "base/bind_helpers.h" 10 #include "chrome/common/automation_messages.h" 11 #include "chrome_frame/test/chrome_frame_test_utils.h" 12 #include "chrome_frame/test/test_server.h" 13 #include "chrome_frame/test/test_with_web_server.h" 14 #include "chrome_frame/urlmon_url_request.h" 15 #include "chrome_frame/urlmon_url_request_private.h" 16 #include "testing/gmock/include/gmock/gmock.h" 17 #include "testing/gmock_mutant.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 using testing::CreateFunctor; 21 22 using chrome_frame_test::kChromeFrameLongNavigationTimeout; 23 24 static void AppendToStream(IStream* s, void* buffer, ULONG cb) { 25 ULONG bytes_written; 26 LARGE_INTEGER current_pos; 27 LARGE_INTEGER zero = {0}; 28 // Remember current position. 29 ASSERT_HRESULT_SUCCEEDED(s->Seek(zero, STREAM_SEEK_CUR, 30 reinterpret_cast<ULARGE_INTEGER*>(¤t_pos))); 31 // Seek to the end. 32 ASSERT_HRESULT_SUCCEEDED(s->Seek(zero, STREAM_SEEK_END, NULL)); 33 ASSERT_HRESULT_SUCCEEDED(s->Write(buffer, cb, &bytes_written)); 34 ASSERT_EQ(cb, bytes_written); 35 // Seek to original position. 36 ASSERT_HRESULT_SUCCEEDED(s->Seek(current_pos, STREAM_SEEK_SET, NULL)); 37 } 38 39 class MockUrlDelegate : public PluginUrlRequestDelegate { 40 public: 41 MOCK_METHOD9(OnResponseStarted, void(int request_id, const char* mime_type, 42 const char* headers, int size, base::Time last_modified, 43 const std::string& redirect_url, int redirect_status, 44 const net::HostPortPair& socket_address, uint64 upload_size)); 45 MOCK_METHOD2(OnReadComplete, void(int request_id, const std::string& data)); 46 MOCK_METHOD2(OnResponseEnd, void(int request_id, 47 const net::URLRequestStatus& status)); 48 MOCK_METHOD4(OnCookiesRetrieved, void(bool success, const GURL& url, 49 const std::string& cookie, int cookie_id)); 50 51 void PostponeReadRequest(chrome_frame_test::TimedMsgLoop* loop, 52 UrlmonUrlRequest* request, int bytes_to_read) { 53 loop->PostTask(FROM_HERE, 54 base::Bind(&MockUrlDelegate::RequestRead, 55 base::Unretained(this), request, bytes_to_read)); 56 } 57 58 private: 59 void RequestRead(UrlmonUrlRequest* request, int bytes_to_read) { 60 request->Read(bytes_to_read); 61 } 62 }; 63 64 // Simplest UrlmonUrlRequest. Retrieve a file from local web server. 65 TEST(UrlmonUrlRequestTest, Simple1) { 66 MockUrlDelegate mock; 67 chrome_frame_test::TimedMsgLoop loop; 68 69 testing::StrictMock<MockWebServer> mock_server(1337, 70 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()), 71 chrome_frame_test::GetTestDataFolder()); 72 mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE)); 73 74 CComObjectStackEx<UrlmonUrlRequest> request; 75 76 request.AddRef(); 77 request.Initialize(&mock, 1, // request_id 78 WideToUTF8(mock_server.Resolve(L"chrome_frame_window_open.html")), 79 "get", 80 "", // referrer 81 "", // extra request 82 NULL, // upload data 83 ResourceType::MAIN_FRAME, // resource type 84 true, 85 0); // frame busting 86 87 testing::InSequence s; 88 EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_, 89 testing::_, testing::_, testing::_, 90 testing::_, testing::_)) 91 .Times(1) 92 .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor( 93 &request, &UrlmonUrlRequest::Read, 512)))); 94 95 96 EXPECT_CALL(mock, OnReadComplete(1, testing::Property(&std::string::size, 97 testing::Gt(0u)))) 98 .Times(testing::AtLeast(1)) 99 .WillRepeatedly(testing::InvokeWithoutArgs(CreateFunctor(&mock, 100 &MockUrlDelegate::PostponeReadRequest, &loop, &request, 64))); 101 102 EXPECT_CALL(mock, OnResponseEnd(1, testing::_)) 103 .Times(1) 104 .WillOnce(QUIT_LOOP_SOON(loop, base::TimeDelta::FromSeconds(2))); 105 106 request.Start(); 107 loop.RunFor(kChromeFrameLongNavigationTimeout); 108 request.Release(); 109 } 110 111 // Same as Simple1 except we use the HEAD verb to fetch only the headers 112 // from the server. 113 TEST(UrlmonUrlRequestTest, Head) { 114 MockUrlDelegate mock; 115 chrome_frame_test::TimedMsgLoop loop; 116 // Use SimpleWebServer instead of the python server to support HEAD 117 // requests. 118 test_server::SimpleWebServer server(13337); 119 test_server::SimpleResponse head_response("/head", ""); 120 server.AddResponse(&head_response); 121 122 CComObjectStackEx<UrlmonUrlRequest> request; 123 124 request.AddRef(); 125 request.Initialize(&mock, 1, // request_id 126 base::StringPrintf("http://%s:13337/head", server.host().c_str()), 127 "head", 128 "", // referrer 129 "", // extra request 130 NULL, // upload data 131 ResourceType::MAIN_FRAME, // resource type 132 true, 133 0); // frame busting 134 135 testing::InSequence s; 136 EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_, 137 testing::_, testing::_, testing::_, 138 testing::_, testing::_)) 139 .Times(1) 140 .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor( 141 &request, &UrlmonUrlRequest::Read, 512)))); 142 143 // For HEAD requests we don't expect content reads. 144 EXPECT_CALL(mock, OnReadComplete(1, testing::_)).Times(0); 145 146 EXPECT_CALL(mock, OnResponseEnd(1, testing::_)) 147 .Times(1) 148 .WillOnce(QUIT_LOOP_SOON(loop, base::TimeDelta::FromSeconds(2))); 149 150 request.Start(); 151 loop.RunFor(kChromeFrameLongNavigationTimeout); 152 request.Release(); 153 } 154 155 TEST(UrlmonUrlRequestTest, UnreachableUrl) { 156 MockUrlDelegate mock; 157 chrome_frame_test::TimedMsgLoop loop; 158 CComObjectStackEx<UrlmonUrlRequest> request; 159 160 testing::StrictMock<MockWebServer> mock_server(1337, 161 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()), 162 chrome_frame_test::GetTestDataFolder()); 163 mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE)); 164 165 GURL unreachable(WideToUTF8(mock_server.Resolve( 166 L"non_existing.html"))); 167 168 request.AddRef(); 169 request.Initialize(&mock, 1, // request_id 170 unreachable.spec(), "get", 171 "", // referrer 172 "", // extra request 173 NULL, // upload data 174 ResourceType::MAIN_FRAME, // resource type 175 true, 176 0); // frame busting 177 178 // Expect headers 179 EXPECT_CALL(mock, OnResponseStarted(1, testing::_, 180 testing::StartsWith("HTTP/1.1 404"), 181 testing::_, testing::_, testing::_, 182 testing::_, testing::_, testing::_)) 183 .Times(1) 184 .WillOnce(QUIT_LOOP_SOON(loop, base::TimeDelta::FromSeconds(2))); 185 186 EXPECT_CALL(mock, OnResponseEnd(1, testing::Property( 187 &net::URLRequestStatus::error, 188 net::ERR_TUNNEL_CONNECTION_FAILED))) 189 .Times(testing::AtMost(1)); 190 191 request.Start(); 192 loop.RunFor(kChromeFrameLongNavigationTimeout); 193 request.Release(); 194 } 195 196 TEST(UrlmonUrlRequestTest, ZeroLengthResponse) { 197 MockUrlDelegate mock; 198 chrome_frame_test::TimedMsgLoop loop; 199 200 testing::StrictMock<MockWebServer> mock_server(1337, 201 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()), 202 chrome_frame_test::GetTestDataFolder()); 203 mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE)); 204 205 CComObjectStackEx<UrlmonUrlRequest> request; 206 207 request.AddRef(); 208 request.Initialize(&mock, 1, // request_id 209 WideToUTF8(mock_server.Resolve(L"empty.html")), "get", 210 "", // referrer 211 "", // extra request 212 NULL, // upload data 213 ResourceType::MAIN_FRAME, // resource type 214 true, 215 0); // frame busting 216 217 // Expect headers 218 EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_, 219 testing::_, testing::_, testing::_, 220 testing::_, testing::_)) 221 .Times(1) 222 .WillOnce(QUIT_LOOP(loop)); 223 224 request.Start(); 225 loop.RunFor(kChromeFrameLongNavigationTimeout); 226 EXPECT_FALSE(loop.WasTimedOut()); 227 228 // Should stay quiet, since we do not ask for anything for awhile. 229 EXPECT_CALL(mock, OnResponseEnd(1, testing::_)).Times(0); 230 loop.RunFor(base::TimeDelta::FromSeconds(3)); 231 232 // Invoke read. Only now the response end ("server closed the connection") 233 // is supposed to be delivered. 234 EXPECT_CALL(mock, OnResponseEnd(1, testing::Property( 235 &net::URLRequestStatus::is_success, true))).Times(1); 236 request.Read(512); 237 request.Release(); 238 } 239 240 ACTION_P4(ManagerRead, loop, mgr, request_id, bytes_to_read) { 241 loop->PostTask(FROM_HERE, 242 base::Bind(&UrlmonUrlRequestManager::ReadUrlRequest, 243 base::Unretained(mgr), request_id, bytes_to_read)); 244 } 245 ACTION_P3(ManagerEndRequest, loop, mgr, request_id) { 246 loop->PostTask(FROM_HERE, base::Bind(&UrlmonUrlRequestManager::EndUrlRequest, 247 base::Unretained(mgr), request_id, 248 net::URLRequestStatus())); 249 } 250 251 // Simplest test - retrieve file from local web server. 252 TEST(UrlmonUrlRequestManagerTest, Simple1) { 253 MockUrlDelegate mock; 254 chrome_frame_test::TimedMsgLoop loop; 255 256 testing::StrictMock<MockWebServer> mock_server(1337, 257 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()), 258 chrome_frame_test::GetTestDataFolder()); 259 mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE)); 260 261 scoped_ptr<UrlmonUrlRequestManager> mgr(new UrlmonUrlRequestManager()); 262 mgr->set_delegate(&mock); 263 AutomationURLRequest r1; 264 r1.url = WideToUTF8(mock_server.Resolve(L"chrome_frame_window_open.html")); 265 r1.method = "get"; 266 r1.resource_type = 0; 267 r1.load_flags = 0; 268 269 EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_, 270 testing::_, testing::_, testing::_, testing::_, 271 testing::_)) 272 .Times(1) 273 .WillOnce(ManagerRead(&loop, mgr.get(), 1, 512)); 274 275 EXPECT_CALL(mock, OnReadComplete(1, testing::Property(&std::string::size, 276 testing::Gt(0u)))) 277 .Times(testing::AtLeast(1)) 278 .WillRepeatedly(ManagerRead(&loop, mgr.get(), 1, 2)); 279 280 EXPECT_CALL(mock, OnResponseEnd(1, testing::_)) 281 .Times(1) 282 .WillOnce(QUIT_LOOP_SOON(loop, base::TimeDelta::FromSeconds(2))); 283 284 mgr->StartUrlRequest(1, r1); 285 loop.RunFor(kChromeFrameLongNavigationTimeout); 286 mgr.reset(); 287 } 288 289 TEST(UrlmonUrlRequestManagerTest, Abort1) { 290 MockUrlDelegate mock; 291 chrome_frame_test::TimedMsgLoop loop; 292 293 testing::StrictMock<MockWebServer> mock_server(1337, 294 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()), 295 chrome_frame_test::GetTestDataFolder()); 296 mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE)); 297 298 scoped_ptr<UrlmonUrlRequestManager> mgr(new UrlmonUrlRequestManager()); 299 mgr->set_delegate(&mock); 300 AutomationURLRequest r1; 301 r1.url = WideToUTF8(mock_server.Resolve(L"chrome_frame_window_open.html")); 302 r1.method = "get"; 303 r1.resource_type = 0; 304 r1.load_flags = 0; 305 306 EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_, 307 testing::_, testing::_, testing::_, testing::_, 308 testing::_)) 309 .Times(1) 310 .WillOnce(testing::DoAll( 311 ManagerEndRequest(&loop, mgr.get(), 1), 312 QUIT_LOOP_SOON(loop, base::TimeDelta::FromSeconds(3)))); 313 314 EXPECT_CALL(mock, OnReadComplete(1, testing::_)) 315 .Times(0); 316 317 EXPECT_CALL(mock, OnResponseEnd(1, testing::_)) 318 .Times(0); 319 320 mgr->StartUrlRequest(1, r1); 321 loop.RunFor(kChromeFrameLongNavigationTimeout); 322 mgr.reset(); 323 } 324