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" |
15 #include "chrome/common/net/net_error_tracker.h" | |
11 #include "content/public/common/content_client.h" | 16 #include "content/public/common/content_client.h" |
12 #include "content/public/common/url_constants.h" | 17 #include "content/public/common/url_constants.h" |
13 #include "content/public/renderer/content_renderer_client.h" | 18 #include "content/public/renderer/content_renderer_client.h" |
14 #include "content/public/renderer/render_thread.h" | 19 #include "content/public/renderer/render_thread.h" |
15 #include "content/public/renderer/render_view.h" | 20 #include "content/public/renderer/render_view.h" |
16 #include "googleurl/src/gurl.h" | 21 #include "googleurl/src/gurl.h" |
17 #include "ipc/ipc_message.h" | 22 #include "ipc/ipc_message.h" |
18 #include "ipc/ipc_message_macros.h" | 23 #include "ipc/ipc_message_macros.h" |
19 #include "net/base/net_errors.h" | 24 #include "net/base/net_errors.h" |
20 #include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h" | 25 #include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h" |
21 #include "third_party/WebKit/Source/Platform/chromium/public/WebURLError.h" | 26 #include "third_party/WebKit/Source/Platform/chromium/public/WebURLError.h" |
22 #include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h" | 27 #include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h" |
23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h" | 28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h" |
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
25 | 30 |
26 using base::DictionaryValue; | 31 using base::DictionaryValue; |
27 using chrome_common_net::DnsProbeResult; | 32 using base::JSONWriter; |
33 using chrome_common_net::DnsProbeStatus; | |
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 GURL GetProvisionallyLoadingURLFromWebFrame(WebKit::WebFrame* frame) { |
36 return frame->provisionalDataSource()->request().url(); | 44 return frame->provisionalDataSource()->request().url(); |
37 } | 45 } |
38 | 46 |
39 bool IsErrorPage(const GURL& url) { | 47 bool IsErrorPage(const GURL& url) { |
40 return (url.spec() == kUnreachableWebDataURL); | 48 return (url.spec() == kUnreachableWebDataURL); |
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 || |
56 error.reason == net::ERR_NAME_RESOLUTION_FAILED); | |
48 } | 57 } |
49 | 58 |
50 NetErrorTracker::FrameType GetFrameType(WebKit::WebFrame* frame) { | 59 NetErrorTracker::FrameType GetFrameType(WebKit::WebFrame* frame) { |
51 return frame->parent() ? NetErrorTracker::FRAME_SUB | 60 return frame->parent() ? NetErrorTracker::FRAME_SUB |
52 : NetErrorTracker::FRAME_MAIN; | 61 : NetErrorTracker::FRAME_MAIN; |
53 } | 62 } |
54 | 63 |
55 NetErrorTracker::PageType GetPageType(WebKit::WebFrame* frame) { | 64 NetErrorTracker::PageType GetPageType(WebKit::WebFrame* frame) { |
56 bool error_page = IsErrorPage(GetProvisionallyLoadingURLFromWebFrame(frame)); | 65 bool error_page = IsErrorPage(GetProvisionallyLoadingURLFromWebFrame(frame)); |
57 return error_page ? NetErrorTracker::PAGE_ERROR | 66 return error_page ? NetErrorTracker::PAGE_ERROR |
58 : NetErrorTracker::PAGE_NORMAL; | 67 : NetErrorTracker::PAGE_NORMAL; |
59 } | 68 } |
60 | 69 |
61 NetErrorTracker::ErrorType GetErrorType(const WebKit::WebURLError& error) { | 70 NetErrorTracker::ErrorType GetErrorType(const WebKit::WebURLError& error) { |
62 return IsDnsError(error.reason) ? NetErrorTracker::ERROR_DNS | 71 return IsDnsError(error) ? NetErrorTracker::ERROR_DNS |
63 : NetErrorTracker::ERROR_OTHER; | 72 : 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 } | 73 } |
95 | 74 |
96 } // namespace | 75 } // namespace |
97 | 76 |
98 NetErrorHelper::NetErrorHelper(RenderView* render_view) | 77 NetErrorHelper::NetErrorHelper(RenderView* render_view) |
99 : RenderViewObserver(render_view), | 78 : RenderViewObserver(render_view), |
100 ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(base::Bind( | 79 state_(IDLE), |
101 &NetErrorHelper::TrackerCallback, | 80 ALLOW_THIS_IN_INITIALIZER_LIST(tracker_( |
102 base::Unretained(this)))), | 81 base::Bind(&NetErrorHelper::TrackerCallback, |
103 dns_error_page_state_(NetErrorTracker::DNS_ERROR_PAGE_NONE), | 82 base::Unretained(this)))) { |
104 updated_error_page_(false) { | |
105 } | 83 } |
106 | 84 |
107 NetErrorHelper::~NetErrorHelper() { | 85 NetErrorHelper::~NetErrorHelper() { |
108 } | 86 } |
109 | 87 |
110 void NetErrorHelper::DidStartProvisionalLoad(WebKit::WebFrame* frame) { | 88 void NetErrorHelper::DidStartProvisionalLoad(WebKit::WebFrame* frame) { |
111 tracker_.OnStartProvisionalLoad(GetFrameType(frame), GetPageType(frame)); | 89 tracker_.OnStartProvisionalLoad(GetFrameType(frame), GetPageType(frame)); |
112 } | 90 } |
113 | 91 |
114 void NetErrorHelper::DidFailProvisionalLoad(WebKit::WebFrame* frame, | 92 void NetErrorHelper::DidFailProvisionalLoad(WebKit::WebFrame* frame, |
115 const WebKit::WebURLError& error) { | 93 const WebKit::WebURLError& error) { |
116 tracker_.OnFailProvisionalLoad(GetFrameType(frame), GetErrorType(error)); | 94 tracker_.OnFailProvisionalLoad(GetFrameType(frame), GetErrorType(error)); |
95 last_error_ = error; | |
117 } | 96 } |
118 | 97 |
119 void NetErrorHelper::DidCommitProvisionalLoad(WebKit::WebFrame* frame, | 98 void NetErrorHelper::DidCommitProvisionalLoad(WebKit::WebFrame* frame, |
120 bool is_new_navigation) { | 99 bool is_new_navigation) { |
121 tracker_.OnCommitProvisionalLoad(GetFrameType(frame)); | 100 tracker_.OnCommitProvisionalLoad(GetFrameType(frame)); |
122 } | 101 } |
123 | 102 |
124 void NetErrorHelper::DidFinishLoad(WebKit::WebFrame* frame) { | 103 void NetErrorHelper::DidFinishLoad(WebKit::WebFrame* frame) { |
125 tracker_.OnFinishLoad(GetFrameType(frame)); | 104 tracker_.OnFinishLoad(GetFrameType(frame)); |
126 } | 105 } |
127 | 106 |
107 void NetErrorHelper::TrackerCallback( | |
108 NetErrorTracker::DnsErrorPageState tracker_state) { | |
109 if (tracker_state == NetErrorTracker::DNS_ERROR_PAGE_LOADED) | |
110 state_ = AWAITING_INITIAL_IPC; | |
111 else | |
112 state_ = IDLE; | |
113 | |
114 DVLOG(1) << "Renderer in tracker state " << tracker_state | |
115 << ", new state " << state_ << "."; | |
116 } | |
117 | |
128 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) { | 118 bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) { |
129 bool handled = true; | 119 bool handled = true; |
130 | 120 |
131 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message) | 121 IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message) |
132 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo) | 122 IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo) |
133 IPC_MESSAGE_UNHANDLED(handled = false) | 123 IPC_MESSAGE_UNHANDLED(handled = false) |
134 IPC_END_MESSAGE_MAP() | 124 IPC_END_MESSAGE_MAP() |
135 | 125 |
136 return handled; | 126 return handled; |
137 } | 127 } |
138 | 128 |
139 void NetErrorHelper::OnNetErrorInfo(int dns_probe_result) { | 129 bool NetErrorHelper::GetErrorStringsForDnsProbe( |
140 DVLOG(1) << "Received DNS probe result " << dns_probe_result; | 130 const WebKit::WebURLError& error, |
131 base::DictionaryValue* strings, | |
132 const std::string& locale) { | |
133 if (!IsDnsError(error)) | |
134 return false; | |
141 | 135 |
142 if (dns_probe_result < 0 || | 136 if (!DnsProbesEnabledByFieldTrial()) { |
143 dns_probe_result >= chrome_common_net::DNS_PROBE_MAX) { | 137 DVLOG(1) << "Ignoring DNS error; probes disabled by field trial."; |
144 DLOG(WARNING) << "Ignoring DNS probe result: invalid result " | 138 return false; |
145 << dns_probe_result; | 139 } |
140 | |
141 // Get the strings for a fake "DNS probe possible" error | |
142 WebKit::WebURLError fake_error; | |
143 fake_error.domain = WebKit::WebString::fromUTF8( | |
144 chrome_common_net::kDnsProbeErrorDomain); | |
145 fake_error.reason = chrome_common_net::DNS_PROBE_POSSIBLE; | |
146 fake_error.unreachableURL = error.unreachableURL; | |
147 LocalizedError::GetStrings(fake_error, strings, locale); | |
148 return true; | |
149 } | |
150 | |
151 void NetErrorHelper::OnNetErrorInfo(int status_num) { | |
152 if (status_num < 0 || | |
153 status_num >= chrome_common_net::DNS_PROBE_MAX) { | |
154 LOG(WARNING) << "Ignoring NetErrorInfo: invalid status " << status_num; | |
146 NOTREACHED(); | 155 NOTREACHED(); |
147 return; | 156 return; |
148 } | 157 } |
149 | 158 |
150 if (dns_error_page_state_ != NetErrorTracker::DNS_ERROR_PAGE_LOADED) { | 159 DVLOG(1) << "Renderer received status " |
151 DVLOG(1) << "Ignoring DNS probe result: not on DNS error page."; | 160 << DnsProbeStatusToString(status_num); |
161 | |
162 DnsProbeStatus status = static_cast<DnsProbeStatus>(status_num); | |
163 bool is_finished = status >= chrome_common_net::DNS_PROBE_FINISHED_UNKNOWN; | |
164 | |
165 if (status == chrome_common_net::DNS_PROBE_POSSIBLE) { | |
166 DLOG(WARNING) << "Ignoring NetErrorInfo: DNS_PROBE_POSSIBLE from browser."; | |
167 NOTREACHED(); | |
152 return; | 168 return; |
153 } | 169 } |
154 | 170 |
155 if (updated_error_page_) { | 171 if (state_ == IDLE) { |
156 DVLOG(1) << "Ignoring DNS probe result: already updated error page."; | 172 // Unexpected IPC in idle; the browser sent the status after the renderer |
173 // started loading a new page but before the browser became aware of it. | |
174 DVLOG(1) << "Ignoring NetErrorInfo: in state IDLE"; | |
157 return; | 175 return; |
158 } | 176 } |
159 | 177 |
160 UpdateErrorPage(static_cast<DnsProbeResult>(dns_probe_result)); | 178 if (state_ == AWAITING_PROBE_RESULT && !is_finished) { |
161 updated_error_page_ = true; | 179 DLOG(WARNING) << "Ignoring NetErrorInfo: " |
180 << "non-FINISHED status in state AWAITING_PROBE_RESULT."; | |
181 NOTREACHED(); | |
182 return; | |
183 } | |
184 | |
185 if (status == chrome_common_net::DNS_PROBE_STARTED) { | |
186 DCHECK_EQ(AWAITING_INITIAL_IPC, state_); | |
187 state_ = AWAITING_PROBE_RESULT; | |
188 } else { | |
189 state_ = IDLE; | |
190 } | |
191 | |
192 DVLOG(1) << "Renderer in new state " << state_ << "."; | |
193 | |
194 last_status_ = status; | |
mmenke
2013/04/10 16:56:58
Don't think last_status_ serves any purpose - can
Deprecated (see juliatuttle)
2013/04/10 23:42:32
Done.
| |
195 | |
196 UpdateErrorPage(); | |
162 } | 197 } |
163 | 198 |
164 void NetErrorHelper::TrackerCallback( | 199 WebKit::WebURLError NetErrorHelper::MakeUpdatedError() { |
mmenke
2013/04/10 16:56:58
Doesn't always make a WebKitError. Suggest GetFin
mmenke
2013/04/10 16:56:58
This can be const.
Deprecated (see juliatuttle)
2013/04/10 23:42:32
GetUpdatedError(), since it's not necessarily the
Deprecated (see juliatuttle)
2013/04/10 23:42:32
Done.
| |
165 NetErrorTracker::DnsErrorPageState state) { | 200 // If a probe didn't run or wasn't conclusive, restore the original error. |
166 dns_error_page_state_ = state; | 201 if (last_status_ == chrome_common_net::DNS_PROBE_NOT_RUN |
202 || last_status_ == chrome_common_net::DNS_PROBE_FINISHED_UNKNOWN) | |
mmenke
2013/04/10 16:56:58
nit: Put "||" on previous line.
mmenke
2013/04/10 16:56:58
nit: Use braces in if's where the condition uses
Deprecated (see juliatuttle)
2013/04/10 23:42:32
Done.
Deprecated (see juliatuttle)
2013/04/10 23:42:32
Done.
| |
203 return last_error_; | |
167 | 204 |
168 if (state == NetErrorTracker::DNS_ERROR_PAGE_LOADED) | 205 WebKit::WebURLError error; |
169 updated_error_page_ = false; | 206 error.domain = WebKit::WebString::fromUTF8( |
207 chrome_common_net::kDnsProbeErrorDomain); | |
208 error.reason = last_status_; | |
209 error.unreachableURL = last_error_.unreachableURL; | |
210 | |
211 return error; | |
170 } | 212 } |
171 | 213 |
172 void NetErrorHelper::UpdateErrorPage(DnsProbeResult dns_probe_result) { | 214 void NetErrorHelper::UpdateErrorPage() { |
173 DVLOG(1) << "Updating error page with result " << dns_probe_result; | |
174 | |
175 int net_error = DnsProbeResultToNetError(dns_probe_result); | |
176 if (net_error == net::OK) | |
177 return; | |
178 | |
179 DVLOG(1) << "net error code is " << net_error; | |
180 | |
181 DictionaryValue error_strings; | 215 DictionaryValue error_strings; |
182 LocalizedError::GetStrings(NetErrorToWebURLError(net_error), | 216 LocalizedError::GetStrings(MakeUpdatedError(), |
183 &error_strings, | 217 &error_strings, |
184 RenderThread::Get()->GetLocale()); | 218 RenderThread::Get()->GetLocale()); |
185 | 219 |
186 // TODO(ttuttle): Update error page with error_strings. | 220 std::string json; |
221 JSONWriter::Write(&error_strings, &json); | |
222 | |
223 std::string js = "updateForDnsProbe(" + json + ");"; | |
224 string16 js16; | |
225 if (!UTF8ToUTF16(js.c_str(), js.length(), &js16)) { | |
226 NOTREACHED(); | |
227 return; | |
228 } | |
229 | |
230 DVLOG(1) << "Renderer updating error page."; | |
231 DVLOG(2) << "New strings: " << js; | |
232 | |
233 string16 frame_xpath; | |
234 render_view()->EvaluateScript(frame_xpath, js16, 0, false); | |
187 } | 235 } |
OLD | NEW |