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 "content/browser/loader/async_resource_handler.h" | 5 #include "content/browser/loader/async_resource_handler.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 }; | 204 }; |
205 | 205 |
206 AsyncResourceHandler::AsyncResourceHandler(net::URLRequest* request, | 206 AsyncResourceHandler::AsyncResourceHandler(net::URLRequest* request, |
207 ResourceDispatcherHostImpl* rdh) | 207 ResourceDispatcherHostImpl* rdh) |
208 : ResourceHandler(request), | 208 : ResourceHandler(request), |
209 ResourceMessageDelegate(request), | 209 ResourceMessageDelegate(request), |
210 rdh_(rdh), | 210 rdh_(rdh), |
211 pending_data_count_(0), | 211 pending_data_count_(0), |
212 allocation_size_(0), | 212 allocation_size_(0), |
213 total_read_body_bytes_(0), | 213 total_read_body_bytes_(0), |
214 did_defer_(false), | |
215 has_checked_for_sufficient_resources_(false), | 214 has_checked_for_sufficient_resources_(false), |
216 sent_received_response_msg_(false), | 215 sent_received_response_msg_(false), |
217 sent_data_buffer_msg_(false), | 216 sent_data_buffer_msg_(false), |
218 inlining_helper_(new InliningHelper), | 217 inlining_helper_(new InliningHelper), |
219 reported_transfer_size_(0) { | 218 reported_transfer_size_(0) { |
220 DCHECK(GetRequestInfo()->requester_info()->IsRenderer()); | 219 DCHECK(GetRequestInfo()->requester_info()->IsRenderer()); |
221 InitializeResourceBufferConstants(); | 220 InitializeResourceBufferConstants(); |
222 } | 221 } |
223 | 222 |
224 AsyncResourceHandler::~AsyncResourceHandler() { | 223 AsyncResourceHandler::~AsyncResourceHandler() { |
(...skipping 29 matching lines...) Expand all Loading... |
254 if (buffer_->CanAllocate()) | 253 if (buffer_->CanAllocate()) |
255 ResumeIfDeferred(); | 254 ResumeIfDeferred(); |
256 } | 255 } |
257 } | 256 } |
258 | 257 |
259 void AsyncResourceHandler::OnUploadProgressACK(int request_id) { | 258 void AsyncResourceHandler::OnUploadProgressACK(int request_id) { |
260 if (upload_progress_tracker_) | 259 if (upload_progress_tracker_) |
261 upload_progress_tracker_->OnAckReceived(); | 260 upload_progress_tracker_->OnAckReceived(); |
262 } | 261 } |
263 | 262 |
264 bool AsyncResourceHandler::OnRequestRedirected( | 263 void AsyncResourceHandler::OnRequestRedirected( |
265 const net::RedirectInfo& redirect_info, | 264 const net::RedirectInfo& redirect_info, |
266 ResourceResponse* response, | 265 ResourceResponse* response, |
267 bool* defer) { | 266 std::unique_ptr<ResourceController> controller) { |
268 ResourceMessageFilter* filter = GetFilter(); | 267 ResourceMessageFilter* filter = GetFilter(); |
269 if (!filter) | 268 if (!filter) { |
270 return false; | 269 controller->Cancel(); |
271 | 270 return; |
272 *defer = did_defer_ = true; | 271 } |
273 OnDefer(); | |
274 | 272 |
275 NetLogObserver::PopulateResponseInfo(request(), response); | 273 NetLogObserver::PopulateResponseInfo(request(), response); |
276 response->head.encoded_data_length = request()->GetTotalReceivedBytes(); | 274 response->head.encoded_data_length = request()->GetTotalReceivedBytes(); |
277 reported_transfer_size_ = 0; | 275 reported_transfer_size_ = 0; |
278 response->head.request_start = request()->creation_time(); | 276 response->head.request_start = request()->creation_time(); |
279 response->head.response_start = TimeTicks::Now(); | 277 response->head.response_start = TimeTicks::Now(); |
280 // TODO(davidben): Is it necessary to pass the new first party URL for | 278 // TODO(davidben): Is it necessary to pass the new first party URL for |
281 // cookies? The only case where it can change is top-level navigation requests | 279 // cookies? The only case where it can change is top-level navigation requests |
282 // and hopefully those will eventually all be owned by the browser. It's | 280 // and hopefully those will eventually all be owned by the browser. It's |
283 // possible this is still needed while renderer-owned ones exist. | 281 // possible this is still needed while renderer-owned ones exist. |
284 return filter->Send(new ResourceMsg_ReceivedRedirect( | 282 if (filter->Send(new ResourceMsg_ReceivedRedirect( |
285 GetRequestID(), redirect_info, response->head)); | 283 GetRequestID(), redirect_info, response->head))) { |
| 284 OnDefer(std::move(controller)); |
| 285 } else { |
| 286 controller->Cancel(); |
| 287 } |
286 } | 288 } |
287 | 289 |
288 bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response, | 290 void AsyncResourceHandler::OnResponseStarted( |
289 bool* defer) { | 291 ResourceResponse* response, |
| 292 std::unique_ptr<ResourceController> controller) { |
290 // For changes to the main frame, inform the renderer of the new URL's | 293 // For changes to the main frame, inform the renderer of the new URL's |
291 // per-host settings before the request actually commits. This way the | 294 // per-host settings before the request actually commits. This way the |
292 // renderer will be able to set these precisely at the time the | 295 // renderer will be able to set these precisely at the time the |
293 // request commits, avoiding the possibility of e.g. zooming the old content | 296 // request commits, avoiding the possibility of e.g. zooming the old content |
294 // or of having to layout the new content twice. | 297 // or of having to layout the new content twice. |
| 298 DCHECK(!has_controller()); |
295 | 299 |
296 response_started_ticks_ = base::TimeTicks::Now(); | 300 response_started_ticks_ = base::TimeTicks::Now(); |
297 | 301 |
298 // We want to send a final upload progress message prior to sending the | 302 // We want to send a final upload progress message prior to sending the |
299 // response complete message even if we're waiting for an ack to to a | 303 // response complete message even if we're waiting for an ack to to a |
300 // previous upload progress message. | 304 // previous upload progress message. |
301 if (upload_progress_tracker_) { | 305 if (upload_progress_tracker_) { |
302 upload_progress_tracker_->OnUploadCompleted(); | 306 upload_progress_tracker_->OnUploadCompleted(); |
303 upload_progress_tracker_ = nullptr; | 307 upload_progress_tracker_ = nullptr; |
304 } | 308 } |
305 | 309 |
306 const ResourceRequestInfoImpl* info = GetRequestInfo(); | 310 const ResourceRequestInfoImpl* info = GetRequestInfo(); |
307 if (rdh_->delegate()) { | 311 if (rdh_->delegate()) { |
308 rdh_->delegate()->OnResponseStarted(request(), info->GetContext(), | 312 rdh_->delegate()->OnResponseStarted(request(), info->GetContext(), |
309 response); | 313 response); |
310 } | 314 } |
311 | 315 |
312 ResourceMessageFilter* filter = GetFilter(); | 316 ResourceMessageFilter* filter = GetFilter(); |
313 if (!filter) | 317 if (!filter) { |
314 return false; | 318 controller->Cancel(); |
| 319 return; |
| 320 } |
315 | 321 |
316 NetLogObserver::PopulateResponseInfo(request(), response); | 322 NetLogObserver::PopulateResponseInfo(request(), response); |
317 response->head.encoded_data_length = request()->raw_header_size(); | 323 response->head.encoded_data_length = request()->raw_header_size(); |
318 | 324 |
319 // If the parent handler downloaded the resource to a file, grant the child | 325 // If the parent handler downloaded the resource to a file, grant the child |
320 // read permissions on it. | 326 // read permissions on it. |
321 if (!response->head.download_file_path.empty()) { | 327 if (!response->head.download_file_path.empty()) { |
322 rdh_->RegisterDownloadedTempFile( | 328 rdh_->RegisterDownloadedTempFile( |
323 info->GetChildID(), info->GetRequestID(), | 329 info->GetChildID(), info->GetRequestID(), |
324 response->head.download_file_path); | 330 response->head.download_file_path); |
325 } | 331 } |
326 | 332 |
327 response->head.request_start = request()->creation_time(); | 333 response->head.request_start = request()->creation_time(); |
328 response->head.response_start = TimeTicks::Now(); | 334 response->head.response_start = TimeTicks::Now(); |
329 filter->Send( | 335 filter->Send( |
330 new ResourceMsg_ReceivedResponse(GetRequestID(), response->head)); | 336 new ResourceMsg_ReceivedResponse(GetRequestID(), response->head)); |
331 sent_received_response_msg_ = true; | 337 sent_received_response_msg_ = true; |
332 | 338 |
333 if (request()->response_info().metadata.get()) { | 339 if (request()->response_info().metadata.get()) { |
334 std::vector<char> copy(request()->response_info().metadata->data(), | 340 std::vector<char> copy(request()->response_info().metadata->data(), |
335 request()->response_info().metadata->data() + | 341 request()->response_info().metadata->data() + |
336 request()->response_info().metadata->size()); | 342 request()->response_info().metadata->size()); |
337 filter->Send(new ResourceMsg_ReceivedCachedMetadata(GetRequestID(), copy)); | 343 filter->Send(new ResourceMsg_ReceivedCachedMetadata(GetRequestID(), copy)); |
338 } | 344 } |
339 | 345 |
340 inlining_helper_->OnResponseReceived(*response); | 346 inlining_helper_->OnResponseReceived(*response); |
341 return true; | 347 controller->Resume(); |
342 } | 348 } |
343 | 349 |
344 bool AsyncResourceHandler::OnWillStart(const GURL& url, bool* defer) { | 350 void AsyncResourceHandler::OnWillStart( |
| 351 const GURL& url, |
| 352 std::unique_ptr<ResourceController> controller) { |
345 ResourceMessageFilter* filter = GetFilter(); | 353 ResourceMessageFilter* filter = GetFilter(); |
346 if (!filter) | 354 if (!filter) { |
347 return false; | 355 controller->Cancel(); |
| 356 return; |
| 357 } |
348 | 358 |
349 if (GetRequestInfo()->is_upload_progress_enabled() && | 359 if (GetRequestInfo()->is_upload_progress_enabled() && |
350 request()->has_upload()) { | 360 request()->has_upload()) { |
351 upload_progress_tracker_ = base::MakeUnique<UploadProgressTracker>( | 361 upload_progress_tracker_ = base::MakeUnique<UploadProgressTracker>( |
352 FROM_HERE, | 362 FROM_HERE, |
353 base::BindRepeating(&AsyncResourceHandler::SendUploadProgress, | 363 base::BindRepeating(&AsyncResourceHandler::SendUploadProgress, |
354 base::Unretained(this)), | 364 base::Unretained(this)), |
355 request()); | 365 request()); |
356 } | 366 } |
357 return true; | 367 controller->Resume(); |
358 } | 368 } |
359 | 369 |
360 bool AsyncResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, | 370 bool AsyncResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, |
361 int* buf_size, | 371 int* buf_size, |
362 int min_size) { | 372 int min_size) { |
| 373 DCHECK(!has_controller()); |
363 DCHECK_EQ(-1, min_size); | 374 DCHECK_EQ(-1, min_size); |
364 | 375 |
| 376 // TODO(mmenke): Should fail with ERR_INSUFFICIENT_RESOURCES here. |
365 if (!CheckForSufficientResource()) | 377 if (!CheckForSufficientResource()) |
366 return false; | 378 return false; |
367 | 379 |
368 // Return early if InliningHelper allocates the buffer, so that we should | 380 // Return early if InliningHelper allocates the buffer, so that we should |
369 // inline the data into the IPC message without allocating SharedMemory. | 381 // inline the data into the IPC message without allocating SharedMemory. |
370 if (inlining_helper_->PrepareInlineBufferIfApplicable(buf, buf_size)) | 382 if (inlining_helper_->PrepareInlineBufferIfApplicable(buf, buf_size)) |
371 return true; | 383 return true; |
372 | 384 |
373 if (!EnsureResourceBufferIsInitialized()) | 385 if (!EnsureResourceBufferIsInitialized()) |
374 return false; | 386 return false; |
375 | 387 |
376 DCHECK(buffer_->CanAllocate()); | 388 DCHECK(buffer_->CanAllocate()); |
377 char* memory = buffer_->Allocate(&allocation_size_); | 389 char* memory = buffer_->Allocate(&allocation_size_); |
378 CHECK(memory); | 390 CHECK(memory); |
379 | 391 |
380 *buf = new DependentIOBuffer(buffer_.get(), memory); | 392 *buf = new DependentIOBuffer(buffer_.get(), memory); |
381 *buf_size = allocation_size_; | 393 *buf_size = allocation_size_; |
382 | 394 |
383 return true; | 395 return true; |
384 } | 396 } |
385 | 397 |
386 bool AsyncResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { | 398 void AsyncResourceHandler::OnReadCompleted( |
| 399 int bytes_read, |
| 400 std::unique_ptr<ResourceController> controller) { |
| 401 DCHECK(!has_controller()); |
387 DCHECK_GE(bytes_read, 0); | 402 DCHECK_GE(bytes_read, 0); |
388 | 403 |
389 if (!bytes_read) | 404 if (!bytes_read) { |
390 return true; | 405 controller->Resume(); |
| 406 return; |
| 407 } |
391 | 408 |
392 ResourceMessageFilter* filter = GetFilter(); | 409 ResourceMessageFilter* filter = GetFilter(); |
393 if (!filter) | 410 if (!filter) { |
394 return false; | 411 controller->Cancel(); |
| 412 return; |
| 413 } |
395 | 414 |
396 int encoded_data_length = CalculateEncodedDataLengthToReport(); | 415 int encoded_data_length = CalculateEncodedDataLengthToReport(); |
397 if (!first_chunk_read_) | 416 if (!first_chunk_read_) |
398 encoded_data_length -= request()->raw_header_size(); | 417 encoded_data_length -= request()->raw_header_size(); |
399 | 418 |
400 first_chunk_read_ = true; | 419 first_chunk_read_ = true; |
401 | 420 |
402 // Return early if InliningHelper handled the received data. | 421 // Return early if InliningHelper handled the received data. |
403 if (inlining_helper_->SendInlinedDataIfApplicable( | 422 if (inlining_helper_->SendInlinedDataIfApplicable( |
404 bytes_read, encoded_data_length, filter, | 423 bytes_read, encoded_data_length, filter, GetRequestID())) { |
405 GetRequestID())) | 424 controller->Resume(); |
406 return true; | 425 return; |
| 426 } |
407 | 427 |
408 buffer_->ShrinkLastAllocation(bytes_read); | 428 buffer_->ShrinkLastAllocation(bytes_read); |
409 | 429 |
410 total_read_body_bytes_ += bytes_read; | 430 total_read_body_bytes_ += bytes_read; |
411 | 431 |
412 if (!sent_data_buffer_msg_) { | 432 if (!sent_data_buffer_msg_) { |
413 base::SharedMemoryHandle handle = base::SharedMemory::DuplicateHandle( | 433 base::SharedMemoryHandle handle = base::SharedMemory::DuplicateHandle( |
414 buffer_->GetSharedMemory().handle()); | 434 buffer_->GetSharedMemory().handle()); |
415 if (!base::SharedMemory::IsHandleValid(handle)) | 435 if (!base::SharedMemory::IsHandleValid(handle)) { |
416 return false; | 436 controller->Cancel(); |
| 437 return; |
| 438 } |
417 filter->Send(new ResourceMsg_SetDataBuffer( | 439 filter->Send(new ResourceMsg_SetDataBuffer( |
418 GetRequestID(), handle, buffer_->GetSharedMemory().mapped_size(), | 440 GetRequestID(), handle, buffer_->GetSharedMemory().mapped_size(), |
419 filter->peer_pid())); | 441 filter->peer_pid())); |
420 sent_data_buffer_msg_ = true; | 442 sent_data_buffer_msg_ = true; |
421 } | 443 } |
422 | 444 |
423 int data_offset = buffer_->GetLastAllocationOffset(); | 445 int data_offset = buffer_->GetLastAllocationOffset(); |
424 | 446 |
425 filter->Send(new ResourceMsg_DataReceived(GetRequestID(), data_offset, | 447 filter->Send(new ResourceMsg_DataReceived(GetRequestID(), data_offset, |
426 bytes_read, encoded_data_length)); | 448 bytes_read, encoded_data_length)); |
427 ++pending_data_count_; | 449 ++pending_data_count_; |
428 | 450 |
429 if (!buffer_->CanAllocate()) { | 451 if (!buffer_->CanAllocate()) { |
430 *defer = did_defer_ = true; | 452 OnDefer(std::move(controller)); |
431 OnDefer(); | 453 } else { |
| 454 controller->Resume(); |
432 } | 455 } |
433 | |
434 return true; | |
435 } | 456 } |
436 | 457 |
437 void AsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) { | 458 void AsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) { |
438 int encoded_data_length = CalculateEncodedDataLengthToReport(); | 459 int encoded_data_length = CalculateEncodedDataLengthToReport(); |
439 | 460 |
440 ResourceMessageFilter* filter = GetFilter(); | 461 ResourceMessageFilter* filter = GetFilter(); |
441 if (filter) { | 462 if (filter) { |
442 filter->Send(new ResourceMsg_DataDownloaded( | 463 filter->Send(new ResourceMsg_DataDownloaded( |
443 GetRequestID(), bytes_downloaded, encoded_data_length)); | 464 GetRequestID(), bytes_downloaded, encoded_data_length)); |
444 } | 465 } |
445 } | 466 } |
446 | 467 |
447 void AsyncResourceHandler::OnResponseCompleted( | 468 void AsyncResourceHandler::OnResponseCompleted( |
448 const net::URLRequestStatus& status, | 469 const net::URLRequestStatus& status, |
449 bool* defer) { | 470 std::unique_ptr<ResourceController> controller) { |
450 ResourceMessageFilter* filter = GetFilter(); | 471 ResourceMessageFilter* filter = GetFilter(); |
451 if (!filter) | 472 if (!filter) { |
| 473 controller->Resume(); |
452 return; | 474 return; |
| 475 } |
453 | 476 |
454 // Ensure sending the final upload progress message here, since | 477 // Ensure sending the final upload progress message here, since |
455 // OnResponseCompleted can be called without OnResponseStarted on cancellation | 478 // OnResponseCompleted can be called without OnResponseStarted on cancellation |
456 // or error cases. | 479 // or error cases. |
457 if (upload_progress_tracker_) { | 480 if (upload_progress_tracker_) { |
458 upload_progress_tracker_->OnUploadCompleted(); | 481 upload_progress_tracker_->OnUploadCompleted(); |
459 upload_progress_tracker_ = nullptr; | 482 upload_progress_tracker_ = nullptr; |
460 } | 483 } |
461 | 484 |
462 // If we crash here, figure out what URL the renderer was requesting. | 485 // If we crash here, figure out what URL the renderer was requesting. |
(...skipping 26 matching lines...) Expand all Loading... |
489 request_complete_data.exists_in_cache = request()->response_info().was_cached; | 512 request_complete_data.exists_in_cache = request()->response_info().was_cached; |
490 request_complete_data.completion_time = TimeTicks::Now(); | 513 request_complete_data.completion_time = TimeTicks::Now(); |
491 request_complete_data.encoded_data_length = | 514 request_complete_data.encoded_data_length = |
492 request()->GetTotalReceivedBytes(); | 515 request()->GetTotalReceivedBytes(); |
493 request_complete_data.encoded_body_length = request()->GetRawBodyBytes(); | 516 request_complete_data.encoded_body_length = request()->GetRawBodyBytes(); |
494 filter->Send( | 517 filter->Send( |
495 new ResourceMsg_RequestComplete(GetRequestID(), request_complete_data)); | 518 new ResourceMsg_RequestComplete(GetRequestID(), request_complete_data)); |
496 | 519 |
497 if (status.is_success()) | 520 if (status.is_success()) |
498 RecordHistogram(); | 521 RecordHistogram(); |
| 522 controller->Resume(); |
499 } | 523 } |
500 | 524 |
501 bool AsyncResourceHandler::EnsureResourceBufferIsInitialized() { | 525 bool AsyncResourceHandler::EnsureResourceBufferIsInitialized() { |
502 DCHECK(has_checked_for_sufficient_resources_); | 526 DCHECK(has_checked_for_sufficient_resources_); |
503 | 527 |
504 if (buffer_.get() && buffer_->IsInitialized()) | 528 if (buffer_.get() && buffer_->IsInitialized()) |
505 return true; | 529 return true; |
506 | 530 |
507 buffer_ = new ResourceBuffer(); | 531 buffer_ = new ResourceBuffer(); |
508 return buffer_->Initialize(kBufferSize, | 532 return buffer_->Initialize(kBufferSize, |
509 kMinAllocationSize, | 533 kMinAllocationSize, |
510 kMaxAllocationSize); | 534 kMaxAllocationSize); |
511 } | 535 } |
512 | 536 |
513 void AsyncResourceHandler::ResumeIfDeferred() { | 537 void AsyncResourceHandler::ResumeIfDeferred() { |
514 if (did_defer_) { | 538 if (has_controller()) { |
515 did_defer_ = false; | |
516 request()->LogUnblocked(); | 539 request()->LogUnblocked(); |
517 controller()->Resume(); | 540 Resume(); |
518 } | 541 } |
519 } | 542 } |
520 | 543 |
521 void AsyncResourceHandler::OnDefer() { | 544 void AsyncResourceHandler::OnDefer( |
| 545 std::unique_ptr<ResourceController> controller) { |
| 546 HoldController(std::move(controller)); |
522 request()->LogBlockedBy("AsyncResourceHandler"); | 547 request()->LogBlockedBy("AsyncResourceHandler"); |
523 } | 548 } |
524 | 549 |
525 bool AsyncResourceHandler::CheckForSufficientResource() { | 550 bool AsyncResourceHandler::CheckForSufficientResource() { |
526 if (has_checked_for_sufficient_resources_) | 551 if (has_checked_for_sufficient_resources_) |
527 return true; | 552 return true; |
528 has_checked_for_sufficient_resources_ = true; | 553 has_checked_for_sufficient_resources_ = true; |
529 | 554 |
530 if (rdh_->HasSufficientResourcesForRequest(request())) | 555 if (rdh_->HasSufficientResourcesForRequest(request())) |
531 return true; | 556 return true; |
532 | 557 |
533 controller()->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); | |
534 return false; | 558 return false; |
535 } | 559 } |
536 | 560 |
537 int AsyncResourceHandler::CalculateEncodedDataLengthToReport() { | 561 int AsyncResourceHandler::CalculateEncodedDataLengthToReport() { |
538 const auto transfer_size = request()->GetTotalReceivedBytes(); | 562 const auto transfer_size = request()->GetTotalReceivedBytes(); |
539 const auto difference = transfer_size - reported_transfer_size_; | 563 const auto difference = transfer_size - reported_transfer_size_; |
540 reported_transfer_size_ = transfer_size; | 564 reported_transfer_size_ = transfer_size; |
541 return difference; | 565 return difference; |
542 } | 566 } |
543 | 567 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 void AsyncResourceHandler::SendUploadProgress( | 622 void AsyncResourceHandler::SendUploadProgress( |
599 const net::UploadProgress& progress) { | 623 const net::UploadProgress& progress) { |
600 ResourceMessageFilter* filter = GetFilter(); | 624 ResourceMessageFilter* filter = GetFilter(); |
601 if (!filter) | 625 if (!filter) |
602 return; | 626 return; |
603 filter->Send(new ResourceMsg_UploadProgress( | 627 filter->Send(new ResourceMsg_UploadProgress( |
604 GetRequestID(), progress.position(), progress.size())); | 628 GetRequestID(), progress.position(), progress.size())); |
605 } | 629 } |
606 | 630 |
607 } // namespace content | 631 } // namespace content |
OLD | NEW |