| OLD | NEW |
| (Empty) |
| 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 <vector> | |
| 6 | |
| 7 #include "base/file_path.h" | |
| 8 #include "base/message_loop.h" | |
| 9 #include "base/process_util.h" | |
| 10 #include "chrome/browser/browser_thread.h" | |
| 11 #include "chrome/browser/child_process_security_policy.h" | |
| 12 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" | |
| 13 #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" | |
| 14 #include "chrome/browser/renderer_host/resource_handler.h" | |
| 15 #include "chrome/browser/renderer_host/resource_message_filter.h" | |
| 16 #include "chrome/common/chrome_plugin_lib.h" | |
| 17 #include "chrome/common/render_messages.h" | |
| 18 #include "chrome/common/render_messages_params.h" | |
| 19 #include "chrome/common/resource_response.h" | |
| 20 #include "net/base/net_errors.h" | |
| 21 #include "net/base/upload_data.h" | |
| 22 #include "net/http/http_util.h" | |
| 23 #include "net/url_request/url_request.h" | |
| 24 #include "net/url_request/url_request_job.h" | |
| 25 #include "net/url_request/url_request_test_job.h" | |
| 26 #include "testing/gtest/include/gtest/gtest.h" | |
| 27 #include "webkit/appcache/appcache_interfaces.h" | |
| 28 | |
| 29 // TODO(eroman): Write unit tests for SafeBrowsing that exercise | |
| 30 // SafeBrowsingResourceHandler. | |
| 31 | |
| 32 namespace { | |
| 33 | |
| 34 // Returns the resource response header structure for this request. | |
| 35 void GetResponseHead(const std::vector<IPC::Message>& messages, | |
| 36 ResourceResponseHead* response_head) { | |
| 37 ASSERT_GE(messages.size(), 2U); | |
| 38 | |
| 39 // The first messages should be received response. | |
| 40 ASSERT_EQ(ViewMsg_Resource_ReceivedResponse::ID, messages[0].type()); | |
| 41 | |
| 42 void* iter = NULL; | |
| 43 int request_id; | |
| 44 ASSERT_TRUE(IPC::ReadParam(&messages[0], &iter, &request_id)); | |
| 45 ASSERT_TRUE(IPC::ReadParam(&messages[0], &iter, response_head)); | |
| 46 } | |
| 47 | |
| 48 } // namespace | |
| 49 | |
| 50 static int RequestIDForMessage(const IPC::Message& msg) { | |
| 51 int request_id = -1; | |
| 52 switch (msg.type()) { | |
| 53 case ViewMsg_Resource_UploadProgress::ID: | |
| 54 case ViewMsg_Resource_ReceivedResponse::ID: | |
| 55 case ViewMsg_Resource_ReceivedRedirect::ID: | |
| 56 case ViewMsg_Resource_DataReceived::ID: | |
| 57 case ViewMsg_Resource_RequestComplete::ID: | |
| 58 request_id = IPC::MessageIterator(msg).NextInt(); | |
| 59 break; | |
| 60 } | |
| 61 return request_id; | |
| 62 } | |
| 63 | |
| 64 static ViewHostMsg_Resource_Request CreateResourceRequest( | |
| 65 const char* method, | |
| 66 ResourceType::Type type, | |
| 67 const GURL& url) { | |
| 68 ViewHostMsg_Resource_Request request; | |
| 69 request.method = std::string(method); | |
| 70 request.url = url; | |
| 71 request.first_party_for_cookies = url; // bypass third-party cookie blocking | |
| 72 request.load_flags = 0; | |
| 73 request.origin_pid = 0; | |
| 74 request.resource_type = type; | |
| 75 request.request_context = 0; | |
| 76 request.appcache_host_id = appcache::kNoHostId; | |
| 77 request.download_to_file = false; | |
| 78 request.host_renderer_id = -1; | |
| 79 request.host_render_view_id = -1; | |
| 80 return request; | |
| 81 } | |
| 82 | |
| 83 // Spin up the message loop to kick off the request. | |
| 84 static void KickOffRequest() { | |
| 85 MessageLoop::current()->RunAllPending(); | |
| 86 } | |
| 87 | |
| 88 // We may want to move this to a shared space if it is useful for something else | |
| 89 class ResourceIPCAccumulator { | |
| 90 public: | |
| 91 void AddMessage(const IPC::Message& msg) { | |
| 92 messages_.push_back(msg); | |
| 93 } | |
| 94 | |
| 95 // This groups the messages by their request ID. The groups will be in order | |
| 96 // that the first message for each request ID was received, and the messages | |
| 97 // within the groups will be in the order that they appeared. | |
| 98 // Note that this clears messages_. | |
| 99 typedef std::vector< std::vector<IPC::Message> > ClassifiedMessages; | |
| 100 void GetClassifiedMessages(ClassifiedMessages* msgs); | |
| 101 | |
| 102 std::vector<IPC::Message> messages_; | |
| 103 }; | |
| 104 | |
| 105 // This is very inefficient as a result of repeatedly extracting the ID, use | |
| 106 // only for tests! | |
| 107 void ResourceIPCAccumulator::GetClassifiedMessages(ClassifiedMessages* msgs) { | |
| 108 while (!messages_.empty()) { | |
| 109 std::vector<IPC::Message> cur_requests; | |
| 110 cur_requests.push_back(messages_[0]); | |
| 111 int cur_id = RequestIDForMessage(messages_[0]); | |
| 112 | |
| 113 // find all other messages with this ID | |
| 114 for (int i = 1; i < static_cast<int>(messages_.size()); i++) { | |
| 115 int id = RequestIDForMessage(messages_[i]); | |
| 116 if (id == cur_id) { | |
| 117 cur_requests.push_back(messages_[i]); | |
| 118 messages_.erase(messages_.begin() + i); | |
| 119 i--; | |
| 120 } | |
| 121 } | |
| 122 messages_.erase(messages_.begin()); | |
| 123 msgs->push_back(cur_requests); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 // This class forwards the incoming messages to the ResourceDispatcherHostTest. | |
| 128 // This is used to emulate different sub-processes, since this filter will | |
| 129 // have a different ID than the original. For the test, we want all the incoming | |
| 130 // messages to go to the same place, which is why this forwards. | |
| 131 class ForwardingFilter : public ResourceMessageFilter { | |
| 132 public: | |
| 133 explicit ForwardingFilter(IPC::Message::Sender* dest) | |
| 134 : ResourceMessageFilter(ChildProcessInfo::GenerateChildProcessUniqueId(), | |
| 135 ChildProcessInfo::RENDER_PROCESS, | |
| 136 NULL), | |
| 137 dest_(dest) { | |
| 138 OnChannelConnected(base::GetCurrentProcId()); | |
| 139 } | |
| 140 | |
| 141 // ResourceMessageFilter override | |
| 142 virtual bool Send(IPC::Message* msg) { | |
| 143 if (!dest_) | |
| 144 return false; | |
| 145 return dest_->Send(msg); | |
| 146 } | |
| 147 | |
| 148 private: | |
| 149 IPC::Message::Sender* dest_; | |
| 150 | |
| 151 DISALLOW_COPY_AND_ASSIGN(ForwardingFilter); | |
| 152 }; | |
| 153 | |
| 154 class ResourceDispatcherHostTest : public testing::Test, | |
| 155 public IPC::Message::Sender { | |
| 156 public: | |
| 157 ResourceDispatcherHostTest() | |
| 158 : ALLOW_THIS_IN_INITIALIZER_LIST(filter_(new ForwardingFilter(this))), | |
| 159 ui_thread_(BrowserThread::UI, &message_loop_), | |
| 160 io_thread_(BrowserThread::IO, &message_loop_), | |
| 161 old_factory_(NULL), | |
| 162 resource_type_(ResourceType::SUB_RESOURCE) { | |
| 163 } | |
| 164 // IPC::Message::Sender implementation | |
| 165 virtual bool Send(IPC::Message* msg) { | |
| 166 accum_.AddMessage(*msg); | |
| 167 delete msg; | |
| 168 return true; | |
| 169 } | |
| 170 | |
| 171 protected: | |
| 172 // testing::Test | |
| 173 virtual void SetUp() { | |
| 174 DCHECK(!test_fixture_); | |
| 175 test_fixture_ = this; | |
| 176 ChildProcessSecurityPolicy::GetInstance()->Add(0); | |
| 177 net::URLRequest::RegisterProtocolFactory( | |
| 178 "test", | |
| 179 &ResourceDispatcherHostTest::Factory); | |
| 180 EnsureTestSchemeIsAllowed(); | |
| 181 } | |
| 182 | |
| 183 virtual void TearDown() { | |
| 184 net::URLRequest::RegisterProtocolFactory("test", NULL); | |
| 185 if (!scheme_.empty()) | |
| 186 net::URLRequest::RegisterProtocolFactory(scheme_, old_factory_); | |
| 187 | |
| 188 DCHECK(test_fixture_ == this); | |
| 189 test_fixture_ = NULL; | |
| 190 | |
| 191 host_.Shutdown(); | |
| 192 | |
| 193 ChildProcessSecurityPolicy::GetInstance()->Remove(0); | |
| 194 | |
| 195 // The plugin lib is automatically loaded during these test | |
| 196 // and we want a clean environment for other tests. | |
| 197 ChromePluginLib::UnloadAllPlugins(); | |
| 198 | |
| 199 // Flush the message loop to make Purify happy. | |
| 200 message_loop_.RunAllPending(); | |
| 201 } | |
| 202 | |
| 203 // Creates a request using the current test object as the filter. | |
| 204 void MakeTestRequest(int render_view_id, | |
| 205 int request_id, | |
| 206 const GURL& url); | |
| 207 | |
| 208 // Generates a request using the given filter. This will probably be a | |
| 209 // ForwardingFilter. | |
| 210 void MakeTestRequest(ResourceMessageFilter* filter, | |
| 211 int render_view_id, | |
| 212 int request_id, | |
| 213 const GURL& url); | |
| 214 | |
| 215 void MakeCancelRequest(int request_id); | |
| 216 | |
| 217 void EnsureTestSchemeIsAllowed() { | |
| 218 static bool have_white_listed_test_scheme = false; | |
| 219 | |
| 220 if (!have_white_listed_test_scheme) { | |
| 221 ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme("test"); | |
| 222 have_white_listed_test_scheme = true; | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 // Sets a particular response for any request from now on. To switch back to | |
| 227 // the default bahavior, pass an empty |headers|. |headers| should be raw- | |
| 228 // formatted (NULLs instead of EOLs). | |
| 229 void SetResponse(const std::string& headers, const std::string& data) { | |
| 230 response_headers_ = headers; | |
| 231 response_data_ = data; | |
| 232 } | |
| 233 | |
| 234 // Sets a particular resource type for any request from now on. | |
| 235 void SetResourceType(ResourceType::Type type) { | |
| 236 resource_type_ = type; | |
| 237 } | |
| 238 | |
| 239 // Intercepts requests for the given protocol. | |
| 240 void HandleScheme(const std::string& scheme) { | |
| 241 DCHECK(scheme_.empty()); | |
| 242 DCHECK(!old_factory_); | |
| 243 scheme_ = scheme; | |
| 244 old_factory_ = net::URLRequest::RegisterProtocolFactory( | |
| 245 scheme_, &ResourceDispatcherHostTest::Factory); | |
| 246 } | |
| 247 | |
| 248 // Our own net::URLRequestJob factory. | |
| 249 static net::URLRequestJob* Factory(net::URLRequest* request, | |
| 250 const std::string& scheme) { | |
| 251 if (test_fixture_->response_headers_.empty()) { | |
| 252 return new net::URLRequestTestJob(request); | |
| 253 } else { | |
| 254 return new net::URLRequestTestJob(request, | |
| 255 test_fixture_->response_headers_, | |
| 256 test_fixture_->response_data_, | |
| 257 false); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 scoped_refptr<ForwardingFilter> filter_; | |
| 262 MessageLoopForIO message_loop_; | |
| 263 BrowserThread ui_thread_; | |
| 264 BrowserThread io_thread_; | |
| 265 ResourceDispatcherHost host_; | |
| 266 ResourceIPCAccumulator accum_; | |
| 267 std::string response_headers_; | |
| 268 std::string response_data_; | |
| 269 std::string scheme_; | |
| 270 net::URLRequest::ProtocolFactory* old_factory_; | |
| 271 ResourceType::Type resource_type_; | |
| 272 static ResourceDispatcherHostTest* test_fixture_; | |
| 273 }; | |
| 274 // Static. | |
| 275 ResourceDispatcherHostTest* ResourceDispatcherHostTest::test_fixture_ = NULL; | |
| 276 | |
| 277 void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id, | |
| 278 int request_id, | |
| 279 const GURL& url) { | |
| 280 MakeTestRequest(filter_.get(), render_view_id, request_id, url); | |
| 281 } | |
| 282 | |
| 283 void ResourceDispatcherHostTest::MakeTestRequest( | |
| 284 ResourceMessageFilter* filter, | |
| 285 int render_view_id, | |
| 286 int request_id, | |
| 287 const GURL& url) { | |
| 288 ViewHostMsg_Resource_Request request = | |
| 289 CreateResourceRequest("GET", resource_type_, url); | |
| 290 ViewHostMsg_RequestResource msg(render_view_id, request_id, request); | |
| 291 bool msg_was_ok; | |
| 292 host_.OnMessageReceived(msg, filter, &msg_was_ok); | |
| 293 KickOffRequest(); | |
| 294 } | |
| 295 | |
| 296 void ResourceDispatcherHostTest::MakeCancelRequest(int request_id) { | |
| 297 host_.CancelRequest(filter_->child_id(), request_id, false); | |
| 298 } | |
| 299 | |
| 300 void CheckSuccessfulRequest(const std::vector<IPC::Message>& messages, | |
| 301 const std::string& reference_data) { | |
| 302 // A successful request will have received 4 messages: | |
| 303 // ReceivedResponse (indicates headers received) | |
| 304 // DataReceived (data) | |
| 305 // XXX DataReceived (0 bytes remaining from a read) | |
| 306 // RequestComplete (request is done) | |
| 307 // | |
| 308 // This function verifies that we received 4 messages and that they | |
| 309 // are appropriate. | |
| 310 ASSERT_EQ(3U, messages.size()); | |
| 311 | |
| 312 // The first messages should be received response | |
| 313 ASSERT_EQ(ViewMsg_Resource_ReceivedResponse::ID, messages[0].type()); | |
| 314 | |
| 315 // followed by the data, currently we only do the data in one chunk, but | |
| 316 // should probably test multiple chunks later | |
| 317 ASSERT_EQ(ViewMsg_Resource_DataReceived::ID, messages[1].type()); | |
| 318 | |
| 319 void* iter = NULL; | |
| 320 int request_id; | |
| 321 ASSERT_TRUE(IPC::ReadParam(&messages[1], &iter, &request_id)); | |
| 322 base::SharedMemoryHandle shm_handle; | |
| 323 ASSERT_TRUE(IPC::ReadParam(&messages[1], &iter, &shm_handle)); | |
| 324 uint32 data_len; | |
| 325 ASSERT_TRUE(IPC::ReadParam(&messages[1], &iter, &data_len)); | |
| 326 | |
| 327 ASSERT_EQ(reference_data.size(), data_len); | |
| 328 base::SharedMemory shared_mem(shm_handle, true); // read only | |
| 329 shared_mem.Map(data_len); | |
| 330 const char* data = static_cast<char*>(shared_mem.memory()); | |
| 331 ASSERT_EQ(0, memcmp(reference_data.c_str(), data, data_len)); | |
| 332 | |
| 333 // followed by a 0-byte read | |
| 334 //ASSERT_EQ(ViewMsg_Resource_DataReceived::ID, messages[2].type()); | |
| 335 | |
| 336 // the last message should be all data received | |
| 337 ASSERT_EQ(ViewMsg_Resource_RequestComplete::ID, messages[2].type()); | |
| 338 } | |
| 339 | |
| 340 // Tests whether many messages get dispatched properly. | |
| 341 TEST_F(ResourceDispatcherHostTest, TestMany) { | |
| 342 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 343 | |
| 344 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
| 345 MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2()); | |
| 346 MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); | |
| 347 | |
| 348 // flush all the pending requests | |
| 349 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 350 | |
| 351 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 352 | |
| 353 // sorts out all the messages we saw by request | |
| 354 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 355 accum_.GetClassifiedMessages(&msgs); | |
| 356 | |
| 357 // there are three requests, so we should have gotten them classified as such | |
| 358 ASSERT_EQ(3U, msgs.size()); | |
| 359 | |
| 360 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
| 361 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_2()); | |
| 362 CheckSuccessfulRequest(msgs[2], net::URLRequestTestJob::test_data_3()); | |
| 363 } | |
| 364 | |
| 365 // Tests whether messages get canceled properly. We issue three requests, | |
| 366 // cancel one of them, and make sure that each sent the proper notifications. | |
| 367 TEST_F(ResourceDispatcherHostTest, Cancel) { | |
| 368 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 369 | |
| 370 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
| 371 MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2()); | |
| 372 MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); | |
| 373 MakeCancelRequest(2); | |
| 374 | |
| 375 // flush all the pending requests | |
| 376 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 377 MessageLoop::current()->RunAllPending(); | |
| 378 | |
| 379 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 380 | |
| 381 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 382 accum_.GetClassifiedMessages(&msgs); | |
| 383 | |
| 384 // there are three requests, so we should have gotten them classified as such | |
| 385 ASSERT_EQ(3U, msgs.size()); | |
| 386 | |
| 387 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
| 388 CheckSuccessfulRequest(msgs[2], net::URLRequestTestJob::test_data_3()); | |
| 389 | |
| 390 // Check that request 2 got canceled. | |
| 391 ASSERT_EQ(2U, msgs[1].size()); | |
| 392 ASSERT_EQ(ViewMsg_Resource_ReceivedResponse::ID, msgs[1][0].type()); | |
| 393 ASSERT_EQ(ViewMsg_Resource_RequestComplete::ID, msgs[1][1].type()); | |
| 394 | |
| 395 int request_id; | |
| 396 net::URLRequestStatus status; | |
| 397 | |
| 398 void* iter = NULL; | |
| 399 ASSERT_TRUE(IPC::ReadParam(&msgs[1][1], &iter, &request_id)); | |
| 400 ASSERT_TRUE(IPC::ReadParam(&msgs[1][1], &iter, &status)); | |
| 401 | |
| 402 EXPECT_EQ(net::URLRequestStatus::CANCELED, status.status()); | |
| 403 } | |
| 404 | |
| 405 // The host delegate acts as a second one so we can have some requests | |
| 406 // pending and some canceled. | |
| 407 class TestFilter : public ForwardingFilter { | |
| 408 public: | |
| 409 TestFilter() | |
| 410 : ForwardingFilter(NULL), | |
| 411 has_canceled_(false), | |
| 412 received_after_canceled_(0) { | |
| 413 } | |
| 414 | |
| 415 // ForwardingFilter override | |
| 416 virtual bool Send(IPC::Message* msg) { | |
| 417 // no messages should be received when the process has been canceled | |
| 418 if (has_canceled_) | |
| 419 received_after_canceled_++; | |
| 420 delete msg; | |
| 421 return true; | |
| 422 } | |
| 423 bool has_canceled_; | |
| 424 int received_after_canceled_; | |
| 425 }; | |
| 426 | |
| 427 // Tests CancelRequestsForProcess | |
| 428 TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { | |
| 429 scoped_refptr<TestFilter> test_filter = new TestFilter(); | |
| 430 | |
| 431 // request 1 goes to the test delegate | |
| 432 ViewHostMsg_Resource_Request request = CreateResourceRequest( | |
| 433 "GET", ResourceType::SUB_RESOURCE, net::URLRequestTestJob::test_url_1()); | |
| 434 | |
| 435 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 436 | |
| 437 MakeTestRequest(test_filter.get(), 0, 1, | |
| 438 net::URLRequestTestJob::test_url_1()); | |
| 439 | |
| 440 // request 2 goes to us | |
| 441 MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2()); | |
| 442 | |
| 443 // request 3 goes to the test delegate | |
| 444 MakeTestRequest(test_filter.get(), 0, 3, | |
| 445 net::URLRequestTestJob::test_url_3()); | |
| 446 | |
| 447 // TODO(mbelshe): | |
| 448 // Now that the async IO path is in place, the IO always completes on the | |
| 449 // initial call; so the requests have already completed. This basically | |
| 450 // breaks the whole test. | |
| 451 //EXPECT_EQ(3, host_.pending_requests()); | |
| 452 | |
| 453 // Process each request for one level so one callback is called. | |
| 454 for (int i = 0; i < 3; i++) | |
| 455 EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); | |
| 456 | |
| 457 // Cancel the requests to the test process. | |
| 458 host_.CancelRequestsForProcess(filter_->child_id()); | |
| 459 test_filter->has_canceled_ = true; | |
| 460 | |
| 461 // Flush all the pending requests. | |
| 462 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 463 | |
| 464 EXPECT_EQ(0, host_.pending_requests()); | |
| 465 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
| 466 | |
| 467 // The test delegate should not have gotten any messages after being canceled. | |
| 468 ASSERT_EQ(0, test_filter->received_after_canceled_); | |
| 469 | |
| 470 // We should have gotten exactly one result. | |
| 471 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 472 accum_.GetClassifiedMessages(&msgs); | |
| 473 ASSERT_EQ(1U, msgs.size()); | |
| 474 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2()); | |
| 475 } | |
| 476 | |
| 477 // Tests blocking and resuming requests. | |
| 478 TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) { | |
| 479 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
| 480 | |
| 481 host_.BlockRequestsForRoute(filter_->child_id(), 1); | |
| 482 host_.BlockRequestsForRoute(filter_->child_id(), 2); | |
| 483 host_.BlockRequestsForRoute(filter_->child_id(), 3); | |
| 484 | |
| 485 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
| 486 MakeTestRequest(1, 2, net::URLRequestTestJob::test_url_2()); | |
| 487 MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); | |
| 488 MakeTestRequest(1, 4, net::URLRequestTestJob::test_url_1()); | |
| 489 MakeTestRequest(2, 5, net::URLRequestTestJob::test_url_2()); | |
| 490 MakeTestRequest(3, 6, net::URLRequestTestJob::test_url_3()); | |
| 491 | |
| 492 // Flush all the pending requests | |
| 493 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 494 | |
| 495 // Sort out all the messages we saw by request | |
| 496 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 497 accum_.GetClassifiedMessages(&msgs); | |
| 498 | |
| 499 // All requests but the 2 for the RVH 0 should have been blocked. | |
| 500 ASSERT_EQ(2U, msgs.size()); | |
| 501 | |
| 502 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
| 503 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3()); | |
| 504 | |
| 505 // Resume requests for RVH 1 and flush pending requests. | |
| 506 host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 1); | |
| 507 KickOffRequest(); | |
| 508 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 509 | |
| 510 msgs.clear(); | |
| 511 accum_.GetClassifiedMessages(&msgs); | |
| 512 ASSERT_EQ(2U, msgs.size()); | |
| 513 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2()); | |
| 514 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_1()); | |
| 515 | |
| 516 // Test that new requests are not blocked for RVH 1. | |
| 517 MakeTestRequest(1, 7, net::URLRequestTestJob::test_url_1()); | |
| 518 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 519 msgs.clear(); | |
| 520 accum_.GetClassifiedMessages(&msgs); | |
| 521 ASSERT_EQ(1U, msgs.size()); | |
| 522 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
| 523 | |
| 524 // Now resumes requests for all RVH (2 and 3). | |
| 525 host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 2); | |
| 526 host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 3); | |
| 527 KickOffRequest(); | |
| 528 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 529 | |
| 530 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
| 531 | |
| 532 msgs.clear(); | |
| 533 accum_.GetClassifiedMessages(&msgs); | |
| 534 ASSERT_EQ(2U, msgs.size()); | |
| 535 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2()); | |
| 536 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3()); | |
| 537 } | |
| 538 | |
| 539 // Tests blocking and canceling requests. | |
| 540 TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) { | |
| 541 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
| 542 | |
| 543 host_.BlockRequestsForRoute(filter_->child_id(), 1); | |
| 544 | |
| 545 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
| 546 MakeTestRequest(1, 2, net::URLRequestTestJob::test_url_2()); | |
| 547 MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); | |
| 548 MakeTestRequest(1, 4, net::URLRequestTestJob::test_url_1()); | |
| 549 | |
| 550 // Flush all the pending requests. | |
| 551 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 552 | |
| 553 // Sort out all the messages we saw by request. | |
| 554 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 555 accum_.GetClassifiedMessages(&msgs); | |
| 556 | |
| 557 // The 2 requests for the RVH 0 should have been processed. | |
| 558 ASSERT_EQ(2U, msgs.size()); | |
| 559 | |
| 560 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
| 561 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3()); | |
| 562 | |
| 563 // Cancel requests for RVH 1. | |
| 564 host_.CancelBlockedRequestsForRoute(filter_->child_id(), 1); | |
| 565 KickOffRequest(); | |
| 566 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 567 | |
| 568 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
| 569 | |
| 570 msgs.clear(); | |
| 571 accum_.GetClassifiedMessages(&msgs); | |
| 572 ASSERT_EQ(0U, msgs.size()); | |
| 573 } | |
| 574 | |
| 575 // Tests that blocked requests are canceled if their associated process dies. | |
| 576 TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) { | |
| 577 // This second filter is used to emulate a second process. | |
| 578 scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter(this); | |
| 579 | |
| 580 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
| 581 EXPECT_EQ(0, | |
| 582 host_.GetOutstandingRequestsMemoryCost(second_filter->child_id())); | |
| 583 | |
| 584 host_.BlockRequestsForRoute(second_filter->child_id(), 0); | |
| 585 | |
| 586 MakeTestRequest(filter_.get(), 0, 1, net::URLRequestTestJob::test_url_1()); | |
| 587 MakeTestRequest(second_filter.get(), 0, 2, | |
| 588 net::URLRequestTestJob::test_url_2()); | |
| 589 MakeTestRequest(filter_.get(), 0, 3, net::URLRequestTestJob::test_url_3()); | |
| 590 MakeTestRequest(second_filter.get(), 0, 4, | |
| 591 net::URLRequestTestJob::test_url_1()); | |
| 592 | |
| 593 // Simulate process death. | |
| 594 host_.CancelRequestsForProcess(second_filter->child_id()); | |
| 595 | |
| 596 // Flush all the pending requests. | |
| 597 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 598 | |
| 599 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
| 600 EXPECT_EQ(0, | |
| 601 host_.GetOutstandingRequestsMemoryCost(second_filter->child_id())); | |
| 602 | |
| 603 // Sort out all the messages we saw by request. | |
| 604 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 605 accum_.GetClassifiedMessages(&msgs); | |
| 606 | |
| 607 // The 2 requests for the RVH 0 should have been processed. | |
| 608 ASSERT_EQ(2U, msgs.size()); | |
| 609 | |
| 610 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
| 611 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3()); | |
| 612 | |
| 613 EXPECT_TRUE(host_.blocked_requests_map_.empty()); | |
| 614 } | |
| 615 | |
| 616 // Tests that blocked requests don't leak when the ResourceDispatcherHost goes | |
| 617 // away. Note that we rely on Purify for finding the leaks if any. | |
| 618 // If this test turns the Purify bot red, check the ResourceDispatcherHost | |
| 619 // destructor to make sure the blocked requests are deleted. | |
| 620 TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) { | |
| 621 // This second filter is used to emulate a second process. | |
| 622 scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter(this); | |
| 623 | |
| 624 host_.BlockRequestsForRoute(filter_->child_id(), 1); | |
| 625 host_.BlockRequestsForRoute(filter_->child_id(), 2); | |
| 626 host_.BlockRequestsForRoute(second_filter->child_id(), 1); | |
| 627 | |
| 628 MakeTestRequest(filter_.get(), 0, 1, net::URLRequestTestJob::test_url_1()); | |
| 629 MakeTestRequest(filter_.get(), 1, 2, net::URLRequestTestJob::test_url_2()); | |
| 630 MakeTestRequest(filter_.get(), 0, 3, net::URLRequestTestJob::test_url_3()); | |
| 631 MakeTestRequest(second_filter.get(), 1, 4, | |
| 632 net::URLRequestTestJob::test_url_1()); | |
| 633 MakeTestRequest(filter_.get(), 2, 5, net::URLRequestTestJob::test_url_2()); | |
| 634 MakeTestRequest(filter_.get(), 2, 6, net::URLRequestTestJob::test_url_3()); | |
| 635 | |
| 636 // Flush all the pending requests. | |
| 637 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 638 } | |
| 639 | |
| 640 // Test the private helper method "CalculateApproximateMemoryCost()". | |
| 641 TEST_F(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) { | |
| 642 net::URLRequest req(GURL("http://www.google.com"), NULL); | |
| 643 EXPECT_EQ(4427, ResourceDispatcherHost::CalculateApproximateMemoryCost(&req)); | |
| 644 | |
| 645 // Add 9 bytes of referrer. | |
| 646 req.set_referrer("123456789"); | |
| 647 EXPECT_EQ(4436, ResourceDispatcherHost::CalculateApproximateMemoryCost(&req)); | |
| 648 | |
| 649 // Add 33 bytes of upload content. | |
| 650 std::string upload_content; | |
| 651 upload_content.resize(33); | |
| 652 std::fill(upload_content.begin(), upload_content.end(), 'x'); | |
| 653 req.AppendBytesToUpload(upload_content.data(), upload_content.size()); | |
| 654 | |
| 655 // Since the upload throttling is disabled, this has no effect on the cost. | |
| 656 EXPECT_EQ(4436, ResourceDispatcherHost::CalculateApproximateMemoryCost(&req)); | |
| 657 | |
| 658 // Add a file upload -- should have no effect. | |
| 659 req.AppendFileToUpload(FilePath(FILE_PATH_LITERAL("does-not-exist.png"))); | |
| 660 EXPECT_EQ(4436, ResourceDispatcherHost::CalculateApproximateMemoryCost(&req)); | |
| 661 } | |
| 662 | |
| 663 // Test the private helper method "IncrementOutstandingRequestsMemoryCost()". | |
| 664 TEST_F(ResourceDispatcherHostTest, IncrementOutstandingRequestsMemoryCost) { | |
| 665 // Add some counts for render_process_host=7 | |
| 666 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(7)); | |
| 667 EXPECT_EQ(1, host_.IncrementOutstandingRequestsMemoryCost(1, 7)); | |
| 668 EXPECT_EQ(2, host_.IncrementOutstandingRequestsMemoryCost(1, 7)); | |
| 669 EXPECT_EQ(3, host_.IncrementOutstandingRequestsMemoryCost(1, 7)); | |
| 670 | |
| 671 // Add some counts for render_process_host=3 | |
| 672 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(3)); | |
| 673 EXPECT_EQ(1, host_.IncrementOutstandingRequestsMemoryCost(1, 3)); | |
| 674 EXPECT_EQ(2, host_.IncrementOutstandingRequestsMemoryCost(1, 3)); | |
| 675 | |
| 676 // Remove all the counts for render_process_host=7 | |
| 677 EXPECT_EQ(3, host_.GetOutstandingRequestsMemoryCost(7)); | |
| 678 EXPECT_EQ(2, host_.IncrementOutstandingRequestsMemoryCost(-1, 7)); | |
| 679 EXPECT_EQ(1, host_.IncrementOutstandingRequestsMemoryCost(-1, 7)); | |
| 680 EXPECT_EQ(0, host_.IncrementOutstandingRequestsMemoryCost(-1, 7)); | |
| 681 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(7)); | |
| 682 | |
| 683 // Remove all the counts for render_process_host=3 | |
| 684 EXPECT_EQ(2, host_.GetOutstandingRequestsMemoryCost(3)); | |
| 685 EXPECT_EQ(1, host_.IncrementOutstandingRequestsMemoryCost(-1, 3)); | |
| 686 EXPECT_EQ(0, host_.IncrementOutstandingRequestsMemoryCost(-1, 3)); | |
| 687 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(3)); | |
| 688 | |
| 689 // When an entry reaches 0, it should be deleted. | |
| 690 EXPECT_TRUE(host_.outstanding_requests_memory_cost_map_.end() == | |
| 691 host_.outstanding_requests_memory_cost_map_.find(7)); | |
| 692 EXPECT_TRUE(host_.outstanding_requests_memory_cost_map_.end() == | |
| 693 host_.outstanding_requests_memory_cost_map_.find(3)); | |
| 694 } | |
| 695 | |
| 696 // Test that when too many requests are outstanding for a particular | |
| 697 // render_process_host_id, any subsequent request from it fails. | |
| 698 TEST_F(ResourceDispatcherHostTest, TooManyOutstandingRequests) { | |
| 699 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
| 700 | |
| 701 // Expected cost of each request as measured by | |
| 702 // ResourceDispatcherHost::CalculateApproximateMemoryCost(). | |
| 703 int kMemoryCostOfTest2Req = | |
| 704 ResourceDispatcherHost::kAvgBytesPerOutstandingRequest + | |
| 705 std::string("GET").size() + | |
| 706 net::URLRequestTestJob::test_url_2().spec().size(); | |
| 707 | |
| 708 // Tighten the bound on the ResourceDispatcherHost, to speed things up. | |
| 709 int kMaxCostPerProcess = 440000; | |
| 710 host_.set_max_outstanding_requests_cost_per_process(kMaxCostPerProcess); | |
| 711 | |
| 712 // Determine how many instance of test_url_2() we can request before | |
| 713 // throttling kicks in. | |
| 714 size_t kMaxRequests = kMaxCostPerProcess / kMemoryCostOfTest2Req; | |
| 715 | |
| 716 // This second filter is used to emulate a second process. | |
| 717 scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter(this); | |
| 718 | |
| 719 // Saturate the number of outstanding requests for our process. | |
| 720 for (size_t i = 0; i < kMaxRequests; ++i) { | |
| 721 MakeTestRequest(filter_.get(), 0, i + 1, | |
| 722 net::URLRequestTestJob::test_url_2()); | |
| 723 } | |
| 724 | |
| 725 // Issue two more requests for our process -- these should fail immediately. | |
| 726 MakeTestRequest(filter_.get(), 0, kMaxRequests + 1, | |
| 727 net::URLRequestTestJob::test_url_2()); | |
| 728 MakeTestRequest(filter_.get(), 0, kMaxRequests + 2, | |
| 729 net::URLRequestTestJob::test_url_2()); | |
| 730 | |
| 731 // Issue two requests for the second process -- these should succeed since | |
| 732 // it is just process 0 that is saturated. | |
| 733 MakeTestRequest(second_filter.get(), 0, kMaxRequests + 3, | |
| 734 net::URLRequestTestJob::test_url_2()); | |
| 735 MakeTestRequest(second_filter.get(), 0, kMaxRequests + 4, | |
| 736 net::URLRequestTestJob::test_url_2()); | |
| 737 | |
| 738 // Flush all the pending requests. | |
| 739 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 740 MessageLoop::current()->RunAllPending(); | |
| 741 | |
| 742 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
| 743 | |
| 744 // Sorts out all the messages we saw by request. | |
| 745 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 746 accum_.GetClassifiedMessages(&msgs); | |
| 747 | |
| 748 // We issued (kMaxRequests + 4) total requests. | |
| 749 ASSERT_EQ(kMaxRequests + 4, msgs.size()); | |
| 750 | |
| 751 // Check that the first kMaxRequests succeeded. | |
| 752 for (size_t i = 0; i < kMaxRequests; ++i) | |
| 753 CheckSuccessfulRequest(msgs[i], net::URLRequestTestJob::test_data_2()); | |
| 754 | |
| 755 // Check that the subsequent two requests (kMaxRequests + 1) and | |
| 756 // (kMaxRequests + 2) were failed, since the per-process bound was reached. | |
| 757 for (int i = 0; i < 2; ++i) { | |
| 758 // Should have sent a single RequestComplete message. | |
| 759 int index = kMaxRequests + i; | |
| 760 EXPECT_EQ(1U, msgs[index].size()); | |
| 761 EXPECT_EQ(ViewMsg_Resource_RequestComplete::ID, msgs[index][0].type()); | |
| 762 | |
| 763 // The RequestComplete message should have had status | |
| 764 // (CANCELLED, ERR_INSUFFICIENT_RESOURCES). | |
| 765 int request_id; | |
| 766 net::URLRequestStatus status; | |
| 767 | |
| 768 void* iter = NULL; | |
| 769 EXPECT_TRUE(IPC::ReadParam(&msgs[index][0], &iter, &request_id)); | |
| 770 EXPECT_TRUE(IPC::ReadParam(&msgs[index][0], &iter, &status)); | |
| 771 | |
| 772 EXPECT_EQ(index + 1, request_id); | |
| 773 EXPECT_EQ(net::URLRequestStatus::CANCELED, status.status()); | |
| 774 EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES, status.os_error()); | |
| 775 } | |
| 776 | |
| 777 // The final 2 requests should have succeeded. | |
| 778 CheckSuccessfulRequest(msgs[kMaxRequests + 2], | |
| 779 net::URLRequestTestJob::test_data_2()); | |
| 780 CheckSuccessfulRequest(msgs[kMaxRequests + 3], | |
| 781 net::URLRequestTestJob::test_data_2()); | |
| 782 } | |
| 783 | |
| 784 // Tests that we sniff the mime type for a simple request. | |
| 785 TEST_F(ResourceDispatcherHostTest, MimeSniffed) { | |
| 786 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 787 | |
| 788 std::string response("HTTP/1.1 200 OK\n\n"); | |
| 789 std::string raw_headers(net::HttpUtil::AssembleRawHeaders(response.data(), | |
| 790 response.size())); | |
| 791 std::string response_data("<html><title>Test One</title></html>"); | |
| 792 SetResponse(raw_headers, response_data); | |
| 793 | |
| 794 HandleScheme("http"); | |
| 795 MakeTestRequest(0, 1, GURL("http:bla")); | |
| 796 | |
| 797 // Flush all pending requests. | |
| 798 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 799 | |
| 800 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 801 | |
| 802 // Sorts out all the messages we saw by request. | |
| 803 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 804 accum_.GetClassifiedMessages(&msgs); | |
| 805 ASSERT_EQ(1U, msgs.size()); | |
| 806 | |
| 807 ResourceResponseHead response_head; | |
| 808 GetResponseHead(msgs[0], &response_head); | |
| 809 ASSERT_EQ("text/html", response_head.mime_type); | |
| 810 } | |
| 811 | |
| 812 // Tests that we don't sniff the mime type when the server provides one. | |
| 813 TEST_F(ResourceDispatcherHostTest, MimeNotSniffed) { | |
| 814 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 815 | |
| 816 std::string response("HTTP/1.1 200 OK\n" | |
| 817 "Content-type: image/jpeg\n\n"); | |
| 818 std::string raw_headers(net::HttpUtil::AssembleRawHeaders(response.data(), | |
| 819 response.size())); | |
| 820 std::string response_data("<html><title>Test One</title></html>"); | |
| 821 SetResponse(raw_headers, response_data); | |
| 822 | |
| 823 HandleScheme("http"); | |
| 824 MakeTestRequest(0, 1, GURL("http:bla")); | |
| 825 | |
| 826 // Flush all pending requests. | |
| 827 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 828 | |
| 829 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 830 | |
| 831 // Sorts out all the messages we saw by request. | |
| 832 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 833 accum_.GetClassifiedMessages(&msgs); | |
| 834 ASSERT_EQ(1U, msgs.size()); | |
| 835 | |
| 836 ResourceResponseHead response_head; | |
| 837 GetResponseHead(msgs[0], &response_head); | |
| 838 ASSERT_EQ("image/jpeg", response_head.mime_type); | |
| 839 } | |
| 840 | |
| 841 // Tests that we don't sniff the mime type when there is no message body. | |
| 842 TEST_F(ResourceDispatcherHostTest, MimeNotSniffed2) { | |
| 843 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 844 | |
| 845 std::string response("HTTP/1.1 304 Not Modified\n\n"); | |
| 846 std::string raw_headers(net::HttpUtil::AssembleRawHeaders(response.data(), | |
| 847 response.size())); | |
| 848 std::string response_data; | |
| 849 SetResponse(raw_headers, response_data); | |
| 850 | |
| 851 HandleScheme("http"); | |
| 852 MakeTestRequest(0, 1, GURL("http:bla")); | |
| 853 | |
| 854 // Flush all pending requests. | |
| 855 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 856 | |
| 857 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 858 | |
| 859 // Sorts out all the messages we saw by request. | |
| 860 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 861 accum_.GetClassifiedMessages(&msgs); | |
| 862 ASSERT_EQ(1U, msgs.size()); | |
| 863 | |
| 864 ResourceResponseHead response_head; | |
| 865 GetResponseHead(msgs[0], &response_head); | |
| 866 ASSERT_EQ("", response_head.mime_type); | |
| 867 } | |
| 868 | |
| 869 TEST_F(ResourceDispatcherHostTest, MimeSniff204) { | |
| 870 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 871 | |
| 872 std::string response("HTTP/1.1 204 No Content\n\n"); | |
| 873 std::string raw_headers(net::HttpUtil::AssembleRawHeaders(response.data(), | |
| 874 response.size())); | |
| 875 std::string response_data; | |
| 876 SetResponse(raw_headers, response_data); | |
| 877 | |
| 878 HandleScheme("http"); | |
| 879 MakeTestRequest(0, 1, GURL("http:bla")); | |
| 880 | |
| 881 // Flush all pending requests. | |
| 882 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 883 | |
| 884 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 885 | |
| 886 // Sorts out all the messages we saw by request. | |
| 887 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 888 accum_.GetClassifiedMessages(&msgs); | |
| 889 ASSERT_EQ(1U, msgs.size()); | |
| 890 | |
| 891 ResourceResponseHead response_head; | |
| 892 GetResponseHead(msgs[0], &response_head); | |
| 893 ASSERT_EQ("text/plain", response_head.mime_type); | |
| 894 } | |
| 895 | |
| 896 // Tests for crbug.com/31266 (Non-2xx + application/octet-stream). | |
| 897 TEST_F(ResourceDispatcherHostTest, ForbiddenDownload) { | |
| 898 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 899 | |
| 900 std::string response("HTTP/1.1 403 Forbidden\n" | |
| 901 "Content-disposition: attachment; filename=blah\n" | |
| 902 "Content-type: application/octet-stream\n\n"); | |
| 903 std::string raw_headers(net::HttpUtil::AssembleRawHeaders(response.data(), | |
| 904 response.size())); | |
| 905 std::string response_data("<html><title>Test One</title></html>"); | |
| 906 SetResponse(raw_headers, response_data); | |
| 907 | |
| 908 // Only MAIN_FRAMEs can trigger a download. | |
| 909 SetResourceType(ResourceType::MAIN_FRAME); | |
| 910 | |
| 911 HandleScheme("http"); | |
| 912 MakeTestRequest(0, 1, GURL("http:bla")); | |
| 913 | |
| 914 // Flush all pending requests. | |
| 915 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
| 916 | |
| 917 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
| 918 | |
| 919 // Sorts out all the messages we saw by request. | |
| 920 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
| 921 accum_.GetClassifiedMessages(&msgs); | |
| 922 | |
| 923 // We should have gotten one RequestComplete message. | |
| 924 ASSERT_EQ(1U, msgs[0].size()); | |
| 925 EXPECT_EQ(ViewMsg_Resource_RequestComplete::ID, msgs[0][0].type()); | |
| 926 | |
| 927 // The RequestComplete message should have had status | |
| 928 // (CANCELED, ERR_FILE_NOT_FOUND). | |
| 929 int request_id; | |
| 930 net::URLRequestStatus status; | |
| 931 | |
| 932 void* iter = NULL; | |
| 933 EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id)); | |
| 934 EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &status)); | |
| 935 | |
| 936 EXPECT_EQ(1, request_id); | |
| 937 EXPECT_EQ(net::URLRequestStatus::CANCELED, status.status()); | |
| 938 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, status.os_error()); | |
| 939 } | |
| 940 | |
| 941 class DummyResourceHandler : public ResourceHandler { | |
| 942 public: | |
| 943 DummyResourceHandler() {} | |
| 944 | |
| 945 // Called as upload progress is made. | |
| 946 bool OnUploadProgress(int request_id, uint64 position, uint64 size) { | |
| 947 return true; | |
| 948 } | |
| 949 | |
| 950 bool OnRequestRedirected(int request_id, const GURL& url, | |
| 951 ResourceResponse* response, bool* defer) { | |
| 952 return true; | |
| 953 } | |
| 954 | |
| 955 bool OnResponseStarted(int request_id, ResourceResponse* response) { | |
| 956 return true; | |
| 957 } | |
| 958 | |
| 959 bool OnWillStart(int request_id, const GURL& url, bool* defer) { | |
| 960 return true; | |
| 961 } | |
| 962 | |
| 963 bool OnWillRead( | |
| 964 int request_id, net::IOBuffer** buf, int* buf_size, int min_size) { | |
| 965 return true; | |
| 966 } | |
| 967 | |
| 968 bool OnReadCompleted(int request_id, int* bytes_read) { return true; } | |
| 969 | |
| 970 bool OnResponseCompleted( | |
| 971 int request_id, | |
| 972 const net::URLRequestStatus& status, | |
| 973 const std::string& info) { | |
| 974 return true; | |
| 975 } | |
| 976 | |
| 977 void OnRequestClosed() {} | |
| 978 | |
| 979 private: | |
| 980 DISALLOW_COPY_AND_ASSIGN(DummyResourceHandler); | |
| 981 }; | |
| 982 | |
| 983 class ApplyExtensionLocalizationFilterTest : public testing::Test { | |
| 984 protected: | |
| 985 void SetUp() { | |
| 986 url_.reset(new GURL( | |
| 987 "chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/popup.html")); | |
| 988 resource_type_ = ResourceType::STYLESHEET; | |
| 989 resource_handler_.reset(new DummyResourceHandler()); | |
| 990 request_info_.reset(CreateNewResourceRequestInfo()); | |
| 991 } | |
| 992 | |
| 993 ResourceDispatcherHostRequestInfo* CreateNewResourceRequestInfo() { | |
| 994 return new ResourceDispatcherHostRequestInfo( | |
| 995 resource_handler_.get(), ChildProcessInfo::RENDER_PROCESS, 0, 0, 0, | |
| 996 ResourceType::STYLESHEET, 0U, false, false, false, -1, -1); | |
| 997 } | |
| 998 | |
| 999 scoped_ptr<GURL> url_; | |
| 1000 ResourceType::Type resource_type_; | |
| 1001 scoped_ptr<DummyResourceHandler> resource_handler_; | |
| 1002 scoped_ptr<ResourceDispatcherHostRequestInfo> request_info_; | |
| 1003 }; | |
| 1004 | |
| 1005 TEST_F(ApplyExtensionLocalizationFilterTest, WrongScheme) { | |
| 1006 url_.reset(new GURL("html://behllobkkfkfnphdnhnkndlbkcpglgmj/popup.html")); | |
| 1007 ResourceDispatcherHost::ApplyExtensionLocalizationFilter(*url_, | |
| 1008 resource_type_, request_info_.get()); | |
| 1009 | |
| 1010 EXPECT_FALSE(request_info_->replace_extension_localization_templates()); | |
| 1011 } | |
| 1012 | |
| 1013 TEST_F(ApplyExtensionLocalizationFilterTest, GoodScheme) { | |
| 1014 ResourceDispatcherHost::ApplyExtensionLocalizationFilter(*url_, | |
| 1015 resource_type_, request_info_.get()); | |
| 1016 | |
| 1017 EXPECT_TRUE(request_info_->replace_extension_localization_templates()); | |
| 1018 } | |
| 1019 | |
| 1020 TEST_F(ApplyExtensionLocalizationFilterTest, GoodSchemeWrongResourceType) { | |
| 1021 resource_type_ = ResourceType::MAIN_FRAME; | |
| 1022 ResourceDispatcherHost::ApplyExtensionLocalizationFilter(*url_, | |
| 1023 resource_type_, request_info_.get()); | |
| 1024 | |
| 1025 EXPECT_FALSE(request_info_->replace_extension_localization_templates()); | |
| 1026 } | |
| OLD | NEW |