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.
5 // See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
7 #include "content/common/resource_dispatcher.h"
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/file_path.h"
13 #include "base/message_loop.h"
14 #include "base/shared_memory.h"
15 #include "base/string_util.h"
16 #include "content/common/inter_process_time_ticks_converter.h"
17 #include "content/common/request_extra_data.h"
18 #include "content/common/resource_messages.h"
19 #include "content/public/common/resource_dispatcher_delegate.h"
20 #include "content/public/common/resource_response.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/net_util.h"
23 #include "net/base/upload_data.h"
24 #include "net/http/http_response_headers.h"
25 #include "webkit/glue/resource_type.h"
27 using content::InterProcessTimeTicksConverter
;
28 using content::LocalTimeDelta
;
29 using content::LocalTimeTicks
;
30 using content::RemoteTimeDelta
;
31 using content::RemoteTimeTicks
;
33 // Each resource request is assigned an ID scoped to this process.
34 static int MakeRequestID() {
35 // NOTE: The resource_dispatcher_host also needs probably unique
36 // request_ids, so they count down from -2 (-1 is a special we're
37 // screwed value), while the renderer process counts up.
38 static int next_request_id
= 0;
39 return next_request_id
++;
42 // ResourceLoaderBridge implementation ----------------------------------------
44 namespace webkit_glue
{
46 class IPCResourceLoaderBridge
: public ResourceLoaderBridge
{
48 IPCResourceLoaderBridge(ResourceDispatcher
* dispatcher
,
49 const webkit_glue::ResourceLoaderBridge::RequestInfo
& request_info
);
50 virtual ~IPCResourceLoaderBridge();
52 // ResourceLoaderBridge
53 virtual void AppendDataToUpload(const char* data
, int data_len
);
54 virtual void AppendFileRangeToUpload(
58 const base::Time
& expected_modification_time
);
59 virtual void AppendBlobToUpload(const GURL
& blob_url
);
60 virtual void SetUploadIdentifier(int64 identifier
);
61 virtual bool Start(Peer
* peer
);
62 virtual void Cancel();
63 virtual void SetDefersLoading(bool value
);
64 virtual void SyncLoad(SyncLoadResponse
* response
);
65 virtual void UpdateRoutingId(int new_routing_id
);
68 ResourceLoaderBridge::Peer
* peer_
;
70 // The resource dispatcher for this loader. The bridge doesn't own it, but
71 // it's guaranteed to outlive the bridge.
72 ResourceDispatcher
* dispatcher_
;
74 // The request to send, created on initialization for modification and
76 ResourceHostMsg_Request request_
;
78 // ID for the request, valid once Start()ed, -1 if not valid yet.
81 // The routing id used when sending IPC messages.
84 bool is_synchronous_request_
;
87 IPCResourceLoaderBridge::IPCResourceLoaderBridge(
88 ResourceDispatcher
* dispatcher
,
89 const webkit_glue::ResourceLoaderBridge::RequestInfo
& request_info
)
91 dispatcher_(dispatcher
),
93 routing_id_(request_info
.routing_id
),
94 is_synchronous_request_(false) {
95 DCHECK(dispatcher_
) << "no resource dispatcher";
96 request_
.method
= request_info
.method
;
97 request_
.url
= request_info
.url
;
98 request_
.first_party_for_cookies
= request_info
.first_party_for_cookies
;
99 request_
.referrer
= request_info
.referrer
;
100 request_
.referrer_policy
= request_info
.referrer_policy
;
101 request_
.headers
= request_info
.headers
;
102 request_
.load_flags
= request_info
.load_flags
;
103 request_
.origin_pid
= request_info
.requestor_pid
;
104 request_
.resource_type
= request_info
.request_type
;
105 request_
.request_context
= request_info
.request_context
;
106 request_
.appcache_host_id
= request_info
.appcache_host_id
;
107 request_
.download_to_file
= request_info
.download_to_file
;
108 request_
.has_user_gesture
= request_info
.has_user_gesture
;
109 if (request_info
.extra_data
) {
110 RequestExtraData
* extra_data
=
111 static_cast<RequestExtraData
*>(request_info
.extra_data
);
112 request_
.is_main_frame
= extra_data
->is_main_frame();
113 request_
.frame_id
= extra_data
->frame_id();
114 request_
.parent_is_main_frame
= extra_data
->parent_is_main_frame();
115 request_
.parent_frame_id
= extra_data
->parent_frame_id();
116 request_
.transition_type
= extra_data
->transition_type();
117 request_
.transferred_request_child_id
=
118 extra_data
->transferred_request_child_id();
119 request_
.transferred_request_request_id
=
120 extra_data
->transferred_request_request_id();
122 request_
.is_main_frame
= false;
123 request_
.frame_id
= -1;
124 request_
.parent_is_main_frame
= false;
125 request_
.parent_frame_id
= -1;
126 request_
.transition_type
= content::PAGE_TRANSITION_LINK
;
127 request_
.transferred_request_child_id
= -1;
128 request_
.transferred_request_request_id
= -1;
132 IPCResourceLoaderBridge::~IPCResourceLoaderBridge() {
133 // we remove our hook for the resource dispatcher only when going away, since
134 // it doesn't keep track of whether we've force terminated the request
135 if (request_id_
>= 0) {
136 // this operation may fail, as the dispatcher will have preemptively
137 // removed us when the renderer sends the ReceivedAllData message.
138 dispatcher_
->RemovePendingRequest(request_id_
);
140 if (request_
.download_to_file
) {
141 dispatcher_
->message_sender()->Send(
142 new ResourceHostMsg_ReleaseDownloadedFile(request_id_
));
147 void IPCResourceLoaderBridge::AppendDataToUpload(const char* data
,
149 DCHECK(request_id_
== -1) << "request already started";
151 // don't bother appending empty data segments
155 if (!request_
.upload_data
)
156 request_
.upload_data
= new net::UploadData();
157 request_
.upload_data
->AppendBytes(data
, data_len
);
160 void IPCResourceLoaderBridge::AppendFileRangeToUpload(
161 const FilePath
& path
, uint64 offset
, uint64 length
,
162 const base::Time
& expected_modification_time
) {
163 DCHECK(request_id_
== -1) << "request already started";
165 if (!request_
.upload_data
)
166 request_
.upload_data
= new net::UploadData();
167 request_
.upload_data
->AppendFileRange(path
, offset
, length
,
168 expected_modification_time
);
171 void IPCResourceLoaderBridge::AppendBlobToUpload(const GURL
& blob_url
) {
172 DCHECK(request_id_
== -1) << "request already started";
174 if (!request_
.upload_data
)
175 request_
.upload_data
= new net::UploadData();
176 request_
.upload_data
->AppendBlob(blob_url
);
179 void IPCResourceLoaderBridge::SetUploadIdentifier(int64 identifier
) {
180 DCHECK(request_id_
== -1) << "request already started";
182 if (!request_
.upload_data
)
183 request_
.upload_data
= new net::UploadData();
184 request_
.upload_data
->set_identifier(identifier
);
187 // Writes a footer on the message and sends it
188 bool IPCResourceLoaderBridge::Start(Peer
* peer
) {
189 if (request_id_
!= -1) {
190 NOTREACHED() << "Starting a request twice";
196 // generate the request ID, and append it to the message
197 request_id_
= dispatcher_
->AddPendingRequest(
198 peer_
, request_
.resource_type
, request_
.url
);
200 return dispatcher_
->message_sender()->Send(
201 new ResourceHostMsg_RequestResource(routing_id_
, request_id_
, request_
));
204 void IPCResourceLoaderBridge::Cancel() {
205 if (request_id_
< 0) {
206 NOTREACHED() << "Trying to cancel an unstarted request";
210 if (!is_synchronous_request_
)
211 dispatcher_
->CancelPendingRequest(routing_id_
, request_id_
);
213 // We can't remove the request ID from the resource dispatcher because more
214 // data might be pending. Sending the cancel message may cause more data
215 // to be flushed, and will then cause a complete message to be sent.
218 void IPCResourceLoaderBridge::SetDefersLoading(bool value
) {
219 if (request_id_
< 0) {
220 NOTREACHED() << "Trying to (un)defer an unstarted request";
224 dispatcher_
->SetDefersLoading(request_id_
, value
);
227 void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse
* response
) {
228 if (request_id_
!= -1) {
229 NOTREACHED() << "Starting a request twice";
230 response
->status
.set_status(net::URLRequestStatus::FAILED
);
234 request_id_
= MakeRequestID();
235 is_synchronous_request_
= true;
237 content::SyncLoadResult result
;
238 IPC::SyncMessage
* msg
= new ResourceHostMsg_SyncLoad(routing_id_
, request_id_
,
240 // NOTE: This may pump events (see RenderThread::Send).
241 if (!dispatcher_
->message_sender()->Send(msg
)) {
242 response
->status
.set_status(net::URLRequestStatus::FAILED
);
246 response
->status
= result
.status
;
247 response
->url
= result
.final_url
;
248 response
->headers
= result
.headers
;
249 response
->mime_type
= result
.mime_type
;
250 response
->charset
= result
.charset
;
251 response
->request_time
= result
.request_time
;
252 response
->response_time
= result
.response_time
;
253 response
->encoded_data_length
= result
.encoded_data_length
;
254 response
->connection_id
= result
.connection_id
;
255 response
->connection_reused
= result
.connection_reused
;
256 response
->load_timing
= result
.load_timing
;
257 response
->devtools_info
= result
.devtools_info
;
258 response
->data
.swap(result
.data
);
259 response
->download_file_path
= result
.download_file_path
;
262 void IPCResourceLoaderBridge::UpdateRoutingId(int new_routing_id
) {
263 if (request_id_
< 0) {
264 NOTREACHED() << "Trying to update an unstarted request";
268 routing_id_
= new_routing_id
;
269 dispatcher_
->message_sender()->Send(
270 new ResourceHostMsg_TransferRequestToNewPage(new_routing_id
,
274 } // namespace webkit_glue
276 // ResourceDispatcher ---------------------------------------------------------
278 ResourceDispatcher::ResourceDispatcher(IPC::Message::Sender
* sender
)
279 : message_sender_(sender
),
280 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
284 ResourceDispatcher::~ResourceDispatcher() {
287 // ResourceDispatcher implementation ------------------------------------------
289 bool ResourceDispatcher::OnMessageReceived(const IPC::Message
& message
) {
290 if (!IsResourceDispatcherMessage(message
)) {
297 if (!message
.ReadInt(&iter
, &request_id
)) {
298 NOTREACHED() << "malformed resource message";
302 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
304 // Release resources in the message if it is a data message.
305 ReleaseResourcesInDataMessage(message
);
309 if (request_info
->is_deferred
) {
310 request_info
->deferred_message_queue
.push_back(new IPC::Message(message
));
313 // Make sure any deferred messages are dispatched before we dispatch more.
314 if (!request_info
->deferred_message_queue
.empty()) {
315 FlushDeferredMessages(request_id
);
316 // The request could have been deferred now. If yes then the current
317 // message has to be queued up. The request_info instance should remain
318 // valid here as there are pending messages for it.
319 DCHECK(pending_requests_
.find(request_id
) != pending_requests_
.end());
320 if (request_info
->is_deferred
) {
321 request_info
->deferred_message_queue
.push_back(new IPC::Message(message
));
326 DispatchMessage(message
);
330 ResourceDispatcher::PendingRequestInfo
*
331 ResourceDispatcher::GetPendingRequestInfo(int request_id
) {
332 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
333 if (it
== pending_requests_
.end()) {
334 // This might happen for kill()ed requests on the webkit end.
337 return &(it
->second
);
340 void ResourceDispatcher::OnUploadProgress(
341 const IPC::Message
& message
, int request_id
, int64 position
, int64 size
) {
342 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
346 request_info
->peer
->OnUploadProgress(position
, size
);
348 // Acknowledge receipt
349 message_sender()->Send(
350 new ResourceHostMsg_UploadProgress_ACK(message
.routing_id(), request_id
));
353 void ResourceDispatcher::OnReceivedResponse(
354 int request_id
, const content::ResourceResponseHead
& response_head
) {
355 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
358 request_info
->response_start
= base::TimeTicks::Now();
361 webkit_glue::ResourceLoaderBridge::Peer
* new_peer
=
362 delegate_
->OnReceivedResponse(
363 request_info
->peer
, response_head
.mime_type
, request_info
->url
);
365 request_info
->peer
= new_peer
;
368 webkit_glue::ResourceResponseInfo renderer_response_info
;
369 ToResourceResponseInfo(*request_info
, response_head
, &renderer_response_info
);
370 request_info
->peer
->OnReceivedResponse(renderer_response_info
);
373 void ResourceDispatcher::OnReceivedCachedMetadata(
374 int request_id
, const std::vector
<char>& data
) {
375 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
380 request_info
->peer
->OnReceivedCachedMetadata(&data
.front(), data
.size());
383 void ResourceDispatcher::OnReceivedData(const IPC::Message
& message
,
385 base::SharedMemoryHandle shm_handle
,
387 int encoded_data_length
) {
388 // Acknowledge the reception of this data.
389 message_sender()->Send(
390 new ResourceHostMsg_DataReceived_ACK(message
.routing_id(), request_id
));
392 const bool shm_valid
= base::SharedMemory::IsHandleValid(shm_handle
);
393 DCHECK((shm_valid
&& data_len
> 0) || (!shm_valid
&& !data_len
));
394 base::SharedMemory
shared_mem(shm_handle
, true); // read only
396 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
400 if (data_len
> 0 && shared_mem
.Map(data_len
)) {
401 const char* data
= static_cast<char*>(shared_mem
.memory());
402 request_info
->peer
->OnReceivedData(data
, data_len
, encoded_data_length
);
406 void ResourceDispatcher::OnDownloadedData(const IPC::Message
& message
,
409 // Acknowledge the reception of this message.
410 message_sender()->Send(
411 new ResourceHostMsg_DataDownloaded_ACK(message
.routing_id(), request_id
));
413 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
417 request_info
->peer
->OnDownloadedData(data_len
);
420 void ResourceDispatcher::OnReceivedRedirect(
421 const IPC::Message
& message
,
424 const content::ResourceResponseHead
& response_head
) {
425 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
428 request_info
->response_start
= base::TimeTicks::Now();
430 int32 routing_id
= message
.routing_id();
431 bool has_new_first_party_for_cookies
= false;
432 GURL new_first_party_for_cookies
;
433 webkit_glue::ResourceResponseInfo renderer_response_info
;
434 ToResourceResponseInfo(*request_info
, response_head
, &renderer_response_info
);
435 if (request_info
->peer
->OnReceivedRedirect(new_url
, renderer_response_info
,
436 &has_new_first_party_for_cookies
,
437 &new_first_party_for_cookies
)) {
438 // Double-check if the request is still around. The call above could
439 // potentially remove it.
440 request_info
= GetPendingRequestInfo(request_id
);
443 request_info
->pending_redirect_message
.reset(
444 new ResourceHostMsg_FollowRedirect(routing_id
, request_id
,
445 has_new_first_party_for_cookies
,
446 new_first_party_for_cookies
));
447 if (!request_info
->is_deferred
) {
448 FollowPendingRedirect(request_id
, *request_info
);
451 CancelPendingRequest(routing_id
, request_id
);
455 void ResourceDispatcher::FollowPendingRedirect(
457 PendingRequestInfo
& request_info
) {
458 IPC::Message
* msg
= request_info
.pending_redirect_message
.release();
460 message_sender()->Send(msg
);
463 void ResourceDispatcher::OnRequestComplete(
465 const net::URLRequestStatus
& status
,
466 const std::string
& security_info
,
467 const base::TimeTicks
& browser_completion_time
) {
468 PendingRequestInfo
* request_info
= GetPendingRequestInfo(request_id
);
471 request_info
->completion_time
= base::TimeTicks::Now();
473 webkit_glue::ResourceLoaderBridge::Peer
* peer
= request_info
->peer
;
476 webkit_glue::ResourceLoaderBridge::Peer
* new_peer
=
477 delegate_
->OnRequestComplete(
478 request_info
->peer
, request_info
->resource_type
, status
);
480 request_info
->peer
= new_peer
;
483 base::TimeTicks renderer_completion_time
= ToRendererCompletionTime(
484 *request_info
, browser_completion_time
);
485 // The request ID will be removed from our pending list in the destructor.
486 // Normally, dispatching this message causes the reference-counted request to
488 peer
->OnCompletedRequest(status
, security_info
, renderer_completion_time
);
491 int ResourceDispatcher::AddPendingRequest(
492 webkit_glue::ResourceLoaderBridge::Peer
* callback
,
493 ResourceType::Type resource_type
,
494 const GURL
& request_url
) {
495 // Compute a unique request_id for this renderer process.
496 int id
= MakeRequestID();
497 pending_requests_
[id
] =
498 PendingRequestInfo(callback
, resource_type
, request_url
);
502 bool ResourceDispatcher::RemovePendingRequest(int request_id
) {
503 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
504 if (it
== pending_requests_
.end())
507 PendingRequestInfo
& request_info
= it
->second
;
508 ReleaseResourcesInMessageQueue(&request_info
.deferred_message_queue
);
509 pending_requests_
.erase(it
);
514 void ResourceDispatcher::CancelPendingRequest(int routing_id
,
516 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
517 if (it
== pending_requests_
.end()) {
518 DLOG(WARNING
) << "unknown request";
522 PendingRequestInfo
& request_info
= it
->second
;
523 ReleaseResourcesInMessageQueue(&request_info
.deferred_message_queue
);
524 pending_requests_
.erase(it
);
526 message_sender()->Send(
527 new ResourceHostMsg_CancelRequest(routing_id
, request_id
));
530 void ResourceDispatcher::SetDefersLoading(int request_id
, bool value
) {
531 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
532 if (it
== pending_requests_
.end()) {
533 DLOG(ERROR
) << "unknown request";
536 PendingRequestInfo
& request_info
= it
->second
;
538 request_info
.is_deferred
= value
;
539 } else if (request_info
.is_deferred
) {
540 request_info
.is_deferred
= false;
542 FollowPendingRedirect(request_id
, request_info
);
544 MessageLoop::current()->PostTask(FROM_HERE
,
545 base::Bind(&ResourceDispatcher::FlushDeferredMessages
,
546 weak_factory_
.GetWeakPtr(), request_id
));
550 void ResourceDispatcher::DispatchMessage(const IPC::Message
& message
) {
551 IPC_BEGIN_MESSAGE_MAP(ResourceDispatcher
, message
)
552 IPC_MESSAGE_HANDLER(ResourceMsg_UploadProgress
, OnUploadProgress
)
553 IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedResponse
, OnReceivedResponse
)
554 IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedCachedMetadata
,
555 OnReceivedCachedMetadata
)
556 IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedRedirect
, OnReceivedRedirect
)
557 IPC_MESSAGE_HANDLER(ResourceMsg_DataReceived
, OnReceivedData
)
558 IPC_MESSAGE_HANDLER(ResourceMsg_DataDownloaded
, OnDownloadedData
)
559 IPC_MESSAGE_HANDLER(ResourceMsg_RequestComplete
, OnRequestComplete
)
560 IPC_END_MESSAGE_MAP()
563 void ResourceDispatcher::FlushDeferredMessages(int request_id
) {
564 PendingRequestList::iterator it
= pending_requests_
.find(request_id
);
565 if (it
== pending_requests_
.end()) // The request could have become invalid.
567 PendingRequestInfo
& request_info
= it
->second
;
568 if (request_info
.is_deferred
)
570 // Because message handlers could result in request_info being destroyed,
571 // we need to work with a stack reference to the deferred queue.
573 q
.swap(request_info
.deferred_message_queue
);
575 IPC::Message
* m
= q
.front();
579 // If this request is deferred in the context of the above message, then
580 // we should honor the same and stop dispatching further messages.
581 // We need to find the request again in the list as it may have completed
582 // by now and the request_info instance above may be invalid.
583 PendingRequestList::iterator index
= pending_requests_
.find(request_id
);
584 if (index
!= pending_requests_
.end()) {
585 PendingRequestInfo
& pending_request
= index
->second
;
586 if (pending_request
.is_deferred
) {
587 pending_request
.deferred_message_queue
.swap(q
);
594 webkit_glue::ResourceLoaderBridge
* ResourceDispatcher::CreateBridge(
595 const webkit_glue::ResourceLoaderBridge::RequestInfo
& request_info
) {
596 return new webkit_glue::IPCResourceLoaderBridge(this, request_info
);
599 void ResourceDispatcher::ToResourceResponseInfo(
600 const PendingRequestInfo
& request_info
,
601 const content::ResourceResponseHead
& browser_info
,
602 webkit_glue::ResourceResponseInfo
* renderer_info
) const {
603 *renderer_info
= browser_info
;
604 if (request_info
.request_start
.is_null() ||
605 request_info
.response_start
.is_null() ||
606 browser_info
.request_start
.is_null() ||
607 browser_info
.response_start
.is_null()) {
610 content::InterProcessTimeTicksConverter
converter(
611 LocalTimeTicks::FromTimeTicks(request_info
.request_start
),
612 LocalTimeTicks::FromTimeTicks(request_info
.response_start
),
613 RemoteTimeTicks::FromTimeTicks(browser_info
.request_start
),
614 RemoteTimeTicks::FromTimeTicks(browser_info
.response_start
));
616 LocalTimeTicks renderer_base_ticks
= converter
.ToLocalTimeTicks(
617 RemoteTimeTicks::FromTimeTicks(browser_info
.load_timing
.base_ticks
));
618 renderer_info
->load_timing
.base_ticks
= renderer_base_ticks
.ToTimeTicks();
620 #define CONVERT(field) \
621 LocalTimeDelta renderer_##field = converter.ToLocalTimeDelta( \
622 RemoteTimeDelta::FromRawDelta(browser_info.load_timing.field)); \
623 renderer_info->load_timing.field = renderer_##field.ToInt32()
625 CONVERT(proxy_start
);
628 CONVERT(connect_start
);
629 CONVERT(connect_end
);
634 CONVERT(receive_headers_start
);
635 CONVERT(receive_headers_end
);
640 base::TimeTicks
ResourceDispatcher::ToRendererCompletionTime(
641 const PendingRequestInfo
& request_info
,
642 const base::TimeTicks
& browser_completion_time
) const {
643 if (request_info
.completion_time
.is_null()) {
644 return browser_completion_time
;
647 // TODO(simonjam): The optimal lower bound should be the most recent value of
648 // TimeTicks::Now() returned to WebKit. Is it worth trying to cache that?
649 // Until then, |response_start| is used as it is the most recent value
650 // returned for this request.
651 int64 result
= std::max(browser_completion_time
.ToInternalValue(),
652 request_info
.response_start
.ToInternalValue());
653 result
= std::min(result
, request_info
.completion_time
.ToInternalValue());
654 return base::TimeTicks::FromInternalValue(result
);
658 bool ResourceDispatcher::IsResourceDispatcherMessage(
659 const IPC::Message
& message
) {
660 switch (message
.type()) {
661 case ResourceMsg_UploadProgress::ID
:
662 case ResourceMsg_ReceivedResponse::ID
:
663 case ResourceMsg_ReceivedCachedMetadata::ID
:
664 case ResourceMsg_ReceivedRedirect::ID
:
665 case ResourceMsg_DataReceived::ID
:
666 case ResourceMsg_DataDownloaded::ID
:
667 case ResourceMsg_RequestComplete::ID
:
678 void ResourceDispatcher::ReleaseResourcesInDataMessage(
679 const IPC::Message
& message
) {
682 if (!message
.ReadInt(&iter
, &request_id
)) {
683 NOTREACHED() << "malformed resource message";
687 // If the message contains a shared memory handle, we should close the
688 // handle or there will be a memory leak.
689 if (message
.type() == ResourceMsg_DataReceived::ID
) {
690 base::SharedMemoryHandle shm_handle
;
691 if (IPC::ParamTraits
<base::SharedMemoryHandle
>::Read(&message
,
694 base::SharedMemory::CloseHandle(shm_handle
);
700 void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue
* queue
) {
701 while (!queue
->empty()) {
702 IPC::Message
* message
= queue
->front();
703 ReleaseResourcesInDataMessage(*message
);