12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/resource_scheduler.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/common/resource_messages.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/resource_message_delegate.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/resource_controller.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/resource_request_info.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/resource_throttle.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_message_macros.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/base/host_port_pair.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/load_flags.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/request_priority.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/http/http_server_properties.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_request.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/url_request/url_request_context.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const size_t kMaxNumDelayableRequestsPerClient = 10;
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A thin wrapper around net::PriorityQueue that deals with
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ScheduledResourceRequests instead of PriorityQueue::Pointers.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ResourceScheduler::RequestQueue {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RequestQueue() : queue_(net::NUM_PRIORITIES) {}
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ~RequestQueue() {}
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Adds |request| to the queue with given |priority|.
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Insert(ScheduledResourceRequest* request,
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              net::RequestPriority priority) {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!ContainsKey(pointers_, request));
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NetQueue::Pointer pointer = queue_.Insert(request, priority);
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pointers_[request] = pointer;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Removes |request| from the queue.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Erase(ScheduledResourceRequest* request) {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PointerMap::iterator it = pointers_.find(request);
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(it != pointers_.end());
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    queue_.Erase(it->second);
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pointers_.erase(it);
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns the highest priority request that's queued, or NULL if none are.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduledResourceRequest* FirstMax() {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return queue_.FirstMax().value();
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns true if |request| is queued.
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool IsQueued(ScheduledResourceRequest* request) const {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ContainsKey(pointers_, request);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns true if no requests are queued.
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool IsEmpty() const { return queue_.size() == 0; }
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef net::PriorityQueue<ScheduledResourceRequest*> NetQueue;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::map<ScheduledResourceRequest*, NetQueue::Pointer> PointerMap;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NetQueue queue_;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PointerMap pointers_;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is the handle we return to the ResourceDispatcherHostImpl so it can
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// interact with the request.
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ResourceScheduler::ScheduledResourceRequest
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public ResourceMessageDelegate,
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      public ResourceThrottle {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduledResourceRequest(const ClientId& client_id,
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           net::URLRequest* request,
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           ResourceScheduler* scheduler)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : ResourceMessageDelegate(request),
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        client_id_(client_id),
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request_(request),
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ready_(false),
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        deferred_(false),
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        scheduler_(scheduler) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~ScheduledResourceRequest() {
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scheduler_->RemoveRequest(this);
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start() {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ready_ = true;
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (deferred_ && request_->status().is_success()) {
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      deferred_ = false;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      controller()->Resume();
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const ClientId& client_id() const { return client_id_; }
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::URLRequest* url_request() { return request_; }
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const net::URLRequest* url_request() const { return request_; }
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ResourceMessageDelegate interface:
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool OnMessageReceived(const IPC::Message& message,
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 bool* message_was_ok) OVERRIDE {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool handled = true;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_BEGIN_MESSAGE_MAP_EX(ScheduledResourceRequest, message, *message_was_ok)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      IPC_MESSAGE_UNHANDLED(handled = false)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_END_MESSAGE_MAP_EX()
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return handled;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ResourceThrottle interface:
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void WillStartRequest(bool* defer) OVERRIDE {
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    deferred_ = *defer = !ready_;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void DidChangePriority(int request_id, net::RequestPriority new_priority) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scheduler_->ReprioritizeRequest(this, new_priority);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientId client_id_;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::URLRequest* request_;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool ready_;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool deferred_;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ResourceScheduler* scheduler_;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Each client represents a tab.
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct ResourceScheduler::Client {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Client() : has_body(false) {}
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ~Client() {}
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool has_body;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RequestQueue pending_requests;
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RequestSet in_flight_requests;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourceScheduler::ResourceScheduler() {
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourceScheduler::~ResourceScheduler() {
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(unowned_requests_.empty());
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(client_map_.empty());
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int child_id,
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int route_id,
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequest* url_request) {
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientId client_id = MakeClientId(child_id, route_id);
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ScheduledResourceRequest> request(
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new ScheduledResourceRequest(client_id, url_request, this));
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientMap::iterator it = client_map_.find(client_id);
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it == client_map_.end()) {
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // There are several ways this could happen:
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // 1. <a ping> requests don't have a route_id.
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // 2. Most unittests don't send the IPCs needed to register Clients.
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // 3. The tab is closed while a RequestResource IPC is in flight.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unowned_requests_.insert(request.get());
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request->Start();
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return request.PassAs<ResourceThrottle>();
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Client* client = it->second;
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ShouldStartRequest(request.get(), client)) {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartRequest(request.get(), client);
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    client->pending_requests.Insert(request.get(), url_request->priority());
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return request.PassAs<ResourceThrottle>();
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ContainsKey(unowned_requests_, request)) {
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unowned_requests_.erase(request);
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientMap::iterator client_it = client_map_.find(request->client_id());
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (client_it == client_map_.end()) {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Client* client = client_it->second;
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (client->pending_requests.IsQueued(request)) {
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    client->pending_requests.Erase(request);
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!ContainsKey(client->in_flight_requests, request));
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t erased = client->in_flight_requests.erase(request);
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(erased);
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Removing this request may have freed up another to load.
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LoadAnyStartablePendingRequests(client);
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::OnClientCreated(int child_id, int route_id) {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientId client_id = MakeClientId(child_id, route_id);
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!ContainsKey(client_map_, client_id));
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client_map_[client_id] = new Client;
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientId client_id = MakeClientId(child_id, route_id);
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ContainsKey(client_map_, client_id));
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientMap::iterator it = client_map_.find(client_id);
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Client* client = it->second;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // FYI, ResourceDispatcherHost cancels all of the requests after this function
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // is called. It should end up canceling all of the requests except for a
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // cross-renderer navigation.
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (RequestSet::iterator it = client->in_flight_requests.begin();
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != client->in_flight_requests.end(); ++it) {
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unowned_requests_.insert(*it);
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client->in_flight_requests.clear();
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete client;
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client_map_.erase(it);
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::OnNavigate(int child_id, int route_id) {
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientId client_id = MakeClientId(child_id, route_id);
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientMap::iterator it = client_map_.find(client_id);
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it == client_map_.end()) {
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The client was likely deleted shortly before we received this IPC.
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Client* client = it->second;
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client->has_body = false;
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::OnWillInsertBody(int child_id, int route_id) {
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientId client_id = MakeClientId(child_id, route_id);
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientMap::iterator it = client_map_.find(client_id);
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it == client_map_.end()) {
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The client was likely deleted shortly before we received this IPC.
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Client* client = it->second;
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client->has_body = false;
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!client->has_body) {
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    client->has_body = true;
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LoadAnyStartablePendingRequests(client);
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::StartRequest(ScheduledResourceRequest* request,
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     Client* client) {
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client->in_flight_requests.insert(request);
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request->Start();
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request,
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            net::RequestPriority new_priority) {
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::RequestPriority old_priority = request->url_request()->priority();
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(new_priority, old_priority);
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request->url_request()->SetPriority(new_priority);
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientMap::iterator client_it = client_map_.find(request->client_id());
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (client_it == client_map_.end()) {
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The client was likely deleted shortly before we received this IPC.
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Client *client = client_it->second;
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!client->pending_requests.IsQueued(request)) {
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(ContainsKey(client->in_flight_requests, request));
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Request has already started.
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client->pending_requests.Erase(request);
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client->pending_requests.Insert(request, request->url_request()->priority());
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_priority > old_priority) {
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Check if this request is now able to load at its new priority.
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LoadAnyStartablePendingRequests(client);
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::LoadAnyStartablePendingRequests(Client* client) {
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (!client->pending_requests.IsEmpty()) {
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ScheduledResourceRequest* request = client->pending_requests.FirstMax();
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (ShouldStartRequest(request, client)) {
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client->pending_requests.Erase(request);
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StartRequest(request, client);
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)size_t ResourceScheduler::GetNumDelayableRequestsInFlight(
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Client* client) const {
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t count = 0;
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (RequestSet::iterator it = client->in_flight_requests.begin();
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != client->in_flight_requests.end(); ++it) {
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if ((*it)->url_request()->priority() < net::LOW) {
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const net::HttpServerProperties& http_server_properties =
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          *(*it)->url_request()->context()->http_server_properties();
318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (!http_server_properties.SupportsSpdy(
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          net::HostPortPair::FromURL((*it)->url_request()->url()))) {
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        ++count;
321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return count;
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ShouldStartRequest is the main scheduling algorithm.
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Requests are categorized into two categories:
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 1. Immediately issued requests, which are:
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//   * Higher priority requests (>= net::LOW).
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//   * Synchronous requests.
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   * Requests to SPDY-capable origin servers.
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 2. The remainder are delayable requests, which follow these rules:
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//   * If no high priority requests are in flight, start loading low priority
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//     requests.
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//   * Once the renderer has a <body>, start loading delayable requests.
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//   * Never exceed 10 delayable requests in flight per client.
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch//   * Prior to <body>, allow one delayable request to load at a time.
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ResourceScheduler::ShouldStartRequest(ScheduledResourceRequest* request,
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           Client* client) const {
346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const net::URLRequest& url_request = *request->url_request();
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const net::HttpServerProperties& http_server_properties =
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      *url_request.context()->http_server_properties();
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(willchan): We should really improve this algorithm as described in
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // crbug.com/164101. Also, theoretically we should not count a SPDY request
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // against the delayable requests limit.
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool origin_supports_spdy = http_server_properties.SupportsSpdy(
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      net::HostPortPair::FromURL(url_request.url()));
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (url_request.priority() >= net::LOW ||
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !ResourceRequestInfo::ForRequest(&url_request)->IsAsync() ||
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      origin_supports_spdy) {
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t num_delayable_requests_in_flight =
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetNumDelayableRequestsInFlight(client);
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_delayable_requests_in_flight >= kMaxNumDelayableRequestsPerClient) {
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool have_immediate_requests_in_flight =
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client->in_flight_requests.size() > num_delayable_requests_in_flight;
370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (have_immediate_requests_in_flight && !client->has_body &&
371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      num_delayable_requests_in_flight != 0) {
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int child_id, int route_id) {
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
384