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

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: Tweak things, clean up unit tests Created 7 years, 6 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/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/Source/WebKit/chromium/public/WebDataSource.h" 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" 27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
25 28
26 using base::DictionaryValue; 29 using base::DictionaryValue;
27 using chrome_common_net::DnsProbeResult; 30 using base::JSONWriter;
31 using chrome_common_net::DnsProbeStatus;
32 using chrome_common_net::DnsProbeStatusIsFinished;
33 using chrome_common_net::DnsProbeStatusToString;
34 using chrome_common_net::DnsProbesEnabledByFieldTrial;
28 using content::RenderThread; 35 using content::RenderThread;
29 using content::RenderView; 36 using content::RenderView;
30 using content::RenderViewObserver; 37 using content::RenderViewObserver;
31 using content::kUnreachableWebDataURL; 38 using content::kUnreachableWebDataURL;
32 39
33 namespace { 40 namespace {
34 41
35 GURL GetProvisionallyLoadingURLFromWebFrame(WebKit::WebFrame* frame) { 42 bool IsLoadingErrorPage(WebKit::WebFrame* frame) {
36 return frame->provisionalDataSource()->request().url(); 43 GURL url = frame->provisionalDataSource()->request().url();
44 return url.spec() == kUnreachableWebDataURL;
37 } 45 }
38 46
39 bool IsErrorPage(const GURL& url) { 47 bool IsMainFrame(const WebKit::WebFrame* frame) {
40 return (url.spec() == kUnreachableWebDataURL); 48 return !frame->parent();
41 } 49 }
42 50
43 // Returns whether |net_error| is a DNS-related error (and therefore whether 51 // Returns whether |net_error| is a DNS-related error (and therefore whether
44 // the tab helper should start a DNS probe after receiving it.) 52 // the tab helper should start a DNS probe after receiving it.)
45 bool IsDnsError(int net_error) { 53 bool IsDnsError(const WebKit::WebURLError& error) {
46 return net_error == net::ERR_NAME_NOT_RESOLVED || 54 return std::string(error.domain.utf8()) == net::kErrorDomain &&
47 net_error == net::ERR_NAME_RESOLUTION_FAILED; 55 (error.reason == net::ERR_NAME_NOT_RESOLVED ||
48 } 56 error.reason == net::ERR_NAME_RESOLUTION_FAILED);
49
50 NetErrorTracker::FrameType GetFrameType(WebKit::WebFrame* frame) {
51 return frame->parent() ? NetErrorTracker::FRAME_SUB
52 : NetErrorTracker::FRAME_MAIN;
53 }
54
55 NetErrorTracker::PageType GetPageType(WebKit::WebFrame* frame) {
56 bool error_page = IsErrorPage(GetProvisionallyLoadingURLFromWebFrame(frame));
57 return error_page ? NetErrorTracker::PAGE_ERROR
58 : NetErrorTracker::PAGE_NORMAL;
59 }
60
61 NetErrorTracker::ErrorType GetErrorType(const WebKit::WebURLError& error) {
62 return IsDnsError(error.reason) ? NetErrorTracker::ERROR_DNS
63 : NetErrorTracker::ERROR_OTHER;
64 }
65
66 // Converts a DNS probe result into a net error. Returns OK if the error page
67 // should not be changed from the original DNS error.
68 int DnsProbeResultToNetError(DnsProbeResult result) {
69 switch (result) {
70 case chrome_common_net::DNS_PROBE_UNKNOWN:
71 return net::OK;
72 case chrome_common_net::DNS_PROBE_NO_INTERNET:
73 // TODO(ttuttle): This is not the same error as when NCN returns this;
74 // ideally we should have two separate error codes for "no network" and
75 // "network with no internet".
76 return net::ERR_INTERNET_DISCONNECTED;
77 case chrome_common_net::DNS_PROBE_BAD_CONFIG:
78 // This is unspecific enough that we should still show the full DNS error
79 // page.
80 return net::OK;
81 case chrome_common_net::DNS_PROBE_NXDOMAIN:
82 return net::ERR_NAME_NOT_RESOLVED;
83 default:
84 NOTREACHED();
85 return net::OK;
86 }
87 }
88
89 WebKit::WebURLError NetErrorToWebURLError(int net_error) {
90 WebKit::WebURLError error;
91 error.domain = WebKit::WebString::fromUTF8(net::kErrorDomain);
92 error.reason = net_error;
93 return error;
94 } 57 }
95 58
96 } // namespace 59 } // namespace
97 60
98 NetErrorHelper::NetErrorHelper(RenderView* render_view) 61 NetErrorHelper::NetErrorHelper(RenderView* render_view)
99 : RenderViewObserver(render_view), 62 : RenderViewObserver(render_view),
100 tracker_(base::Bind(&NetErrorHelper::TrackerCallback, 63 last_status_(chrome_common_net::DNS_PROBE_POSSIBLE),
101 base::Unretained(this))), 64 dns_error_active_(false),
102 dns_error_page_state_(NetErrorTracker::DNS_ERROR_PAGE_NONE), 65 page_loaded_(false),
103 updated_error_page_(false),
104 is_failed_post_(false) { 66 is_failed_post_(false) {
105 } 67 }
106 68
107 NetErrorHelper::~NetErrorHelper() { 69 NetErrorHelper::~NetErrorHelper() {
108 } 70 }
109 71
110 void NetErrorHelper::DidStartProvisionalLoad(WebKit::WebFrame* frame) { 72 void NetErrorHelper::DidStartProvisionalLoad(WebKit::WebFrame* frame) {
111 tracker_.OnStartProvisionalLoad(GetFrameType(frame), GetPageType(frame)); 73 OnStartLoad(IsMainFrame(frame), IsLoadingErrorPage(frame));
112 } 74 }
113 75
114 void NetErrorHelper::DidFailProvisionalLoad(WebKit::WebFrame* frame, 76 void NetErrorHelper::DidFailProvisionalLoad(WebKit::WebFrame* frame,
115 const WebKit::WebURLError& error) { 77 const WebKit::WebURLError& error) {
116 WebKit::WebDataSource* data_source = frame->provisionalDataSource(); 78 const bool main_frame = IsMainFrame(frame);
117 const WebKit::WebURLRequest& failed_request = data_source->request(); 79 const bool dns_error = IsDnsError(error);
118 is_failed_post_ = EqualsASCII(failed_request.httpMethod(), "POST"); 80
119 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 }
120 } 90 }
121 91
122 void NetErrorHelper::DidCommitProvisionalLoad(WebKit::WebFrame* frame, 92 void NetErrorHelper::DidCommitProvisionalLoad(WebKit::WebFrame* frame,
123 bool is_new_navigation) { 93 bool is_new_navigation) {
124 tracker_.OnCommitProvisionalLoad(GetFrameType(frame)); 94 OnCommitLoad(IsMainFrame(frame));
125 } 95 }
126 96
127 void NetErrorHelper::DidFinishLoad(WebKit::WebFrame* frame) { 97 void NetErrorHelper::DidFinishLoad(WebKit::WebFrame* frame) {
128 tracker_.OnFinishLoad(GetFrameType(frame)); 98 OnFinishLoad(IsMainFrame(frame));
99 }
100
101 void NetErrorHelper::OnStartLoad(bool is_main_frame, bool is_error_page) {
102 if (!is_main_frame)
103 return;
104
105 is_error_page_ = is_error_page;
106 }
107
108 void NetErrorHelper::OnFailLoad(bool is_main_frame, bool is_dns_error) {
109 if (!is_main_frame || !is_dns_error)
110 return;
111
112 dns_error_active_ = true;
mmenke 2013/06/13 20:04:55 I think the state machine here is too confusing.
Deprecated (see juliatuttle) 2013/06/18 19:36:37 Done. I had to clear page_loaded in OnFailLoad to
113 last_status_ = chrome_common_net::DNS_PROBE_POSSIBLE;
114 }
115
116 void NetErrorHelper::OnCommitLoad(bool is_main_frame) {
117 if (!is_main_frame)
118 return;
119
120 if (!is_error_page_)
121 dns_error_active_ = false;
122
123 page_loaded_ = false;
124 }
125
126 void NetErrorHelper::OnFinishLoad(bool is_main_frame) {
mmenke 2013/06/13 20:04:55 This should check if it's a main frame, presumably
Deprecated (see juliatuttle) 2013/06/18 19:36:37 Done.
127 page_loaded_ = true;
128
129 if (dns_error_active_ && is_error_page_) {
130 DVLOG(1) << "Error page finished loading; updating.";
131 UpdateErrorPage();
132 }
129 } 133 }
130 134
131 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) { 135 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) {
132 bool handled = true; 136 bool handled = true;
133 137
134 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message) 138 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message)
135 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo) 139 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo)
136 IPC_MESSAGE_UNHANDLED(handled = false) 140 IPC_MESSAGE_UNHANDLED(handled = false)
137 IPC_END_MESSAGE_MAP() 141 IPC_END_MESSAGE_MAP()
138 142
139 return handled; 143 return handled;
140 } 144 }
141 145
142 void NetErrorHelper::OnNetErrorInfo(int dns_probe_result) { 146 bool NetErrorHelper::GetErrorStringsForDnsProbe(
143 DVLOG(1) << "Received DNS probe result " << dns_probe_result; 147 WebKit::WebFrame* frame,
148 const WebKit::WebURLError& error,
149 bool is_failed_post,
150 const std::string& locale,
151 base::DictionaryValue* error_strings) {
152 if (!IsMainFrame(frame))
153 return false;
144 154
145 if (dns_probe_result < 0 || 155 if (!IsDnsError(error))
146 dns_probe_result >= chrome_common_net::DNS_PROBE_MAX) { 156 return false;
147 DLOG(WARNING) << "Ignoring DNS probe result: invalid result " 157
148 << dns_probe_result; 158 // Get the strings for a fake "DNS probe possible" error.
159 WebKit::WebURLError fake_error;
160 fake_error.domain = WebKit::WebString::fromUTF8(
161 chrome_common_net::kDnsProbeErrorDomain);
162 fake_error.reason = chrome_common_net::DNS_PROBE_POSSIBLE;
163 fake_error.unreachableURL = error.unreachableURL;
164 LocalizedError::GetStrings(
165 fake_error, is_failed_post, locale, error_strings);
166 return true;
167 }
168
169 void NetErrorHelper::OnNetErrorInfo(int status_num) {
170 if (status_num < 0 ||
171 status_num >= chrome_common_net::DNS_PROBE_MAX) {
mmenke 2013/06/13 20:04:55 Think we can just DCHECK on this, with the branch
Deprecated (see juliatuttle) 2013/06/18 19:36:37 Done.
172 LOG(WARNING) << "Ignoring NetErrorInfo: invalid status " << status_num;
149 NOTREACHED(); 173 NOTREACHED();
150 return; 174 return;
151 } 175 }
152 176
153 if (dns_error_page_state_ != NetErrorTracker::DNS_ERROR_PAGE_LOADED) { 177 DVLOG(1) << "Received status "
154 DVLOG(1) << "Ignoring DNS probe result: not on DNS error page."; 178 << DnsProbeStatusToString(status_num);
179
180 DnsProbeStatus status = static_cast<DnsProbeStatus>(status_num);
181 if (status == chrome_common_net::DNS_PROBE_POSSIBLE) {
mmenke 2013/06/13 20:04:55 Same as above comment - I think a DCHECK is suffic
Deprecated (see juliatuttle) 2013/06/18 19:36:37 Done.
182 NOTREACHED();
155 return; 183 return;
156 } 184 }
157 185
158 if (updated_error_page_) { 186 if (!dns_error_active_) {
159 DVLOG(1) << "Ignoring DNS probe result: already updated error page."; 187 DVLOG(1) << "Ignoring NetErrorInfo: no active DNS error";
160 return; 188 return;
161 } 189 }
162 190
163 UpdateErrorPage(static_cast<DnsProbeResult>(dns_probe_result)); 191 last_status_ = status;
164 updated_error_page_ = true; 192
193 if (page_loaded_)
194 UpdateErrorPage();
mmenke 2013/06/13 20:04:55 Can this happen: page_loaded_ starts as true (aft
Deprecated (see juliatuttle) 2013/06/18 19:36:37 ...ha, that is the exact race condition I just fou
165 } 195 }
166 196
167 void NetErrorHelper::TrackerCallback( 197 void NetErrorHelper::UpdateErrorPage() {
168 NetErrorTracker::DnsErrorPageState state) {
169 dns_error_page_state_ = state;
170
171 if (state == NetErrorTracker::DNS_ERROR_PAGE_LOADED)
172 updated_error_page_ = false;
173 }
174
175 void NetErrorHelper::UpdateErrorPage(DnsProbeResult dns_probe_result) {
176 DVLOG(1) << "Updating error page with result " << dns_probe_result;
177
178 int net_error = DnsProbeResultToNetError(dns_probe_result);
179 if (net_error == net::OK)
180 return;
181
182 DVLOG(1) << "net error code is " << net_error;
183
184 DictionaryValue error_strings; 198 DictionaryValue error_strings;
185 LocalizedError::GetStrings(NetErrorToWebURLError(net_error), 199 LocalizedError::GetStrings(GetUpdatedError(),
186 is_failed_post_, 200 is_failed_post_,
187 RenderThread::Get()->GetLocale(), 201 RenderThread::Get()->GetLocale(),
188 &error_strings); 202 &error_strings);
189 203
190 // TODO(ttuttle): Update error page with error_strings. 204 std::string json;
205 JSONWriter::Write(&error_strings, &json);
206
207 std::string js = "if (window.updateForDnsProbe) "
208 "updateForDnsProbe(" + json + ");";
209 string16 js16;
210 if (!UTF8ToUTF16(js.c_str(), js.length(), &js16)) {
211 NOTREACHED();
212 return;
213 }
214
215 DVLOG(1) << "Updating error page with status "
216 << chrome_common_net::DnsProbeStatusToString(last_status_);
217 DVLOG(2) << "New strings: " << js;
218
219 string16 frame_xpath;
220 render_view()->EvaluateScript(frame_xpath, js16, 0, false);
mmenke 2013/06/13 20:04:55 Should we do something to prevent too many updates
Deprecated (see juliatuttle) 2013/06/18 19:36:37 We could? I don't think it'd be a huge deal if it
191 } 221 }
222
223 WebKit::WebURLError NetErrorHelper::GetUpdatedError() const {
224 // If a probe didn't run or wasn't conclusive, restore the original error.
225 if (last_status_ == chrome_common_net::DNS_PROBE_NOT_RUN ||
226 last_status_ == chrome_common_net::DNS_PROBE_FINISHED_UNKNOWN) {
227 return last_error_;
228 }
229
230 WebKit::WebURLError error;
231 error.domain = WebKit::WebString::fromUTF8(
232 chrome_common_net::kDnsProbeErrorDomain);
233 error.reason = last_status_;
234 error.unreachableURL = last_error_.unreachableURL;
235
236 return error;
237 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698