|
1 <?xml version="1.0" encoding="UTF-8"?> |
|
2 |
|
3 <!DOCTYPE html [ |
|
4 <!ENTITY % htmlDTD |
|
5 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
|
6 "DTD/xhtml1-strict.dtd"> |
|
7 %htmlDTD; |
|
8 <!ENTITY % netErrorDTD |
|
9 SYSTEM "chrome://global/locale/netError.dtd"> |
|
10 %netErrorDTD; |
|
11 <!ENTITY % globalDTD |
|
12 SYSTEM "chrome://global/locale/global.dtd"> |
|
13 %globalDTD; |
|
14 ]> |
|
15 |
|
16 <!-- This Source Code Form is subject to the terms of the Mozilla Public |
|
17 - License, v. 2.0. If a copy of the MPL was not distributed with this |
|
18 - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> |
|
19 |
|
20 <html xmlns="http://www.w3.org/1999/xhtml"> |
|
21 <head> |
|
22 <meta name="viewport" content="width=device-width; user-scalable=false;" /> |
|
23 <title>&loadError.label;</title> |
|
24 <link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all" /> |
|
25 <!-- If the location of the favicon is changed here, the FAVICON_ERRORPAGE_URL symbol in |
|
26 toolkit/components/places/src/nsFaviconService.h should be updated. --> |
|
27 <link rel="icon" type="image/png" id="favicon" href="chrome://global/skin/icons/warning-16.png"/> |
|
28 |
|
29 <script type="application/javascript"><![CDATA[ |
|
30 // Error url MUST be formatted like this: |
|
31 // moz-neterror:page?e=error&u=url&d=desc |
|
32 // |
|
33 // or optionally, to specify an alternate CSS class to allow for |
|
34 // custom styling and favicon: |
|
35 // |
|
36 // moz-neterror:page?e=error&u=url&s=classname&d=desc |
|
37 |
|
38 // Note that this file uses document.documentURI to get |
|
39 // the URL (with the format from above). This is because |
|
40 // document.location.href gets the current URI off the docshell, |
|
41 // which is the URL displayed in the location bar, i.e. |
|
42 // the URI that the user attempted to load. |
|
43 |
|
44 function getErrorCode() |
|
45 { |
|
46 var url = document.documentURI; |
|
47 var error = url.search(/e\=/); |
|
48 var duffUrl = url.search(/\&u\=/); |
|
49 return decodeURIComponent(url.slice(error + 2, duffUrl)); |
|
50 } |
|
51 |
|
52 function getCSSClass() |
|
53 { |
|
54 var url = document.documentURI; |
|
55 var matches = url.match(/s\=([^&]+)\&/); |
|
56 // s is optional, if no match just return nothing |
|
57 if (!matches || matches.length < 2) |
|
58 return ""; |
|
59 |
|
60 // parenthetical match is the second entry |
|
61 return decodeURIComponent(matches[1]); |
|
62 } |
|
63 |
|
64 function getDescription() |
|
65 { |
|
66 var url = document.documentURI; |
|
67 var desc = url.search(/d\=/); |
|
68 |
|
69 // desc == -1 if not found; if so, return an empty string |
|
70 // instead of what would turn out to be portions of the URI |
|
71 if (desc == -1) |
|
72 return ""; |
|
73 |
|
74 return decodeURIComponent(url.slice(desc + 2)); |
|
75 } |
|
76 |
|
77 function retryThis(buttonEl) |
|
78 { |
|
79 // Note: The application may wish to handle switching off "offline mode" |
|
80 // before this event handler runs, but using a capturing event handler. |
|
81 |
|
82 // Session history has the URL of the page that failed |
|
83 // to load, not the one of the error page. So, just call |
|
84 // reload(), which will also repost POST data correctly. |
|
85 try { |
|
86 location.reload(); |
|
87 } catch (e) { |
|
88 // We probably tried to reload a URI that caused an exception to |
|
89 // occur; e.g. a nonexistent file. |
|
90 } |
|
91 |
|
92 buttonEl.disabled = true; |
|
93 } |
|
94 |
|
95 function initPage() |
|
96 { |
|
97 var err = getErrorCode(); |
|
98 |
|
99 // if it's an unknown error or there's no title or description |
|
100 // defined, get the generic message |
|
101 var errTitle = document.getElementById("et_" + err); |
|
102 var errDesc = document.getElementById("ed_" + err); |
|
103 if (!errTitle || !errDesc) |
|
104 { |
|
105 errTitle = document.getElementById("et_generic"); |
|
106 errDesc = document.getElementById("ed_generic"); |
|
107 } |
|
108 |
|
109 var title = document.querySelector(".errorTitleText"); |
|
110 if (title) |
|
111 { |
|
112 title.parentNode.replaceChild(errTitle, title); |
|
113 // change id to the replaced child's id so styling works |
|
114 errTitle.classList.add("errorTitleText"); |
|
115 } |
|
116 |
|
117 var sd = document.getElementById("errorShortDescText"); |
|
118 if (sd) |
|
119 sd.textContent = getDescription(); |
|
120 |
|
121 var ld = document.getElementById("errorLongDesc"); |
|
122 if (ld) |
|
123 { |
|
124 ld.parentNode.replaceChild(errDesc, ld); |
|
125 // change id to the replaced child's id so styling works |
|
126 errDesc.id = "errorLongDesc"; |
|
127 } |
|
128 |
|
129 // remove undisplayed errors to avoid bug 39098 |
|
130 var errContainer = document.getElementById("errorContainer"); |
|
131 errContainer.parentNode.removeChild(errContainer); |
|
132 |
|
133 var className = getCSSClass(); |
|
134 if (className && className != "expertBadCert") { |
|
135 // Associate a CSS class with the root of the page, if one was passed in, |
|
136 // to allow custom styling. |
|
137 // Not "expertBadCert" though, don't want to deal with the favicon |
|
138 document.documentElement.className = className; |
|
139 |
|
140 // Also, if they specified a CSS class, they must supply their own |
|
141 // favicon. In order to trigger the browser to repaint though, we |
|
142 // need to remove/add the link element. |
|
143 var favicon = document.getElementById("favicon"); |
|
144 var faviconParent = favicon.parentNode; |
|
145 faviconParent.removeChild(favicon); |
|
146 favicon.setAttribute("href", "chrome://global/skin/icons/" + className + "_favicon.png"); |
|
147 faviconParent.appendChild(favicon); |
|
148 } |
|
149 if (className == "expertBadCert") { |
|
150 showSecuritySection(); |
|
151 } |
|
152 |
|
153 if (err == "remoteXUL") { |
|
154 // Remove the "Try again" button for remote XUL errors given that |
|
155 // it is useless. |
|
156 document.getElementById("errorTryAgain").style.display = "none"; |
|
157 } |
|
158 |
|
159 if (err == "cspFrameAncestorBlocked") { |
|
160 // Remove the "Try again" button for CSP frame ancestors violation, since it's |
|
161 // almost certainly useless. (Bug 553180) |
|
162 document.getElementById("errorTryAgain").style.display = "none"; |
|
163 } |
|
164 |
|
165 if (err == "nssBadCert") { |
|
166 // Remove the "Try again" button for security exceptions, since it's |
|
167 // almost certainly useless. |
|
168 document.getElementById("errorTryAgain").style.display = "none"; |
|
169 document.getElementById("errorPage").setAttribute("class", "certerror"); |
|
170 addDomainErrorLink(); |
|
171 } |
|
172 else { |
|
173 // Remove the override block for non-certificate errors. CSS-hiding |
|
174 // isn't good enough here, because of bug 39098 |
|
175 var secOverride = document.getElementById("securityOverrideDiv"); |
|
176 secOverride.parentNode.removeChild(secOverride); |
|
177 } |
|
178 } |
|
179 |
|
180 function showSecuritySection() { |
|
181 // Swap link out, content in |
|
182 document.getElementById('securityOverrideContent').style.display = ''; |
|
183 document.getElementById('securityOverrideLink').style.display = 'none'; |
|
184 } |
|
185 |
|
186 /* In the case of SSL error pages about domain mismatch, see if |
|
187 we can hyperlink the user to the correct site. We don't want |
|
188 to do this generically since it allows MitM attacks to redirect |
|
189 users to a site under attacker control, but in certain cases |
|
190 it is safe (and helpful!) to do so. Bug 402210 |
|
191 */ |
|
192 function addDomainErrorLink() { |
|
193 // Rather than textContent, we need to treat description as HTML |
|
194 var sd = document.getElementById("errorShortDescText"); |
|
195 if (sd) { |
|
196 var desc = getDescription(); |
|
197 |
|
198 // sanitize description text - see bug 441169 |
|
199 |
|
200 // First, find the index of the <a> tag we care about, being careful not to |
|
201 // use an over-greedy regex |
|
202 var re = /<a id="cert_domain_link" title="([^"]+)">/; |
|
203 var result = re.exec(desc); |
|
204 if(!result) |
|
205 return; |
|
206 |
|
207 // Remove sd's existing children |
|
208 sd.textContent = ""; |
|
209 |
|
210 // Everything up to the link should be text content |
|
211 sd.appendChild(document.createTextNode(desc.slice(0, result.index))); |
|
212 |
|
213 // Now create the link itself |
|
214 var anchorEl = document.createElement("a"); |
|
215 anchorEl.setAttribute("id", "cert_domain_link"); |
|
216 anchorEl.setAttribute("title", result[1]); |
|
217 anchorEl.appendChild(document.createTextNode(result[1])); |
|
218 sd.appendChild(anchorEl); |
|
219 |
|
220 // Finally, append text for anything after the closing </a> |
|
221 sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length))); |
|
222 } |
|
223 |
|
224 var link = document.getElementById('cert_domain_link'); |
|
225 if (!link) |
|
226 return; |
|
227 |
|
228 var okHost = link.getAttribute("title"); |
|
229 var thisHost = document.location.hostname; |
|
230 var proto = document.location.protocol; |
|
231 |
|
232 // If okHost is a wildcard domain ("*.example.com") let's |
|
233 // use "www" instead. "*.example.com" isn't going to |
|
234 // get anyone anywhere useful. bug 432491 |
|
235 okHost = okHost.replace(/^\*\./, "www."); |
|
236 |
|
237 /* case #1: |
|
238 * example.com uses an invalid security certificate. |
|
239 * |
|
240 * The certificate is only valid for www.example.com |
|
241 * |
|
242 * Make sure to include the "." ahead of thisHost so that |
|
243 * a MitM attack on paypal.com doesn't hyperlink to "notpaypal.com" |
|
244 * |
|
245 * We'd normally just use a RegExp here except that we lack a |
|
246 * library function to escape them properly (bug 248062), and |
|
247 * domain names are famous for having '.' characters in them, |
|
248 * which would allow spurious and possibly hostile matches. |
|
249 */ |
|
250 if (endsWith(okHost, "." + thisHost)) |
|
251 link.href = proto + okHost; |
|
252 |
|
253 /* case #2: |
|
254 * browser.garage.maemo.org uses an invalid security certificate. |
|
255 * |
|
256 * The certificate is only valid for garage.maemo.org |
|
257 */ |
|
258 if (endsWith(thisHost, "." + okHost)) |
|
259 link.href = proto + okHost; |
|
260 } |
|
261 |
|
262 function endsWith(haystack, needle) { |
|
263 return haystack.slice(-needle.length) == needle; |
|
264 } |
|
265 |
|
266 ]]></script> |
|
267 </head> |
|
268 |
|
269 <body id="errorPage" dir="&locale.dir;"> |
|
270 |
|
271 <!-- ERROR ITEM CONTAINER (removed during loading to avoid bug 39098) --> |
|
272 <div id="errorContainer"> |
|
273 <div id="errorTitlesContainer"> |
|
274 <h1 id="et_generic">&generic.title;</h1> |
|
275 <h1 id="et_dnsNotFound">&dnsNotFound.title;</h1> |
|
276 <h1 id="et_fileNotFound">&fileNotFound.title;</h1> |
|
277 <h1 id="et_malformedURI">&malformedURI.title;</h1> |
|
278 <h1 id="et_unknownProtocolFound">&unknownProtocolFound.title;</h1> |
|
279 <h1 id="et_connectionFailure">&connectionFailure.title;</h1> |
|
280 <h1 id="et_netTimeout">&netTimeout.title;</h1> |
|
281 <h1 id="et_redirectLoop">&redirectLoop.title;</h1> |
|
282 <h1 id="et_unknownSocketType">&unknownSocketType.title;</h1> |
|
283 <h1 id="et_netReset">&netReset.title;</h1> |
|
284 <h1 id="et_notCached">¬Cached.title;</h1> |
|
285 <h1 id="et_netOffline">&netOffline.title;</h1> |
|
286 <h1 id="et_netInterrupt">&netInterrupt.title;</h1> |
|
287 <h1 id="et_deniedPortAccess">&deniedPortAccess.title;</h1> |
|
288 <h1 id="et_proxyResolveFailure">&proxyResolveFailure.title;</h1> |
|
289 <h1 id="et_proxyConnectFailure">&proxyConnectFailure.title;</h1> |
|
290 <h1 id="et_contentEncodingError">&contentEncodingError.title;</h1> |
|
291 <h1 id="et_unsafeContentType">&unsafeContentType.title;</h1> |
|
292 <h1 id="et_nssFailure2">&nssFailure2.title;</h1> |
|
293 <h1 id="et_nssBadCert">&nssBadCert.title;</h1> |
|
294 <h1 id="et_cspFrameAncestorBlocked">&cspFrameAncestorBlocked.title;</h1> |
|
295 <h1 id="et_remoteXUL">&remoteXUL.title;</h1> |
|
296 <h1 id="et_corruptedContentError">&corruptedContentError.title;</h1> |
|
297 </div> |
|
298 <div id="errorDescriptionsContainer"> |
|
299 <div id="ed_generic">&generic.longDesc;</div> |
|
300 <div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div> |
|
301 <div id="ed_fileNotFound">&fileNotFound.longDesc;</div> |
|
302 <div id="ed_malformedURI">&malformedURI.longDesc;</div> |
|
303 <div id="ed_unknownProtocolFound">&unknownProtocolFound.longDesc;</div> |
|
304 <div id="ed_connectionFailure">&connectionFailure.longDesc;</div> |
|
305 <div id="ed_netTimeout">&netTimeout.longDesc;</div> |
|
306 <div id="ed_redirectLoop">&redirectLoop.longDesc;</div> |
|
307 <div id="ed_unknownSocketType">&unknownSocketType.longDesc;</div> |
|
308 <div id="ed_netReset">&netReset.longDesc;</div> |
|
309 <div id="ed_notCached">¬Cached.longDesc;</div> |
|
310 <div id="ed_netOffline">&netOffline.longDesc2;</div> |
|
311 <div id="ed_netInterrupt">&netInterrupt.longDesc;</div> |
|
312 <div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div> |
|
313 <div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc;</div> |
|
314 <div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div> |
|
315 <div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div> |
|
316 <div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div> |
|
317 <div id="ed_nssFailure2">&nssFailure2.longDesc;</div> |
|
318 <div id="ed_nssBadCert">&nssBadCert.longDesc2;</div> |
|
319 <div id="ed_cspFrameAncestorBlocked">&cspFrameAncestorBlocked.longDesc;</div> |
|
320 <div id="ed_remoteXUL">&remoteXUL.longDesc;</div> |
|
321 <div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div> |
|
322 </div> |
|
323 </div> |
|
324 |
|
325 <!-- PAGE CONTAINER (for styling purposes only) --> |
|
326 <div id="errorPageContainer" class="section"> |
|
327 |
|
328 <!-- Error Title --> |
|
329 <div id="errorTitle" class="section-header"> |
|
330 <span id="errorTitleIcon"></span> |
|
331 <h1 class="errorTitleText" /> |
|
332 </div> |
|
333 |
|
334 <!-- LONG CONTENT (the section most likely to require scrolling) --> |
|
335 <div id="errorLongContent" class="section-details"> |
|
336 |
|
337 <!-- Short Description --> |
|
338 <div id="errorShortDesc"> |
|
339 <p id="errorShortDescText" /> |
|
340 </div> |
|
341 |
|
342 <!-- Long Description (Note: See netError.dtd for used XHTML tags) --> |
|
343 <div id="errorLongDesc" /> |
|
344 |
|
345 <!-- Override section - For ssl errors only. Removed on init for other |
|
346 error types. --> |
|
347 <div id="securityOverrideDiv"> |
|
348 <a id="securityOverrideLink" href="javascript:showSecuritySection();" >&securityOverride.linkText;</a> |
|
349 <div id="securityOverrideContent" style="display: none;">&securityOverride.warningContent;</div> |
|
350 </div> |
|
351 </div> |
|
352 |
|
353 <div class="section-footer"> |
|
354 <!-- Retry Button --> |
|
355 <button id="errorTryAgain" onclick="retryThis(this);">&retry.label;</button> |
|
356 </div> |
|
357 |
|
358 </div> |
|
359 |
|
360 <!-- |
|
361 - Note: It is important to run the script this way, instead of using |
|
362 - an onload handler. This is because error pages are loaded as |
|
363 - LOAD_BACKGROUND, which means that onload handlers will not be executed. |
|
364 --> |
|
365 <script type="application/javascript">initPage();</script> |
|
366 |
|
367 </body> |
|
368 </html> |