Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1388)

Unified Diff: chrome/browser/extensions/user_script_listener.cc

Issue 173239: Delay request loading until all user scripts that request depends on are ready. (Closed)
Patch Set: linux and mac fixes Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/user_script_listener.cc
diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc
new file mode 100644
index 0000000000000000000000000000000000000000..94b58bf0da897f32227e5d39812515519706b4a7
--- /dev/null
+++ b/chrome/browser/extensions/user_script_listener.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/user_script_listener.h"
+
+#include "base/message_loop.h"
+#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_service.h"
+#include "net/url_request/url_request.h"
+
+UserScriptListener::UserScriptListener(MessageLoop* ui_loop,
+ MessageLoop* io_loop,
+ ResourceDispatcherHost* rdh)
+ : ui_loop_(ui_loop),
+ io_loop_(io_loop),
+ resource_dispatcher_host_(rdh),
+ user_scripts_ready_(false) {
+ DCHECK(ui_loop_);
+ DCHECK_EQ(ui_loop_, MessageLoop::current());
+ DCHECK(resource_dispatcher_host_);
+
+ // IO loop can be NULL in unit tests.
+ if (!io_loop_)
+ io_loop_ = ui_loop;
+
+ registrar_.Add(this, NotificationType::EXTENSION_LOADED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::USER_SCRIPTS_UPDATED,
+ NotificationService::AllSources());
+}
+
+bool UserScriptListener::ShouldStartRequest(URLRequest* request) {
+ DCHECK_EQ(io_loop_, MessageLoop::current());
+
+ // If it's a frame load, then we need to check the URL against the list of
+ // user scripts to see if we need to wait.
+ ResourceDispatcherHost::ExtraRequestInfo* info =
+ ResourceDispatcherHost::ExtraInfoForRequest(request);
+ DCHECK(info);
+
+ if (info->resource_type != ResourceType::MAIN_FRAME &&
+ info->resource_type != ResourceType::SUB_FRAME) {
+ return true;
+ }
+
+ if (user_scripts_ready_)
+ return true;
+
+ // User scripts aren't ready yet. If one of them wants to inject into this
+ // request, we'll need to wait for it before we can start this request.
+ bool found_match = false;
+ for (URLPatterns::iterator it = url_patterns_.begin();
+ it != url_patterns_.end(); ++it) {
+ if ((*it).MatchesUrl(request->url())) {
+ found_match = true;
+ break;
+ }
+ }
+
+ if (!found_match)
+ return true;
+
+ // Queue this request up.
+ delayed_request_ids_.push_front(ResourceDispatcherHost::GlobalRequestID(
+ info->process_id, info->request_id));
+ return false;
+}
+
+void UserScriptListener::StartDelayedRequests() {
+ DCHECK_EQ(io_loop_, MessageLoop::current());
+
+ user_scripts_ready_ = true;
+
+ if (resource_dispatcher_host_) {
+ for (DelayedRequests::iterator it = delayed_request_ids_.begin();
+ it != delayed_request_ids_.end(); ++it) {
+ URLRequest* request = resource_dispatcher_host_->GetURLRequest(*it);
+ if (request) {
+ // The request shouldn't have started (SUCCESS is the initial state).
+ DCHECK(request->status().status() == URLRequestStatus::SUCCESS);
+ request->Start();
+ }
+ }
+ }
+
+ delayed_request_ids_.clear();
+}
+
+void UserScriptListener::AppendNewURLPatterns(const URLPatterns& new_patterns) {
+ DCHECK_EQ(io_loop_, MessageLoop::current());
+
+ user_scripts_ready_ = false;
+ url_patterns_.insert(url_patterns_.end(),
+ new_patterns.begin(), new_patterns.end());
+}
+
+void UserScriptListener::ReplaceURLPatterns(const URLPatterns& patterns) {
+ DCHECK_EQ(io_loop_, MessageLoop::current());
+ url_patterns_ = patterns;
+}
+
+void UserScriptListener::CollectURLPatterns(Extension* extension,
+ URLPatterns* patterns) {
+ DCHECK_EQ(ui_loop_, MessageLoop::current());
+
+ const UserScriptList& scripts = extension->content_scripts();
+ for (UserScriptList::const_iterator iter = scripts.begin();
+ iter != scripts.end(); ++iter) {
+ patterns->insert(patterns->end(),
+ (*iter).url_patterns().begin(),
+ (*iter).url_patterns().end());
+ }
+}
+
+void UserScriptListener::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(ui_loop_, MessageLoop::current());
+
+ switch (type.value) {
+ case NotificationType::EXTENSION_LOADED: {
+ Extension* extension = Details<Extension>(details).ptr();
+ if (extension->content_scripts().empty())
+ return; // no new patterns from this extension.
+
+ URLPatterns new_patterns;
+ CollectURLPatterns(Details<Extension>(details).ptr(), &new_patterns);
+ if (!new_patterns.empty()) {
+ io_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &UserScriptListener::AppendNewURLPatterns, new_patterns));
+ }
+ break;
+ }
+
+ case NotificationType::EXTENSION_UNLOADED: {
+ Extension* unloaded_extension = Details<Extension>(details).ptr();
+ if (unloaded_extension->content_scripts().empty())
+ return; // no patterns to delete for this extension.
+
+ // Clear all our patterns and reregister all the still-loaded extensions.
+ URLPatterns new_patterns;
+ ExtensionsService* service = Source<ExtensionsService>(source).ptr();
+ for (ExtensionList::const_iterator it = service->extensions()->begin();
+ it != service->extensions()->end(); ++it) {
+ if (*it != unloaded_extension)
+ CollectURLPatterns(*it, &new_patterns);
+ }
+ io_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &UserScriptListener::ReplaceURLPatterns, new_patterns));
+ break;
+ }
+
+ case NotificationType::USER_SCRIPTS_UPDATED: {
+ io_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &UserScriptListener::StartDelayedRequests));
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ }
+}
« no previous file with comments | « chrome/browser/extensions/user_script_listener.h ('k') | chrome/browser/extensions/user_script_listener_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698