Have the authenticating_url_loader cache token per-origin.

R=blundell@chromium.org

Review URL: https://codereview.chromium.org/1161603003
diff --git a/services/authenticating_url_loader/BUILD.gn b/services/authenticating_url_loader/BUILD.gn
index 730270e..5dd07b7 100644
--- a/services/authenticating_url_loader/BUILD.gn
+++ b/services/authenticating_url_loader/BUILD.gn
@@ -25,5 +25,6 @@
     "//mojo/services/authenticating_url_loader/public/interfaces",
     "//mojo/services/authentication/public/interfaces",
     "//mojo/services/network/public/interfaces",
+    "//url",
   ]
 }
diff --git a/services/authenticating_url_loader/authenticating_url_loader_factory_impl.cc b/services/authenticating_url_loader/authenticating_url_loader_factory_impl.cc
index f3e2bbf..5ed1a7d 100644
--- a/services/authenticating_url_loader/authenticating_url_loader_factory_impl.cc
+++ b/services/authenticating_url_loader/authenticating_url_loader_factory_impl.cc
@@ -39,7 +39,7 @@
   url_loaders_.push_back(std::unique_ptr<AuthenticatingURLLoaderImpl>(
       new AuthenticatingURLLoaderImpl(
           loader_request.Pass(), authentication_service_.get(),
-          network_service_.get(),
+          network_service_.get(), &cached_tokens_,
           base::Bind(&AuthenticatingURLLoaderFactoryImpl::DeleteURLLoader,
                      base::Unretained(this)))));
 }
diff --git a/services/authenticating_url_loader/authenticating_url_loader_factory_impl.h b/services/authenticating_url_loader/authenticating_url_loader_factory_impl.h
index 03f9307..f120cd3 100644
--- a/services/authenticating_url_loader/authenticating_url_loader_factory_impl.h
+++ b/services/authenticating_url_loader/authenticating_url_loader_factory_impl.h
@@ -13,6 +13,7 @@
 #include "mojo/services/authenticating_url_loader/public/interfaces/authenticating_url_loader_factory.mojom.h"
 #include "mojo/services/authentication/public/interfaces/authentication.mojom.h"
 #include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "url/gurl.h"
 
 namespace mojo {
 
@@ -46,6 +47,7 @@
   authentication::AuthenticationServicePtr authentication_service_;
   NetworkServicePtr network_service_;
   std::vector<std::unique_ptr<AuthenticatingURLLoaderImpl>> url_loaders_;
+  std::map<GURL, std::string> cached_tokens_;
 };
 
 }  // namespace mojo
diff --git a/services/authenticating_url_loader/authenticating_url_loader_impl.cc b/services/authenticating_url_loader/authenticating_url_loader_impl.cc
index 53b0324..df1919a 100644
--- a/services/authenticating_url_loader/authenticating_url_loader_impl.cc
+++ b/services/authenticating_url_loader/authenticating_url_loader_impl.cc
@@ -14,13 +14,15 @@
     InterfaceRequest<AuthenticatingURLLoader> request,
     authentication::AuthenticationService* authentication_service,
     NetworkService* network_service,
+    std::map<GURL, std::string>* cached_tokens,
     const Callback<void(AuthenticatingURLLoaderImpl*)>&
         connection_error_callback)
     : binding_(this, request.Pass()),
       authentication_service_(authentication_service),
       network_service_(network_service),
       connection_error_callback_(connection_error_callback),
-      request_authorization_state_(REQUEST_NOT_AUTHORIZED) {
+      request_authorization_state_(REQUEST_INITIAL),
+      cached_tokens_(cached_tokens) {
   binding_.set_error_handler(this);
 }
 
@@ -38,11 +40,15 @@
     callback.Run(nullptr);
     return;
   }
-  url_ = request->url;
+  url_ = GURL(request->url);
   auto_follow_redirects_ = request->auto_follow_redirects;
   bypass_cache_ = request->bypass_cache;
   headers_ = request->headers.Clone();
   pending_request_callback_ = callback;
+  if (cached_tokens_->find(url_.GetOrigin()) != cached_tokens_->end()) {
+    request->headers.push_back("Authorization: Bearer " +
+                               (*cached_tokens_)[url_.GetOrigin()]);
+  }
   StartNetworkRequest(request.Pass());
 }
 
@@ -50,7 +56,7 @@
     const Callback<void(URLResponsePtr)>& callback) {
   mojo::String error;
 
-  if (!url_ || !url_loader_) {
+  if (!url_.is_valid() || !url_loader_) {
     error = "No redirect to follow";
   }
 
@@ -60,7 +66,7 @@
         "called when auto_follow_redirects has been set";
   }
 
-  if (username_ || (request_authorization_state_ != REQUEST_NOT_AUTHORIZED)) {
+  if (username_ || (request_authorization_state_ != REQUEST_INITIAL)) {
     error = "Not in the right state to follow a redirect";
   }
 
@@ -88,9 +94,9 @@
 
 void AuthenticatingURLLoaderImpl::OnLoadComplete(URLResponsePtr response) {
   if (response->redirect_url) {
-    url_ = response->redirect_url;
+    url_ = GURL(response->redirect_url);
     username_ = nullptr;
-    request_authorization_state_ = REQUEST_NOT_AUTHORIZED;
+    request_authorization_state_ = REQUEST_INITIAL;
 
     if (auto_follow_redirects_) {
       FollowRedirectInternal();
@@ -105,38 +111,39 @@
   url_loader_.reset();
 
   if (response->status_code != 401 || !authentication_service_ ||
-      request_authorization_state_ == REQUEST_AUTHORIZED_WITH_FRESH_TOKEN) {
+      request_authorization_state_ == REQUEST_USED_FRESH_AUTH_SERVICE_TOKEN) {
     pending_request_callback_.Run(response.Pass());
     return;
   }
 
   pending_response_ = response.Pass();
 
-  if (request_authorization_state_ == REQUEST_NOT_AUTHORIZED) {
+  if (request_authorization_state_ == REQUEST_INITIAL) {
     DCHECK(!username_);
-    request_authorization_state_ = REQUEST_AUTHORIZED_WITH_CACHED_TOKEN;
+    request_authorization_state_ = REQUEST_USED_CURRENT_AUTH_SERVICE_TOKEN;
     authentication_service_->SelectAccount(
         base::Bind(&AuthenticatingURLLoaderImpl::OnAccountSelected,
                    base::Unretained(this)));
     return;
   }
 
-  DCHECK(request_authorization_state_ == REQUEST_AUTHORIZED_WITH_CACHED_TOKEN);
+  DCHECK(request_authorization_state_ ==
+         REQUEST_USED_CURRENT_AUTH_SERVICE_TOKEN);
   // Clear the cached token in case the failure was due to that token being
   // stale and try again. If a fresh token doesn't work, we'll have to give up.
   DCHECK(authentication_service_);
   DCHECK(username_);
   authentication_service_->ClearOAuth2Token(token_);
   token_ = String();
-  request_authorization_state_ = REQUEST_AUTHORIZED_WITH_FRESH_TOKEN;
+  request_authorization_state_ = REQUEST_USED_FRESH_AUTH_SERVICE_TOKEN;
   OnAccountSelected(username_, String());
 }
 
 void AuthenticatingURLLoaderImpl::FollowRedirectInternal() {
-  DCHECK(url_);
+  DCHECK(url_.is_valid());
   DCHECK(url_loader_);
   DCHECK(!username_);
-  DCHECK(request_authorization_state_ == REQUEST_NOT_AUTHORIZED);
+  DCHECK(request_authorization_state_ == REQUEST_INITIAL);
 
   url_loader_->FollowRedirect(base::Bind(
       &AuthenticatingURLLoaderImpl::OnLoadComplete, base::Unretained(this)));
@@ -171,6 +178,7 @@
   }
 
   DCHECK(token);
+  (*cached_tokens_)[url_.GetOrigin()] = token;
   token_ = token;
   mojo::Array<mojo::String> headers(0);
   if (headers_)
@@ -178,7 +186,7 @@
   headers.push_back("Authorization: Bearer " + token.get());
 
   URLRequestPtr request(mojo::URLRequest::New());
-  request->url = url_;
+  request->url = url_.spec();
   request->auto_follow_redirects = false;
   request->bypass_cache = bypass_cache_;
   request->headers = headers.Pass();
diff --git a/services/authenticating_url_loader/authenticating_url_loader_impl.h b/services/authenticating_url_loader/authenticating_url_loader_impl.h
index a3ef28f..f2ee787 100644
--- a/services/authenticating_url_loader/authenticating_url_loader_impl.h
+++ b/services/authenticating_url_loader/authenticating_url_loader_impl.h
@@ -10,15 +10,16 @@
 #include "mojo/services/authenticating_url_loader/public/interfaces/authenticating_url_loader.mojom.h"
 #include "mojo/services/authentication/public/interfaces/authentication.mojom.h"
 #include "mojo/services/network/public/interfaces/url_loader.mojom.h"
+#include "url/gurl.h"
 
 namespace mojo {
 
 class NetworkService;
 
 enum RequestAuthorizationState {
-  REQUEST_NOT_AUTHORIZED,
-  REQUEST_AUTHORIZED_WITH_CACHED_TOKEN,
-  REQUEST_AUTHORIZED_WITH_FRESH_TOKEN,
+  REQUEST_INITIAL,
+  REQUEST_USED_CURRENT_AUTH_SERVICE_TOKEN,
+  REQUEST_USED_FRESH_AUTH_SERVICE_TOKEN,
 };
 
 class AuthenticatingURLLoaderImpl : public AuthenticatingURLLoader,
@@ -28,6 +29,7 @@
       InterfaceRequest<AuthenticatingURLLoader> request,
       authentication::AuthenticationService* authentication_service,
       NetworkService* network_service,
+      std::map<GURL, std::string>* cached_tokens,
       const Callback<void(AuthenticatingURLLoaderImpl*)>&
           connection_error_callback);
   ~AuthenticatingURLLoaderImpl() override;
@@ -61,13 +63,14 @@
   URLLoaderPtr url_loader_;
   URLResponsePtr pending_response_;
   RequestAuthorizationState request_authorization_state_;
-  String url_;
+  GURL url_;
   bool auto_follow_redirects_;
   bool bypass_cache_;
   Array<String> headers_;
   String username_;
   String token_;
   Callback<void(URLResponsePtr)> pending_request_callback_;
+  std::map<GURL, std::string>* cached_tokens_;
 };
 
 }  // namespace mojo