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
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_EXTENSIONS_WEBSTORE_STANDALONE_INSTALLER_H_
6#define CHROME_BROWSER_EXTENSIONS_WEBSTORE_STANDALONE_INSTALLER_H_
7
8#include <string>
9
10#include "base/callback.h"
11#include "base/memory/ref_counted.h"
12#include "base/memory/scoped_ptr.h"
13#include "chrome/browser/extensions/active_install_data.h"
14#include "chrome/browser/extensions/extension_install_prompt.h"
15#include "chrome/browser/extensions/webstore_data_fetcher_delegate.h"
16#include "chrome/browser/extensions/webstore_install_helper.h"
17#include "chrome/browser/extensions/webstore_installer.h"
18#include "chrome/common/extensions/webstore_install_result.h"
19#include "net/url_request/url_fetcher_delegate.h"
20#include "third_party/skia/include/core/SkBitmap.h"
21
22class GURL;
23
24namespace base {
25class DictionaryValue;
26}
27
28namespace net {
29class URLFetcher;
30}
31
32namespace extensions {
33class Extension;
34class WebstoreDataFetcher;
35
36// A a purely abstract base for concrete classes implementing various types of
37// standalone installs:
38// 1) Downloads and parses metadata from the webstore.
39// 2) Optionally shows an install dialog.
40// 3) Starts download once the user confirms (if confirmation was requested).
41// 4) Optionally shows a post-install UI.
42// Follows the Template Method pattern. Implementing subclasses must override
43// the primitive hooks in the corresponding section below.
44
45class WebstoreStandaloneInstaller
46    : public base::RefCountedThreadSafe<WebstoreStandaloneInstaller>,
47      public ExtensionInstallPrompt::Delegate,
48      public WebstoreDataFetcherDelegate,
49      public WebstoreInstaller::Delegate,
50      public WebstoreInstallHelper::Delegate {
51 public:
52  // A callback for when the install process completes, successfully or not. If
53  // there was a failure, |success| will be false and |error| may contain a
54  // developer-readable error message about why it failed.
55  typedef base::Callback<void(bool success,
56                              const std::string& error,
57                              webstore_install::Result result)> Callback;
58
59  WebstoreStandaloneInstaller(const std::string& webstore_item_id,
60                              Profile* profile,
61                              const Callback& callback);
62  void BeginInstall();
63
64 protected:
65  virtual ~WebstoreStandaloneInstaller();
66
67  // Runs the callback; primarily used for running a callback before it is
68  // cleared in AbortInstall().
69  void RunCallback(
70      bool success, const std::string& error, webstore_install::Result result);
71
72  // Called when the install should be aborted. The callback is cleared.
73  void AbortInstall();
74
75  // Checks InstallTracker and returns true if the same extension is not
76  // currently being installed. Registers this install with the InstallTracker.
77  bool EnsureUniqueInstall(webstore_install::Result* reason,
78                           std::string* error);
79
80  // Called when the install is complete.
81  virtual void CompleteInstall(webstore_install::Result result,
82                               const std::string& error);
83
84  // Called when the installer should proceed to prompt the user.
85  void ProceedWithInstallPrompt();
86
87  // Lazily creates a dummy extension for display from the parsed manifest. This
88  // is safe to call from OnManifestParsed() onwards. The manifest may be
89  // invalid, thus the caller must check that the return value is not NULL.
90  scoped_refptr<const Extension> GetLocalizedExtensionForDisplay();
91
92  // Template Method's hooks to be implemented by subclasses.
93
94  // Called when this install is about to be registered with the InstallTracker.
95  // Allows subclasses to set properties of the install data.
96  virtual void InitInstallData(ActiveInstallData* install_data) const;
97
98  // Called at certain check points of the workflow to decide whether it makes
99  // sense to proceed with installation. A requestor can be a website that
100  // initiated an inline installation, or a command line option.
101  virtual bool CheckRequestorAlive() const = 0;
102
103  // Requestor's URL, if any. Should be an empty GURL if URL is meaningless
104  // (e.g. for a command line option).
105  virtual const GURL& GetRequestorURL() const = 0;
106
107  // Should a new tab be opened after installation to show the newly installed
108  // extension's icon?
109  virtual bool ShouldShowPostInstallUI() const = 0;
110
111  // Should pop up an "App installed" bubble after installation?
112  virtual bool ShouldShowAppInstalledBubble() const = 0;
113
114  // In the very least this should return a dummy WebContents (required
115  // by some calls even when no prompt or other UI is shown). A non-dummy
116  // WebContents is required if the prompt returned by CreateInstallPromt()
117  // contains a navigable link(s). Returned WebContents should correspond
118  // to |profile| passed into the constructor.
119  virtual content::WebContents* GetWebContents() const = 0;
120
121  // Should return an installation prompt with desired properties or NULL if
122  // no prompt should be shown.
123  virtual scoped_refptr<ExtensionInstallPrompt::Prompt> CreateInstallPrompt()
124      const = 0;
125
126  // Perform all necessary checks to make sure inline install is permitted,
127  // e.g. in the extension's properties in the store. The implementation may
128  // choose to ignore such properties.
129  virtual bool CheckInlineInstallPermitted(
130      const base::DictionaryValue& webstore_data,
131      std::string* error) const = 0;
132
133  // Perform all necessary checks to make sure that requestor is allowed to
134  // initiate this install (e.g. that the requestor's URL matches the verified
135  // author's site specified in the extension's properties in the store).
136  virtual bool CheckRequestorPermitted(
137      const base::DictionaryValue& webstore_data,
138      std::string* error) const = 0;
139
140  // Will be called after the extension's manifest has been successfully parsed.
141  // Subclasses can perform asynchronous checks at this point and call
142  // ProceedWithInstallPrompt() to proceed with the install or otherwise call
143  // CompleteInstall() with an error code. The default implementation calls
144  // ProceedWithInstallPrompt().
145  virtual void OnManifestParsed();
146
147  // Returns an install UI to be shown. By default, this returns an install UI
148  // that is a transient child of the host window for GetWebContents().
149  virtual scoped_ptr<ExtensionInstallPrompt> CreateInstallUI();
150
151  // Create an approval to pass installation parameters to the CrxInstaller.
152  virtual scoped_ptr<WebstoreInstaller::Approval> CreateApproval() const;
153
154  // ExtensionInstallPrompt::Delegate interface implementation.
155  virtual void InstallUIProceed() OVERRIDE;
156  virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
157
158  // Accessors to be used by subclasses.
159  bool show_user_count() const { return show_user_count_; }
160  const std::string& localized_user_count() const {
161    return localized_user_count_;
162  }
163  double average_rating() const { return average_rating_; }
164  int rating_count() const { return rating_count_; }
165  void set_install_source(WebstoreInstaller::InstallSource source) {
166    install_source_ = source;
167  }
168  WebstoreInstaller::InstallSource install_source() const {
169    return install_source_;
170  }
171  Profile* profile() const { return profile_; }
172  const std::string& id() const { return id_; }
173  const base::DictionaryValue* manifest() const { return manifest_.get(); }
174  const Extension* localized_extension_for_display() const {
175    return localized_extension_for_display_.get();
176  }
177
178 private:
179  friend class base::RefCountedThreadSafe<WebstoreStandaloneInstaller>;
180  FRIEND_TEST_ALL_PREFIXES(WebstoreStandaloneInstallerTest, DomainVerification);
181
182  // Several delegate/client interface implementations follow. The normal flow
183  // (for successful installs) is:
184  //
185  // 1. BeginInstall: starts the fetch of data from the webstore
186  // 2. OnURLFetchComplete: starts the parsing of data from the webstore
187  // 3. OnWebstoreResponseParseSuccess: starts the parsing of the manifest and
188  //    fetching of icon data.
189  // 4. OnWebstoreParseSuccess: shows the install UI
190  // 5. InstallUIProceed: initiates the .crx download/install
191  //
192  // All flows (whether successful or not) end up in CompleteInstall, which
193  // informs our delegate of success/failure.
194
195  // WebstoreDataFetcherDelegate interface implementation.
196  virtual void OnWebstoreRequestFailure() OVERRIDE;
197
198  virtual void OnWebstoreResponseParseSuccess(
199      scoped_ptr<base::DictionaryValue> webstore_data) OVERRIDE;
200
201  virtual void OnWebstoreResponseParseFailure(
202      const std::string& error) OVERRIDE;
203
204  // WebstoreInstallHelper::Delegate interface implementation.
205  virtual void OnWebstoreParseSuccess(
206      const std::string& id,
207      const SkBitmap& icon,
208      base::DictionaryValue* parsed_manifest) OVERRIDE;
209  virtual void OnWebstoreParseFailure(
210      const std::string& id,
211      InstallHelperResultCode result_code,
212      const std::string& error_message) OVERRIDE;
213
214  // WebstoreInstaller::Delegate interface implementation.
215  virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE;
216  virtual void OnExtensionInstallFailure(
217      const std::string& id,
218      const std::string& error,
219      WebstoreInstaller::FailureReason reason) OVERRIDE;
220
221  void ShowInstallUI();
222  void OnWebStoreDataFetcherDone();
223
224  // Input configuration.
225  std::string id_;
226  Callback callback_;
227  Profile* profile_;
228  WebstoreInstaller::InstallSource install_source_;
229
230  // Installation dialog and its underlying prompt.
231  scoped_ptr<ExtensionInstallPrompt> install_ui_;
232  scoped_refptr<ExtensionInstallPrompt::Prompt> install_prompt_;
233
234  // For fetching webstore JSON data.
235  scoped_ptr<WebstoreDataFetcher> webstore_data_fetcher_;
236
237  // Extracted from the webstore JSON data response.
238  std::string localized_name_;
239  std::string localized_description_;
240  bool show_user_count_;
241  std::string localized_user_count_;
242  double average_rating_;
243  int rating_count_;
244  scoped_ptr<base::DictionaryValue> webstore_data_;
245  scoped_ptr<base::DictionaryValue> manifest_;
246  SkBitmap icon_;
247
248  // Active install registered with the InstallTracker.
249  scoped_ptr<ScopedActiveInstall> scoped_active_install_;
250
251  // Created by ShowInstallUI() when a prompt is shown (if
252  // the implementor returns a non-NULL in CreateInstallPrompt()).
253  scoped_refptr<Extension> localized_extension_for_display_;
254
255  DISALLOW_IMPLICIT_CONSTRUCTORS(WebstoreStandaloneInstaller);
256};
257
258}  // namespace extensions
259
260#endif  // CHROME_BROWSER_EXTENSIONS_WEBSTORE_STANDALONE_INSTALLER_H_
261