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_USER_SCRIPT_LISTENER_H_
6 #define CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_LISTENER_H_
7 
8 #include <list>
9 #include <map>
10 
11 #include "base/compiler_specific.h"
12 #include "base/containers/circular_deque.h"
13 #include "base/macros.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/scoped_observer.h"
16 #include "content/public/browser/notification_observer.h"
17 #include "content/public/browser/notification_registrar.h"
18 #include "extensions/browser/extension_registry.h"
19 #include "extensions/browser/extension_registry_observer.h"
20 #include "extensions/browser/user_script_loader.h"
21 
22 class GURL;
23 class URLPattern;
24 
25 namespace content {
26 class BrowserContext;
27 class NavigationHandle;
28 class NavigationThrottle;
29 }
30 
31 namespace extensions {
32 class Extension;
33 
34 // This class handles delaying of resource loads that depend on unloaded user
35 // scripts. For each request that comes in, we check if it depends on a user
36 // script, and if so, whether that user script is ready; if not, we delay the
37 // request.
38 //
39 // This class lives on the UI thread.
40 class UserScriptListener : public content::NotificationObserver,
41                            public ExtensionRegistryObserver,
42                            public UserScriptLoader::Observer {
43  public:
44   UserScriptListener();
45   ~UserScriptListener() override;
46 
47   // Constructs a NavigationThrottle if the UserScriptListener needs to delay
48   // the given navigation. Otherwise, this method returns NULL.
49   std::unique_ptr<content::NavigationThrottle> CreateNavigationThrottle(
50       content::NavigationHandle* navigation_handle);
51 
52   void SetUserScriptsNotReadyForTesting(content::BrowserContext* context);
53   void TriggerUserScriptsReadyForTesting(content::BrowserContext* context);
54 
55  private:
56   using URLPatterns = std::list<URLPattern>;
57 
58   bool ShouldDelayRequest(const GURL& url);
59   void StartDelayedRequests();
60 
61   // Update user_scripts_ready_ based on the status of all profiles. On a
62   // transition from false to true, we resume all delayed requests.
63   void CheckIfAllUserScriptsReady();
64 
65   // Resume any requests that we delayed in order to wait for user scripts.
66   void UserScriptsReady(content::BrowserContext* context);
67 
68   // Clean up per-profile information related to the given profile.
69   void ProfileDestroyed(content::BrowserContext* context);
70 
71   // Appends new url patterns to our list, also setting user_scripts_ready_
72   // to false.
73   void AppendNewURLPatterns(content::BrowserContext* context,
74                             const URLPatterns& new_patterns);
75 
76   // Replaces our url pattern list. This is only used when patterns have been
77   // deleted, so user_scripts_ready_ remains unchanged.
78   void ReplaceURLPatterns(content::BrowserContext* context,
79                           const URLPatterns& patterns);
80 
81   // True if all user scripts from all profiles are ready.
82   bool user_scripts_ready_ = false;
83 
84   // Stores a throttle per URL request that we have delayed.
85   class Throttle;
86   using WeakThrottle = base::WeakPtr<Throttle>;
87   using WeakThrottleList = base::circular_deque<WeakThrottle>;
88   WeakThrottleList throttles_;
89 
90   // Per-profile bookkeeping so we know when all user scripts are ready.
91   struct ProfileData;
92   using ProfileDataMap = std::map<content::BrowserContext*, ProfileData>;
93   ProfileDataMap profile_data_;
94 
95   // --- UI thread:
96 
97   // Helper to collect the extension's user script URL patterns in a list and
98   // return it.
99   void CollectURLPatterns(const Extension* extension,
100                           URLPatterns* patterns);
101 
102   // content::NotificationObserver
103   void Observe(int type,
104                const content::NotificationSource& source,
105                const content::NotificationDetails& details) override;
106 
107   // ExtensionRegistryObserver:
108   void OnExtensionLoaded(content::BrowserContext* browser_context,
109                          const Extension* extension) override;
110   void OnExtensionUnloaded(content::BrowserContext* browser_context,
111                            const Extension* extension,
112                            UnloadedExtensionReason reason) override;
113   void OnShutdown(ExtensionRegistry* registry) override;
114 
115   // UserScriptLoader::Observer:
116   void OnScriptsLoaded(UserScriptLoader* loader,
117                        content::BrowserContext* browser_context) override;
118   void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) override;
119 
120   ScopedObserver<extensions::ExtensionRegistry,
121                  extensions::ExtensionRegistryObserver>
122       extension_registry_observer_{this};
123   ScopedObserver<extensions::UserScriptLoader,
124                  extensions::UserScriptLoader::Observer>
125       user_script_loader_observer_{this};
126 
127   content::NotificationRegistrar registrar_;
128 
129   DISALLOW_COPY_AND_ASSIGN(UserScriptListener);
130 };
131 
132 }  // namespace extensions
133 
134 #endif  // CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_LISTENER_H_
135