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#ifndef EXTENSIONS_RENDERER_SCRIPT_INJECTION_H_
6#define EXTENSIONS_RENDERER_SCRIPT_INJECTION_H_
7
8#include <map>
9#include <set>
10#include <string>
11
12#include "base/basictypes.h"
13#include "base/macros.h"
14#include "base/memory/scoped_ptr.h"
15#include "base/memory/scoped_vector.h"
16#include "base/timer/elapsed_timer.h"
17#include "extensions/common/user_script.h"
18
19class GURL;
20
21namespace blink {
22class WebFrame;
23}
24
25namespace content {
26class RenderView;
27}
28
29namespace extensions {
30class UserScriptSlave;
31
32// This class is a wrapper around a UserScript that knows how to inject itself
33// into a frame.
34class ScriptInjection {
35 public:
36  // Map of extensions IDs to the executing script paths.
37  typedef std::map<std::string, std::set<std::string> > ExecutingScriptsMap;
38
39  // A struct containing information about a script run.
40  struct ScriptsRunInfo {
41    ScriptsRunInfo();
42    ~ScriptsRunInfo();
43
44    // The number of CSS scripts injected.
45    size_t num_css;
46    // The number of JS scripts injected.
47    size_t num_js;
48    // A map of extension ids to executing script paths.
49    ExecutingScriptsMap executing_scripts;
50    // The elapsed time since the ScriptsRunInfo was constructed.
51    base::ElapsedTimer timer;
52
53   private:
54    DISALLOW_COPY_AND_ASSIGN(ScriptsRunInfo);
55  };
56
57  // Return the URL to use as the document url when checking permissions for
58  // script injection.
59  static GURL GetDocumentUrlForFrame(blink::WebFrame* frame);
60
61  ScriptInjection(scoped_ptr<UserScript> script,
62                  UserScriptSlave* user_script_slave);
63  ~ScriptInjection();
64
65  // Inject the script into the given |frame| if the script should run on the
66  // frame and has permission to do so. If the script requires user consent,
67  // this will register a pending request to inject at a later time.
68  // If the script is run immediately, |scripts_run_info| is updated with
69  // information about the run.
70  void InjectIfAllowed(blink::WebFrame* frame,
71                       UserScript::RunLocation location,
72                       const GURL& document_url,
73                       ScriptsRunInfo* scripts_run_info);
74
75  // If a request with the given |request_id| exists, runs that request and
76  // modifies |scripts_run_info| with information about the run. Otherwise, does
77  // nothing.
78  // If |frame_out| is non-NULL and a script was run, |frame_out| will be
79  // populated with the frame in which the script was run.
80  // Returns true if the request was found *and* the script was run.
81  bool NotifyScriptPermitted(int64 request_id,
82                             content::RenderView* render_view,
83                             ScriptsRunInfo* scripts_run_info,
84                             blink::WebFrame** frame_out);
85
86  // Notififies the Injection that the frame has been detached (i.e. is about
87  // to be destroyed).
88  void FrameDetached(blink::WebFrame* frame);
89
90  void SetScript(scoped_ptr<UserScript> script);
91
92  const std::string& extension_id() { return extension_id_; }
93  const UserScript* script() { return script_.get(); }
94
95 private:
96  struct PendingInjection;
97
98  // Returns true if this ScriptInjection wants to run on the given |frame| at
99  // the given |run_location| (i.e., if this script would inject either JS or
100  // CSS).
101  bool WantsToRun(blink::WebFrame* frame,
102                  UserScript::RunLocation run_location,
103                  const GURL& document_url) const;
104
105  // Returns true if the script will inject [css|js] at the given
106  // |run_location|.
107  bool ShouldInjectJS(UserScript::RunLocation run_location) const;
108  bool ShouldInjectCSS(UserScript::RunLocation run_location) const;
109
110  // Injects the script into the given |frame|, and updates |scripts_run_info|
111  // information about the run.
112  void Inject(blink::WebFrame* frame,
113              UserScript::RunLocation run_location,
114              ScriptsRunInfo* scripts_run_info) const;
115
116  // Injects the [css|js] scripts into the frame, and stores the results of
117  // the run in |scripts_run_info|.
118  void InjectJS(blink::WebFrame* frame, ScriptsRunInfo* scripts_run_info) const;
119  void InjectCSS(blink::WebFrame* frame, ScriptsRunInfo* scripts_run_info)
120      const;
121
122  // The UserScript this is injecting.
123  scoped_ptr<UserScript> script_;
124
125  // The associated extension's id.
126  std::string extension_id_;
127
128  // The associated UserScriptSlave.
129  // It's unfortunate that this is needed, but we use it to get the isolated
130  // world ids and the associated extensions.
131  // TODO(rdevlin.cronin): It would be nice to clean this up more.
132  UserScriptSlave* user_script_slave_;
133
134  // True if the script is a standalone script or emulates greasemonkey.
135  bool is_standalone_or_emulate_greasemonkey_;
136
137  ScopedVector<PendingInjection> pending_injections_;
138
139  DISALLOW_COPY_AND_ASSIGN(ScriptInjection);
140};
141
142}  // namespace extensions
143
144#endif  // EXTENSIONS_RENDERER_SCRIPT_INJECTION_H_
145