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