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 |