Bug 435325: Offline mode error page should go online when clicking 'Try Again'. Add a goOnline() method to nsDOMWindowUtils, and call that from about:neterror in the netOffline case. ui-r=faaborg, r=bz, gavin.
authorSteffen Wilberg <steffen.wilberg@web.de>
Sat, 11 Jun 2011 15:38:40 +0200
changeset 70914 ae5f9abf13d9acbc7dff10f353512e7277cd9257
parent 70913 e802d263c27ec5b91df1a154e8e9327115332d43
child 70915 85a2a18ab8ee93d178d33f9219a38d2dd2d074f0
push id20444
push usersteffen.wilberg@web.de
push dateSat, 11 Jun 2011 13:39:30 +0000
treeherdermozilla-central@ae5f9abf13d9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfaaborg, bz, gavin
bugs435325
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 435325: Offline mode error page should go online when clicking 'Try Again'. Add a goOnline() method to nsDOMWindowUtils, and call that from about:neterror in the netOffline case. ui-r=faaborg, r=bz, gavin.
browser/locales/en-US/chrome/overrides/netError.dtd
docshell/resources/content/netError.xhtml
docshell/test/browser/Makefile.in
docshell/test/browser/browser_bug435325.js
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/locales/en-US/chrome/netError.dtd
mobile/chrome/content/content.js
mobile/locales/en-US/chrome/overrides/netError.dtd
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -48,24 +48,19 @@
     <strong>/</strong>).</li>
 </ul>
 ">
 
 <!ENTITY netInterrupt.title "The connection was interrupted">
 <!ENTITY netInterrupt.longDesc "&sharedLongDesc;">
 
 <!ENTITY netOffline.title "Offline mode">
-<!-- LOCALIZATION NOTE (netOffline.overrideLongDesc) - This string should
-     indicate that "Work Offline" is a menu item without being too specific,
-     since it could be in either the normal menu (Mac/Linux) or the Firefox button
-     menu (Windows).
--->
-<!ENTITY netOffline.overrideLongDesc "
+<!ENTITY netOffline.longDesc2 "
 <ul>
-  <li>Uncheck the &quot;Work Offline&quot; menu item, then try again.</li>
+  <li>Press &quot;Try Again&quot; to switch to online mode and reload the page.</li>
 </ul>
 ">
 
 <!ENTITY contentEncodingError.title "Content Encoding Error">
 <!ENTITY contentEncodingError.longDesc "
 <ul>
   <li>Please contact the website owners to inform them of this problem.</li>
 </ul>
--- a/docshell/resources/content/netError.xhtml
+++ b/docshell/resources/content/netError.xhtml
@@ -3,18 +3,16 @@
 <!DOCTYPE html [
   <!ENTITY % htmlDTD
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "DTD/xhtml1-strict.dtd">
   %htmlDTD;
   <!ENTITY % netErrorDTD
     SYSTEM "chrome://global/locale/netError.dtd">
   %netErrorDTD;
-  <!-- Fallback in case netOffline.overrideLongDesc is not defined -->
-  <!ENTITY netOffline.overrideLongDesc "&netOffline.longDesc;">
   <!ENTITY % globalDTD
     SYSTEM "chrome://global/locale/global.dtd">
   %globalDTD;
 ]>
 
 <!-- ***** BEGIN LICENSE BLOCK *****
    - Version: MPL 1.1/GPL 2.0/LGPL 2.1
    -
@@ -37,16 +35,17 @@
    -
    - Contributor(s):
    -   Adam Lock <adamlock@netscape.com>
    -   William R. Price <wrprice@alumni.rice.edu>
    -   Henrik Skupin <mozilla@hskupin.info>
    -   Jeff Walden <jwalden+code@mit.edu>
    -   Johnathan Nightingale <johnath@mozilla.com>
    -   Ehsan Akhgari <ehsan.akhgari@gmail.com>
+   -   Steffen Wilberg <steffen.wilberg@web.de>
    -
    - Alternatively, the contents of this file may be used under the terms of
    - either the GNU General Public License Version 2 or later (the "GPL"), or
    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    - in which case the provisions of the GPL or the LGPL are applicable instead
    - of those above. If you wish to allow use of your version of this file only
    - under the terms of either the GPL or the LGPL, and not to allow others to
    - use your version of this file under the terms of the MPL, indicate your
@@ -110,16 +109,23 @@
         if (desc == -1)
           return "";
 
         return decodeURIComponent(url.slice(desc + 2));
       }
 
       function retryThis(buttonEl)
       {
+        // If this is the "Offline mode" page, go online!
+        if (getErrorCode() == "netOffline") {
+          window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                .getInterface(Components.interfaces.nsIDOMWindowUtils)
+                .goOnline();
+        }
+
         // Session history has the URL of the page that failed
         // to load, not the one of the error page. So, just call
         // reload(), which will also repost POST data correctly.
         try {
           location.reload();
         } catch (e) {
           // We probably tried to reload a URI that caused an exception to
           // occur;  e.g. a nonexistent file.
@@ -337,17 +343,17 @@
         <div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
         <div id="ed_malformedURI">&malformedURI.longDesc;</div>
         <div id="ed_protocolNotFound">&protocolNotFound.longDesc;</div>
         <div id="ed_connectionFailure">&connectionFailure.longDesc;</div>
         <div id="ed_netTimeout">&netTimeout.longDesc;</div>
         <div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
         <div id="ed_unknownSocketType">&unknownSocketType.longDesc;</div>
         <div id="ed_netReset">&netReset.longDesc;</div>
-        <div id="ed_netOffline">&netOffline.overrideLongDesc;</div>
+        <div id="ed_netOffline">&netOffline.longDesc2;</div>
         <div id="ed_netInterrupt">&netInterrupt.longDesc;</div>
         <div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div>
         <div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc;</div>
         <div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div>
         <div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div>
         <div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div>
         <div id="ed_nssFailure2">&nssFailure2.longDesc;</div>
         <div id="ed_nssBadCert">&nssBadCert.longDesc2;</div>
--- a/docshell/test/browser/Makefile.in
+++ b/docshell/test/browser/Makefile.in
@@ -45,16 +45,17 @@ include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES =	\
 		browser_bug92473.js \
 		test-form_sjis.html \
 		browser_bug134911.js \
 		browser_bug349769.js \
 		browser_bug388121-1.js \
 		browser_bug388121-2.js \
+		browser_bug435325.js \
 		browser_bug441169.js \
 		browser_bug420605.js \
 		file_bug420605.html \
 		browser_bug503832.js \
 		browser_loadDisallowInherit.js \
 		file_bug503832.html \
 		browser_bug554155.js \
 		browser_bug655273.js \
new file mode 100644
--- /dev/null
+++ b/docshell/test/browser/browser_bug435325.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* Ensure that clicking the button in the Offline mode neterror page makes the browser go online. See bug 435325. */
+/* TEST_PATH=docshell/test/browser/browser_bug435325.js make -C $(OBJDIR) mochitest-browser-chrome */
+
+function test() {
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  window.addEventListener("DOMContentLoaded", checkPage, false);
+
+  // Go offline and disable the cache, then try to load the test URL.
+  Services.io.offline = true;
+  gPrefService.setBoolPref("browser.cache.disk.enable", false);
+  gPrefService.setBoolPref("browser.cache.memory.enable", false);
+  content.location = "http://example.com/";
+}
+
+function checkPage() {
+  if(content.location == "about:blank") {
+    info("got about:blank, which is expected once, so return");
+    return;
+  }
+
+  window.removeEventListener("DOMContentLoaded", checkPage, false);
+
+  ok(Services.io.offline, "Setting Services.io.offline to true.");
+  is(gBrowser.contentDocument.documentURI.substring(0,27),
+    "about:neterror?e=netOffline", "Loading the Offline mode neterror page.");
+
+  // Now press the "Try Again" button
+  ok(gBrowser.contentDocument.getElementById("errorTryAgain"),
+    "The error page has got a #errorTryAgain element");
+  gBrowser.contentDocument.getElementById("errorTryAgain").click();
+
+  ok(!Services.io.offline, "After clicking the Try Again button, we're back "
+   +" online. This depends on Components.interfaces.nsIDOMWindowUtils being "
+   +"available from untrusted content (bug 435325).");
+
+  finish();
+}
+
+registerCleanupFunction(function() {
+  gPrefService.setBoolPref("browser.cache.disk.enable", true);
+  gPrefService.setBoolPref("browser.cache.memory.enable", true);
+  Services.io.offline = false;
+  gBrowser.removeCurrentTab();
+});
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -76,16 +76,17 @@
 #if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2)
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #endif
 
 #include "jsobj.h"
 
 #include "Layers.h"
+#include "nsIIOService.h"
 
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 
 static PRBool IsUniversalXPConnectCapable()
 {
@@ -1766,16 +1767,40 @@ nsDOMWindowUtils::GetCursorType(PRInt16 
 
   // fetch cursor value from window's widget
   *aCursor = widget->GetCursor();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::GoOnline()
+{
+  // This is only allowed from about:neterror, which is unprivileged, so it
+  // can't access the io-service itself.
+  NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIDocument> doc(do_QueryInterface(mWindow->GetExtantDocument()));
+  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIURI> documentURI;
+  documentURI = doc->GetDocumentURI();
+
+  nsCAutoString spec;
+  documentURI->GetSpec(spec);
+  if (!StringBeginsWith(spec,  NS_LITERAL_CSTRING("about:neterror?")))
+    return NS_ERROR_DOM_SECURITY_ERR;
+
+  nsCOMPtr<nsIIOService> ios = do_GetService("@mozilla.org/network/io-service;1");
+  if (ios) {
+    ios->SetOffline(PR_FALSE); // !offline
+    return NS_OK;
+  }
+  return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::GetDisplayDPI(float *aDPI)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return NS_ERROR_FAILURE;
 
   *aDPI = widget->GetDPI();
 
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -61,17 +61,17 @@ interface nsIDOMNode;
 interface nsIDOMNodeList;
 interface nsIDOMElement;
 interface nsIDOMHTMLCanvasElement;
 interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 
-[scriptable, uuid(663e33d7-eca2-42e8-af92-5df6a5e222df)]
+[scriptable, uuid(b46050ea-6f18-11e0-bf00-f389b7004a12)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -798,16 +798,23 @@ interface nsIDOMWindowUtils : nsISupport
 
   /**
    * Suspend/resume timeouts on this window and its descendant windows.
    */
   void suspendTimeouts();
   void resumeTimeouts();
 
   /**
+   * Set the network status to online from the Offline mode error page.
+   *
+   * The caller of this method must be about:neterror.
+   */
+  void goOnline();
+
+  /**
    * What type of layer manager the widget associated with this window is
    * using. "Basic" is unaccelerated; other types are accelerated. Throws an
    * error if there is no widget associated with this window.
    */
   readonly attribute AString layerManagerType;
 
   /**
    * The DPI of the display
--- a/dom/locales/en-US/chrome/netError.dtd
+++ b/dom/locales/en-US/chrome/netError.dtd
@@ -20,18 +20,17 @@
 
 <!ENTITY malformedURI.title "Invalid Address">
 <!ENTITY malformedURI.longDesc "<p>The provided address is not in a recognized format. Please check the location bar for mistakes and try again.</p>">
 
 <!ENTITY netInterrupt.title "Data Transfer Interrupted">
 <!ENTITY netInterrupt.longDesc "<p>The browser connected successfully, but the connection was interrupted while transferring information.  Please try again.</p><ul><li>Are you unable to browse other sites? Check the computer's network connection.</li><li>Still having trouble? Consult your network administrator or Internet provider for assistance.</li></ul>">
 
 <!ENTITY netOffline.title "Offline Mode">
-<!ENTITY netOffline.longDesc "<p>The browser is operating in its offline mode and cannot connect to the requested item.</p><ul><li>Is the computer connected to an active network?</li><li>Place the browser in online mode and try again.</li></ul>">
-<!ENTITY netOffline.overrideLongDesc "<p>The browser is operating in its offline mode and cannot connect to the requested item.</p><ul><li>Is the computer connected to an active network?</li><li>Place the browser in online mode and try again.</li></ul>">
+<!ENTITY netOffline.longDesc2 "<p>The browser is operating in its offline mode and cannot connect to the requested item.</p><ul><li>Is the computer connected to an active network?</li><li>Press &quot;Try Again&quot; to switch to online mode and reload the page.</li></ul>">
 
 <!ENTITY contentEncodingError.title "Content Encoding Error">
 <!ENTITY contentEncodingError.longDesc "<p>The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
 
 <!ENTITY unsafeContentType.title "Unsafe File Type">
 <!ENTITY unsafeContentType.longDesc "
 <ul>
   <li>Please contact the website owners to inform them of this problem.</li>
--- a/mobile/chrome/content/content.js
+++ b/mobile/chrome/content/content.js
@@ -347,21 +347,16 @@ let Content = {
           let perm = errorDoc.getElementById("permanentExceptionButton");
           let temp = errorDoc.getElementById("temporaryExceptionButton");
           if (ot == temp || ot == perm) {
             let action = (ot == perm ? "permanent" : "temporary");
             sendAsyncMessage("Browser:CertException", { url: errorDoc.location.href, action: action });
           } else if (ot == errorDoc.getElementById("getMeOutOfHereButton")) {
             sendAsyncMessage("Browser:CertException", { url: errorDoc.location.href, action: "leave" });
           }
-        } else if (/^about:neterror\?e=netOffline/.test(errorDoc.documentURI)) {
-          if (ot == errorDoc.getElementById("errorTryAgain")) {
-            // Make sure we're online before attempting to load
-            Util.forceOnline();
-          }
         } else if (/^about:blocked/.test(errorDoc.documentURI)) {
           // The event came from a button on a malware/phishing block page
           // First check whether it's malware or phishing, so that we can
           // use the right strings/links
           let isMalware = /e=malwareBlocked/.test(errorDoc.documentURI);
     
           if (ot == errorDoc.getElementById("getMeOutButton")) {
             sendAsyncMessage("Browser:BlockedSite", { url: errorDoc.location.href, action: "leave" });
--- a/mobile/locales/en-US/chrome/overrides/netError.dtd
+++ b/mobile/locales/en-US/chrome/overrides/netError.dtd
@@ -48,17 +48,17 @@
     <strong>/</strong>).</li>
 </ul>
 ">
 
 <!ENTITY netInterrupt.title "The connection was interrupted">
 <!ENTITY netInterrupt.longDesc "&sharedLongDesc;">
 
 <!ENTITY netOffline.title "Offline mode">
-<!ENTITY netOffline.overrideLongDesc "
+<!ENTITY netOffline.longDesc2 "
 <ul>
   <li>Try again. &brandShortName; will attempt to open a connection and reload the page.</li>
 </ul>
 ">
 
 <!ENTITY contentEncodingError.title "Content Encoding Error">
 <!ENTITY contentEncodingError.longDesc "
 <ul>