<webview> WebRequest API tied to webview instance ID instead of guest instance ID

This permits installing WebRequest API listeners prior to initial navigation and prior to attachment.

BUG=171421
Test=WebViewInteractiveTest.NewWindow

Review URL: https://chromiumcodereview.appspot.com/15894014

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@204213 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index cfcedc7..6381e399 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -678,8 +678,10 @@
   return activity_log->IsLogEnabled();
 }
 
-void ChromeContentBrowserClient::GuestWebContentsCreated(
-    WebContents* guest_web_contents, WebContents* embedder_web_contents) {
+void ChromeContentBrowserClient::GuestWebContentsAttached(
+    WebContents* guest_web_contents,
+    WebContents* embedder_web_contents,
+    int browser_plugin_instance_id) {
   Profile* profile = Profile::FromBrowserContext(
       embedder_web_contents->GetBrowserContext());
   ExtensionService* service =
@@ -697,7 +699,10 @@
   // TODO(fsamuel): This should be replaced with WebViewGuest or AdViewGuest
   // once they are ready.
   extensions::TabHelper::CreateForWebContents(guest_web_contents);
-  new WebViewGuest(guest_web_contents, embedder_web_contents, extension->id());
+  new WebViewGuest(guest_web_contents,
+                   embedder_web_contents,
+                   extension->id(),
+                   browser_plugin_instance_id);
 }
 
 void ChromeContentBrowserClient::RenderProcessHostCreated(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 6472748..db7b5b8d 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -59,9 +59,10 @@
       bool* in_memory) OVERRIDE;
   virtual content::WebContentsViewDelegate* GetWebContentsViewDelegate(
       content::WebContents* web_contents) OVERRIDE;
-  virtual void GuestWebContentsCreated(
+  virtual void GuestWebContentsAttached(
       content::WebContents* guest_web_contents,
-      content::WebContents* embedder_web_contents) OVERRIDE;
+      content::WebContents* embedder_web_contents,
+      int browser_plugin_instance_id) OVERRIDE;
   virtual void RenderProcessHostCreated(
       content::RenderProcessHost* host) OVERRIDE;
   virtual bool ShouldUseProcessPerSite(content::BrowserContext* browser_context,
diff --git a/chrome/browser/extensions/api/web_request/web_request_api.cc b/chrome/browser/extensions/api/web_request/web_request_api.cc
index 401741f6..e43a471 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api.cc
@@ -394,7 +394,8 @@
   RequestFilter filter;
   int extra_info_spec;
   int embedder_process_id;
-  int web_view_instance_id;
+  int embedder_routing_id;
+  int webview_instance_id;
   base::WeakPtr<IPC::Sender> ipc_sender;
   mutable std::set<uint64> blocked_requests;
 
@@ -1155,7 +1156,8 @@
     const RequestFilter& filter,
     int extra_info_spec,
     int embedder_process_id,
-    int web_view_instance_id,
+    int embedder_routing_id,
+    int webview_instance_id,
     base::WeakPtr<IPC::Sender> ipc_sender) {
 
   if (!IsWebRequestEvent(event_name))
@@ -1169,7 +1171,8 @@
   listener.extra_info_spec = extra_info_spec;
   listener.ipc_sender = ipc_sender;
   listener.embedder_process_id = embedder_process_id;
-  listener.web_view_instance_id = web_view_instance_id;
+  listener.embedder_routing_id = embedder_routing_id;
+  listener.webview_instance_id = webview_instance_id;
 
   if (listeners_[profile][event_name].count(listener) != 0u) {
     // This is likely an abuse of the API by a malicious extension.
@@ -1219,7 +1222,7 @@
     void* profile,
     const std::string& extension_id,
     int embedder_process_id,
-    int web_view_instance_id) {
+    int webview_instance_id) {
   // Iterate over all listeners of all WebRequest events to delete
   // any listeners that belong to the provided <webview>.
   ListenerMapForProfile& map_for_profile = listeners_[profile];
@@ -1231,7 +1234,7 @@
          listener_iter != listeners.end(); ++listener_iter) {
       const EventListener& listener = *listener_iter;
       if (listener.embedder_process_id == embedder_process_id &&
-          listener.web_view_instance_id == web_view_instance_id)
+          listener.webview_instance_id == webview_instance_id)
         listeners_to_delete.push_back(listener);
     }
     for (size_t i = 0; i < listeners_to_delete.size(); ++i) {
@@ -1326,9 +1329,9 @@
     std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
         matching_listeners) {
   std::string web_request_event_name(event_name);
-  ExtensionRendererState::WebViewInfo web_view_info;
+  ExtensionRendererState::WebViewInfo webview_info;
   bool is_guest = ExtensionRendererState::GetInstance()->
-      GetWebViewInfo(render_process_host_id, routing_id, &web_view_info);
+      GetWebViewInfo(render_process_host_id, routing_id, &webview_info);
   if (is_guest)
     web_request_event_name.replace(0, sizeof(kWebRequest) - 1, kWebView);
 
@@ -1343,8 +1346,9 @@
     }
 
     if (is_guest &&
-        (it->embedder_process_id != web_view_info.embedder_process_id ||
-         it->web_view_instance_id != web_view_info.web_view_instance_id))
+        (it->embedder_process_id != webview_info.embedder_process_id ||
+         it->embedder_routing_id != webview_info.embedder_routing_id ||
+         it->webview_instance_id != webview_info.instance_id))
       continue;
 
     if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url))
@@ -2037,19 +2041,20 @@
   std::string sub_event_name;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
 
-  int web_view_instance_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id));
+  int webview_instance_id = 0;
+  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &webview_instance_id));
 
   base::WeakPtr<ChromeRenderMessageFilter> ipc_sender = ipc_sender_weak();
 
   int embedder_process_id =
       ipc_sender.get() ? ipc_sender->render_process_id() : -1;
+  int embedder_routing_id = routing_id();
 
   const Extension* extension =
       extension_info_map()->extensions().GetByID(extension_id());
   std::string extension_name = extension ? extension->name() : extension_id();
 
-  bool is_guest = web_view_instance_id != 0;
+  bool is_guest = webview_instance_id != 0;
   // We check automatically whether the extension has the 'webRequest'
   // permission. For blocking calls we require the additional permission
   // 'webRequestBlocking'.
@@ -2078,7 +2083,8 @@
       ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
           profile_id(), extension_id(), extension_name,
           event_name, sub_event_name, filter, extra_info_spec,
-          embedder_process_id, web_view_instance_id, ipc_sender_weak());
+          embedder_process_id, embedder_routing_id, webview_instance_id,
+          ipc_sender_weak());
   EXTENSION_FUNCTION_VALIDATE(success);
 
   helpers::ClearCacheOnNavigation();
diff --git a/chrome/browser/extensions/api/web_request/web_request_api.h b/chrome/browser/extensions/api/web_request/web_request_api.h
index 108174c..3a0d43e 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api.h
+++ b/chrome/browser/extensions/api/web_request/web_request_api.h
@@ -246,6 +246,7 @@
       const RequestFilter& filter,
       int extra_info_spec,
       int embedder_process_id,
+      int embedder_routing_id,
       int web_view_instance_id,
       base::WeakPtr<IPC::Sender> ipc_sender);
 
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index e6e39cd..dac311d1 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -225,12 +225,12 @@
   base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
-      filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, -1,
-      ipc_sender_factory.GetWeakPtr());
+      filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1,
+      MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2",
-      filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, -1,
-      ipc_sender_factory.GetWeakPtr());
+      filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1,
+      MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr());
 
   net::URLRequestJobFactoryImpl job_factory;
   job_factory.SetProtocolHandler(
@@ -360,12 +360,12 @@
   base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
     &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
-    filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, -1,
-    ipc_sender_factory.GetWeakPtr());
+    filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1,
+    MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
     &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2",
-    filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, -1,
-    ipc_sender_factory.GetWeakPtr());
+    filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1,
+    MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr());
 
   GURL request_url("about:blank");
   net::URLRequest request(request_url, &delegate_, context_.get());
@@ -428,11 +428,11 @@
   base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
     &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
-    filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, -1,
-    ipc_sender_factory.GetWeakPtr());
+    filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1,
+    MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
     &profile_, extension_id, extension_id, kEventName2, kEventName2 + "/1",
-    filter, 0, -1, -1, ipc_sender_factory.GetWeakPtr());
+    filter, 0, -1, MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr());
 
   GURL request_url("about:blank");
   net::URLRequest request(request_url, &delegate_, context_.get());
@@ -617,7 +617,7 @@
   ASSERT_TRUE(GenerateInfoSpec(string_spec_post, &extra_info_spec_body));
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
-      filter, extra_info_spec_body, -1, -1,
+      filter, extra_info_spec_body, -1, MSG_ROUTING_NONE, -1,
       ipc_sender_factory.GetWeakPtr());
 
   FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2);
@@ -634,7 +634,7 @@
       GenerateInfoSpec(string_spec_no_post, &extra_info_spec_empty));
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
-      filter, extra_info_spec_empty, -1, -1,
+      filter, extra_info_spec_empty, -1, MSG_ROUTING_NONE, -1,
       ipc_sender_factory.GetWeakPtr());
 
   FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2);
@@ -645,7 +645,7 @@
   // Subscribe to OnBeforeRequest with requestBody requirement.
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
-      filter, extra_info_spec_body, -1, -1,
+      filter, extra_info_spec_body, -1, MSG_ROUTING_NONE, -1,
       ipc_sender_factory.GetWeakPtr());
 
   // Part 3.
@@ -704,7 +704,8 @@
   // Subscribe to OnBeforeRequest with requestBody requirement.
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
-      filter, extra_info_spec, -1, -1, ipc_sender_factory.GetWeakPtr());
+      filter, extra_info_spec, -1, MSG_ROUTING_NONE, -1,
+      ipc_sender_factory.GetWeakPtr());
 
   // The request URL can be arbitrary but must have an HTTP or HTTPS scheme.
   const GURL request_url("http://www.example.com");
@@ -817,19 +818,19 @@
   // higher precedence than extension 1.
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
-      filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, -1,
-      ipc_sender_factory.GetWeakPtr());
+      filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1,
+      MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2",
-      filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, -1,
-      ipc_sender_factory.GetWeakPtr());
+      filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1,
+      MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr());
 
   // Install one extension that observes the final headers.
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension3_id, extension3_id, keys::kOnSendHeadersEvent,
       std::string(keys::kOnSendHeadersEvent) + "/3", filter,
-      ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS, -1, -1,
-      ipc_sender_factory.GetWeakPtr());
+      ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS, -1,
+      MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr());
 
   GURL request_url("http://doesnotexist/does_not_exist.html");
   net::URLRequest request(request_url, &delegate_, context_.get());
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 6aa978c..fcf5cf6 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -264,7 +264,8 @@
       render_view_host_->GetRoutingID(), level, message));
 }
 
-IOThreadExtensionFunction::IOThreadExtensionFunction() {
+IOThreadExtensionFunction::IOThreadExtensionFunction()
+    : routing_id_(MSG_ROUTING_NONE) {
 }
 
 IOThreadExtensionFunction::~IOThreadExtensionFunction() {
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index 4218786e..4afc40d1 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -405,14 +405,18 @@
 
   virtual IOThreadExtensionFunction* AsIOThreadExtensionFunction() OVERRIDE;
 
-  void set_ipc_sender(base::WeakPtr<ChromeRenderMessageFilter> ipc_sender) {
+  void set_ipc_sender(base::WeakPtr<ChromeRenderMessageFilter> ipc_sender,
+                      int routing_id) {
     ipc_sender_ = ipc_sender;
+    routing_id_ = routing_id;
   }
 
   base::WeakPtr<ChromeRenderMessageFilter> ipc_sender_weak() const {
     return ipc_sender_;
   }
 
+  int routing_id() const { return routing_id_; }
+
   void set_extension_info_map(const ExtensionInfoMap* extension_info_map) {
     extension_info_map_ = extension_info_map;
   }
@@ -433,6 +437,7 @@
 
  private:
   base::WeakPtr<ChromeRenderMessageFilter> ipc_sender_;
+  int routing_id_;
 
   scoped_refptr<const ExtensionInfoMap> extension_info_map_;
 };
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index a9fb3f7..ed05d09 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -279,7 +279,7 @@
     NOTREACHED();
     return;
   }
-  function_io->set_ipc_sender(ipc_sender);
+  function_io->set_ipc_sender(ipc_sender, routing_id);
   function_io->set_extension_info_map(extension_info_map);
   function->set_include_incognito(
       extension_info_map->IsIncognitoEnabled(extension->id()));
diff --git a/chrome/browser/extensions/extension_renderer_state.cc b/chrome/browser/extensions/extension_renderer_state.cc
index 62516b0..c43c690 100644
--- a/chrome/browser/extensions/extension_renderer_state.cc
+++ b/chrome/browser/extensions/extension_renderer_state.cc
@@ -8,6 +8,7 @@
 #include "base/bind_helpers.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/tab_contents/retargeting_details.h"
+#include "chrome/browser/webview/webview_guest.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_details.h"
@@ -37,22 +38,12 @@
   }
 
   virtual void RenderViewHostDestroyed(content::RenderViewHost* host) OVERRIDE {
-    if (host->GetProcess()->IsGuest()) {
-      BrowserThread::PostTask(
-          BrowserThread::IO, FROM_HERE,
-          base::Bind(
-              &ExtensionRendererState::RemoveWebView,
-              base::Unretained(ExtensionRendererState::GetInstance()),
-              host->GetProcess()->GetID(),
-              host->GetRoutingID()));
-    } else {
-      BrowserThread::PostTask(
-          BrowserThread::IO, FROM_HERE,
-          base::Bind(
-              &ExtensionRendererState::ClearTabAndWindowId,
-              base::Unretained(ExtensionRendererState::GetInstance()),
-              host->GetProcess()->GetID(), host->GetRoutingID()));
-    }
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(
+            &ExtensionRendererState::ClearTabAndWindowId,
+            base::Unretained(ExtensionRendererState::GetInstance()),
+            host->GetProcess()->GetID(), host->GetRoutingID()));
 
     delete this;
   }
@@ -88,9 +79,6 @@
   registrar_.Add(this,
                  content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
                  content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this,
-                 content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
-                 content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Add(this, chrome::NOTIFICATION_TAB_PARENTED,
                  content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Add(this, chrome::NOTIFICATION_RETARGETING,
@@ -128,33 +116,6 @@
 
       break;
     }
-    case content::NOTIFICATION_WEB_CONTENTS_CONNECTED: {
-      WebContents* web_contents = content::Source<WebContents>(source).ptr();
-      if (!web_contents->GetRenderProcessHost()->IsGuest())
-        return;
-
-      WebContents* embedder_web_contents =
-          web_contents->GetEmbedderWebContents();
-      if (!embedder_web_contents)
-        return;
-      WebViewInfo web_view_info;
-      web_view_info.embedder_process_id =
-          embedder_web_contents->GetRenderProcessHost()->GetID();
-      web_view_info.embedder_routing_id =
-          embedder_web_contents->GetRoutingID();
-      web_view_info.web_view_instance_id =
-          web_contents->GetEmbeddedInstanceID();
-
-      BrowserThread::PostTask(
-          BrowserThread::IO, FROM_HERE,
-          base::Bind(
-              &ExtensionRendererState::AddWebView,
-              base::Unretained(ExtensionRendererState::GetInstance()),
-              web_contents->GetRenderProcessHost()->GetID(),
-              web_contents->GetRoutingID(),
-              web_view_info));
-      break;
-    }
     case chrome::NOTIFICATION_TAB_PARENTED: {
       WebContents* web_contents = content::Source<WebContents>(source).ptr();
       SessionTabHelper* session_tab_helper =
@@ -249,27 +210,27 @@
 
 void ExtensionRendererState::AddWebView(int guest_process_id,
                                         int guest_routing_id,
-                                        const WebViewInfo& web_view_info) {
+                                        const WebViewInfo& webview_info) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   RenderId render_id(guest_process_id, guest_routing_id);
-  web_view_info_map_[render_id] = web_view_info;
+  webview_info_map_[render_id] = webview_info;
 }
 
 void ExtensionRendererState::RemoveWebView(int guest_process_id,
                                            int guest_routing_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   RenderId render_id(guest_process_id, guest_routing_id);
-  web_view_info_map_.erase(render_id);
+  webview_info_map_.erase(render_id);
 }
 
 bool ExtensionRendererState::GetWebViewInfo(int guest_process_id,
                                             int guest_routing_id,
-                                            WebViewInfo* web_view_info) {
+                                            WebViewInfo* webview_info) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   RenderId render_id(guest_process_id, guest_routing_id);
-  WebViewInfoMap::iterator iter = web_view_info_map_.find(render_id);
-  if (iter != web_view_info_map_.end()) {
-    *web_view_info = iter->second;
+  WebViewInfoMap::iterator iter = webview_info_map_.find(render_id);
+  if (iter != webview_info_map_.end()) {
+    *webview_info = iter->second;
     return true;
   }
   return false;
diff --git a/chrome/browser/extensions/extension_renderer_state.h b/chrome/browser/extensions/extension_renderer_state.h
index 04a48bd..8118585 100644
--- a/chrome/browser/extensions/extension_renderer_state.h
+++ b/chrome/browser/extensions/extension_renderer_state.h
@@ -12,6 +12,10 @@
 #include "base/basictypes.h"
 #include "base/memory/singleton.h"
 
+namespace chrome {
+class WebViewGuest;
+}  // namespace chrome
+
 // This class keeps track of renderer state for use on the IO thread. All
 // methods should be called on the IO thread except for Init and Shutdown.
 class ExtensionRendererState {
@@ -19,7 +23,8 @@
   struct WebViewInfo {
     int embedder_process_id;
     int embedder_routing_id;
-    int web_view_instance_id;
+    int guest_instance_id;
+    int instance_id;
   };
 
   static ExtensionRendererState* GetInstance();
@@ -32,7 +37,7 @@
   // Looks up the information for the embedder <webview> for a given render
   // view, if one exists. Called on the IO thread.
   bool GetWebViewInfo(int guest_process_id, int guest_routing_id,
-                      WebViewInfo* web_view_info);
+                      WebViewInfo* webview_info);
 
   // Looks up the tab and window ID for a given render view. Returns true
   // if we have the IDs in our map. Called on the IO thread.
@@ -43,6 +48,7 @@
   class RenderViewHostObserver;
   class TabObserver;
   friend class TabObserver;
+  friend class chrome::WebViewGuest;
   friend struct DefaultSingletonTraits<ExtensionRendererState>;
 
   typedef std::pair<int, int> RenderId;
@@ -61,12 +67,12 @@
 
   // Adds or removes a <webview> guest render process from the set.
   void AddWebView(int render_process_host_id, int routing_id,
-                  const WebViewInfo& web_view_info);
+                  const WebViewInfo& webview_info);
   void RemoveWebView(int render_process_host_id, int routing_id);
 
   TabObserver* observer_;
   TabAndWindowIdMap map_;
-  WebViewInfoMap web_view_info_map_;
+  WebViewInfoMap webview_info_map_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionRendererState);
 };
diff --git a/chrome/browser/webview/webview_guest.cc b/chrome/browser/webview/webview_guest.cc
index 643486b..a073eaa 100644
--- a/chrome/browser/webview/webview_guest.cc
+++ b/chrome/browser/webview/webview_guest.cc
@@ -6,6 +6,7 @@
 
 #include "base/lazy_instance.h"
 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
+#include "chrome/browser/extensions/extension_renderer_state.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/site_instance.h"
@@ -26,46 +27,51 @@
     void* profile,
     const std::string& extension_id,
     int embedder_process_id,
-    int web_view_instance_id) {
+    int guest_instance_id) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   ExtensionWebRequestEventRouter::GetInstance()->RemoveWebViewEventListeners(
-      profile, extension_id, embedder_process_id, web_view_instance_id);
+      profile, extension_id, embedder_process_id, guest_instance_id);
 }
 
 }  // namespace
 
 WebViewGuest::WebViewGuest(WebContents* guest_web_contents,
                            WebContents* embedder_web_contents,
-                           const std::string& extension_id)
+                           const std::string& extension_id,
+                           int webview_instance_id)
     : WebContentsObserver(guest_web_contents),
       embedder_web_contents_(embedder_web_contents),
       extension_id_(extension_id),
       embedder_render_process_id_(
           embedder_web_contents->GetRenderProcessHost()->GetID()),
       profile_(guest_web_contents->GetBrowserContext()),
-      instance_id_(guest_web_contents->GetEmbeddedInstanceID()) {
+      guest_instance_id_(guest_web_contents->GetEmbeddedInstanceID()),
+      webview_instance_id_(webview_instance_id) {
   webview_profile_map.Get()[profile_].insert(
-      std::make_pair(instance_id_, this));
+      std::make_pair(guest_instance_id_, this));
+
+  AddWebViewToExtensionRendererState();
 }
 
 // static
-WebViewGuest* WebViewGuest::From(void* profile, int instance_id) {
+WebViewGuest* WebViewGuest::From(void* profile, int guest_instance_id) {
   WebViewProfileMap* profile_map = webview_profile_map.Pointer();
   WebViewProfileMap::iterator it = profile_map->find(profile);
   if (it == profile_map->end())
     return NULL;
   const WebViewGuestMap& guest_map = it->second;
-  WebViewGuestMap::const_iterator guest_it = guest_map.find(instance_id);
+  WebViewGuestMap::const_iterator guest_it = guest_map.find(guest_instance_id);
   return guest_it == guest_map.end() ? NULL : guest_it->second;
 }
 
 WebViewGuest::~WebViewGuest() {
-  webview_profile_map.Get()[profile_].erase(instance_id_);
+  webview_profile_map.Get()[profile_].erase(guest_instance_id_);
   if (webview_profile_map.Get()[profile_].empty())
     webview_profile_map.Get().erase(profile_);
 }
 
 void WebViewGuest::WebContentsDestroyed(WebContents* web_contents) {
+  RemoveWebViewFromExtensionRendererState(web_contents);
   content::BrowserThread::PostTask(
       content::BrowserThread::IO,
       FROM_HERE,
@@ -73,8 +79,38 @@
           &RemoveWebViewEventListenersOnIOThread,
           profile_, extension_id_,
           embedder_render_process_id_,
-          instance_id_));
+          webview_instance_id_));
   delete this;
 }
 
+void WebViewGuest::AddWebViewToExtensionRendererState() {
+  ExtensionRendererState::WebViewInfo webview_info;
+  webview_info.embedder_process_id =
+      embedder_web_contents()->GetRenderProcessHost()->GetID();
+  webview_info.embedder_routing_id = embedder_web_contents()->GetRoutingID();
+  webview_info.guest_instance_id = guest_instance_id_;
+  webview_info.instance_id = webview_instance_id_;
+
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO, FROM_HERE,
+      base::Bind(
+          &ExtensionRendererState::AddWebView,
+          base::Unretained(ExtensionRendererState::GetInstance()),
+          web_contents()->GetRenderProcessHost()->GetID(),
+          web_contents()->GetRoutingID(),
+          webview_info));
+}
+
+// static
+void WebViewGuest::RemoveWebViewFromExtensionRendererState(
+    WebContents* web_contents) {
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO, FROM_HERE,
+      base::Bind(
+          &ExtensionRendererState::RemoveWebView,
+          base::Unretained(ExtensionRendererState::GetInstance()),
+          web_contents->GetRenderProcessHost()->GetID(),
+          web_contents->GetRoutingID()));
+}
+
 }  // namespace chrome
diff --git a/chrome/browser/webview/webview_guest.h b/chrome/browser/webview/webview_guest.h
index 135bb68..91dd737 100644
--- a/chrome/browser/webview/webview_guest.h
+++ b/chrome/browser/webview/webview_guest.h
@@ -11,12 +11,17 @@
 
 // A WebViewGuest is a WebContentsObserver on the guest WebContents of a
 // <webview> tag. It provides the browser-side implementation of the <webview>
-// API and manages the lifetime of <webview> extension events.
+// API and manages the lifetime of <webview> extension events. WebViewGuest is
+// created on attachment. That is, when a guest WebContents is associated with
+// a particular embedder WebContents. This happens on either initial navigation
+// or through the use of the New Window API, when a new window is attached to
+// a particular <webview>.
 class WebViewGuest : public content::WebContentsObserver {
  public:
   WebViewGuest(content::WebContents* guest_web_contents,
                content::WebContents* embedder_web_contents,
-               const std::string& extension_id);
+               const std::string& extension_id,
+               int webview_instance_id);
 
   static WebViewGuest* From(void* profile, int instance_id);
 
@@ -28,18 +33,29 @@
     return WebContentsObserver::web_contents();
   }
 
+  int instance_id() const { return webview_instance_id_; }
+
  private:
   virtual ~WebViewGuest();
   virtual void WebContentsDestroyed(
       content::WebContents* web_contents) OVERRIDE;
 
+  void AddWebViewToExtensionRendererState();
+  static void RemoveWebViewFromExtensionRendererState(
+      content::WebContents* web_contents);
+
   content::WebContents* embedder_web_contents_;
   const std::string extension_id_;
   const int embedder_render_process_id_;
   // Profile and instance ID are cached here because |web_contents()| is
   // null on destruction.
   void* profile_;
-  const int instance_id_;
+  // |guest_instance_id_| is a profile-wide unique identifier for a guest
+  // WebContents.
+  const int guest_instance_id_;
+  // |webview_instance_id_| is an identifier that's unique within a particular
+  // embedder RenderView for a particular <webview> instance.
+  int webview_instance_id_;
 
   DISALLOW_COPY_AND_ASSIGN(WebViewGuest);
 };
diff --git a/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js b/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
index 262fa21..65c3a5f 100644
--- a/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
+++ b/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
@@ -230,6 +230,42 @@
   embedder.setUpNewWindowRequest_(webview, 'about:blank', '', testName);
 };
 
+embedder.tests.testNewWindowWebRequest =
+    function testNewWindowWebRequest() {
+  var testName = 'testNewWindowExecuteScript';
+  var webview = embedder.setUpGuest_('foobar');
+
+  var onNewWindow = function(e) {
+    chrome.test.log('Embedder notified on newwindow');
+    embedder.assertCorrectEvent_(e, '');
+
+    var newwebview = document.createElement('webview');
+    document.querySelector('#webview-tag-container').appendChild(newwebview);
+    var calledWebRequestEvent = false;
+    e.preventDefault();
+    // The WebRequest API is not exposed until the <webview> MutationObserver
+    // picks up the <webview> in the DOM. Thus, we cannot immediately access
+    // WebRequest API.
+    window.setTimeout(function() {
+      newwebview.onBeforeRequest.addListener(function(e) {
+          if (!calledWebRequestEvent) {
+            calledWebRequestEvent = true;
+            chrome.test.succeed();
+          }
+        }, { urls: ['<all_urls>'] }, ['blocking']);
+      try {
+        e.window.attach(newwebview);
+      } catch (e) {
+        chrome.test.fail();
+      }
+    }, 0);
+  };
+  webview.addEventListener('newwindow', onNewWindow);
+
+  // Load a new window with the given name.
+  embedder.setUpNewWindowRequest_(webview, 'guest.html', '', testName);
+};
+
 onload = function() {
   chrome.test.getConfig(function(config) {
     embedder.setUp(config);
@@ -239,7 +275,8 @@
       embedder.tests.testNoName,
       embedder.tests.testNewWindowRedirect,
       embedder.tests.testNewWindowClose,
-      embedder.tests.testNewWindowExecuteScript
+      embedder.tests.testNewWindowExecuteScript,
+      embedder.tests.testNewWindowWebRequest
     ]);
   });
 };