OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <vector> | 5 #include <vector> |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
11 #include "base/memory/scoped_vector.h" | 11 #include "base/memory/scoped_vector.h" |
| 12 #include "base/memory/shared_memory.h" |
12 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
13 #include "base/pickle.h" | 14 #include "base/pickle.h" |
14 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
15 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/string_split.h" | 17 #include "base/strings/string_split.h" |
17 #include "content/browser/browser_thread_impl.h" | 18 #include "content/browser/browser_thread_impl.h" |
18 #include "content/browser/child_process_security_policy_impl.h" | 19 #include "content/browser/child_process_security_policy_impl.h" |
19 #include "content/browser/loader/cross_site_resource_handler.h" | 20 #include "content/browser/loader/cross_site_resource_handler.h" |
20 #include "content/browser/loader/detachable_resource_handler.h" | 21 #include "content/browser/loader/detachable_resource_handler.h" |
21 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 22 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 } | 76 } |
76 | 77 |
77 void GenerateIPCMessage( | 78 void GenerateIPCMessage( |
78 scoped_refptr<ResourceMessageFilter> filter, | 79 scoped_refptr<ResourceMessageFilter> filter, |
79 scoped_ptr<IPC::Message> message) { | 80 scoped_ptr<IPC::Message> message) { |
80 bool msg_is_ok; | 81 bool msg_is_ok; |
81 ResourceDispatcherHostImpl::Get()->OnMessageReceived( | 82 ResourceDispatcherHostImpl::Get()->OnMessageReceived( |
82 *message, filter.get(), &msg_is_ok); | 83 *message, filter.get(), &msg_is_ok); |
83 } | 84 } |
84 | 85 |
| 86 // On Windows, ResourceMsg_SetDataBuffer supplies a HANDLE which is not |
| 87 // automatically released. |
| 88 // |
| 89 // See ResourceDispatcher::ReleaseResourcesInDataMessage. |
| 90 // |
| 91 // TODO(davidben): It would be nice if the behavior for base::SharedMemoryHandle |
| 92 // were more like it is in POSIX where the received fds are tracked in a |
| 93 // ref-counted core that closes them if not extracted. |
| 94 void ReleaseHandlesInMessage(const IPC::Message& message) { |
| 95 if (message.type() == ResourceMsg_SetDataBuffer::ID) { |
| 96 PickleIterator iter(message); |
| 97 int request_id; |
| 98 CHECK(message.ReadInt(&iter, &request_id)); |
| 99 base::SharedMemoryHandle shm_handle; |
| 100 if (IPC::ParamTraits<base::SharedMemoryHandle>::Read(&message, |
| 101 &iter, |
| 102 &shm_handle)) { |
| 103 if (base::SharedMemory::IsHandleValid(shm_handle)) |
| 104 base::SharedMemory::CloseHandle(shm_handle); |
| 105 } |
| 106 } |
| 107 } |
| 108 |
85 } // namespace | 109 } // namespace |
86 | 110 |
87 static int RequestIDForMessage(const IPC::Message& msg) { | 111 static int RequestIDForMessage(const IPC::Message& msg) { |
88 int request_id = -1; | 112 int request_id = -1; |
89 switch (msg.type()) { | 113 switch (msg.type()) { |
90 case ResourceMsg_UploadProgress::ID: | 114 case ResourceMsg_UploadProgress::ID: |
91 case ResourceMsg_ReceivedResponse::ID: | 115 case ResourceMsg_ReceivedResponse::ID: |
92 case ResourceMsg_ReceivedRedirect::ID: | 116 case ResourceMsg_ReceivedRedirect::ID: |
93 case ResourceMsg_SetDataBuffer::ID: | 117 case ResourceMsg_SetDataBuffer::ID: |
94 case ResourceMsg_DataReceived::ID: | 118 case ResourceMsg_DataReceived::ID: |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 } | 150 } |
127 | 151 |
128 // Spin up the message loop to kick off the request. | 152 // Spin up the message loop to kick off the request. |
129 static void KickOffRequest() { | 153 static void KickOffRequest() { |
130 base::MessageLoop::current()->RunUntilIdle(); | 154 base::MessageLoop::current()->RunUntilIdle(); |
131 } | 155 } |
132 | 156 |
133 // We may want to move this to a shared space if it is useful for something else | 157 // We may want to move this to a shared space if it is useful for something else |
134 class ResourceIPCAccumulator { | 158 class ResourceIPCAccumulator { |
135 public: | 159 public: |
| 160 ~ResourceIPCAccumulator() { |
| 161 for (size_t i = 0; i < messages_.size(); i++) { |
| 162 ReleaseHandlesInMessage(messages_[i]); |
| 163 } |
| 164 } |
| 165 |
| 166 // On Windows, takes ownership of SharedMemoryHandles in |msg|. |
136 void AddMessage(const IPC::Message& msg) { | 167 void AddMessage(const IPC::Message& msg) { |
137 messages_.push_back(msg); | 168 messages_.push_back(msg); |
138 } | 169 } |
139 | 170 |
140 // This groups the messages by their request ID. The groups will be in order | 171 // This groups the messages by their request ID. The groups will be in order |
141 // that the first message for each request ID was received, and the messages | 172 // that the first message for each request ID was received, and the messages |
142 // within the groups will be in the order that they appeared. | 173 // within the groups will be in the order that they appeared. |
143 // Note that this clears messages_. | 174 // Note that this clears messages_. The caller takes ownership of any |
| 175 // SharedMemoryHandles in messages placed into |msgs|. |
144 typedef std::vector< std::vector<IPC::Message> > ClassifiedMessages; | 176 typedef std::vector< std::vector<IPC::Message> > ClassifiedMessages; |
145 void GetClassifiedMessages(ClassifiedMessages* msgs); | 177 void GetClassifiedMessages(ClassifiedMessages* msgs); |
146 | 178 |
147 private: | 179 private: |
148 std::vector<IPC::Message> messages_; | 180 std::vector<IPC::Message> messages_; |
149 }; | 181 }; |
150 | 182 |
151 // This is very inefficient as a result of repeatedly extracting the ID, use | 183 // This is very inefficient as a result of repeatedly extracting the ID, use |
152 // only for tests! | 184 // only for tests! |
153 void ResourceIPCAccumulator::GetClassifiedMessages(ClassifiedMessages* msgs) { | 185 void ResourceIPCAccumulator::GetClassifiedMessages(ClassifiedMessages* msgs) { |
(...skipping 12 matching lines...) Expand all Loading... |
166 messages_.erase(messages_.begin() + i); | 198 messages_.erase(messages_.begin() + i); |
167 i--; | 199 i--; |
168 } | 200 } |
169 } | 201 } |
170 msgs->push_back(cur_requests); | 202 msgs->push_back(cur_requests); |
171 } | 203 } |
172 messages_.erase(messages_.begin()); | 204 messages_.erase(messages_.begin()); |
173 } | 205 } |
174 } | 206 } |
175 | 207 |
176 // This class forwards the incoming messages to the ResourceDispatcherHostTest. | |
177 // This is used to emulate different sub-processes, since this filter will | 208 // This is used to emulate different sub-processes, since this filter will |
178 // have a different ID than the original. For the test, we want all the incoming | 209 // have a different ID than the original. |
179 // messages to go to the same place, which is why this forwards. | 210 class TestFilter : public ResourceMessageFilter { |
180 class ForwardingFilter : public ResourceMessageFilter { | |
181 public: | 211 public: |
182 explicit ForwardingFilter(IPC::Sender* dest, | 212 explicit TestFilter(ResourceContext* resource_context) |
183 ResourceContext* resource_context) | 213 : ResourceMessageFilter( |
184 : ResourceMessageFilter( | 214 ChildProcessHostImpl::GenerateChildProcessUniqueId(), |
185 ChildProcessHostImpl::GenerateChildProcessUniqueId(), | 215 PROCESS_TYPE_RENDERER, NULL, NULL, NULL, NULL, |
186 PROCESS_TYPE_RENDERER, NULL, NULL, NULL, NULL, | 216 base::Bind(&TestFilter::GetContexts, base::Unretained(this))), |
187 base::Bind(&ForwardingFilter::GetContexts, | 217 resource_context_(resource_context), |
188 base::Unretained(this))), | 218 canceled_(false), |
189 dest_(dest), | 219 received_after_canceled_(0) { |
190 resource_context_(resource_context) { | |
191 ChildProcessSecurityPolicyImpl::GetInstance()->Add(child_id()); | 220 ChildProcessSecurityPolicyImpl::GetInstance()->Add(child_id()); |
192 set_peer_pid_for_testing(base::GetCurrentProcId()); | 221 set_peer_pid_for_testing(base::GetCurrentProcId()); |
193 } | 222 } |
194 | 223 |
| 224 void set_canceled(bool canceled) { canceled_ = canceled; } |
| 225 int received_after_canceled() const { return received_after_canceled_; } |
| 226 |
195 // ResourceMessageFilter override | 227 // ResourceMessageFilter override |
196 virtual bool Send(IPC::Message* msg) OVERRIDE { | 228 virtual bool Send(IPC::Message* msg) OVERRIDE { |
197 if (!dest_) | 229 // No messages should be received when the process has been canceled. |
198 return false; | 230 if (canceled_) |
199 return dest_->Send(msg); | 231 received_after_canceled_++; |
| 232 ReleaseHandlesInMessage(*msg); |
| 233 delete msg; |
| 234 return true; |
200 } | 235 } |
201 | 236 |
202 ResourceContext* resource_context() { return resource_context_; } | 237 ResourceContext* resource_context() { return resource_context_; } |
203 | 238 |
204 protected: | 239 protected: |
205 virtual ~ForwardingFilter() {} | 240 virtual ~TestFilter() {} |
206 | 241 |
207 private: | 242 private: |
208 void GetContexts(const ResourceHostMsg_Request& request, | 243 void GetContexts(const ResourceHostMsg_Request& request, |
209 ResourceContext** resource_context, | 244 ResourceContext** resource_context, |
210 net::URLRequestContext** request_context) { | 245 net::URLRequestContext** request_context) { |
211 *resource_context = resource_context_; | 246 *resource_context = resource_context_; |
212 *request_context = resource_context_->GetRequestContext(); | 247 *request_context = resource_context_->GetRequestContext(); |
213 } | 248 } |
214 | 249 |
| 250 ResourceContext* resource_context_; |
| 251 bool canceled_; |
| 252 int received_after_canceled_; |
| 253 |
| 254 DISALLOW_COPY_AND_ASSIGN(TestFilter); |
| 255 }; |
| 256 |
| 257 |
| 258 // This class forwards the incoming messages to the ResourceDispatcherHostTest. |
| 259 // For the test, we want all the incoming messages to go to the same place, |
| 260 // which is why this forwards. |
| 261 class ForwardingFilter : public TestFilter { |
| 262 public: |
| 263 explicit ForwardingFilter(IPC::Sender* dest, |
| 264 ResourceContext* resource_context) |
| 265 : TestFilter(resource_context), |
| 266 dest_(dest) { |
| 267 } |
| 268 |
| 269 // TestFilter override |
| 270 virtual bool Send(IPC::Message* msg) OVERRIDE { |
| 271 return dest_->Send(msg); |
| 272 } |
| 273 |
| 274 private: |
| 275 virtual ~ForwardingFilter() {} |
| 276 |
215 IPC::Sender* dest_; | 277 IPC::Sender* dest_; |
216 ResourceContext* resource_context_; | |
217 | 278 |
218 DISALLOW_COPY_AND_ASSIGN(ForwardingFilter); | 279 DISALLOW_COPY_AND_ASSIGN(ForwardingFilter); |
219 }; | 280 }; |
220 | 281 |
221 // This class is a variation on URLRequestTestJob that will call | 282 // This class is a variation on URLRequestTestJob that will call |
222 // URLRequest::OnBeforeNetworkStart before starting. | 283 // URLRequest::OnBeforeNetworkStart before starting. |
223 class URLRequestTestDelayedNetworkJob : public net::URLRequestTestJob { | 284 class URLRequestTestDelayedNetworkJob : public net::URLRequestTestJob { |
224 public: | 285 public: |
225 URLRequestTestDelayedNetworkJob(net::URLRequest* request, | 286 URLRequestTestDelayedNetworkJob(net::URLRequest* request, |
226 net::NetworkDelegate* network_delegate) | 287 net::NetworkDelegate* network_delegate) |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
615 if (send_data_received_acks_ && | 676 if (send_data_received_acks_ && |
616 msg->type() == ResourceMsg_DataReceived::ID) { | 677 msg->type() == ResourceMsg_DataReceived::ID) { |
617 GenerateDataReceivedACK(*msg); | 678 GenerateDataReceivedACK(*msg); |
618 } | 679 } |
619 | 680 |
620 if (wait_for_request_complete_loop_ && | 681 if (wait_for_request_complete_loop_ && |
621 msg->type() == ResourceMsg_RequestComplete::ID) { | 682 msg->type() == ResourceMsg_RequestComplete::ID) { |
622 wait_for_request_complete_loop_->Quit(); | 683 wait_for_request_complete_loop_->Quit(); |
623 } | 684 } |
624 | 685 |
| 686 // Do not release handles in it yet; the accumulator owns them now. |
625 delete msg; | 687 delete msg; |
626 return true; | 688 return true; |
627 } | 689 } |
628 | 690 |
629 protected: | 691 protected: |
630 // testing::Test | 692 // testing::Test |
631 virtual void SetUp() OVERRIDE { | 693 virtual void SetUp() OVERRIDE { |
632 DCHECK(!test_fixture_); | 694 DCHECK(!test_fixture_); |
633 test_fixture_ = this; | 695 test_fixture_ = this; |
634 ChildProcessSecurityPolicyImpl::GetInstance()->Add(0); | 696 ChildProcessSecurityPolicyImpl::GetInstance()->Add(0); |
(...skipping 778 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1413 ResourceIPCAccumulator::ClassifiedMessages msgs; | 1475 ResourceIPCAccumulator::ClassifiedMessages msgs; |
1414 accum_.GetClassifiedMessages(&msgs); | 1476 accum_.GetClassifiedMessages(&msgs); |
1415 | 1477 |
1416 // Check the cancellation | 1478 // Check the cancellation |
1417 ASSERT_EQ(1U, msgs.size()); | 1479 ASSERT_EQ(1U, msgs.size()); |
1418 ASSERT_EQ(1U, msgs[0].size()); | 1480 ASSERT_EQ(1U, msgs[0].size()); |
1419 | 1481 |
1420 CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_ACCESS_DENIED); | 1482 CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_ACCESS_DENIED); |
1421 } | 1483 } |
1422 | 1484 |
1423 // The host delegate acts as a second one so we can have some requests | |
1424 // pending and some canceled. | |
1425 class TestFilter : public ForwardingFilter { | |
1426 public: | |
1427 explicit TestFilter(ResourceContext* resource_context) | |
1428 : ForwardingFilter(NULL, resource_context), | |
1429 has_canceled_(false), | |
1430 received_after_canceled_(0) { | |
1431 } | |
1432 | |
1433 // ForwardingFilter override | |
1434 virtual bool Send(IPC::Message* msg) OVERRIDE { | |
1435 // no messages should be received when the process has been canceled | |
1436 if (has_canceled_) | |
1437 received_after_canceled_++; | |
1438 delete msg; | |
1439 return true; | |
1440 } | |
1441 | |
1442 bool has_canceled_; | |
1443 int received_after_canceled_; | |
1444 | |
1445 private: | |
1446 virtual ~TestFilter() {} | |
1447 }; | |
1448 | |
1449 // Tests CancelRequestsForProcess | 1485 // Tests CancelRequestsForProcess |
1450 TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { | 1486 TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { |
1451 scoped_refptr<TestFilter> test_filter = new TestFilter( | 1487 scoped_refptr<TestFilter> test_filter = new TestFilter( |
1452 browser_context_->GetResourceContext()); | 1488 browser_context_->GetResourceContext()); |
1453 child_ids_.insert(test_filter->child_id()); | 1489 child_ids_.insert(test_filter->child_id()); |
1454 | 1490 |
1455 // request 1 goes to the test delegate | 1491 // request 1 goes to the test delegate |
1456 ResourceHostMsg_Request request = CreateResourceRequest( | 1492 ResourceHostMsg_Request request = CreateResourceRequest( |
1457 "GET", ResourceType::SUB_RESOURCE, net::URLRequestTestJob::test_url_1()); | 1493 "GET", ResourceType::SUB_RESOURCE, net::URLRequestTestJob::test_url_1()); |
1458 | 1494 |
(...skipping 26 matching lines...) Expand all Loading... |
1485 //EXPECT_EQ(3, host_.pending_requests()); | 1521 //EXPECT_EQ(3, host_.pending_requests()); |
1486 | 1522 |
1487 // Process test_url_2 and test_url_3 for one level so one callback is called. | 1523 // Process test_url_2 and test_url_3 for one level so one callback is called. |
1488 // We'll cancel test_url_4 (detachable) before processing it to verify that it | 1524 // We'll cancel test_url_4 (detachable) before processing it to verify that it |
1489 // delays the cancel. | 1525 // delays the cancel. |
1490 for (int i = 0; i < 2; i++) | 1526 for (int i = 0; i < 2; i++) |
1491 EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); | 1527 EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); |
1492 | 1528 |
1493 // Cancel the requests to the test process. | 1529 // Cancel the requests to the test process. |
1494 host_.CancelRequestsForProcess(filter_->child_id()); | 1530 host_.CancelRequestsForProcess(filter_->child_id()); |
1495 test_filter->has_canceled_ = true; | 1531 test_filter->set_canceled(true); |
1496 | 1532 |
1497 // The requests should all be cancelled, except request 4, which is detached. | 1533 // The requests should all be cancelled, except request 4, which is detached. |
1498 EXPECT_EQ(1, host_.pending_requests()); | 1534 EXPECT_EQ(1, host_.pending_requests()); |
1499 GlobalRequestID global_request_id(filter_->child_id(), 4); | 1535 GlobalRequestID global_request_id(filter_->child_id(), 4); |
1500 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest( | 1536 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest( |
1501 host_.GetURLRequest(global_request_id)); | 1537 host_.GetURLRequest(global_request_id)); |
1502 ASSERT_TRUE(info->detachable_handler()->is_detached()); | 1538 ASSERT_TRUE(info->detachable_handler()->is_detached()); |
1503 | 1539 |
1504 // Flush all the pending requests. | 1540 // Flush all the pending requests. |
1505 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | 1541 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} |
1506 | 1542 |
1507 EXPECT_EQ(0, host_.pending_requests()); | 1543 EXPECT_EQ(0, host_.pending_requests()); |
1508 | 1544 |
1509 // The test delegate should not have gotten any messages after being canceled. | 1545 // The test delegate should not have gotten any messages after being canceled. |
1510 ASSERT_EQ(0, test_filter->received_after_canceled_); | 1546 ASSERT_EQ(0, test_filter->received_after_canceled()); |
1511 | 1547 |
1512 // There should be two results. | 1548 // There should be two results. |
1513 ResourceIPCAccumulator::ClassifiedMessages msgs; | 1549 ResourceIPCAccumulator::ClassifiedMessages msgs; |
1514 accum_.GetClassifiedMessages(&msgs); | 1550 accum_.GetClassifiedMessages(&msgs); |
1515 ASSERT_EQ(2U, msgs.size()); | 1551 ASSERT_EQ(2U, msgs.size()); |
1516 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2()); | 1552 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2()); |
1517 // The detachable request was cancelled by the renderer before it | 1553 // The detachable request was cancelled by the renderer before it |
1518 // finished. From the perspective of the renderer, it should have cancelled. | 1554 // finished. From the perspective of the renderer, it should have cancelled. |
1519 ASSERT_EQ(2U, msgs[1].size()); | 1555 ASSERT_EQ(2U, msgs[1].size()); |
1520 ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[1][0].type()); | 1556 ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[1][0].type()); |
(...skipping 1372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2893 // message loop for the delete itself. (This relies on the delete happening on | 2929 // message loop for the delete itself. (This relies on the delete happening on |
2894 // the FILE thread which is mapped to main thread in this test.) | 2930 // the FILE thread which is mapped to main thread in this test.) |
2895 base::RunLoop().RunUntilIdle(); | 2931 base::RunLoop().RunUntilIdle(); |
2896 | 2932 |
2897 EXPECT_FALSE(base::PathExists(response_head.download_file_path)); | 2933 EXPECT_FALSE(base::PathExists(response_head.download_file_path)); |
2898 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( | 2934 EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( |
2899 filter_->child_id(), response_head.download_file_path)); | 2935 filter_->child_id(), response_head.download_file_path)); |
2900 } | 2936 } |
2901 | 2937 |
2902 } // namespace content | 2938 } // namespace content |
OLD | NEW |