| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/alternate_nav_url_fetcher.h" | |
| 6 | |
| 7 #include "chrome/browser/api/infobars/infobar_service.h" | |
| 8 #include "chrome/browser/infobars/alternate_nav_infobar_delegate.h" | |
| 9 #include "chrome/browser/intranet_redirect_detector.h" | |
| 10 #include "chrome/browser/profiles/profile.h" | |
| 11 #include "chrome/common/chrome_notification_types.h" | |
| 12 #include "content/public/browser/navigation_controller.h" | |
| 13 #include "content/public/browser/notification_service.h" | |
| 14 #include "content/public/browser/render_process_host.h" | |
| 15 #include "content/public/browser/render_view_host.h" | |
| 16 #include "content/public/browser/web_contents.h" | |
| 17 #include "net/base/load_flags.h" | |
| 18 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | |
| 19 #include "net/url_request/url_fetcher.h" | |
| 20 #include "net/url_request/url_request.h" | |
| 21 | |
| 22 using content::NavigationController; | |
| 23 | |
| 24 AlternateNavURLFetcher::AlternateNavURLFetcher( | |
| 25 const GURL& alternate_nav_url) | |
| 26 : alternate_nav_url_(alternate_nav_url), | |
| 27 controller_(NULL), | |
| 28 state_(NOT_STARTED), | |
| 29 navigated_to_entry_(false) { | |
| 30 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, | |
| 31 content::NotificationService::AllSources()); | |
| 32 registrar_.Add(this, chrome::NOTIFICATION_INSTANT_COMMITTED, | |
| 33 content::NotificationService::AllSources()); | |
| 34 } | |
| 35 | |
| 36 AlternateNavURLFetcher::~AlternateNavURLFetcher() { | |
| 37 } | |
| 38 | |
| 39 void AlternateNavURLFetcher::Observe( | |
| 40 int type, | |
| 41 const content::NotificationSource& source, | |
| 42 const content::NotificationDetails& details) { | |
| 43 switch (type) { | |
| 44 case content::NOTIFICATION_NAV_ENTRY_PENDING: { | |
| 45 // If we've already received a notification for the same controller, we | |
| 46 // should delete ourselves as that indicates that the page is being | |
| 47 // re-loaded so this instance is now stale. | |
| 48 NavigationController* controller = | |
| 49 content::Source<NavigationController>(source).ptr(); | |
| 50 if (controller_ == controller) { | |
| 51 delete this; | |
| 52 } else if (!controller_) { | |
| 53 // Start listening for the commit notification. | |
| 54 DCHECK(controller->GetPendingEntry()); | |
| 55 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
| 56 content::Source<NavigationController>( | |
| 57 controller)); | |
| 58 StartFetch(controller); | |
| 59 } | |
| 60 break; | |
| 61 } | |
| 62 | |
| 63 case chrome::NOTIFICATION_INSTANT_COMMITTED: { | |
| 64 // See above. | |
| 65 NavigationController* controller = | |
| 66 &content::Source<content::WebContents>(source)->GetController(); | |
| 67 if (controller_ == controller) { | |
| 68 delete this; | |
| 69 } else if (!controller_) { | |
| 70 navigated_to_entry_ = true; | |
| 71 StartFetch(controller); | |
| 72 } | |
| 73 break; | |
| 74 } | |
| 75 | |
| 76 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: | |
| 77 // The page was navigated, we can show the infobar now if necessary. | |
| 78 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
| 79 content::Source<NavigationController>(controller_)); | |
| 80 navigated_to_entry_ = true; | |
| 81 ShowInfobarIfPossible(); | |
| 82 // WARNING: |this| may be deleted! | |
| 83 break; | |
| 84 | |
| 85 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: | |
| 86 // We have been closed. In order to prevent the URLFetcher from trying to | |
| 87 // access the controller that will be invalid, we delete ourselves. | |
| 88 // This deletes the URLFetcher and insures its callback won't be called. | |
| 89 delete this; | |
| 90 break; | |
| 91 | |
| 92 default: | |
| 93 NOTREACHED(); | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 void AlternateNavURLFetcher::OnURLFetchComplete( | |
| 98 const net::URLFetcher* source) { | |
| 99 DCHECK_EQ(fetcher_.get(), source); | |
| 100 SetStatusFromURLFetch( | |
| 101 source->GetURL(), source->GetStatus(), source->GetResponseCode()); | |
| 102 ShowInfobarIfPossible(); | |
| 103 // WARNING: |this| may be deleted! | |
| 104 } | |
| 105 | |
| 106 void AlternateNavURLFetcher::StartFetch(NavigationController* controller) { | |
| 107 controller_ = controller; | |
| 108 content::WebContents* web_contents = controller_->GetWebContents(); | |
| 109 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | |
| 110 content::Source<content::WebContents>(web_contents)); | |
| 111 | |
| 112 DCHECK_EQ(NOT_STARTED, state_); | |
| 113 state_ = IN_PROGRESS; | |
| 114 fetcher_.reset(net::URLFetcher::Create(GURL(alternate_nav_url_), | |
| 115 net::URLFetcher::HEAD, this)); | |
| 116 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); | |
| 117 fetcher_->SetRequestContext( | |
| 118 controller_->GetBrowserContext()->GetRequestContext()); | |
| 119 fetcher_->SetStopOnRedirect(true); | |
| 120 fetcher_->Start(); | |
| 121 } | |
| 122 | |
| 123 void AlternateNavURLFetcher::SetStatusFromURLFetch( | |
| 124 const GURL& url, | |
| 125 const net::URLRequestStatus& status, | |
| 126 int response_code) { | |
| 127 if (status.is_success()) { | |
| 128 // HTTP 2xx, 401, and 407 all indicate that the target address exists. | |
| 129 state_ = (((response_code / 100) == 2) || (response_code == 401) || | |
| 130 (response_code == 407)) ? SUCCEEDED : FAILED; | |
| 131 } else { | |
| 132 // If we got HTTP 3xx, we'll have auto-canceled; treat this as evidence the | |
| 133 // target address exists as long as we're not redirected to a common | |
| 134 // location every time, lest we annoy the user with infobars on everything | |
| 135 // they type. See comments on IntranetRedirectDetector. | |
| 136 state_ = ((status.status() == net::URLRequestStatus::CANCELED) && | |
| 137 ((response_code / 100) == 3) && | |
| 138 !net::RegistryControlledDomainService::SameDomainOrHost(url, | |
| 139 IntranetRedirectDetector::RedirectOrigin())) ? SUCCEEDED : FAILED; | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 void AlternateNavURLFetcher::ShowInfobarIfPossible() { | |
| 144 if (navigated_to_entry_ && (state_ == SUCCEEDED)) { | |
| 145 AlternateNavInfoBarDelegate::Create( | |
| 146 InfoBarService::FromWebContents(controller_->GetWebContents()), | |
| 147 alternate_nav_url_); | |
| 148 } else if (state_ != FAILED) { | |
| 149 return; | |
| 150 } | |
| 151 delete this; | |
| 152 } | |
| OLD | NEW |