OLD | NEW |
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" | |
11 #include "base/values.h" | 7 #include "base/values.h" |
12 #include "chrome/common/localized_error.h" | 8 #include "chrome/common/localized_error.h" |
13 #include "chrome/common/net/net_error_info.h" | 9 #include "chrome/common/net/net_error_info.h" |
14 #include "chrome/common/render_messages.h" | 10 #include "chrome/common/render_messages.h" |
15 #include "content/public/common/content_client.h" | 11 #include "content/public/common/content_client.h" |
16 #include "content/public/common/url_constants.h" | 12 #include "content/public/common/url_constants.h" |
17 #include "content/public/renderer/content_renderer_client.h" | 13 #include "content/public/renderer/content_renderer_client.h" |
18 #include "content/public/renderer/render_thread.h" | 14 #include "content/public/renderer/render_thread.h" |
19 #include "content/public/renderer/render_view.h" | 15 #include "content/public/renderer/render_view.h" |
20 #include "ipc/ipc_message.h" | 16 #include "ipc/ipc_message.h" |
21 #include "ipc/ipc_message_macros.h" | 17 #include "ipc/ipc_message_macros.h" |
22 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
23 #include "third_party/WebKit/public/platform/WebURL.h" | 19 #include "third_party/WebKit/public/platform/WebURL.h" |
| 20 #include "third_party/WebKit/public/platform/WebURLError.h" |
24 #include "third_party/WebKit/public/platform/WebURLRequest.h" | 21 #include "third_party/WebKit/public/platform/WebURLRequest.h" |
25 #include "third_party/WebKit/public/web/WebDataSource.h" | 22 #include "third_party/WebKit/public/web/WebDataSource.h" |
26 #include "third_party/WebKit/public/web/WebFrame.h" | 23 #include "third_party/WebKit/public/web/WebFrame.h" |
27 #include "url/gurl.h" | 24 #include "url/gurl.h" |
28 | 25 |
29 using base::JSONWriter; | 26 using chrome_common_net::DnsProbeResult; |
30 using chrome_common_net::DnsProbeStatus; | |
31 using chrome_common_net::DnsProbeStatusIsFinished; | |
32 using chrome_common_net::DnsProbeStatusToString; | |
33 using chrome_common_net::DnsProbesEnabledByFieldTrial; | |
34 using content::RenderThread; | 27 using content::RenderThread; |
35 using content::RenderView; | 28 using content::RenderView; |
36 using content::RenderViewObserver; | 29 using content::RenderViewObserver; |
37 using content::kUnreachableWebDataURL; | 30 using content::kUnreachableWebDataURL; |
38 | 31 |
39 namespace { | 32 namespace { |
40 | 33 |
41 bool IsLoadingErrorPage(WebKit::WebFrame* frame) { | 34 GURL GetProvisionallyLoadingURLFromWebFrame(WebKit::WebFrame* frame) { |
42 GURL url = frame->provisionalDataSource()->request().url(); | 35 return frame->provisionalDataSource()->request().url(); |
43 return url.spec() == kUnreachableWebDataURL; | |
44 } | 36 } |
45 | 37 |
46 bool IsMainFrame(const WebKit::WebFrame* frame) { | 38 bool IsErrorPage(const GURL& url) { |
47 return !frame->parent(); | 39 return (url.spec() == kUnreachableWebDataURL); |
48 } | 40 } |
49 | 41 |
50 // Returns whether |net_error| is a DNS-related error (and therefore whether | 42 // Returns whether |net_error| is a DNS-related error (and therefore whether |
51 // the tab helper should start a DNS probe after receiving it.) | 43 // the tab helper should start a DNS probe after receiving it.) |
52 bool IsDnsError(const WebKit::WebURLError& error) { | 44 bool IsDnsError(int net_error) { |
53 return std::string(error.domain.utf8()) == net::kErrorDomain && | 45 return net_error == net::ERR_NAME_NOT_RESOLVED || |
54 (error.reason == net::ERR_NAME_NOT_RESOLVED || | 46 net_error == net::ERR_NAME_RESOLUTION_FAILED; |
55 error.reason == net::ERR_NAME_RESOLUTION_FAILED); | 47 } |
| 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; |
56 } | 93 } |
57 | 94 |
58 } // namespace | 95 } // namespace |
59 | 96 |
60 NetErrorHelper::NetErrorHelper(RenderView* render_view) | 97 NetErrorHelper::NetErrorHelper(RenderView* render_view) |
61 : RenderViewObserver(render_view), | 98 : RenderViewObserver(render_view), |
62 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE), | 99 tracker_(base::Bind(&NetErrorHelper::TrackerCallback, |
63 last_start_was_error_page_(false), | 100 base::Unretained(this))), |
64 last_fail_was_dns_error_(false), | 101 dns_error_page_state_(NetErrorTracker::DNS_ERROR_PAGE_NONE), |
65 forwarding_probe_results_(false), | 102 updated_error_page_(false), |
66 is_failed_post_(false) { | 103 is_failed_post_(false) { |
67 } | 104 } |
68 | 105 |
69 NetErrorHelper::~NetErrorHelper() { | 106 NetErrorHelper::~NetErrorHelper() { |
70 } | 107 } |
71 | 108 |
72 void NetErrorHelper::DidStartProvisionalLoad(WebKit::WebFrame* frame) { | 109 void NetErrorHelper::DidStartProvisionalLoad(WebKit::WebFrame* frame) { |
73 OnStartLoad(IsMainFrame(frame), IsLoadingErrorPage(frame)); | 110 tracker_.OnStartProvisionalLoad(GetFrameType(frame), GetPageType(frame)); |
74 } | 111 } |
75 | 112 |
76 void NetErrorHelper::DidFailProvisionalLoad(WebKit::WebFrame* frame, | 113 void NetErrorHelper::DidFailProvisionalLoad(WebKit::WebFrame* frame, |
77 const WebKit::WebURLError& error) { | 114 const WebKit::WebURLError& error) { |
78 const bool main_frame = IsMainFrame(frame); | 115 WebKit::WebDataSource* data_source = frame->provisionalDataSource(); |
79 const bool dns_error = IsDnsError(error); | 116 const WebKit::WebURLRequest& failed_request = data_source->request(); |
80 | 117 is_failed_post_ = EqualsASCII(failed_request.httpMethod(), "POST"); |
81 OnFailLoad(main_frame, dns_error); | 118 tracker_.OnFailProvisionalLoad(GetFrameType(frame), GetErrorType(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 } | |
90 } | 119 } |
91 | 120 |
92 void NetErrorHelper::DidCommitProvisionalLoad(WebKit::WebFrame* frame, | 121 void NetErrorHelper::DidCommitProvisionalLoad(WebKit::WebFrame* frame, |
93 bool is_new_navigation) { | 122 bool is_new_navigation) { |
94 OnCommitLoad(IsMainFrame(frame)); | 123 tracker_.OnCommitProvisionalLoad(GetFrameType(frame)); |
95 } | 124 } |
96 | 125 |
97 void NetErrorHelper::DidFinishLoad(WebKit::WebFrame* frame) { | 126 void NetErrorHelper::DidFinishLoad(WebKit::WebFrame* frame) { |
98 OnFinishLoad(IsMainFrame(frame)); | 127 tracker_.OnFinishLoad(GetFrameType(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 // Stop forwarding results. If the page is a DNS error page, forwarding | |
135 // will resume once the page is loaded; if not, it should stay stopped until | |
136 // the next DNS error page. | |
137 forwarding_probe_results_ = false; | |
138 } | |
139 | |
140 void NetErrorHelper::OnFinishLoad(bool is_main_frame) { | |
141 DVLOG(1) << "OnFinishLoad(is_main_frame=" << is_main_frame << ")"; | |
142 | |
143 if (!is_main_frame) | |
144 return; | |
145 | |
146 // If a DNS error page just finished loading, start forwarding probe results | |
147 // to it. | |
148 forwarding_probe_results_ = | |
149 last_fail_was_dns_error_ && last_start_was_error_page_; | |
150 | |
151 if (forwarding_probe_results_ && | |
152 last_probe_status_ != chrome_common_net::DNS_PROBE_POSSIBLE) { | |
153 DVLOG(1) << "Error page finished loading; sending saved status."; | |
154 UpdateErrorPage(); | |
155 } | |
156 } | 128 } |
157 | 129 |
158 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) { | 130 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) { |
159 bool handled = true; | 131 bool handled = true; |
160 | 132 |
161 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message) | 133 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message) |
162 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo) | 134 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo) |
163 IPC_MESSAGE_UNHANDLED(handled = false) | 135 IPC_MESSAGE_UNHANDLED(handled = false) |
164 IPC_END_MESSAGE_MAP() | 136 IPC_END_MESSAGE_MAP() |
165 | 137 |
166 return handled; | 138 return handled; |
167 } | 139 } |
168 | 140 |
169 bool NetErrorHelper::GetErrorStringsForDnsProbe( | 141 void NetErrorHelper::OnNetErrorInfo(int dns_probe_result) { |
170 WebKit::WebFrame* frame, | 142 DVLOG(1) << "Received DNS probe result " << dns_probe_result; |
171 const WebKit::WebURLError& error, | |
172 bool is_failed_post, | |
173 const std::string& locale, | |
174 base::DictionaryValue* error_strings) { | |
175 if (!IsMainFrame(frame)) | |
176 return false; | |
177 | 143 |
178 if (!IsDnsError(error)) | 144 if (dns_probe_result < 0 || |
179 return false; | 145 dns_probe_result >= chrome_common_net::DNS_PROBE_MAX) { |
180 | 146 DLOG(WARNING) << "Ignoring DNS probe result: invalid result " |
181 // Get the strings for a fake "DNS probe possible" error. | 147 << dns_probe_result; |
182 WebKit::WebURLError fake_error; | 148 NOTREACHED(); |
183 fake_error.domain = WebKit::WebString::fromUTF8( | |
184 chrome_common_net::kDnsProbeErrorDomain); | |
185 fake_error.reason = chrome_common_net::DNS_PROBE_POSSIBLE; | |
186 fake_error.unreachableURL = error.unreachableURL; | |
187 LocalizedError::GetStrings( | |
188 fake_error, is_failed_post, locale, error_strings); | |
189 return true; | |
190 } | |
191 | |
192 void NetErrorHelper::OnNetErrorInfo(int status_num) { | |
193 DCHECK(status_num >= 0 && status_num < chrome_common_net::DNS_PROBE_MAX); | |
194 | |
195 DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num); | |
196 | |
197 DnsProbeStatus status = static_cast<DnsProbeStatus>(status_num); | |
198 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status); | |
199 | |
200 if (!(last_fail_was_dns_error_ || forwarding_probe_results_)) { | |
201 DVLOG(1) << "Ignoring NetErrorInfo: no DNS error"; | |
202 return; | 149 return; |
203 } | 150 } |
204 | 151 |
205 last_probe_status_ = status; | 152 if (dns_error_page_state_ != NetErrorTracker::DNS_ERROR_PAGE_LOADED) { |
| 153 DVLOG(1) << "Ignoring DNS probe result: not on DNS error page."; |
| 154 return; |
| 155 } |
206 | 156 |
207 if (forwarding_probe_results_) | 157 if (updated_error_page_) { |
208 UpdateErrorPage(); | 158 DVLOG(1) << "Ignoring DNS probe result: already updated error page."; |
| 159 return; |
| 160 } |
| 161 |
| 162 UpdateErrorPage(static_cast<DnsProbeResult>(dns_probe_result)); |
| 163 updated_error_page_ = true; |
209 } | 164 } |
210 | 165 |
211 void NetErrorHelper::UpdateErrorPage() { | 166 void NetErrorHelper::TrackerCallback( |
212 DCHECK(forwarding_probe_results_); | 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; |
213 | 182 |
214 base::DictionaryValue error_strings; | 183 base::DictionaryValue error_strings; |
215 LocalizedError::GetStrings(GetUpdatedError(), | 184 LocalizedError::GetStrings(NetErrorToWebURLError(net_error), |
216 is_failed_post_, | 185 is_failed_post_, |
217 RenderThread::Get()->GetLocale(), | 186 RenderThread::Get()->GetLocale(), |
218 &error_strings); | 187 &error_strings); |
219 | 188 |
220 std::string json; | 189 // TODO(ttuttle): Update error page with error_strings. |
221 JSONWriter::Write(&error_strings, &json); | |
222 | |
223 std::string js = "if (window.updateForDnsProbe) " | |
224 "updateForDnsProbe(" + json + ");"; | |
225 string16 js16; | |
226 if (!UTF8ToUTF16(js.c_str(), js.length(), &js16)) { | |
227 NOTREACHED(); | |
228 return; | |
229 } | |
230 | |
231 DVLOG(1) << "Updating error page with status " | |
232 << chrome_common_net::DnsProbeStatusToString(last_probe_status_); | |
233 DVLOG(2) << "New strings: " << js; | |
234 | |
235 string16 frame_xpath; | |
236 render_view()->EvaluateScript(frame_xpath, js16, 0, false); | |
237 } | 190 } |
238 | |
239 WebKit::WebURLError NetErrorHelper::GetUpdatedError() const { | |
240 // If a probe didn't run or wasn't conclusive, restore the original error. | |
241 if (last_probe_status_ == chrome_common_net::DNS_PROBE_NOT_RUN || | |
242 last_probe_status_ == | |
243 chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) { | |
244 return last_error_; | |
245 } | |
246 | |
247 WebKit::WebURLError error; | |
248 error.domain = WebKit::WebString::fromUTF8( | |
249 chrome_common_net::kDnsProbeErrorDomain); | |
250 error.reason = last_probe_status_; | |
251 error.unreachableURL = last_error_.unreachableURL; | |
252 | |
253 return error; | |
254 } | |
OLD | NEW |