Fix shell URL resolver.

Fix the resolver so that if we map mojo:a to mojo:b and mojo:b is
handled by a custom loader, then the loader for mojo:b is invoked.

R=aa@chromium.org

Review URL: https://codereview.chromium.org/859863002
diff --git a/shell/application_manager/application_manager.cc b/shell/application_manager/application_manager.cc
index 2ead72e..29d81fc 100644
--- a/shell/application_manager/application_manager.cc
+++ b/shell/application_manager/application_manager.cc
@@ -46,6 +46,10 @@
   return url;
 }
 
+GURL ApplicationManager::Delegate::ResolveMappings(const GURL& url) {
+  return url;
+}
+
 class ApplicationManager::ContentHandlerConnection : public ErrorHandler {
  public:
   ContentHandlerConnection(ApplicationManager* manager,
@@ -112,15 +116,16 @@
     InterfaceRequest<ServiceProvider> services,
     ServiceProviderPtr exposed_services) {
   DCHECK(requested_url.is_valid());
-  ApplicationLoader* loader = GetLoaderForURL(requested_url,
-                                              DONT_INCLUDE_DEFAULT_LOADER);
+  GURL mapped_url = delegate_->ResolveMappings(requested_url);
+  ApplicationLoader* loader =
+      GetLoaderForURL(mapped_url, DONT_INCLUDE_DEFAULT_LOADER);
   if (loader) {
-    ConnectToApplicationImpl(requested_url, requested_url, requestor_url,
+    ConnectToApplicationImpl(requested_url, mapped_url, requestor_url,
                              services.Pass(), exposed_services.Pass(), loader);
     return;
   }
 
-  GURL resolved_url = delegate_->ResolveURL(requested_url);
+  GURL resolved_url = delegate_->ResolveURL(mapped_url);
   loader = GetLoaderForURL(resolved_url, INCLUDE_DEFAULT_LOADER);
   if (loader) {
     ConnectToApplicationImpl(requested_url, resolved_url, requestor_url,
diff --git a/shell/application_manager/application_manager.h b/shell/application_manager/application_manager.h
index c420e51..5a2afb3 100644
--- a/shell/application_manager/application_manager.h
+++ b/shell/application_manager/application_manager.h
@@ -29,6 +29,7 @@
     // Shell pipe goes away.
     virtual void OnApplicationError(const GURL& url);
     virtual GURL ResolveURL(const GURL& url);
+    virtual GURL ResolveMappings(const GURL& url);
   };
 
   // API for testing.
diff --git a/shell/application_manager/application_manager_unittest.cc b/shell/application_manager/application_manager_unittest.cc
index f1a09cd..9352a7d 100644
--- a/shell/application_manager/application_manager_unittest.cc
+++ b/shell/application_manager/application_manager_unittest.cc
@@ -389,13 +389,25 @@
   }
 
   // ApplicationManager::Delegate
-  virtual GURL ResolveURL(const GURL& url) override {
+  virtual GURL ResolveMappings(const GURL& url) override {
     auto it = mappings_.find(url);
     if (it != mappings_.end())
       return it->second;
     return url;
   }
 
+  // ApplicationManager::Delegate
+  virtual GURL ResolveURL(const GURL& url) override {
+    GURL mapped_url = ResolveMappings(url);
+    // The shell automatically map mojo URLs.
+    if (mapped_url.scheme() == "mojo") {
+      url::Replacements<char> replacements;
+      replacements.SetScheme("file", url::Component(0, 4));
+      mapped_url = mapped_url.ReplaceComponents(replacements);
+    }
+    return mapped_url;
+  }
+
   virtual void OnApplicationError(const GURL& url) override {
   }
 
@@ -670,4 +682,18 @@
   EXPECT_EQ(3, test_loader_->num_loads());
 }
 
+TEST_F(ApplicationManagerTest, MappedURLsShouldWorkWithLoaders) {
+  TestApplicationLoader* custom_loader = new TestApplicationLoader;
+  TestContext context;
+  custom_loader->set_context(&context);
+  application_manager_->SetLoaderForURL(make_scoped_ptr(custom_loader),
+                                        GURL("mojo:foo"));
+  test_delegate_.AddMapping(GURL("mojo:foo2"), GURL("mojo:foo"));
+
+  TestServicePtr test_service;
+  application_manager_->ConnectToService(GURL("mojo:foo2"), &test_service);
+  EXPECT_EQ(1, custom_loader->num_loads());
+  custom_loader->set_context(nullptr);
+}
+
 }  // namespace mojo
diff --git a/shell/context.cc b/shell/context.cc
index 5f776e3..37f8348 100644
--- a/shell/context.cc
+++ b/shell/context.cc
@@ -209,6 +209,10 @@
   return mojo_url_resolver_.Resolve(url);
 }
 
+GURL Context::ResolveMappings(const GURL& url) {
+  return mojo_url_resolver_.ApplyCustomMappings(url);
+}
+
 void Context::Run(const GURL& url) {
   ServiceProviderPtr services;
   ServiceProviderPtr exposed_services;
diff --git a/shell/context.h b/shell/context.h
index ab30f14..b20b3fa 100644
--- a/shell/context.h
+++ b/shell/context.h
@@ -43,6 +43,7 @@
   // ApplicationManager::Delegate override.
   void OnApplicationError(const GURL& url) override;
   GURL ResolveURL(const GURL& url) override;
+  GURL ResolveMappings(const GURL& url) override;
 
   std::set<GURL> app_urls_;
   scoped_ptr<TaskRunners> task_runners_;
diff --git a/shell/mojo_url_resolver.h b/shell/mojo_url_resolver.h
index 60e2a34..1b5acba 100644
--- a/shell/mojo_url_resolver.h
+++ b/shell/mojo_url_resolver.h
@@ -45,12 +45,12 @@
   // code for the corresponding Mojo App.
   GURL Resolve(const GURL& mojo_url) const;
 
- private:
   // Applies all custom mappings for |url|, returning the last non-mapped url.
   // For example, if 'a' maps to 'b' and 'b' maps to 'c' calling this with 'a'
   // returns 'c'.
   GURL ApplyCustomMappings(const GURL& url) const;
 
+ private:
   std::map<GURL, GURL> url_map_;
   std::set<GURL> local_file_set_;
   GURL local_apps_url_;