Index application by URL and identity for multiprocess.

This is a baby step in the direction of allowing to run multiple
instance of the same content handler. This will be needed when we enable
multi-process so that 2 application that use the same content handler
can be run in 2 processes.

R=davemoore@chromium.org

Review URL: https://codereview.chromium.org/979203002
diff --git a/shell/application_manager/BUILD.gn b/shell/application_manager/BUILD.gn
index c63eee0..b6a604f 100644
--- a/shell/application_manager/BUILD.gn
+++ b/shell/application_manager/BUILD.gn
@@ -15,6 +15,8 @@
     "data_pipe_peek.h",
     "fetcher.cc",
     "fetcher.h",
+    "identity.cc",
+    "identity.h",
     "local_fetcher.cc",
     "local_fetcher.h",
     "native_runner.h",
diff --git a/shell/application_manager/application_manager.cc b/shell/application_manager/application_manager.cc
index 90df846..68d5837 100644
--- a/shell/application_manager/application_manager.cc
+++ b/shell/application_manager/application_manager.cc
@@ -85,8 +85,8 @@
 }
 
 bool ApplicationManager::TestAPI::HasFactoryForURL(const GURL& url) const {
-  return manager_->url_to_shell_impl_.find(url) !=
-         manager_->url_to_shell_impl_.end();
+  return manager_->identity_to_shell_impl_.find(Identity(url)) !=
+         manager_->identity_to_shell_impl_.end();
 }
 
 ApplicationManager::ApplicationManager(Delegate* delegate)
@@ -101,7 +101,7 @@
 }
 
 void ApplicationManager::TerminateShellConnections() {
-  STLDeleteValues(&url_to_shell_impl_);
+  STLDeleteValues(&identity_to_shell_impl_);
 }
 
 void ApplicationManager::ConnectToApplication(
@@ -199,13 +199,13 @@
     const GURL& requestor_url,
     InterfaceRequest<ServiceProvider> services,
     ServiceProviderPtr exposed_services) {
-  GURL app_url = GetBaseURLAndQuery(resolved_url, nullptr);
+  Identity app_identity(resolved_url);
 
   ApplicationPtr application;
   InterfaceRequest<Application> application_request = GetProxy(&application);
   ShellImpl* shell =
-      new ShellImpl(application.Pass(), this, original_url, app_url);
-  url_to_shell_impl_[app_url] = shell;
+      new ShellImpl(application.Pass(), this, original_url, app_identity);
+  identity_to_shell_impl_[app_identity] = shell;
   shell->InitializeApplication(GetArgsForURL(original_url));
   ConnectToClient(shell, resolved_url, requestor_url, services.Pass(),
                   exposed_services.Pass());
@@ -213,8 +213,8 @@
 }
 
 ShellImpl* ApplicationManager::GetShellImpl(const GURL& url) {
-  const auto& shell_it = url_to_shell_impl_.find(url);
-  if (shell_it != url_to_shell_impl_.end())
+  const auto& shell_it = identity_to_shell_impl_.find(Identity(url));
+  if (shell_it != identity_to_shell_impl_.end())
     return shell_it->second;
   return nullptr;
 }
@@ -338,8 +338,10 @@
     LOG(WARNING) << "--args-for provided for external application " << url
                  << " <ignored>";
   }
-  ShellImpl* shell_impl = new ShellImpl(application.Pass(), this, url, url);
-  url_to_shell_impl_[url] = shell_impl;
+  Identity identity(url);
+  ShellImpl* shell_impl =
+      new ShellImpl(application.Pass(), this, url, identity);
+  identity_to_shell_impl_[identity] = shell_impl;
   shell_impl->InitializeApplication(Array<String>::From(args));
 }
 
@@ -417,13 +419,13 @@
 
 void ApplicationManager::OnShellImplError(ShellImpl* shell_impl) {
   // Called from ~ShellImpl, so we do not need to call Destroy here.
-  const GURL url = shell_impl->url();
+  const Identity identity = shell_impl->identity();
   const GURL requested_url = shell_impl->requested_url();
   // Remove the shell.
-  URLToShellImplMap::iterator it = url_to_shell_impl_.find(url);
-  DCHECK(it != url_to_shell_impl_.end());
+  auto it = identity_to_shell_impl_.find(identity);
+  DCHECK(it != identity_to_shell_impl_.end());
   delete it->second;
-  url_to_shell_impl_.erase(it);
+  identity_to_shell_impl_.erase(it);
   delegate_->OnApplicationError(requested_url);
 }
 
diff --git a/shell/application_manager/application_manager.h b/shell/application_manager/application_manager.h
index 05a4fc9..8ae6eb9 100644
--- a/shell/application_manager/application_manager.h
+++ b/shell/application_manager/application_manager.h
@@ -16,6 +16,7 @@
 #include "mojo/public/interfaces/application/service_provider.mojom.h"
 #include "mojo/services/network/public/interfaces/network_service.mojom.h"
 #include "shell/application_manager/application_loader.h"
+#include "shell/application_manager/identity.h"
 #include "shell/application_manager/native_runner.h"
 #include "url/gurl.h"
 
@@ -133,7 +134,7 @@
 
   typedef std::map<std::string, ApplicationLoader*> SchemeToLoaderMap;
   typedef std::map<GURL, ApplicationLoader*> URLToLoaderMap;
-  typedef std::map<GURL, ShellImpl*> URLToShellImplMap;
+  typedef std::map<Identity, ShellImpl*> IdentityToShellImplMap;
   typedef std::map<GURL, ContentHandlerConnection*> URLToContentHandlerMap;
   typedef std::map<GURL, std::vector<std::string>> URLToArgsMap;
   typedef std::map<std::string, GURL> MimeTypeToURLMap;
@@ -209,7 +210,7 @@
   scoped_ptr<ApplicationLoader> default_loader_;
   scoped_ptr<NativeRunnerFactory> native_runner_factory_;
 
-  URLToShellImplMap url_to_shell_impl_;
+  IdentityToShellImplMap identity_to_shell_impl_;
   URLToContentHandlerMap url_to_content_handler_;
   URLToArgsMap url_to_args_;
   // Note: The keys are URLs after mapping and resolving.
diff --git a/shell/application_manager/identity.cc b/shell/application_manager/identity.cc
new file mode 100644
index 0000000..ea221da
--- /dev/null
+++ b/shell/application_manager/identity.cc
@@ -0,0 +1,28 @@
+// Copyright 2015 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 "shell/application_manager/identity.h"
+
+#include "shell/application_manager/query_util.h"
+
+namespace mojo {
+namespace shell {
+
+Identity::Identity(const GURL& url, const std::string& qualifier)
+    : url(GetBaseURLAndQuery(url, nullptr)), qualifier(qualifier) {
+}
+
+// explicit
+Identity::Identity(const GURL& base_url)
+    : url(GetBaseURLAndQuery(base_url, nullptr)), qualifier(url.spec()) {
+}
+
+bool Identity::operator<(const Identity& other) const {
+  if (url != other.url)
+    return url < other.url;
+  return qualifier < other.qualifier;
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/shell/application_manager/identity.h b/shell/application_manager/identity.h
new file mode 100644
index 0000000..3d7e1d6
--- /dev/null
+++ b/shell/application_manager/identity.h
@@ -0,0 +1,31 @@
+// Copyright 2015 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.
+
+#ifndef SHELL_APPLICATION_MANAGER_IDENTITY_H_
+#define SHELL_APPLICATION_MANAGER_IDENTITY_H_
+
+#include "url/gurl.h"
+
+namespace mojo {
+namespace shell {
+
+/**
+ * Represents the identity of an application. |url| is the url of the
+ * application. |qualifier| is a string that allows to tie a specific instance
+ * of an application to another. It is used by content handlers that need to be
+ * run in the context of another application.
+ */
+struct Identity {
+  Identity(const GURL& url, const std::string& qualifier);
+  explicit Identity(const GURL& url);
+  bool operator<(const Identity& other) const;
+
+  const GURL url;
+  const std::string qualifier;
+};
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // SHELL_APPLICATION_MANAGER_IDENTITY_H_
diff --git a/shell/application_manager/shell_impl.cc b/shell/application_manager/shell_impl.cc
index 289b19b..d519cba 100644
--- a/shell/application_manager/shell_impl.cc
+++ b/shell/application_manager/shell_impl.cc
@@ -14,10 +14,10 @@
 ShellImpl::ShellImpl(ApplicationPtr application,
                      ApplicationManager* manager,
                      const GURL& requested_url,
-                     const GURL& url)
+                     const Identity& identity)
     : manager_(manager),
       requested_url_(requested_url),
-      url_(url),
+      identity_(identity),
       application_(application.Pass()),
       binding_(this) {
   binding_.set_error_handler(this);
@@ -29,7 +29,7 @@
 void ShellImpl::InitializeApplication(Array<String> args) {
   ShellPtr shell;
   binding_.Bind(GetProxy(&shell));
-  application_->Initialize(shell.Pass(), args.Pass(), url_.spec());
+  application_->Initialize(shell.Pass(), args.Pass(), identity_.url.spec());
 }
 
 void ShellImpl::ConnectToClient(const GURL& requested_url,
@@ -49,7 +49,7 @@
     LOG(ERROR) << "Error: invalid URL: " << app_url;
     return;
   }
-  manager_->ConnectToApplication(app_gurl, url_, services.Pass(),
+  manager_->ConnectToApplication(app_gurl, identity_.url, services.Pass(),
                                  exposed_services.Pass());
 }
 
diff --git a/shell/application_manager/shell_impl.h b/shell/application_manager/shell_impl.h
index 5f405e5..f3fcefe 100644
--- a/shell/application_manager/shell_impl.h
+++ b/shell/application_manager/shell_impl.h
@@ -9,6 +9,7 @@
 #include "mojo/public/cpp/bindings/error_handler.h"
 #include "mojo/public/interfaces/application/application.mojom.h"
 #include "mojo/public/interfaces/application/shell.mojom.h"
+#include "shell/application_manager/identity.h"
 #include "url/gurl.h"
 
 namespace mojo {
@@ -22,7 +23,7 @@
             ApplicationManager* manager,
             // The original URL that was first requested, before any resolution.
             const GURL& original_url,
-            const GURL& resolved_url);
+            const Identity& resolved_identity);
 
   ~ShellImpl() override;
 
@@ -34,7 +35,7 @@
                        ServiceProviderPtr exposed_services);
 
   Application* application() { return application_.get(); }
-  const GURL& url() const { return url_; }
+  const Identity& identity() const { return identity_; }
   const GURL& requested_url() const { return requested_url_; }
 
  private:
@@ -48,7 +49,7 @@
 
   ApplicationManager* const manager_;
   const GURL requested_url_;
-  const GURL url_;
+  const Identity identity_;
   ApplicationPtr application_;
   Binding<Shell> binding_;