Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / prerender / prerender_contents.cc
index 82477b2..4f9ff17 100644 (file)
@@ -8,10 +8,10 @@
 #include <functional>
 #include <utility>
 
+#include "apps/ui/web_contents_sizer.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/favicon/favicon_tab_helper.h"
 #include "chrome/browser/history/history_tab_helper.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/prerender/prerender_field_trial.h"
@@ -23,7 +23,7 @@
 #include "chrome/browser/prerender/prerender_tracker.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_tab_contents.h"
+#include "chrome/browser/ui/tab_helpers.h"
 #include "chrome/common/prerender_messages.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/session_storage_namespace.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/common/favicon_url.h"
 #include "content/public/common/frame_navigate_params.h"
+#include "content/public/common/page_transition_types.h"
+#include "net/url_request/url_request_context_getter.h"
 #include "ui/gfx/rect.h"
 
+using content::BrowserThread;
 using content::DownloadItem;
 using content::OpenURLParams;
 using content::RenderViewHost;
 using content::ResourceRedirectDetails;
+using content::ResourceType;
 using content::SessionStorageNamespace;
 using content::WebContents;
 
@@ -65,6 +67,19 @@ enum InternalCookieEvent {
   INTERNAL_COOKIE_EVENT_MAX
 };
 
+// Indicates whether existing cookies were sent, and if they were third party
+// cookies, and whether they were for blocking resources.
+// Each value may be inclusive of previous values. We only care about the
+// value with the highest index that has ever occurred in the course of a
+// prerender.
+enum CookieSendType {
+  COOKIE_SEND_TYPE_NONE = 0,
+  COOKIE_SEND_TYPE_FIRST_PARTY = 1,
+  COOKIE_SEND_TYPE_THIRD_PARTY = 2,
+  COOKIE_SEND_TYPE_THIRD_PARTY_BLOCKING_RESOURCE = 3,
+  COOKIE_SEND_TYPE_MAX
+};
+
 void ResumeThrottles(
     std::vector<base::WeakPtr<PrerenderResourceThrottle> > throttles) {
   for (size_t i = 0; i < throttles.size(); i++) {
@@ -79,6 +94,9 @@ void ResumeThrottles(
 const int PrerenderContents::kNumCookieStatuses =
     (1 << INTERNAL_COOKIE_EVENT_MAX);
 
+// static
+const int PrerenderContents::kNumCookieSendTypes = COOKIE_SEND_TYPE_MAX;
+
 class PrerenderContentsFactoryImpl : public PrerenderContents::Factory {
  public:
   virtual PrerenderContents* CreatePrerenderContents(
@@ -113,9 +131,13 @@ class PrerenderContents::WebContentsDelegateImpl
     return NULL;
   }
 
+  virtual void CloseContents(content::WebContents* contents) OVERRIDE {
+    prerender_contents_->Destroy(FINAL_STATUS_CLOSED);
+  }
+
   virtual void CanDownload(
       RenderViewHost* render_view_host,
-      int request_id,
+      const GURL& url,
       const std::string& request_method,
       const base::Callback<void(bool)>& callback) OVERRIDE {
     prerender_contents_->Destroy(FINAL_STATUS_DOWNLOAD);
@@ -147,10 +169,6 @@ class PrerenderContents::WebContentsDelegateImpl
     return false;
   }
 
-  virtual void JSOutOfMemory(WebContents* tab) OVERRIDE {
-    prerender_contents_->Destroy(FINAL_STATUS_JS_OUT_OF_MEMORY);
-  }
-
   virtual bool ShouldSuppressDialogs() OVERRIDE {
     // We still want to show the user the message when they navigate to this
     // page, so cancel this prerender.
@@ -163,7 +181,6 @@ class PrerenderContents::WebContentsDelegateImpl
   virtual void RegisterProtocolHandler(WebContents* web_contents,
                                        const std::string& protocol,
                                        const GURL& url,
-                                       const base::string16& title,
                                        bool user_gesture) OVERRIDE {
     // TODO(mmenke): Consider supporting this if it is a common case during
     // prerenders.
@@ -171,7 +188,7 @@ class PrerenderContents::WebContentsDelegateImpl
   }
 
   virtual gfx::Size GetSizeForNewRenderView(
-      const WebContents* web_contents) const OVERRIDE {
+      WebContents* web_contents) const OVERRIDE {
     // Have to set the size of the RenderView on initialization to be sure it is
     // set before the RenderView is hidden on all platforms (esp. Android).
     return prerender_contents_->size_;
@@ -185,6 +202,10 @@ void PrerenderContents::Observer::OnPrerenderStopLoading(
     PrerenderContents* contents) {
 }
 
+void PrerenderContents::Observer::OnPrerenderDomContentLoaded(
+    PrerenderContents* contents) {
+}
+
 void PrerenderContents::Observer::OnPrerenderCreatedMatchCompleteReplacement(
     PrerenderContents* contents, PrerenderContents* replacement) {
 }
@@ -195,52 +216,6 @@ PrerenderContents::Observer::Observer() {
 PrerenderContents::Observer::~Observer() {
 }
 
-PrerenderContents::PendingPrerenderInfo::PendingPrerenderInfo(
-    base::WeakPtr<PrerenderHandle> weak_prerender_handle,
-    Origin origin,
-    const GURL& url,
-    const content::Referrer& referrer,
-    const gfx::Size& size)
-    : weak_prerender_handle(weak_prerender_handle),
-      origin(origin),
-      url(url),
-      referrer(referrer),
-      size(size) {
-}
-
-PrerenderContents::PendingPrerenderInfo::~PendingPrerenderInfo() {
-}
-
-void PrerenderContents::AddPendingPrerender(
-    scoped_ptr<PendingPrerenderInfo> pending_prerender_info) {
-  pending_prerenders_.push_back(pending_prerender_info.release());
-}
-
-void PrerenderContents::PrepareForUse() {
-  if (prerender_contents_.get()) {
-    prerender_contents_->SendToAllFrames(
-        new PrerenderMsg_SetIsPrerendering(MSG_ROUTING_NONE, false));
-  }
-
-  NotifyPrerenderStop();
-
-  SessionStorageNamespace* session_storage_namespace = NULL;
-  if (prerender_contents_) {
-    // TODO(ajwong): This does not correctly handle storage for isolated apps.
-    session_storage_namespace = prerender_contents_->
-        GetController().GetDefaultSessionStorageNamespace();
-  }
-  prerender_manager_->StartPendingPrerenders(
-      child_id_, &pending_prerenders_, session_storage_namespace);
-  pending_prerenders_.clear();
-
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&ResumeThrottles, resource_throttles_));
-  resource_throttles_.clear();
-}
-
 PrerenderContents::PrerenderContents(
     PrerenderManager* prerender_manager,
     Profile* profile,
@@ -265,7 +240,9 @@ PrerenderContents::PrerenderContents(
       origin_(origin),
       experiment_id_(experiment_id),
       creator_child_id_(-1),
-      cookie_status_(0) {
+      cookie_status_(0),
+      cookie_send_type_(COOKIE_SEND_TYPE_NONE),
+      network_bytes_(0) {
   DCHECK(prerender_manager != NULL);
 }
 
@@ -283,6 +260,9 @@ PrerenderContents* PrerenderContents::CreateMatchCompleteReplacement() {
   DCHECK_EQ(alias_urls_.front(), new_contents->alias_urls_.front());
   DCHECK_EQ(1u, new_contents->alias_urls_.size());
   new_contents->alias_urls_ = alias_urls_;
+  // Erase all but the first alias URL; the replacement has adopted the
+  // remainder without increasing the renderer-side reference count.
+  alias_urls_.resize(1);
   new_contents->set_match_complete_status(
       PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
   NotifyPrerenderCreatedMatchCompleteReplacement(new_contents);
@@ -313,7 +293,8 @@ PrerenderContents* PrerenderContents::FromWebContents(
 void PrerenderContents::StartPrerendering(
     int creator_child_id,
     const gfx::Size& size,
-    SessionStorageNamespace* session_storage_namespace) {
+    SessionStorageNamespace* session_storage_namespace,
+    net::URLRequestContextGetter* request_context) {
   DCHECK(profile_ != NULL);
   DCHECK(!size.IsEmpty());
   DCHECK(!prerendering_has_started_);
@@ -346,19 +327,13 @@ void PrerenderContents::StartPrerendering(
   alias_session_storage_namespace = session_storage_namespace->CreateAlias();
   prerender_contents_.reset(
       CreateWebContents(alias_session_storage_namespace.get()));
-  BrowserTabContents::AttachTabHelpers(prerender_contents_.get());
-#if defined(OS_ANDROID)
-  // Delay icon fetching until the contents are getting swapped in
-  // to conserve network usage in mobile devices.
-  FaviconTabHelper::FromWebContents(
-      prerender_contents_.get())->set_should_fetch_icons(false);
-#endif  // defined(OS_ANDROID)
+  TabHelpers::AttachTabHelpers(prerender_contents_.get());
   content::WebContentsObserver::Observe(prerender_contents_.get());
 
   web_contents_delegate_.reset(new WebContentsDelegateImpl(this));
   prerender_contents_.get()->SetDelegate(web_contents_delegate_.get());
   // Set the size of the prerender WebContents.
-  prerender_contents_->GetView()->SizeContents(size_);
+  apps::ResizeWebContents(prerender_contents_.get(), size_);
 
   child_id_ = GetRenderViewHost()->GetProcess()->GetID();
   route_id_ = GetRenderViewHost()->GetRoutingID();
@@ -367,19 +342,34 @@ void PrerenderContents::StartPrerendering(
   // the event of a mismatch.
   alias_session_storage_namespace->AddTransactionLogProcessId(child_id_);
 
+  // Add the RenderProcessHost to the Prerender Manager.
+  prerender_manager()->AddPrerenderProcessHost(
+      GetRenderViewHost()->GetProcess());
+
+  // In the prerender tracker, create a Prerender Cookie Store to keep track of
+  // cookie changes performed by the prerender. Once the prerender is shown,
+  // the cookie changes will be committed to the actual cookie store,
+  // otherwise, they will be discarded.
+  // If |request_context| is NULL, the feature must be disabled, so the
+  // operation will not be performed.
+  if (request_context) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&PrerenderTracker::AddPrerenderCookieStoreOnIOThread,
+                   base::Unretained(prerender_manager()->prerender_tracker()),
+                   GetRenderViewHost()->GetProcess()->GetID(),
+                   make_scoped_refptr(request_context),
+                   base::Bind(&PrerenderContents::Destroy,
+                              AsWeakPtr(),
+                              FINAL_STATUS_COOKIE_CONFLICT)));
+  }
+
   NotifyPrerenderStart();
 
   // Close ourselves when the application is shutting down.
   notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
                               content::NotificationService::AllSources());
 
-  // Register for our parent profile to shutdown, so we can shut ourselves down
-  // as well (should only be called for OTR profiles, as we should receive
-  // APP_TERMINATING before non-OTR profiles are destroyed).
-  // TODO(tburkard): figure out if this is needed.
-  notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
-                              content::Source<Profile>(profile_));
-
   // Register to inform new RenderViews that we're prerendering.
   notification_registrar_.Add(
       this, content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
@@ -392,12 +382,16 @@ void PrerenderContents::StartPrerendering(
   content::NavigationController::LoadURLParams load_url_params(
       prerender_url_);
   load_url_params.referrer = referrer_;
-  load_url_params.transition_type =
-      (origin_ == ORIGIN_OMNIBOX || origin_ == ORIGIN_INSTANT)
-          ? content::PageTransitionFromInt(
-                content::PAGE_TRANSITION_TYPED |
-                content::PAGE_TRANSITION_FROM_ADDRESS_BAR)
-          : content::PAGE_TRANSITION_LINK;
+  load_url_params.transition_type = content::PAGE_TRANSITION_LINK;
+  if (origin_ == ORIGIN_OMNIBOX) {
+    load_url_params.transition_type = content::PageTransitionFromInt(
+        content::PAGE_TRANSITION_TYPED |
+        content::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+  } else if (origin_ == ORIGIN_INSTANT) {
+    load_url_params.transition_type = content::PageTransitionFromInt(
+        content::PAGE_TRANSITION_GENERATED |
+        content::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+  }
   load_url_params.override_user_agent =
       prerender_manager_->config().is_overriding_user_agent ?
       content::NavigationController::UA_OVERRIDE_TRUE :
@@ -420,8 +414,10 @@ bool PrerenderContents::GetRouteId(int* route_id) const {
 }
 
 void PrerenderContents::SetFinalStatus(FinalStatus final_status) {
-  DCHECK(final_status >= FINAL_STATUS_USED && final_status < FINAL_STATUS_MAX);
-  DCHECK(final_status_ == FINAL_STATUS_MAX);
+  DCHECK_GE(final_status, FINAL_STATUS_USED);
+  DCHECK_LT(final_status, FINAL_STATUS_MAX);
+
+  DCHECK_EQ(FINAL_STATUS_MAX, final_status_);
 
   final_status_ = final_status;
 }
@@ -434,16 +430,19 @@ PrerenderContents::~PrerenderContents() {
   // Since a lot of prerenders terminate before any meaningful cookie action
   // would have happened, only record the cookie status for prerenders who
   // were used, cancelled, or timed out.
-  if (prerendering_has_started_ &&
-      (final_status() == FINAL_STATUS_USED ||
-       final_status() == FINAL_STATUS_TIMED_OUT ||
-       final_status() == FINAL_STATUS_CANCELLED)) {
+  if (prerendering_has_started_ && final_status() == FINAL_STATUS_USED) {
     prerender_manager_->RecordCookieStatus(origin(), experiment_id(),
                                            cookie_status_);
+    prerender_manager_->RecordCookieSendType(origin(), experiment_id(),
+                                             cookie_send_type_);
   }
   prerender_manager_->RecordFinalStatusWithMatchCompleteStatus(
       origin(), experiment_id(), match_complete_status(), final_status());
 
+  bool used = final_status() == FINAL_STATUS_USED ||
+              final_status() == FINAL_STATUS_WOULD_HAVE_BEEN_USED;
+  prerender_manager_->RecordNetworkBytes(origin(), used, network_bytes_);
+
   // Broadcast the removal of aliases.
   for (content::RenderProcessHost::iterator host_iterator =
            content::RenderProcessHost::AllHostsIterator();
@@ -472,10 +471,8 @@ void PrerenderContents::Observe(int type,
                                 const content::NotificationSource& source,
                                 const content::NotificationDetails& details) {
   switch (type) {
-    case chrome::NOTIFICATION_PROFILE_DESTROYED:
-      Destroy(FINAL_STATUS_PROFILE_DESTROYED);
-      return;
-
+    // TODO(davidben): Try to remove this in favor of relying on
+    // FINAL_STATUS_PROFILE_DESTROYED.
     case chrome::NOTIFICATION_APP_TERMINATING:
       Destroy(FINAL_STATUS_APP_TERMINATING);
       return;
@@ -510,10 +507,6 @@ void PrerenderContents::OnRenderViewHostCreated(
     RenderViewHost* new_render_view_host) {
 }
 
-size_t PrerenderContents::pending_prerender_count() const {
-  return pending_prerenders_.size();
-}
-
 WebContents* PrerenderContents::CreateWebContents(
     SessionStorageNamespace* session_storage_namespace) {
   // TODO(ajwong): Remove the temporary map once prerendering is aware of
@@ -533,6 +526,11 @@ void PrerenderContents::NotifyPrerenderStopLoading() {
   FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStopLoading(this));
 }
 
+void PrerenderContents::NotifyPrerenderDomContentLoaded() {
+  FOR_EACH_OBSERVER(Observer, observer_list_,
+                    OnPrerenderDomContentLoaded(this));
+}
+
 void PrerenderContents::NotifyPrerenderStop() {
   DCHECK_NE(FINAL_STATUS_MAX, final_status_);
   FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStop(this));
@@ -546,20 +544,6 @@ void PrerenderContents::NotifyPrerenderCreatedMatchCompleteReplacement(
                                                                replacement));
 }
 
-void PrerenderContents::DidUpdateFaviconURL(
-    int32 page_id,
-    const std::vector<content::FaviconURL>& urls) {
-  VLOG(1) << "PrerenderContents::OnUpdateFaviconURL" << icon_url_;
-  for (std::vector<content::FaviconURL>::const_iterator it = urls.begin();
-       it != urls.end(); ++it) {
-    if (it->icon_type == content::FaviconURL::FAVICON) {
-      icon_url_ = it->icon_url;
-      VLOG(1) << icon_url_;
-      return;
-    }
-  }
-}
-
 bool PrerenderContents::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   // The following messages we do want to consume.
@@ -634,15 +618,18 @@ void PrerenderContents::DidStopLoading(
   NotifyPrerenderStopLoading();
 }
 
+void PrerenderContents::DocumentLoadedInFrame(
+    content::RenderFrameHost* render_frame_host) {
+  if (!render_frame_host->GetParent())
+    NotifyPrerenderDomContentLoaded();
+}
+
 void PrerenderContents::DidStartProvisionalLoadForFrame(
-    int64 frame_id,
-    int64 parent_frame_id,
-    bool is_main_frame,
+    content::RenderFrameHost* render_frame_host,
     const GURL& validated_url,
     bool is_error_page,
-    bool is_iframe_srcdoc,
-    RenderViewHost* render_view_host) {
-  if (is_main_frame) {
+    bool is_iframe_srcdoc) {
+  if (!render_frame_host->GetParent()) {
     if (!CheckURL(validated_url))
       return;
 
@@ -656,11 +643,10 @@ void PrerenderContents::DidStartProvisionalLoadForFrame(
   }
 }
 
-void PrerenderContents::DidFinishLoad(int64 frame_id,
-                                      const GURL& validated_url,
-                                      bool is_main_frame,
-                                      RenderViewHost* render_view_host) {
-  if (is_main_frame)
+void PrerenderContents::DidFinishLoad(
+    content::RenderFrameHost* render_frame_host,
+    const GURL& validated_url) {
+  if (!render_frame_host->GetParent())
     has_finished_loading_ = true;
 }
 
@@ -698,7 +684,7 @@ void PrerenderContents::DidGetRedirectForResourceRequest(
   // it's a redirect on the top-level resource, the name needs to be remembered
   // for future matching, and if it redirects to an https resource, it needs to
   // be canceled. If a subresource is redirected, nothing changes.
-  if (details.resource_type != ResourceType::MAIN_FRAME)
+  if (details.resource_type != content::RESOURCE_TYPE_MAIN_FRAME)
     return;
   CheckURL(details.new_url);
 }
@@ -808,6 +794,23 @@ bool PrerenderContents::IsCrossSiteNavigationPending() const {
           prerender_contents_->GetPendingSiteInstance());
 }
 
+void PrerenderContents::PrepareForUse() {
+  SetFinalStatus(FINAL_STATUS_USED);
+
+  if (prerender_contents_.get()) {
+    prerender_contents_->SendToAllFrames(
+        new PrerenderMsg_SetIsPrerendering(MSG_ROUTING_NONE, false));
+  }
+
+  NotifyPrerenderStop();
+
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&ResumeThrottles, resource_throttles_));
+  resource_throttles_.clear();
+}
+
 SessionStorageNamespace* PrerenderContents::GetSessionStorageNamespace() const {
   if (!prerender_contents())
     return NULL;
@@ -821,6 +824,8 @@ void PrerenderContents::OnCancelPrerenderForPrinting() {
 
 void PrerenderContents::RecordCookieEvent(CookieEvent event,
                                           bool is_main_frame_http_request,
+                                          bool is_third_party_cookie,
+                                          bool is_for_blocking_resource,
                                           base::Time earliest_create_date) {
   // We don't care about sent cookies that were created after this prerender
   // started.
@@ -858,6 +863,24 @@ void PrerenderContents::RecordCookieEvent(CookieEvent event,
 
   DCHECK_GE(cookie_status_, 0);
   DCHECK_LT(cookie_status_, kNumCookieStatuses);
+
+  CookieSendType send_type = COOKIE_SEND_TYPE_NONE;
+  if (event == COOKIE_EVENT_SEND) {
+    if (!is_third_party_cookie) {
+      send_type = COOKIE_SEND_TYPE_FIRST_PARTY;
+    } else {
+      if (is_for_blocking_resource) {
+        send_type = COOKIE_SEND_TYPE_THIRD_PARTY_BLOCKING_RESOURCE;
+      } else {
+        send_type = COOKIE_SEND_TYPE_THIRD_PARTY;
+      }
+    }
+  }
+  DCHECK_GE(send_type, 0);
+  DCHECK_LT(send_type, COOKIE_SEND_TYPE_MAX);
+
+  if (cookie_send_type_ < send_type)
+    cookie_send_type_ = send_type;
 }
 
  void PrerenderContents::AddResourceThrottle(
@@ -865,4 +888,8 @@ void PrerenderContents::RecordCookieEvent(CookieEvent event,
    resource_throttles_.push_back(throttle);
  }
 
+ void PrerenderContents::AddNetworkBytes(int64 bytes) {
+   network_bytes_ += bytes;
+ }
+
 }  // namespace prerender