Index: content/browser/loader/resource_dispatcher_host_unittest.cc |
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc |
index 4a9e27553dd59efdc099870f899e4872016bbef9..4939b80785ba5b15577e050462513e4b9e00638b 100644 |
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc |
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc |
@@ -15,6 +15,7 @@ |
#include "content/browser/browser_thread_impl.h" |
#include "content/browser/child_process_security_policy_impl.h" |
#include "content/browser/loader/resource_dispatcher_host_impl.h" |
+#include "content/browser/loader/resource_loader.h" |
#include "content/browser/loader/resource_message_filter.h" |
#include "content/browser/loader/resource_request_info_impl.h" |
#include "content/browser/worker_host/worker_service_impl.h" |
@@ -523,7 +524,6 @@ class ResourceDispatcherHostTest : public testing::Test, |
cache_thread_(BrowserThread::CACHE, &message_loop_), |
io_thread_(BrowserThread::IO, &message_loop_), |
old_factory_(NULL), |
- resource_type_(ResourceType::SUB_RESOURCE), |
send_data_received_acks_(false) { |
browser_context_.reset(new TestBrowserContext()); |
BrowserContext::EnsureResourceContextInitialized(browser_context_.get()); |
@@ -594,17 +594,17 @@ class ResourceDispatcherHostTest : public testing::Test, |
message_loop_.RunUntilIdle(); |
} |
- // Creates a request using the current test object as the filter. |
+ // Creates a request using the current test object as the filter and |
+ // SubResource as the resource type. |
void MakeTestRequest(int render_view_id, |
int request_id, |
const GURL& url); |
- // Generates a request using the given filter. This will probably be a |
- // ForwardingFilter. |
- void MakeTestRequest(ResourceMessageFilter* filter, |
- int render_view_id, |
- int request_id, |
- const GURL& url); |
+ // Generates a request using the given filter and resource type. |
+ void MakeTestRequestWithResourceType(ResourceMessageFilter* filter, |
+ int render_view_id, int request_id, |
+ const GURL& url, |
+ ResourceType::Type type); |
void CancelRequest(int request_id); |
@@ -634,11 +634,6 @@ class ResourceDispatcherHostTest : public testing::Test, |
SetResponse(headers, std::string()); |
} |
- // Sets a particular resource type for any request from now on. |
- void SetResourceType(ResourceType::Type type) { |
- resource_type_ = type; |
- } |
- |
void SendDataReceivedACKs(bool send_acks) { |
send_data_received_acks_ = send_acks; |
} |
@@ -724,7 +719,6 @@ class ResourceDispatcherHostTest : public testing::Test, |
std::string response_data_; |
std::string scheme_; |
net::URLRequest::ProtocolFactory* old_factory_; |
- ResourceType::Type resource_type_; |
bool send_data_received_acks_; |
std::set<int> child_ids_; |
static ResourceDispatcherHostTest* test_fixture_; |
@@ -741,19 +735,21 @@ int ResourceDispatcherHostTest::url_request_jobs_created_count_ = 0; |
void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id, |
int request_id, |
const GURL& url) { |
- MakeTestRequest(filter_.get(), render_view_id, request_id, url); |
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id, |
+ url, ResourceType::SUB_RESOURCE); |
} |
-void ResourceDispatcherHostTest::MakeTestRequest( |
+void ResourceDispatcherHostTest::MakeTestRequestWithResourceType( |
ResourceMessageFilter* filter, |
int render_view_id, |
int request_id, |
- const GURL& url) { |
+ const GURL& url, |
+ ResourceType::Type type) { |
// If it's already there, this'll be dropped on the floor, which is fine. |
child_ids_.insert(filter->child_id()); |
ResourceHostMsg_Request request = |
- CreateResourceRequest("GET", resource_type_, url); |
+ CreateResourceRequest("GET", type, url); |
ResourceHostMsg_RequestResource msg(render_view_id, request_id, request); |
bool msg_was_ok; |
host_.OnMessageReceived(msg, filter, &msg_was_ok); |
@@ -778,6 +774,29 @@ void ResourceDispatcherHostTest::CompleteStartRequest( |
URLRequestTestDelayedStartJob::CompleteStart(req); |
} |
+void CheckRequestCompleteErrorCode(const IPC::Message& message, |
+ int expected_error_code) { |
+ // Verify that there was no error. |
+ int request_id; |
+ int error_code; |
+ |
+ ASSERT_EQ(ResourceMsg_RequestComplete::ID, message.type()); |
+ |
+ PickleIterator iter(message); |
+ ASSERT_TRUE(IPC::ReadParam(&message, &iter, &request_id)); |
+ ASSERT_TRUE(IPC::ReadParam(&message, &iter, &error_code)); |
+ ASSERT_EQ(error_code, expected_error_code); |
+} |
+ |
+void ExtractDataOffsetAndLength(const IPC::Message& message, int* data_offset, |
+ int* data_length) { |
+ PickleIterator iter(message); |
+ int request_id; |
+ ASSERT_TRUE(IPC::ReadParam(&message, &iter, &request_id)); |
+ ASSERT_TRUE(IPC::ReadParam(&message, &iter, data_offset)); |
+ ASSERT_TRUE(IPC::ReadParam(&message, &iter, data_length)); |
+} |
+ |
void CheckSuccessfulRequest(const std::vector<IPC::Message>& messages, |
const std::string& reference_data) { |
// A successful request will have received 4 messages: |
@@ -807,12 +826,9 @@ void CheckSuccessfulRequest(const std::vector<IPC::Message>& messages, |
// should probably test multiple chunks later |
ASSERT_EQ(ResourceMsg_DataReceived::ID, messages[2].type()); |
- PickleIterator iter2(messages[2]); |
- ASSERT_TRUE(IPC::ReadParam(&messages[2], &iter2, &request_id)); |
int data_offset; |
- ASSERT_TRUE(IPC::ReadParam(&messages[2], &iter2, &data_offset)); |
int data_length; |
- ASSERT_TRUE(IPC::ReadParam(&messages[2], &iter2, &data_length)); |
+ ExtractDataOffsetAndLength(messages[2], &data_offset, &data_length); |
ASSERT_EQ(reference_data.size(), static_cast<size_t>(data_length)); |
ASSERT_GE(shm_size, data_length); |
@@ -823,7 +839,34 @@ void CheckSuccessfulRequest(const std::vector<IPC::Message>& messages, |
ASSERT_EQ(0, memcmp(reference_data.c_str(), data, data_length)); |
// The last message should be all data received. |
- ASSERT_EQ(ResourceMsg_RequestComplete::ID, messages[3].type()); |
+ CheckRequestCompleteErrorCode(messages[3], net::OK); |
+} |
+ |
+void CheckSuccessfulRedirect(const std::vector<IPC::Message>& messages, |
+ const std::string& reference_data) { |
+ ASSERT_EQ(5U, messages.size()); |
+ ASSERT_EQ(ResourceMsg_ReceivedRedirect::ID, messages[0].type()); |
+ |
+ const std::vector<IPC::Message> second_req_msgs = |
+ std::vector<IPC::Message>(messages.begin() + 1, messages.end()); |
+ CheckSuccessfulRequest(second_req_msgs, reference_data); |
+} |
+ |
+void CheckSuccessfulDetachedRequest( |
+ const std::vector<IPC::Message>& messages) { |
+ // A successful request will have received 2 messages: |
+ // ReceivedResponse (indicates headers received) |
+ // RequestComplete (request is done) |
+ // |
+ // This function verifies that we received 2 messages and that they |
+ // are appropriate. |
+ ASSERT_EQ(2U, messages.size()); |
+ |
+ // The first messages should be received response |
+ ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, messages[0].type()); |
+ |
+ // The last message should be all data received. |
+ CheckRequestCompleteErrorCode(messages[1], net::OK); |
} |
void CheckFailedRequest(const std::vector<IPC::Message>& messages, |
@@ -836,15 +879,8 @@ void CheckFailedRequest(const std::vector<IPC::Message>& messages, |
if (messages.size() == 2) { |
EXPECT_EQ(ResourceMsg_ReceivedResponse::ID, messages[0].type()); |
} |
- EXPECT_EQ(ResourceMsg_RequestComplete::ID, messages[failure_index].type()); |
- int request_id; |
- int error_code; |
- |
- PickleIterator iter(messages[failure_index]); |
- EXPECT_TRUE(IPC::ReadParam(&messages[failure_index], &iter, &request_id)); |
- EXPECT_TRUE(IPC::ReadParam(&messages[failure_index], &iter, &error_code)); |
- EXPECT_EQ(expected_error, error_code); |
+ CheckRequestCompleteErrorCode(messages[failure_index], expected_error); |
} |
// Tests whether many messages get dispatched properly. |
@@ -852,6 +888,14 @@ TEST_F(ResourceDispatcherHostTest, TestMany) { |
MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); |
MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2()); |
MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); |
+ MakeTestRequest(0, 4, net::URLRequestTestJob::test_url_4()); |
+ MakeTestRequest(0, 5, net::URLRequestTestJob::test_url_redirect_to_url_2()); |
+ |
+ // Finish the redirection |
+ ResourceHostMsg_FollowRedirect redirect_msg(5, false, GURL()); |
+ bool msg_was_ok; |
+ host_.OnMessageReceived(redirect_msg, filter_.get(), &msg_was_ok); |
+ base::MessageLoop::current()->RunUntilIdle(); |
// flush all the pending requests |
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
@@ -860,35 +904,32 @@ TEST_F(ResourceDispatcherHostTest, TestMany) { |
ResourceIPCAccumulator::ClassifiedMessages msgs; |
accum_.GetClassifiedMessages(&msgs); |
- // there are three requests, so we should have gotten them classified as such |
- ASSERT_EQ(3U, msgs.size()); |
+ // there are five requests, so we should have gotten them classified as such |
+ ASSERT_EQ(5U, msgs.size()); |
CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); |
CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_2()); |
CheckSuccessfulRequest(msgs[2], net::URLRequestTestJob::test_data_3()); |
+ CheckSuccessfulRequest(msgs[3], net::URLRequestTestJob::test_data_4()); |
+ CheckSuccessfulRedirect(msgs[4], net::URLRequestTestJob::test_data_2()); |
} |
-void CheckCancelledRequestCompleteMessage(const IPC::Message& message) { |
- ASSERT_EQ(ResourceMsg_RequestComplete::ID, message.type()); |
- |
- int request_id; |
- int error_code; |
- |
- PickleIterator iter(message); |
- ASSERT_TRUE(IPC::ReadParam(&message, &iter, &request_id)); |
- ASSERT_TRUE(IPC::ReadParam(&message, &iter, &error_code)); |
- |
- EXPECT_EQ(net::ERR_ABORTED, error_code); |
-} |
- |
-// Tests whether messages get canceled properly. We issue three requests, |
-// cancel one of them, and make sure that each sent the proper notifications. |
+// Tests whether messages get canceled properly. We issue four requests, |
+// cancel two of them, and make sure that each sent the proper notifications. |
TEST_F(ResourceDispatcherHostTest, Cancel) { |
MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); |
MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2()); |
MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 4, |
+ net::URLRequestTestJob::test_url_4(), |
+ ResourceType::PREFETCH); // detachable type |
+ |
CancelRequest(2); |
+ // Cancel request must come from the renderer for a detachable resource to |
+ // delay. |
+ host_.CancelRequest(filter_->child_id(), 4, true); |
+ |
// flush all the pending requests |
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
base::MessageLoop::current()->RunUntilIdle(); |
@@ -896,16 +937,140 @@ TEST_F(ResourceDispatcherHostTest, Cancel) { |
ResourceIPCAccumulator::ClassifiedMessages msgs; |
accum_.GetClassifiedMessages(&msgs); |
- // there are three requests, so we should have gotten them classified as such |
- ASSERT_EQ(3U, msgs.size()); |
+ // there are four requests, so we should have gotten them classified as such |
+ ASSERT_EQ(4U, msgs.size()); |
CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); |
CheckSuccessfulRequest(msgs[2], net::URLRequestTestJob::test_data_3()); |
+ // The detachable resource should have delayed its cancellation and completed. |
+ CheckSuccessfulDetachedRequest(msgs[3]); |
// Check that request 2 got canceled. |
ASSERT_EQ(2U, msgs[1].size()); |
ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[1][0].type()); |
- CheckCancelledRequestCompleteMessage(msgs[1][1]); |
+ CheckRequestCompleteErrorCode(msgs[1][1], net::ERR_ABORTED); |
+} |
+ |
+// Shows that detachable requests will timeout if the request takes too long to |
+// complete. |
+TEST_F(ResourceDispatcherHostTest, DetachableResourceTimesOut) { |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 1, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::PREFETCH); // detachable type |
+ ResourceLoader* loader = host_.GetLoader(filter_->child_id(), 1); |
+ ASSERT_TRUE(loader); |
+ loader->set_detachable_delay_ms(200); |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ host_.CancelRequest(filter_->child_id(), 1, true); |
+ |
+ EXPECT_EQ(1, host_.pending_requests()); |
+ |
+ // Wait until after the delay timer times out before we start processing any |
+ // messages. |
+ base::OneShotTimer<base::MessageLoop> timer; |
+ timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(210), |
+ base::MessageLoop::current(), &base::MessageLoop::QuitWhenIdle); |
+ base::MessageLoop::current()->Run(); |
+ |
+ // We should have cancelled the prefetch by now. |
+ EXPECT_EQ(0, host_.pending_requests()); |
+ |
+ // In case any messages are still to be processed. |
+ while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
+ ResourceIPCAccumulator::ClassifiedMessages msgs; |
+ accum_.GetClassifiedMessages(&msgs); |
+ |
+ ASSERT_EQ(1U, msgs.size()); |
+ |
+ // The request should have cancelled. |
+ ASSERT_EQ(2U, msgs[0].size()); |
+ ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[0][0].type()); |
+ CheckRequestCompleteErrorCode(msgs[0][1], net::ERR_ABORTED); |
+} |
+ |
+// If the filter has disappeared then detachable resources should continue to |
+// load. |
+TEST_F(ResourceDispatcherHostTest, DeletedFilterDetachable) { |
+ ResourceHostMsg_Request request = CreateResourceRequest( |
+ "GET", ResourceType::PREFETCH, net::URLRequestTestJob::test_url_4()); |
+ |
+ ResourceHostMsg_RequestResource msg(0, 1, request); |
+ bool msg_was_ok; |
+ host_.OnMessageReceived(msg, filter_, &msg_was_ok); |
+ |
+ // Remove the filter before processing the request by simulating channel |
+ // closure. |
+ GlobalRequestID global_request_id(filter_->child_id(), 1); |
+ ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest( |
+ host_.GetURLRequest(global_request_id)); |
+ info->filter_->OnChannelClosing(); |
+ info->filter_.reset(); |
+ |
+ EXPECT_EQ(1, host_.pending_requests()); |
+ |
+ KickOffRequest(); |
+ |
+ // Make sure the request wasn't canceled early. |
+ EXPECT_EQ(1, host_.pending_requests()); |
+ |
+ while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
+ EXPECT_EQ(0, host_.pending_requests()); |
+ |
+ // Because the filter was gone, no messages should have been sent. |
+ // TODO(jkarlin): It would be nice to verify that we successfully completed |
+ // the request, but we have no messages to verify with. |
+ ResourceIPCAccumulator::ClassifiedMessages msgs; |
+ accum_.GetClassifiedMessages(&msgs); |
+ ASSERT_EQ(0U, msgs.size()); |
+} |
+ |
+// If the filter has disappeared (original process dies) then detachable |
+// resources should continue to load, even when redirected. |
+TEST_F(ResourceDispatcherHostTest, DeletedFilterDetachableRedirect) { |
+ ResourceHostMsg_Request request = CreateResourceRequest( |
+ "GET", ResourceType::PREFETCH, |
+ net::URLRequestTestJob::test_url_redirect_to_url_2()); |
+ |
+ ResourceHostMsg_RequestResource msg(0, 1, request); |
+ bool msg_was_ok; |
+ host_.OnMessageReceived(msg, filter_, &msg_was_ok); |
+ |
+ // Remove the filter before processing the request by simulating channel |
+ // closure. |
+ GlobalRequestID global_request_id(filter_->child_id(), 1); |
+ ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest( |
+ host_.GetURLRequest(global_request_id)); |
+ info->filter_->OnChannelClosing(); |
+ info->filter_.reset(); |
+ |
+ EXPECT_EQ(1, host_.pending_requests()); |
+ // Verify no redirects before resetting the filter. |
+ net::URLRequest* url_request = host_.GetURLRequest(global_request_id); |
+ EXPECT_EQ(1u, url_request->url_chain().size()); |
+ KickOffRequest(); |
+ |
+ // Verify that a redirect was followed. |
+ EXPECT_EQ(2u, url_request->url_chain().size()); |
+ |
+ // Make sure the request wasn't canceled early. |
+ EXPECT_EQ(1, host_.pending_requests()); |
+ |
+ // Finish up the request. |
+ while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
+ EXPECT_EQ(0, host_.pending_requests()); |
+ |
+ // Because the filter was deleted, no messages should have been sent. |
+ // TODO(jkarlin): It would be nice to verify that we successfully completed |
+ // the request, but we have no messages to verify with. |
+ ResourceIPCAccumulator::ClassifiedMessages msgs; |
+ accum_.GetClassifiedMessages(&msgs); |
+ ASSERT_EQ(0U, msgs.size()); |
} |
TEST_F(ResourceDispatcherHostTest, CancelWhileStartIsDeferred) { |
@@ -950,7 +1115,7 @@ TEST_F(ResourceDispatcherHostTest, CancelInResourceThrottleWillStartRequest) { |
// Check that request got canceled. |
ASSERT_EQ(1U, msgs[0].size()); |
- CheckCancelledRequestCompleteMessage(msgs[0][0]); |
+ CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_ABORTED); |
// Make sure URLRequest is never started. |
EXPECT_EQ(0, url_request_jobs_created_count_); |
@@ -1030,16 +1195,8 @@ TEST_F(ResourceDispatcherHostTest, CancelInDelegate) { |
// Check the cancellation |
ASSERT_EQ(1U, msgs.size()); |
ASSERT_EQ(1U, msgs[0].size()); |
- ASSERT_EQ(ResourceMsg_RequestComplete::ID, msgs[0][0].type()); |
- |
- int request_id; |
- int error_code; |
- |
- PickleIterator iter(msgs[0][0]); |
- ASSERT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id)); |
- ASSERT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &error_code)); |
- EXPECT_EQ(net::ERR_ACCESS_DENIED, error_code); |
+ CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_ACCESS_DENIED); |
} |
// The host delegate acts as a second one so we can have some requests |
@@ -1077,15 +1234,23 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { |
ResourceHostMsg_Request request = CreateResourceRequest( |
"GET", ResourceType::SUB_RESOURCE, net::URLRequestTestJob::test_url_1()); |
- MakeTestRequest(test_filter.get(), 0, 1, |
- net::URLRequestTestJob::test_url_1()); |
+ MakeTestRequestWithResourceType(test_filter.get(), 0, 1, |
+ net::URLRequestTestJob::test_url_1(), |
+ ResourceType::SUB_RESOURCE); |
// request 2 goes to us |
MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2()); |
// request 3 goes to the test delegate |
- MakeTestRequest(test_filter.get(), 0, 3, |
- net::URLRequestTestJob::test_url_3()); |
+ MakeTestRequestWithResourceType(test_filter.get(), 0, 3, |
+ net::URLRequestTestJob::test_url_3(), |
+ ResourceType::SUB_RESOURCE); |
+ |
+ // request 4 goes to us |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 4, |
+ net::URLRequestTestJob::test_url_4(), |
+ ResourceType::PREFETCH); // detachable type |
+ |
// Make sure all requests have finished stage one. test_url_1 will have |
// finished. |
@@ -1097,7 +1262,9 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { |
// breaks the whole test. |
//EXPECT_EQ(3, host_.pending_requests()); |
- // Process each request for one level so one callback is called. |
+ // Process test_url_2 and test_url_3 for one level so one callback is called. |
+ // We'll cancel test_url_4 (detachable) before processing it to verify that it |
+ // delays the cancel. |
for (int i = 0; i < 2; i++) |
EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); |
@@ -1113,11 +1280,52 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { |
// The test delegate should not have gotten any messages after being canceled. |
ASSERT_EQ(0, test_filter->received_after_canceled_); |
- // We should have gotten exactly one result. |
+ // We should have gotten two results. |
ResourceIPCAccumulator::ClassifiedMessages msgs; |
accum_.GetClassifiedMessages(&msgs); |
- ASSERT_EQ(1U, msgs.size()); |
+ ASSERT_EQ(2U, msgs.size()); |
CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2()); |
+ // We cancelled the detachable request before it finished, and it should have |
+ // delayed and completed regardless. |
+ CheckSuccessfulDetachedRequest(msgs[1]); |
+} |
+ |
+TEST_F(ResourceDispatcherHostTest, TestProcessCancelDetachableTimesOut) { |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 1, |
+ net::URLRequestTestJob::test_url_4(), |
+ ResourceType::PREFETCH); // detachable type |
+ ResourceLoader* loader = host_.GetLoader(filter_->child_id(), 1); |
+ EXPECT_TRUE(loader); |
+ loader->set_detachable_delay_ms(200); |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
+ // Cancel the requests to the test process. |
+ host_.CancelRequestsForProcess(filter_->child_id()); |
+ EXPECT_EQ(1, host_.pending_requests()); |
+ |
+ // Wait until after the delay timer times out before we start processing any |
+ // messages. |
+ base::OneShotTimer<base::MessageLoop> timer; |
+ timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(210), |
+ base::MessageLoop::current(), &base::MessageLoop::QuitWhenIdle); |
+ base::MessageLoop::current()->Run(); |
+ |
+ // We should have cancelled the prefetch by now. |
+ EXPECT_EQ(0, host_.pending_requests()); |
+ |
+ // In case any messages are still to be processed. |
+ while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
+ ResourceIPCAccumulator::ClassifiedMessages msgs; |
+ accum_.GetClassifiedMessages(&msgs); |
+ |
+ ASSERT_EQ(1U, msgs.size()); |
+ |
+ // The request should have cancelled. |
+ ASSERT_EQ(2U, msgs[0].size()); |
+ ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[0][0].type()); |
+ CheckRequestCompleteErrorCode(msgs[0][1], net::ERR_ABORTED); |
} |
// Tests blocking and resuming requests. |
@@ -1186,6 +1394,10 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) { |
MakeTestRequest(1, 2, net::URLRequestTestJob::test_url_2()); |
MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); |
MakeTestRequest(1, 4, net::URLRequestTestJob::test_url_1()); |
+ // Blocked detachable resources should not delay cancellation. |
+ MakeTestRequestWithResourceType(filter_.get(), 1, 5, |
+ net::URLRequestTestJob::test_url_4(), |
+ ResourceType::PREFETCH); // detachable type |
// Flush all the pending requests. |
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
@@ -1218,12 +1430,21 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) { |
host_.BlockRequestsForRoute(second_filter->child_id(), 0); |
- MakeTestRequest(filter_.get(), 0, 1, net::URLRequestTestJob::test_url_1()); |
- MakeTestRequest(second_filter.get(), 0, 2, |
- net::URLRequestTestJob::test_url_2()); |
- MakeTestRequest(filter_.get(), 0, 3, net::URLRequestTestJob::test_url_3()); |
- MakeTestRequest(second_filter.get(), 0, 4, |
- net::URLRequestTestJob::test_url_1()); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 1, |
+ net::URLRequestTestJob::test_url_1(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(second_filter.get(), 0, 2, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 3, |
+ net::URLRequestTestJob::test_url_3(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(second_filter.get(), 0, 4, |
+ net::URLRequestTestJob::test_url_1(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(second_filter.get(), 0, 5, |
+ net::URLRequestTestJob::test_url_4(), |
+ ResourceType::PREFETCH); // detachable type |
// Simulate process death. |
host_.CancelRequestsForProcess(second_filter->child_id()); |
@@ -1235,7 +1456,8 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) { |
ResourceIPCAccumulator::ClassifiedMessages msgs; |
accum_.GetClassifiedMessages(&msgs); |
- // The 2 requests for the RVH 0 should have been processed. |
+ // The 2 requests for the RVH 0 should have been processed. Note that |
+ // blocked detachable requests are canceled without delay. |
ASSERT_EQ(2U, msgs.size()); |
CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); |
@@ -1257,13 +1479,30 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) { |
host_.BlockRequestsForRoute(filter_->child_id(), 2); |
host_.BlockRequestsForRoute(second_filter->child_id(), 1); |
- MakeTestRequest(filter_.get(), 0, 1, net::URLRequestTestJob::test_url_1()); |
- MakeTestRequest(filter_.get(), 1, 2, net::URLRequestTestJob::test_url_2()); |
- MakeTestRequest(filter_.get(), 0, 3, net::URLRequestTestJob::test_url_3()); |
- MakeTestRequest(second_filter.get(), 1, 4, |
- net::URLRequestTestJob::test_url_1()); |
- MakeTestRequest(filter_.get(), 2, 5, net::URLRequestTestJob::test_url_2()); |
- MakeTestRequest(filter_.get(), 2, 6, net::URLRequestTestJob::test_url_3()); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 1, |
+ net::URLRequestTestJob::test_url_1(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(filter_.get(), 1, 2, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 3, |
+ net::URLRequestTestJob::test_url_3(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(second_filter.get(), 1, 4, |
+ net::URLRequestTestJob::test_url_1(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(filter_.get(), 2, 5, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(filter_.get(), 2, 6, |
+ net::URLRequestTestJob::test_url_3(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 7, |
+ net::URLRequestTestJob::test_url_4(), |
+ ResourceType::PREFETCH); // detachable type |
+ MakeTestRequestWithResourceType(second_filter.get(), 1, 8, |
+ net::URLRequestTestJob::test_url_4(), |
+ ResourceType::PREFETCH); // detachable type |
host_.CancelRequestsForProcess(filter_->child_id()); |
host_.CancelRequestsForProcess(second_filter->child_id()); |
@@ -1322,22 +1561,27 @@ TEST_F(ResourceDispatcherHostTest, TooMuchOutstandingRequestsMemory) { |
// Saturate the number of outstanding requests for our process. |
for (size_t i = 0; i < kMaxRequests; ++i) { |
- MakeTestRequest(filter_.get(), 0, i + 1, |
- net::URLRequestTestJob::test_url_2()); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, i + 1, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
} |
// Issue two more requests for our process -- these should fail immediately. |
- MakeTestRequest(filter_.get(), 0, kMaxRequests + 1, |
- net::URLRequestTestJob::test_url_2()); |
- MakeTestRequest(filter_.get(), 0, kMaxRequests + 2, |
- net::URLRequestTestJob::test_url_2()); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, kMaxRequests + 1, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, kMaxRequests + 2, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
// Issue two requests for the second process -- these should succeed since |
// it is just process 0 that is saturated. |
- MakeTestRequest(second_filter.get(), 0, kMaxRequests + 3, |
- net::URLRequestTestJob::test_url_2()); |
- MakeTestRequest(second_filter.get(), 0, kMaxRequests + 4, |
- net::URLRequestTestJob::test_url_2()); |
+ MakeTestRequestWithResourceType(second_filter.get(), 0, kMaxRequests + 3, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
+ MakeTestRequestWithResourceType(second_filter.get(), 0, kMaxRequests + 4, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
// Flush all the pending requests. |
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
@@ -1388,23 +1632,27 @@ TEST_F(ResourceDispatcherHostTest, TooManyOutstandingRequests) { |
// Saturate the number of outstanding requests for our process. |
for (size_t i = 0; i < kMaxRequestsPerProcess; ++i) { |
- MakeTestRequest(filter_.get(), 0, i + 1, |
- net::URLRequestTestJob::test_url_2()); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, i + 1, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
} |
// Issue another request for our process -- this should fail immediately. |
- MakeTestRequest(filter_.get(), 0, kMaxRequestsPerProcess + 1, |
- net::URLRequestTestJob::test_url_2()); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, kMaxRequestsPerProcess + 1, |
+ net::URLRequestTestJob::test_url_2(), |
+ ResourceType::SUB_RESOURCE); |
// Issue a request for the second process -- this should succeed, because it |
// is just process 0 that is saturated. |
- MakeTestRequest(second_filter.get(), 0, kMaxRequestsPerProcess + 2, |
- net::URLRequestTestJob::test_url_2()); |
+ MakeTestRequestWithResourceType( |
+ second_filter.get(), 0, kMaxRequestsPerProcess + 2, |
+ net::URLRequestTestJob::test_url_2(), ResourceType::SUB_RESOURCE); |
// Issue a request for the third process -- this should fail, because the |
// global limit has been reached. |
- MakeTestRequest(third_filter.get(), 0, kMaxRequestsPerProcess + 3, |
- net::URLRequestTestJob::test_url_2()); |
+ MakeTestRequestWithResourceType( |
+ third_filter.get(), 0, kMaxRequestsPerProcess + 3, |
+ net::URLRequestTestJob::test_url_2(), ResourceType::SUB_RESOURCE); |
// Flush all the pending requests. |
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
@@ -1544,11 +1792,11 @@ TEST_F(ResourceDispatcherHostTest, ForbiddenDownload) { |
std::string response_data("<html><title>Test One</title></html>"); |
SetResponse(raw_headers, response_data); |
- // Only MAIN_FRAMEs can trigger a download. |
- SetResourceType(ResourceType::MAIN_FRAME); |
- |
HandleScheme("http"); |
- MakeTestRequest(0, 1, GURL("http:bla")); |
+ |
+ // Only MAIN_FRAMEs can trigger a download. |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 1, GURL("http:bla"), |
+ ResourceType::MAIN_FRAME); |
// Flush all pending requests. |
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
@@ -1563,15 +1811,7 @@ TEST_F(ResourceDispatcherHostTest, ForbiddenDownload) { |
// The RequestComplete message should have had the error code of |
// ERR_FILE_NOT_FOUND. |
- int request_id; |
- int error_code; |
- |
- PickleIterator iter(msgs[0][0]); |
- EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id)); |
- EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &error_code)); |
- |
- EXPECT_EQ(1, request_id); |
- EXPECT_EQ(net::ERR_FILE_NOT_FOUND, error_code); |
+ CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_FILE_NOT_FOUND); |
} |
// Test for http://crbug.com/76202 . We don't want to destroy a |
@@ -1595,11 +1835,12 @@ TEST_F(ResourceDispatcherHostTest, IgnoreCancelForDownloads) { |
response_data.resize(1025, ' '); |
SetResponse(raw_headers, response_data); |
- SetResourceType(ResourceType::MAIN_FRAME); |
SetDelayedCompleteJobGeneration(true); |
HandleScheme("http"); |
- MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); |
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id, |
+ GURL("http://example.com/blah"), |
+ ResourceType::MAIN_FRAME); |
// Return some data so that the request is identified as a download |
// and the proper resource handlers are created. |
EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); |
@@ -1630,11 +1871,12 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContext) { |
response_data.resize(1025, ' '); |
SetResponse(raw_headers, response_data); |
- SetResourceType(ResourceType::MAIN_FRAME); |
SetDelayedCompleteJobGeneration(true); |
HandleScheme("http"); |
- MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); |
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id, |
+ GURL("http://example.com/blah"), |
+ ResourceType::MAIN_FRAME); |
// Return some data so that the request is identified as a download |
// and the proper resource handlers are created. |
EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); |
@@ -1658,6 +1900,33 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContext) { |
EXPECT_EQ(0, host_.pending_requests()); |
} |
+TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextDetachable) { |
+ EXPECT_EQ(0, host_.pending_requests()); |
+ |
+ int render_view_id = 0; |
+ int request_id = 1; |
+ |
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id, |
+ net::URLRequestTestJob::test_url_4(), |
+ ResourceType::PREFETCH); // detachable type |
+ |
+ // Simulate a cancel coming from the renderer. |
+ host_.CancelRequest(filter_->child_id(), request_id, true); |
+ |
+ // Since the request had already started processing as detachable, |
+ // the cancellation above should have been ignored and the request |
+ // should still be alive. |
+ EXPECT_EQ(1, host_.pending_requests()); |
+ |
+ // Cancelling by other methods should also be delayed. |
+ host_.CancelRequestsForProcess(render_view_id); |
+ EXPECT_EQ(1, host_.pending_requests()); |
+ |
+ // Cancelling by context should work. |
+ host_.CancelRequestsForContext(filter_->resource_context()); |
+ EXPECT_EQ(0, host_.pending_requests()); |
+} |
+ |
// Test the cancelling of requests that are being transferred to a new renderer |
// due to a redirection. |
TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) { |
@@ -1671,10 +1940,12 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) { |
std::string response_data("<html>foobar</html>"); |
SetResponse(raw_headers, response_data); |
- SetResourceType(ResourceType::MAIN_FRAME); |
HandleScheme("http"); |
- MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); |
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id, |
+ GURL("http://example.com/blah"), |
+ ResourceType::MAIN_FRAME); |
+ |
GlobalRequestID global_request_id(filter_->child_id(), request_id); |
host_.MarkAsTransferredNavigation(global_request_id, |
@@ -1711,7 +1982,6 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationHtml) { |
SetResponse("HTTP/1.1 302 Found\n" |
"Location: http://other.com/blech\n\n"); |
- SetResourceType(ResourceType::MAIN_FRAME); |
HandleScheme("http"); |
// Temporarily replace ContentBrowserClient with one that will trigger the |
@@ -1719,7 +1989,8 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationHtml) { |
TransfersAllNavigationsContentBrowserClient new_client; |
ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client); |
- MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); |
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id, |
+ GURL("http://example.com/blah"), ResourceType::MAIN_FRAME); |
// Now that we're blocked on the redirect, update the response and unblock by |
// telling the AsyncResourceHandler to follow the redirect. |
@@ -1782,7 +2053,6 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationText) { |
SetResponse("HTTP/1.1 302 Found\n" |
"Location: http://other.com/blech\n\n"); |
- SetResourceType(ResourceType::MAIN_FRAME); |
HandleScheme("http"); |
// Temporarily replace ContentBrowserClient with one that will trigger the |
@@ -1790,7 +2060,9 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationText) { |
TransfersAllNavigationsContentBrowserClient new_client; |
ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client); |
- MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); |
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id, |
+ GURL("http://example.com/blah"), |
+ ResourceType::MAIN_FRAME); |
// Now that we're blocked on the redirect, update the response and unblock by |
// telling the AsyncResourceHandler to follow the redirect. Use a text/plain |
@@ -1854,7 +2126,6 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) { |
"Location: http://other.com/blech\n\n"); |
const std::string kResponseBody = "hello world"; |
- SetResourceType(ResourceType::MAIN_FRAME); |
HandleScheme("http"); |
// Temporarily replace ContentBrowserClient with one that will trigger the |
@@ -1943,7 +2214,6 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) { |
SetResponse("HTTP/1.1 302 Found\n" |
"Location: http://other.com/blech\n\n"); |
- SetResourceType(ResourceType::MAIN_FRAME); |
HandleScheme("http"); |
// Temporarily replace ContentBrowserClient with one that will trigger the |
@@ -1951,7 +2221,9 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) { |
TransfersAllNavigationsContentBrowserClient new_client; |
ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client); |
- MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); |
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id, |
+ GURL("http://example.com/blah"), |
+ ResourceType::MAIN_FRAME); |
// Now that we're blocked on the redirect, simulate hitting another redirect. |
SetResponse("HTTP/1.1 302 Found\n" |
@@ -2024,10 +2296,10 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) { |
TEST_F(ResourceDispatcherHostTest, UnknownURLScheme) { |
EXPECT_EQ(0, host_.pending_requests()); |
- SetResourceType(ResourceType::MAIN_FRAME); |
HandleScheme("http"); |
- MakeTestRequest(0, 1, GURL("foo://bar")); |
+ MakeTestRequestWithResourceType(filter_.get(), 0, 1, GURL("foo://bar"), |
+ ResourceType::MAIN_FRAME); |
// Flush all pending requests. |
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
@@ -2042,15 +2314,7 @@ TEST_F(ResourceDispatcherHostTest, UnknownURLScheme) { |
// The RequestComplete message should have the error code of |
// ERR_UNKNOWN_URL_SCHEME. |
- int request_id; |
- int error_code; |
- |
- PickleIterator iter(msgs[0][0]); |
- EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id)); |
- EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &error_code)); |
- |
- EXPECT_EQ(1, request_id); |
- EXPECT_EQ(net::ERR_UNKNOWN_URL_SCHEME, error_code); |
+ CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_UNKNOWN_URL_SCHEME); |
} |
TEST_F(ResourceDispatcherHostTest, DataReceivedACKs) { |
@@ -2074,6 +2338,63 @@ TEST_F(ResourceDispatcherHostTest, DataReceivedACKs) { |
EXPECT_EQ(ResourceMsg_RequestComplete::ID, msgs[0][size - 1].type()); |
} |
+// Request a very large detachable resource and cancel part way. Some of the |
+// data should have been sent to the renderer, but not all. |
+TEST_F(ResourceDispatcherHostTest, DataSentBeforeDetach) { |
+ EXPECT_EQ(0, host_.pending_requests()); |
+ |
+ int render_view_id = 0; |
+ int request_id = 1; |
+ |
+ std::string raw_headers("HTTP\n" |
+ "Content-type: image/jpeg\n\n"); |
+ std::string response_data("01234567890123456789\x01foobar"); |
+ |
+ // Create a response larger than kMaxAllocationSize (currently 32K). Note |
+ // that if this increase beyond 512K we'll need to make the response longer. |
+ const int kAllocSize = 1024*512; |
+ response_data.resize(kAllocSize, ' '); |
+ |
+ SetResponse(raw_headers, response_data); |
+ SetDelayedCompleteJobGeneration(true); |
+ HandleScheme("http"); |
+ |
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id, |
+ GURL("http://example.com/blah"), |
+ ResourceType::PREFETCH); |
+ |
+ // Get a bit of data before cancelling. |
+ EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); |
+ |
+ // Simulate a cancellation coming from the renderer. |
+ ResourceHostMsg_CancelRequest msg(request_id); |
+ bool msg_was_ok; |
+ host_.OnMessageReceived(msg, filter_.get(), &msg_was_ok); |
+ |
+ EXPECT_EQ(1, host_.pending_requests()); |
+ |
+ while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
+ |
+ // Sort all the messages we saw by request. |
+ ResourceIPCAccumulator::ClassifiedMessages msgs; |
+ accum_.GetClassifiedMessages(&msgs); |
+ |
+ EXPECT_EQ(4U, msgs[0].size()); |
+ |
+ // Figure out how many bytes were received by the renderer. |
+ int data_offset; |
+ int data_length; |
+ ExtractDataOffsetAndLength(msgs[0][2], &data_offset, &data_length); |
+ EXPECT_LT(0, data_length); |
+ EXPECT_GT(kAllocSize, data_length); |
+ |
+ // Verify the data that was received before cancellation. Also verify that the |
+ // response completed. |
+ CheckSuccessfulRequest( |
+ msgs[0], |
+ std::string(response_data.begin(), response_data.begin() + data_length)); |
+} |
+ |
TEST_F(ResourceDispatcherHostTest, DelayedDataReceivedACKs) { |
EXPECT_EQ(0, host_.pending_requests()); |