1// Copyright 2014 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.
4
5#include "chrome/browser/component_updater/component_updater_resource_throttle.h"
6
7#include "base/location.h"
8#include "base/memory/weak_ptr.h"
9#include "components/component_updater/component_updater_service.h"
10#include "content/public/browser/browser_thread.h"
11#include "content/public/browser/resource_controller.h"
12#include "content/public/browser/resource_throttle.h"
13
14using content::BrowserThread;
15
16namespace component_updater {
17
18namespace {
19
20///////////////////////////////////////////////////////////////////////////////
21// In charge of blocking url requests until the |crx_id| component has been
22// updated. This class is touched solely from the IO thread. The UI thread
23// can post tasks to it via weak pointers. By default the request is blocked
24// unless the CrxUpdateService calls Unblock().
25// The lifetime is controlled by Chrome's resource loader so the component
26// updater cannot touch objects from this class except via weak pointers.
27class CUResourceThrottle : public content::ResourceThrottle,
28                           public base::SupportsWeakPtr<CUResourceThrottle> {
29 public:
30  CUResourceThrottle();
31  virtual ~CUResourceThrottle();
32
33  // Overriden from ResourceThrottle.
34  virtual void WillStartRequest(bool* defer) OVERRIDE;
35  virtual void WillRedirectRequest(const GURL& new_url, bool* defer) OVERRIDE;
36  virtual const char* GetNameForLogging() const OVERRIDE;
37
38  // Component updater calls this function via PostTask to unblock the request.
39  void Unblock();
40
41  typedef std::vector<base::WeakPtr<CUResourceThrottle> > WeakPtrVector;
42
43 private:
44  enum State { NEW, BLOCKED, UNBLOCKED };
45
46  State state_;
47};
48
49CUResourceThrottle::CUResourceThrottle() : state_(NEW) {
50  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
51}
52
53CUResourceThrottle::~CUResourceThrottle() {
54  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
55}
56
57void CUResourceThrottle::WillStartRequest(bool* defer) {
58  if (state_ != UNBLOCKED) {
59    state_ = BLOCKED;
60    *defer = true;
61  } else {
62    *defer = false;
63  }
64}
65
66void CUResourceThrottle::WillRedirectRequest(const GURL& new_url, bool* defer) {
67  WillStartRequest(defer);
68}
69
70const char* CUResourceThrottle::GetNameForLogging() const {
71  return "ComponentUpdateResourceThrottle";
72}
73
74void CUResourceThrottle::Unblock() {
75  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
76  if (state_ == BLOCKED)
77    controller()->Resume();
78  state_ = UNBLOCKED;
79}
80
81void UnblockThrottleOnUIThread(base::WeakPtr<CUResourceThrottle> rt) {
82  BrowserThread::PostTask(BrowserThread::IO,
83                          FROM_HERE,
84                          base::Bind(&CUResourceThrottle::Unblock, rt));
85}
86
87}  // namespace
88
89content::ResourceThrottle* GetOnDemandResourceThrottle(
90    ComponentUpdateService* cus,
91    const std::string& crx_id) {
92  DCHECK_CURRENTLY_ON(BrowserThread::IO);
93
94  // We give the raw pointer to the caller, who will delete it at will
95  // and we keep for ourselves a weak pointer to it so we can post tasks
96  // from the UI thread without having to track lifetime directly.
97  CUResourceThrottle* rt = new CUResourceThrottle;
98  BrowserThread::PostTask(
99      BrowserThread::UI,
100      FROM_HERE,
101      base::Bind(&ComponentUpdateService::MaybeThrottle,
102                 base::Unretained(cus),
103                 crx_id,
104                 base::Bind(&UnblockThrottleOnUIThread, rt->AsWeakPtr())));
105  return rt;
106}
107
108}  // namespace component_updater
109