Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1123)

Side by Side Diff: chrome/renderer/net/net_error_helper.cc

Issue 13270005: Display DNS probe results. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/net/net_error_helper.h" 5 #include "chrome/renderer/net/net_error_helper.h"
6 6
7 #include <string>
8
9 #include "base/json/json_writer.h"
10 #include "base/strings/utf_string_conversions.h"
7 #include "base/values.h" 11 #include "base/values.h"
8 #include "chrome/common/localized_error.h" 12 #include "chrome/common/localized_error.h"
9 #include "chrome/common/render_messages.h" 13 #include "chrome/common/render_messages.h"
10 #include "chrome/common/net/net_error_info.h" 14 #include "chrome/common/net/net_error_info.h"
11 #include "content/public/common/content_client.h" 15 #include "content/public/common/content_client.h"
12 #include "content/public/common/url_constants.h" 16 #include "content/public/common/url_constants.h"
13 #include "content/public/renderer/content_renderer_client.h" 17 #include "content/public/renderer/content_renderer_client.h"
14 #include "content/public/renderer/render_thread.h" 18 #include "content/public/renderer/render_thread.h"
15 #include "content/public/renderer/render_view.h" 19 #include "content/public/renderer/render_view.h"
16 #include "googleurl/src/gurl.h" 20 #include "googleurl/src/gurl.h"
17 #include "ipc/ipc_message.h" 21 #include "ipc/ipc_message.h"
18 #include "ipc/ipc_message_macros.h" 22 #include "ipc/ipc_message_macros.h"
19 #include "net/base/net_errors.h" 23 #include "net/base/net_errors.h"
20 #include "third_party/WebKit/public/platform/WebURL.h" 24 #include "third_party/WebKit/public/platform/WebURL.h"
21 #include "third_party/WebKit/public/platform/WebURLError.h"
22 #include "third_party/WebKit/public/platform/WebURLRequest.h" 25 #include "third_party/WebKit/public/platform/WebURLRequest.h"
23 #include "third_party/WebKit/public/web/WebDataSource.h" 26 #include "third_party/WebKit/public/web/WebDataSource.h"
24 #include "third_party/WebKit/public/web/WebFrame.h" 27 #include "third_party/WebKit/public/web/WebFrame.h"
25 28
26 using chrome_common_net::DnsProbeResult; 29 using base::JSONWriter;
30 using chrome_common_net::DnsProbeStatus;
31 using chrome_common_net::DnsProbeStatusIsFinished;
32 using chrome_common_net::DnsProbeStatusToString;
33 using chrome_common_net::DnsProbesEnabledByFieldTrial;
27 using content::RenderThread; 34 using content::RenderThread;
28 using content::RenderView; 35 using content::RenderView;
29 using content::RenderViewObserver; 36 using content::RenderViewObserver;
30 using content::kUnreachableWebDataURL; 37 using content::kUnreachableWebDataURL;
31 38
32 namespace { 39 namespace {
33 40
34 GURL GetProvisionallyLoadingURLFromWebFrame(WebKit::WebFrame* frame) { 41 bool IsLoadingErrorPage(WebKit::WebFrame* frame) {
35 return frame->provisionalDataSource()->request().url(); 42 GURL url = frame->provisionalDataSource()->request().url();
43 return url.spec() == kUnreachableWebDataURL;
36 } 44 }
37 45
38 bool IsErrorPage(const GURL& url) { 46 bool IsMainFrame(const WebKit::WebFrame* frame) {
39 return (url.spec() == kUnreachableWebDataURL); 47 return !frame->parent();
40 } 48 }
41 49
42 // Returns whether |net_error| is a DNS-related error (and therefore whether 50 // Returns whether |net_error| is a DNS-related error (and therefore whether
43 // the tab helper should start a DNS probe after receiving it.) 51 // the tab helper should start a DNS probe after receiving it.)
44 bool IsDnsError(int net_error) { 52 bool IsDnsError(const WebKit::WebURLError& error) {
45 return net_error == net::ERR_NAME_NOT_RESOLVED || 53 return std::string(error.domain.utf8()) == net::kErrorDomain &&
46 net_error == net::ERR_NAME_RESOLUTION_FAILED; 54 (error.reason == net::ERR_NAME_NOT_RESOLVED ||
47 } 55 error.reason == net::ERR_NAME_RESOLUTION_FAILED);
48
49 NetErrorTracker::FrameType GetFrameType(WebKit::WebFrame* frame) {
50 return frame->parent() ? NetErrorTracker::FRAME_SUB
51 : NetErrorTracker::FRAME_MAIN;
52 }
53
54 NetErrorTracker::PageType GetPageType(WebKit::WebFrame* frame) {
55 bool error_page = IsErrorPage(GetProvisionallyLoadingURLFromWebFrame(frame));
56 return error_page ? NetErrorTracker::PAGE_ERROR
57 : NetErrorTracker::PAGE_NORMAL;
58 }
59
60 NetErrorTracker::ErrorType GetErrorType(const WebKit::WebURLError& error) {
61 return IsDnsError(error.reason) ? NetErrorTracker::ERROR_DNS
62 : NetErrorTracker::ERROR_OTHER;
63 }
64
65 // Converts a DNS probe result into a net error. Returns OK if the error page
66 // should not be changed from the original DNS error.
67 int DnsProbeResultToNetError(DnsProbeResult result) {
68 switch (result) {
69 case chrome_common_net::DNS_PROBE_UNKNOWN:
70 return net::OK;
71 case chrome_common_net::DNS_PROBE_NO_INTERNET:
72 // TODO(ttuttle): This is not the same error as when NCN returns this;
73 // ideally we should have two separate error codes for "no network" and
74 // "network with no internet".
75 return net::ERR_INTERNET_DISCONNECTED;
76 case chrome_common_net::DNS_PROBE_BAD_CONFIG:
77 // This is unspecific enough that we should still show the full DNS error
78 // page.
79 return net::OK;
80 case chrome_common_net::DNS_PROBE_NXDOMAIN:
81 return net::ERR_NAME_NOT_RESOLVED;
82 default:
83 NOTREACHED();
84 return net::OK;
85 }
86 }
87
88 WebKit::WebURLError NetErrorToWebURLError(int net_error) {
89 WebKit::WebURLError error;
90 error.domain = WebKit::WebString::fromUTF8(net::kErrorDomain);
91 error.reason = net_error;
92 return error;
93 } 56 }
94 57
95 } // namespace 58 } // namespace
96 59
97 NetErrorHelper::NetErrorHelper(RenderView* render_view) 60 NetErrorHelper::NetErrorHelper(RenderView* render_view)
98 : RenderViewObserver(render_view), 61 : RenderViewObserver(render_view),
99 tracker_(base::Bind(&NetErrorHelper::TrackerCallback, 62 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE),
100 base::Unretained(this))), 63 last_start_was_error_page_(false),
101 dns_error_page_state_(NetErrorTracker::DNS_ERROR_PAGE_NONE), 64 last_fail_was_dns_error_(false),
102 updated_error_page_(false), 65 forwarding_probe_results_(false),
103 is_failed_post_(false) { 66 is_failed_post_(false) {
104 } 67 }
105 68
106 NetErrorHelper::~NetErrorHelper() { 69 NetErrorHelper::~NetErrorHelper() {
107 } 70 }
108 71
109 void NetErrorHelper::DidStartProvisionalLoad(WebKit::WebFrame* frame) { 72 void NetErrorHelper::DidStartProvisionalLoad(WebKit::WebFrame* frame) {
110 tracker_.OnStartProvisionalLoad(GetFrameType(frame), GetPageType(frame)); 73 OnStartLoad(IsMainFrame(frame), IsLoadingErrorPage(frame));
111 } 74 }
112 75
113 void NetErrorHelper::DidFailProvisionalLoad(WebKit::WebFrame* frame, 76 void NetErrorHelper::DidFailProvisionalLoad(WebKit::WebFrame* frame,
114 const WebKit::WebURLError& error) { 77 const WebKit::WebURLError& error) {
115 WebKit::WebDataSource* data_source = frame->provisionalDataSource(); 78 const bool main_frame = IsMainFrame(frame);
116 const WebKit::WebURLRequest& failed_request = data_source->request(); 79 const bool dns_error = IsDnsError(error);
117 is_failed_post_ = EqualsASCII(failed_request.httpMethod(), "POST"); 80
118 tracker_.OnFailProvisionalLoad(GetFrameType(frame), GetErrorType(error)); 81 OnFailLoad(main_frame, dns_error);
82
83 if (main_frame && dns_error) {
84 last_error_ = error;
85
86 WebKit::WebDataSource* data_source = frame->provisionalDataSource();
87 const WebKit::WebURLRequest& failed_request = data_source->request();
88 is_failed_post_ = EqualsASCII(failed_request.httpMethod(), "POST");
89 }
mmenke 2013/07/12 16:14:48 Hmm...we're not testing either this or the stuff w
Deprecated (see juliatuttle) 2013/07/12 17:42:49 I'm not sure what a good way to test this would be
mmenke 2013/07/12 18:02:12 We could just pass error and is_failed_post into O
Deprecated (see juliatuttle) 2013/07/12 20:55:55 That seems ugly, and it still wouldn't check the a
mmenke 2013/07/15 16:33:22 My concern isn't so much that we'd overwrite it, b
119 } 90 }
120 91
121 void NetErrorHelper::DidCommitProvisionalLoad(WebKit::WebFrame* frame, 92 void NetErrorHelper::DidCommitProvisionalLoad(WebKit::WebFrame* frame,
122 bool is_new_navigation) { 93 bool is_new_navigation) {
123 tracker_.OnCommitProvisionalLoad(GetFrameType(frame)); 94 OnCommitLoad(IsMainFrame(frame));
124 } 95 }
125 96
126 void NetErrorHelper::DidFinishLoad(WebKit::WebFrame* frame) { 97 void NetErrorHelper::DidFinishLoad(WebKit::WebFrame* frame) {
127 tracker_.OnFinishLoad(GetFrameType(frame)); 98 OnFinishLoad(IsMainFrame(frame));
99 }
100
101 void NetErrorHelper::OnStartLoad(bool is_main_frame, bool is_error_page) {
102 DVLOG(1) << "OnStartLoad(is_main_frame=" << is_main_frame
103 << ", is_error_page=" << is_error_page << ")";
104 if (!is_main_frame)
105 return;
106
107 last_start_was_error_page_ = is_error_page;
108 }
109
110 void NetErrorHelper::OnFailLoad(bool is_main_frame, bool is_dns_error) {
111 DVLOG(1) << "OnFailLoad(is_main_frame=" << is_main_frame
112 << ", is_dns_error=" << is_dns_error << ")";
113
114 if (!is_main_frame)
115 return;
116
117 last_fail_was_dns_error_ = is_dns_error;
118
119 if (is_dns_error) {
120 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE;
121 // If the helper was forwarding probe results and another DNS error has
122 // occurred, stop forwarding probe results until the corresponding (new)
123 // error page loads.
124 forwarding_probe_results_ = false;
125 }
126 }
127
128 void NetErrorHelper::OnCommitLoad(bool is_main_frame) {
129 DVLOG(1) << "OnCommitLoad(is_main_frame=" << is_main_frame << ")";
130
131 if (!is_main_frame)
132 return;
133
134 // If the helper was forwarding probe results and a normal page (or a non-DNS
135 // error page) has committed, stop forwarding probe results, since the DNS
136 // error page is gone.
137 if (!last_start_was_error_page_ || !last_fail_was_dns_error_)
138 forwarding_probe_results_ = false;
mmenke 2013/07/12 16:14:48 Any reason not to just set forwarding to false her
mmenke 2013/07/12 16:14:48 BUG: Need "last_probe_status_ = chrome_common_net
Deprecated (see juliatuttle) 2013/07/12 17:42:49 We do that in OnFailLoad, when a DNS error occurs.
Deprecated (see juliatuttle) 2013/07/12 17:42:49 Hmm, I guess not. If we have two DNS error pages
mmenke 2013/07/12 18:02:12 Hmm...I even searched the page for that. How did
Deprecated (see juliatuttle) 2013/07/12 20:55:55 Added another test that repeats the "DNS_PROBE_FIN
139 }
140
141 void NetErrorHelper::OnFinishLoad(bool is_main_frame) {
142 DVLOG(1) << "OnFinishLoad(is_main_frame=" << is_main_frame << ")";
143
144 if (!is_main_frame)
145 return;
146
147 // If a DNS error page just finished loading, start forwarding probe results
148 // to it.
149 forwarding_probe_results_ =
150 last_fail_was_dns_error_ && last_start_was_error_page_;
mmenke 2013/07/12 16:14:48 No known way to set this to false for the link doc
Deprecated (see juliatuttle) 2013/07/12 17:42:49 Nope. As far as I can tell, the loads are identic
151
152 if (forwarding_probe_results_ &&
153 last_probe_status_ != chrome_common_net::DNS_PROBE_POSSIBLE) {
154 DVLOG(1) << "Error page finished loading; sending saved status.";
155 UpdateErrorPage();
156 }
128 } 157 }
129 158
130 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) { 159 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) {
131 bool handled = true; 160 bool handled = true;
132 161
133 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message) 162 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message)
134 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo) 163 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo)
135 IPC_MESSAGE_UNHANDLED(handled = false) 164 IPC_MESSAGE_UNHANDLED(handled = false)
136 IPC_END_MESSAGE_MAP() 165 IPC_END_MESSAGE_MAP()
137 166
138 return handled; 167 return handled;
139 } 168 }
140 169
141 void NetErrorHelper::OnNetErrorInfo(int dns_probe_result) { 170 bool NetErrorHelper::GetErrorStringsForDnsProbe(
142 DVLOG(1) << "Received DNS probe result " << dns_probe_result; 171 WebKit::WebFrame* frame,
172 const WebKit::WebURLError& error,
173 bool is_failed_post,
174 const std::string& locale,
175 base::DictionaryValue* error_strings) {
176 if (!IsMainFrame(frame))
177 return false;
143 178
144 if (dns_probe_result < 0 || 179 if (!IsDnsError(error))
145 dns_probe_result >= chrome_common_net::DNS_PROBE_MAX) { 180 return false;
146 DLOG(WARNING) << "Ignoring DNS probe result: invalid result " 181
147 << dns_probe_result; 182 // Get the strings for a fake "DNS probe possible" error.
183 WebKit::WebURLError fake_error;
184 fake_error.domain = WebKit::WebString::fromUTF8(
185 chrome_common_net::kDnsProbeErrorDomain);
186 fake_error.reason = chrome_common_net::DNS_PROBE_POSSIBLE;
187 fake_error.unreachableURL = error.unreachableURL;
188 LocalizedError::GetStrings(
189 fake_error, is_failed_post, locale, error_strings);
190 return true;
191 }
192
193 void NetErrorHelper::OnNetErrorInfo(int status_num) {
194 DCHECK(status_num >= 0 && status_num < chrome_common_net::DNS_PROBE_MAX);
195
196 DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num);
197
198 DnsProbeStatus status = static_cast<DnsProbeStatus>(status_num);
199 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status);
200
201 if (!(last_fail_was_dns_error_ || forwarding_probe_results_)) {
202 DVLOG(1) << "Ignoring NetErrorInfo: no DNS error";
203 return;
204 }
205
206 last_probe_status_ = status;
207
208 if (forwarding_probe_results_)
209 UpdateErrorPage();
210 }
211
212 void NetErrorHelper::UpdateErrorPage() {
213 DCHECK(forwarding_probe_results_);
214
215 base::DictionaryValue error_strings;
216 LocalizedError::GetStrings(GetUpdatedError(),
mmenke 2013/07/12 16:14:48 Hmm...between fail and commit, we'd actually displ
Deprecated (see juliatuttle) 2013/07/12 17:42:49 I don't think so? Until the error page commits, w
mmenke 2013/07/15 16:33:22 A page fails with a DNS issue, we commit the page.
217 is_failed_post_,
218 RenderThread::Get()->GetLocale(),
219 &error_strings);
220
221 std::string json;
222 JSONWriter::Write(&error_strings, &json);
223
224 std::string js = "if (window.updateForDnsProbe) "
225 "updateForDnsProbe(" + json + ");";
226 string16 js16;
227 if (!UTF8ToUTF16(js.c_str(), js.length(), &js16)) {
148 NOTREACHED(); 228 NOTREACHED();
149 return; 229 return;
150 } 230 }
151 231
152 if (dns_error_page_state_ != NetErrorTracker::DNS_ERROR_PAGE_LOADED) { 232 DVLOG(1) << "Updating error page with status "
153 DVLOG(1) << "Ignoring DNS probe result: not on DNS error page."; 233 << chrome_common_net::DnsProbeStatusToString(last_probe_status_);
154 return; 234 DVLOG(2) << "New strings: " << js;
235
236 string16 frame_xpath;
237 render_view()->EvaluateScript(frame_xpath, js16, 0, false);
238 }
239
240 WebKit::WebURLError NetErrorHelper::GetUpdatedError() const {
241 // If a probe didn't run or wasn't conclusive, restore the original error.
242 if (last_probe_status_ == chrome_common_net::DNS_PROBE_NOT_RUN ||
243 last_probe_status_ == chrome_common_net::DNS_PROBE_FINISHED_UNKNOWN) {
244 return last_error_;
155 } 245 }
156 246
157 if (updated_error_page_) { 247 WebKit::WebURLError error;
158 DVLOG(1) << "Ignoring DNS probe result: already updated error page."; 248 error.domain = WebKit::WebString::fromUTF8(
159 return; 249 chrome_common_net::kDnsProbeErrorDomain);
160 } 250 error.reason = last_probe_status_;
251 error.unreachableURL = last_error_.unreachableURL;
161 252
162 UpdateErrorPage(static_cast<DnsProbeResult>(dns_probe_result)); 253 return error;
163 updated_error_page_ = true;
164 } 254 }
165
166 void NetErrorHelper::TrackerCallback(
167 NetErrorTracker::DnsErrorPageState state) {
168 dns_error_page_state_ = state;
169
170 if (state == NetErrorTracker::DNS_ERROR_PAGE_LOADED)
171 updated_error_page_ = false;
172 }
173
174 void NetErrorHelper::UpdateErrorPage(DnsProbeResult dns_probe_result) {
175 DVLOG(1) << "Updating error page with result " << dns_probe_result;
176
177 int net_error = DnsProbeResultToNetError(dns_probe_result);
178 if (net_error == net::OK)
179 return;
180
181 DVLOG(1) << "net error code is " << net_error;
182
183 base::DictionaryValue error_strings;
184 LocalizedError::GetStrings(NetErrorToWebURLError(net_error),
185 is_failed_post_,
186 RenderThread::Get()->GetLocale(),
187 &error_strings);
188
189 // TODO(ttuttle): Update error page with error_strings.
190 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698