Home | History | Annotate | Download | only in renderer
      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 "extensions/renderer/user_script_set.h"
      6 
      7 #include "content/public/common/url_constants.h"
      8 #include "content/public/renderer/render_thread.h"
      9 #include "extensions/common/extension.h"
     10 #include "extensions/common/extension_set.h"
     11 #include "extensions/common/permissions/permissions_data.h"
     12 #include "extensions/renderer/extensions_renderer_client.h"
     13 #include "extensions/renderer/script_context.h"
     14 #include "extensions/renderer/script_injection.h"
     15 #include "extensions/renderer/user_script_injector.h"
     16 #include "third_party/WebKit/public/web/WebDocument.h"
     17 #include "third_party/WebKit/public/web/WebFrame.h"
     18 #include "url/gurl.h"
     19 
     20 namespace extensions {
     21 
     22 namespace {
     23 
     24 GURL GetDocumentUrlForFrame(blink::WebFrame* frame) {
     25   GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame);
     26   if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) {
     27     data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
     28                            data_source_url.spec());
     29   }
     30 
     31   return data_source_url;
     32 }
     33 
     34 }  // namespace
     35 
     36 UserScriptSet::UserScriptSet(const ExtensionSet* extensions)
     37     : extensions_(extensions) {
     38 }
     39 
     40 UserScriptSet::~UserScriptSet() {
     41 }
     42 
     43 void UserScriptSet::AddObserver(Observer* observer) {
     44   observers_.AddObserver(observer);
     45 }
     46 
     47 void UserScriptSet::RemoveObserver(Observer* observer) {
     48   observers_.RemoveObserver(observer);
     49 }
     50 
     51 void UserScriptSet::GetActiveExtensionIds(
     52     std::set<std::string>* ids) const {
     53   for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
     54        iter != scripts_.end();
     55        ++iter) {
     56     DCHECK(!(*iter)->extension_id().empty());
     57     ids->insert((*iter)->extension_id());
     58   }
     59 }
     60 
     61 void UserScriptSet::GetInjections(
     62     ScopedVector<ScriptInjection>* injections,
     63     blink::WebFrame* web_frame,
     64     int tab_id,
     65     UserScript::RunLocation run_location) {
     66   GURL document_url = GetDocumentUrlForFrame(web_frame);
     67   for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
     68        iter != scripts_.end();
     69        ++iter) {
     70     const Extension* extension = extensions_->GetByID((*iter)->extension_id());
     71     if (!extension)
     72       continue;
     73     scoped_ptr<ScriptInjection> injection = GetInjectionForScript(
     74         *iter,
     75         web_frame,
     76         tab_id,
     77         run_location,
     78         document_url,
     79         extension,
     80         false /* is_declarative */);
     81     if (injection.get())
     82       injections->push_back(injection.release());
     83   }
     84 }
     85 
     86 bool UserScriptSet::UpdateUserScripts(
     87     base::SharedMemoryHandle shared_memory,
     88     const std::set<std::string>& changed_extensions) {
     89   bool only_inject_incognito =
     90       ExtensionsRendererClient::Get()->IsIncognitoProcess();
     91 
     92   // Create the shared memory object (read only).
     93   shared_memory_.reset(new base::SharedMemory(shared_memory, true));
     94   if (!shared_memory_.get())
     95     return false;
     96 
     97   // First get the size of the memory block.
     98   if (!shared_memory_->Map(sizeof(Pickle::Header)))
     99     return false;
    100   Pickle::Header* pickle_header =
    101       reinterpret_cast<Pickle::Header*>(shared_memory_->memory());
    102 
    103   // Now map in the rest of the block.
    104   int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size;
    105   shared_memory_->Unmap();
    106   if (!shared_memory_->Map(pickle_size))
    107     return false;
    108 
    109   // Unpickle scripts.
    110   uint64 num_scripts = 0;
    111   Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()), pickle_size);
    112   PickleIterator iter(pickle);
    113   CHECK(pickle.ReadUInt64(&iter, &num_scripts));
    114 
    115   scripts_.clear();
    116   scripts_.reserve(num_scripts);
    117   for (uint64 i = 0; i < num_scripts; ++i) {
    118     scoped_ptr<UserScript> script(new UserScript());
    119     script->Unpickle(pickle, &iter);
    120 
    121     // Note that this is a pointer into shared memory. We don't own it. It gets
    122     // cleared up when the last renderer or browser process drops their
    123     // reference to the shared memory.
    124     for (size_t j = 0; j < script->js_scripts().size(); ++j) {
    125       const char* body = NULL;
    126       int body_length = 0;
    127       CHECK(pickle.ReadData(&iter, &body, &body_length));
    128       script->js_scripts()[j].set_external_content(
    129           base::StringPiece(body, body_length));
    130     }
    131     for (size_t j = 0; j < script->css_scripts().size(); ++j) {
    132       const char* body = NULL;
    133       int body_length = 0;
    134       CHECK(pickle.ReadData(&iter, &body, &body_length));
    135       script->css_scripts()[j].set_external_content(
    136           base::StringPiece(body, body_length));
    137     }
    138 
    139     if (only_inject_incognito && !script->is_incognito_enabled())
    140       continue;  // This script shouldn't run in an incognito tab.
    141 
    142     scripts_.push_back(script.release());
    143   }
    144 
    145   FOR_EACH_OBSERVER(Observer,
    146                     observers_,
    147                     OnUserScriptsUpdated(changed_extensions, scripts_.get()));
    148   return true;
    149 }
    150 
    151 scoped_ptr<ScriptInjection> UserScriptSet::GetDeclarativeScriptInjection(
    152     int script_id,
    153     blink::WebFrame* web_frame,
    154     int tab_id,
    155     UserScript::RunLocation run_location,
    156     const GURL& document_url,
    157     const Extension* extension) {
    158   for (ScopedVector<UserScript>::const_iterator it = scripts_.begin();
    159        it != scripts_.end();
    160        ++it) {
    161     if ((*it)->id() == script_id) {
    162       return GetInjectionForScript(*it,
    163                                    web_frame,
    164                                    tab_id,
    165                                    run_location,
    166                                    document_url,
    167                                    extension,
    168                                    true /* is_declarative */);
    169     }
    170   }
    171   return scoped_ptr<ScriptInjection>();
    172 }
    173 
    174 // TODO(dcheng): Scripts can't be injected on a remote frame, so this function
    175 // signature needs to be updated.
    176 scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
    177     UserScript* script,
    178     blink::WebFrame* web_frame,
    179     int tab_id,
    180     UserScript::RunLocation run_location,
    181     const GURL& document_url,
    182     const Extension* extension,
    183     bool is_declarative) {
    184   scoped_ptr<ScriptInjection> injection;
    185   if (web_frame->parent() && !script->match_all_frames())
    186     return injection.Pass();  // Only match subframes if the script declared it.
    187 
    188   GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
    189       web_frame, document_url, script->match_about_blank());
    190 
    191   if (!script->MatchesURL(effective_document_url))
    192     return injection.Pass();
    193 
    194   scoped_ptr<ScriptInjector> injector(new UserScriptInjector(script,
    195                                                              this,
    196                                                              is_declarative));
    197   if (injector->CanExecuteOnFrame(
    198           extension,
    199           web_frame,
    200           -1,  // Content scripts are not tab-specific.
    201           web_frame->top()->document().url()) ==
    202       PermissionsData::ACCESS_DENIED) {
    203     return injection.Pass();
    204   }
    205 
    206   bool inject_css = !script->css_scripts().empty() &&
    207                     run_location == UserScript::DOCUMENT_START;
    208   bool inject_js =
    209       !script->js_scripts().empty() && script->run_location() == run_location;
    210   if (inject_css || inject_js) {
    211     injection.reset(new ScriptInjection(
    212         injector.Pass(),
    213         web_frame->toWebLocalFrame(),
    214         extension->id(),
    215         run_location,
    216         tab_id));
    217   }
    218   return injection.Pass();
    219 }
    220 
    221 }  // namespace extensions
    222