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