Junk captive portal and directory ping
This commit is contained in:
parent
db6eb94ebb
commit
74bd1d375d
|
@ -581,9 +581,6 @@ pref("mousewheel.with_win.action", 1);
|
||||||
pref("browser.xul.error_pages.enabled", true);
|
pref("browser.xul.error_pages.enabled", true);
|
||||||
pref("browser.xul.error_pages.expert_bad_cert", false);
|
pref("browser.xul.error_pages.expert_bad_cert", false);
|
||||||
|
|
||||||
// Enable captive portal detection.
|
|
||||||
pref("network.captive-portal-service.enabled", true);
|
|
||||||
|
|
||||||
// If true, network link events will change the value of navigator.onLine
|
// If true, network link events will change the value of navigator.onLine
|
||||||
pref("network.manage-offline-status", true);
|
pref("network.manage-offline-status", true);
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,6 @@
|
||||||
// e - the error code
|
// e - the error code
|
||||||
// s - custom CSS class to allow alternate styling/favicons
|
// s - custom CSS class to allow alternate styling/favicons
|
||||||
// d - error description
|
// d - error description
|
||||||
// captive - "true" to indicate we're behind a captive portal.
|
|
||||||
// Any other value is ignored.
|
|
||||||
|
|
||||||
// Note that this file uses document.documentURI to get
|
// Note that this file uses document.documentURI to get
|
||||||
// the URL (with the format from above). This is because
|
// the URL (with the format from above). This is because
|
||||||
|
@ -59,10 +57,6 @@
|
||||||
return searchParams.get("d");
|
return searchParams.get("d");
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCaptive() {
|
|
||||||
return searchParams.get("captive") == "true";
|
|
||||||
}
|
|
||||||
|
|
||||||
function retryThis(buttonEl)
|
function retryThis(buttonEl)
|
||||||
{
|
{
|
||||||
// Note: The application may wish to handle switching off "offline mode"
|
// Note: The application may wish to handle switching off "offline mode"
|
||||||
|
@ -166,11 +160,6 @@
|
||||||
{
|
{
|
||||||
var err = getErrorCode();
|
var err = getErrorCode();
|
||||||
gIsCertError = (err == "nssBadCert");
|
gIsCertError = (err == "nssBadCert");
|
||||||
// Only worry about captive portals if this is a cert error.
|
|
||||||
let showCaptivePortalUI = isCaptive() && gIsCertError;
|
|
||||||
if (showCaptivePortalUI) {
|
|
||||||
err = "captivePortal";
|
|
||||||
}
|
|
||||||
|
|
||||||
// if it's an unknown error or there's no title or description
|
// if it's an unknown error or there's no title or description
|
||||||
// defined, get the generic message
|
// defined, get the generic message
|
||||||
|
@ -193,10 +182,7 @@
|
||||||
sd.textContent = getDescription();
|
sd.textContent = getDescription();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (showCaptivePortalUI) {
|
|
||||||
initPageCaptivePortal();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (gIsCertError) {
|
if (gIsCertError) {
|
||||||
initPageCertError();
|
initPageCertError();
|
||||||
return;
|
return;
|
||||||
|
@ -289,29 +275,6 @@
|
||||||
addDomainErrorLink();
|
addDomainErrorLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPageCaptivePortal()
|
|
||||||
{
|
|
||||||
document.body.className = "captiveportal";
|
|
||||||
document.title = document.getElementById("captivePortalPageTitle").textContent;
|
|
||||||
|
|
||||||
document.getElementById("openPortalLoginPageButton")
|
|
||||||
.addEventListener("click", () => {
|
|
||||||
let event = new CustomEvent("AboutNetErrorOpenCaptivePortal", {bubbles:true});
|
|
||||||
document.dispatchEvent(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
addAutofocus("openPortalLoginPageButton");
|
|
||||||
setupAdvancedButton(true);
|
|
||||||
|
|
||||||
addDomainErrorLink();
|
|
||||||
|
|
||||||
// When the portal is freed, an event is generated by the frame script
|
|
||||||
// that we can pick up and attempt to reload the original page.
|
|
||||||
window.addEventListener("AboutNetErrorCaptivePortalFreed", () => {
|
|
||||||
document.location.reload();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function initPageCertError() {
|
function initPageCertError() {
|
||||||
document.body.className = "certerror";
|
document.body.className = "certerror";
|
||||||
document.title = document.getElementById("certErrorPageTitle").textContent;
|
document.title = document.getElementById("certErrorPageTitle").textContent;
|
||||||
|
@ -434,13 +397,11 @@
|
||||||
<body dir="&locale.dir;">
|
<body dir="&locale.dir;">
|
||||||
<!-- Contains an alternate page title set on page init for cert errors. -->
|
<!-- Contains an alternate page title set on page init for cert errors. -->
|
||||||
<div id="certErrorPageTitle" style="display: none;">&certerror.pagetitle1;</div>
|
<div id="certErrorPageTitle" style="display: none;">&certerror.pagetitle1;</div>
|
||||||
<div id="captivePortalPageTitle" style="display: none;">&captivePortal.title;</div>
|
|
||||||
|
|
||||||
<!-- ERROR ITEM CONTAINER (removed during loading to avoid bug 39098) -->
|
<!-- ERROR ITEM CONTAINER (removed during loading to avoid bug 39098) -->
|
||||||
<div id="errorContainer">
|
<div id="errorContainer">
|
||||||
<div id="errorTitlesContainer">
|
<div id="errorTitlesContainer">
|
||||||
<h1 id="et_generic">&generic.title;</h1>
|
<h1 id="et_generic">&generic.title;</h1>
|
||||||
<h1 id="et_captivePortal">&captivePortal.title;</h1>
|
|
||||||
<h1 id="et_dnsNotFound">&dnsNotFound.title;</h1>
|
<h1 id="et_dnsNotFound">&dnsNotFound.title;</h1>
|
||||||
<h1 id="et_fileNotFound">&fileNotFound.title;</h1>
|
<h1 id="et_fileNotFound">&fileNotFound.title;</h1>
|
||||||
<h1 id="et_fileAccessDenied">&fileAccessDenied.title;</h1>
|
<h1 id="et_fileAccessDenied">&fileAccessDenied.title;</h1>
|
||||||
|
@ -470,7 +431,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="errorDescriptionsContainer">
|
<div id="errorDescriptionsContainer">
|
||||||
<div id="ed_generic">&generic.longDesc;</div>
|
<div id="ed_generic">&generic.longDesc;</div>
|
||||||
<div id="ed_captivePortal">&captivePortal.longDesc;</div>
|
|
||||||
<div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div>
|
<div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div>
|
||||||
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
|
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
|
||||||
<div id="ed_fileAccessDenied">&fileAccessDenied.longDesc;</div>
|
<div id="ed_fileAccessDenied">&fileAccessDenied.longDesc;</div>
|
||||||
|
@ -529,12 +489,6 @@
|
||||||
<button id="prefResetButton" class="primary" autocomplete="off">&prefReset.label;</button>
|
<button id="prefResetButton" class="primary" autocomplete="off">&prefReset.label;</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="certErrorAndCaptivePortalButtonContainer" class="button-container">
|
|
||||||
<button id="returnButton" class="primary" autocomplete="off">&returnToPreviousPage.label;</button>
|
|
||||||
<button id="openPortalLoginPageButton" class="primary" autocomplete="off">&openPortalLoginPage.label;</button>
|
|
||||||
<div class="button-spacer"></div>
|
|
||||||
<button id="advancedButton" autocomplete="off">&advanced.label;</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="netErrorButtonContainer" class="button-container">
|
<div id="netErrorButtonContainer" class="button-container">
|
||||||
|
|
|
@ -1,257 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, "cps",
|
|
||||||
"@mozilla.org/network/captive-portal-service;1",
|
|
||||||
"nsICaptivePortalService");
|
|
||||||
|
|
||||||
var CaptivePortalWatcher = {
|
|
||||||
/**
|
|
||||||
* This constant is chosen to be large enough for a portal recheck to complete,
|
|
||||||
* and small enough that the delay in opening a tab isn't too noticeable.
|
|
||||||
* Please see comments for _delayedCaptivePortalDetected for more details.
|
|
||||||
*/
|
|
||||||
PORTAL_RECHECK_DELAY_MS: Preferences.get("captivedetect.portalRecheckDelayMS", 500),
|
|
||||||
|
|
||||||
// This is the value used to identify the captive portal notification.
|
|
||||||
PORTAL_NOTIFICATION_VALUE: "captive-portal-detected",
|
|
||||||
|
|
||||||
// This holds a weak reference to the captive portal tab so that we
|
|
||||||
// don't leak it if the user closes it.
|
|
||||||
_captivePortalTab: null,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a portal is detected when we don't have focus, we first wait for focus
|
|
||||||
* and then add the tab if, after a recheck, the portal is still active. This
|
|
||||||
* is set to true while we wait so that in the unlikely event that we receive
|
|
||||||
* another notification while waiting, we don't do things twice.
|
|
||||||
*/
|
|
||||||
_delayedCaptivePortalDetectedInProgress: false,
|
|
||||||
|
|
||||||
// In the situation above, this is set to true while we wait for the recheck.
|
|
||||||
// This flag exists so that tests can appropriately simulate a recheck.
|
|
||||||
_waitingForRecheck: false,
|
|
||||||
|
|
||||||
get _captivePortalNotification() {
|
|
||||||
let nb = document.getElementById("high-priority-global-notificationbox");
|
|
||||||
return nb.getNotificationWithValue(this.PORTAL_NOTIFICATION_VALUE);
|
|
||||||
},
|
|
||||||
|
|
||||||
get canonicalURL() {
|
|
||||||
return Services.prefs.getCharPref("captivedetect.canonicalURL");
|
|
||||||
},
|
|
||||||
|
|
||||||
get _browserBundle() {
|
|
||||||
delete this._browserBundle;
|
|
||||||
return this._browserBundle =
|
|
||||||
Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
|
||||||
},
|
|
||||||
|
|
||||||
init() {
|
|
||||||
Services.obs.addObserver(this, "captive-portal-login", false);
|
|
||||||
Services.obs.addObserver(this, "captive-portal-login-abort", false);
|
|
||||||
Services.obs.addObserver(this, "captive-portal-login-success", false);
|
|
||||||
|
|
||||||
if (cps.state == cps.LOCKED_PORTAL) {
|
|
||||||
// A captive portal has already been detected.
|
|
||||||
this._captivePortalDetected();
|
|
||||||
|
|
||||||
// Automatically open a captive portal tab if there's no other browser window.
|
|
||||||
let windows = Services.wm.getEnumerator("navigator:browser");
|
|
||||||
if (windows.getNext() == window && !windows.hasMoreElements()) {
|
|
||||||
this.ensureCaptivePortalTab();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cps.recheckCaptivePortal();
|
|
||||||
},
|
|
||||||
|
|
||||||
uninit() {
|
|
||||||
Services.obs.removeObserver(this, "captive-portal-login");
|
|
||||||
Services.obs.removeObserver(this, "captive-portal-login-abort");
|
|
||||||
Services.obs.removeObserver(this, "captive-portal-login-success");
|
|
||||||
|
|
||||||
|
|
||||||
if (this._delayedCaptivePortalDetectedInProgress) {
|
|
||||||
Services.obs.removeObserver(this, "xul-window-visible");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
observe(aSubject, aTopic, aData) {
|
|
||||||
switch (aTopic) {
|
|
||||||
case "captive-portal-login":
|
|
||||||
this._captivePortalDetected();
|
|
||||||
break;
|
|
||||||
case "captive-portal-login-abort":
|
|
||||||
case "captive-portal-login-success":
|
|
||||||
this._captivePortalGone();
|
|
||||||
break;
|
|
||||||
case "xul-window-visible":
|
|
||||||
this._delayedCaptivePortalDetected();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_captivePortalDetected() {
|
|
||||||
if (this._delayedCaptivePortalDetectedInProgress) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
|
||||||
// If no browser window has focus, open and show the tab when we regain focus.
|
|
||||||
// This is so that if a different application was focused, when the user
|
|
||||||
// (re-)focuses a browser window, we open the tab immediately in that window
|
|
||||||
// so they can log in before continuing to browse.
|
|
||||||
if (win != Services.ww.activeWindow) {
|
|
||||||
this._delayedCaptivePortalDetectedInProgress = true;
|
|
||||||
Services.obs.addObserver(this, "xul-window-visible", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._showNotification();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after we regain focus if we detect a portal while a browser window
|
|
||||||
* doesn't have focus. Triggers a portal recheck to reaffirm state, and adds
|
|
||||||
* the tab if needed after a short delay to allow the recheck to complete.
|
|
||||||
*/
|
|
||||||
_delayedCaptivePortalDetected() {
|
|
||||||
if (!this._delayedCaptivePortalDetectedInProgress) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
|
||||||
if (win != Services.ww.activeWindow) {
|
|
||||||
// The window that got focused was not a browser window.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Services.obs.removeObserver(this, "xul-window-visible");
|
|
||||||
this._delayedCaptivePortalDetectedInProgress = false;
|
|
||||||
|
|
||||||
if (win != window) {
|
|
||||||
// Some other browser window got focus, we don't have to do anything.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Trigger a portal recheck. The user may have logged into the portal via
|
|
||||||
// another client, or changed networks.
|
|
||||||
cps.recheckCaptivePortal();
|
|
||||||
this._waitingForRecheck = true;
|
|
||||||
let requestTime = Date.now();
|
|
||||||
|
|
||||||
let self = this;
|
|
||||||
Services.obs.addObserver(function observer() {
|
|
||||||
let time = Date.now() - requestTime;
|
|
||||||
Services.obs.removeObserver(observer, "captive-portal-check-complete");
|
|
||||||
self._waitingForRecheck = false;
|
|
||||||
if (cps.state != cps.LOCKED_PORTAL) {
|
|
||||||
// We're free of the portal!
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time <= self.PORTAL_RECHECK_DELAY_MS) {
|
|
||||||
// The amount of time elapsed since we requested a recheck (i.e. since
|
|
||||||
// the browser window was focused) was small enough that we can add and
|
|
||||||
// focus a tab with the login page with no noticeable delay.
|
|
||||||
self.ensureCaptivePortalTab();
|
|
||||||
}
|
|
||||||
}, "captive-portal-check-complete", false);
|
|
||||||
},
|
|
||||||
|
|
||||||
_captivePortalGone() {
|
|
||||||
if (this._delayedCaptivePortalDetectedInProgress) {
|
|
||||||
Services.obs.removeObserver(this, "xul-window-visible");
|
|
||||||
this._delayedCaptivePortalDetectedInProgress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._removeNotification();
|
|
||||||
},
|
|
||||||
|
|
||||||
handleEvent(aEvent) {
|
|
||||||
if (aEvent.type != "TabSelect" || !this._captivePortalTab || !this._captivePortalNotification) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let tab = this._captivePortalTab.get();
|
|
||||||
let n = this._captivePortalNotification;
|
|
||||||
if (!tab || !n) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let doc = tab.ownerDocument;
|
|
||||||
let button = n.querySelector("button.notification-button");
|
|
||||||
if (doc.defaultView.gBrowser.selectedTab == tab) {
|
|
||||||
button.style.visibility = "hidden";
|
|
||||||
} else {
|
|
||||||
button.style.visibility = "visible";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_showNotification() {
|
|
||||||
let buttons = [
|
|
||||||
{
|
|
||||||
label: this._browserBundle.GetStringFromName("captivePortal.showLoginPage"),
|
|
||||||
callback: () => {
|
|
||||||
this.ensureCaptivePortalTab();
|
|
||||||
|
|
||||||
// Returning true prevents the notification from closing.
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
let message = this._browserBundle.GetStringFromName("captivePortal.infoMessage2");
|
|
||||||
|
|
||||||
let closeHandler = (aEventName) => {
|
|
||||||
if (aEventName != "removed") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gBrowser.tabContainer.removeEventListener("TabSelect", this);
|
|
||||||
};
|
|
||||||
|
|
||||||
let nb = document.getElementById("high-priority-global-notificationbox");
|
|
||||||
nb.appendNotification(message, this.PORTAL_NOTIFICATION_VALUE, "",
|
|
||||||
nb.PRIORITY_INFO_MEDIUM, buttons, closeHandler);
|
|
||||||
|
|
||||||
gBrowser.tabContainer.addEventListener("TabSelect", this);
|
|
||||||
},
|
|
||||||
|
|
||||||
_removeNotification() {
|
|
||||||
let n = this._captivePortalNotification;
|
|
||||||
if (!n || !n.parentNode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
n.close();
|
|
||||||
},
|
|
||||||
|
|
||||||
ensureCaptivePortalTab() {
|
|
||||||
let tab;
|
|
||||||
if (this._captivePortalTab) {
|
|
||||||
tab = this._captivePortalTab.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the tab is gone or going, we need to open a new one.
|
|
||||||
if (!tab || tab.closing || !tab.parentNode) {
|
|
||||||
tab = gBrowser.addTab(this.canonicalURL, { ownerTab: gBrowser.selectedTab });
|
|
||||||
this._captivePortalTab = Cu.getWeakReference(tab);
|
|
||||||
}
|
|
||||||
|
|
||||||
gBrowser.selectedTab = tab;
|
|
||||||
|
|
||||||
let canonicalURI = makeURI(this.canonicalURL);
|
|
||||||
|
|
||||||
// When we are no longer captive, close the tab if it's at the canonical URL.
|
|
||||||
let tabCloser = () => {
|
|
||||||
Services.obs.removeObserver(tabCloser, "captive-portal-login-abort");
|
|
||||||
Services.obs.removeObserver(tabCloser, "captive-portal-login-success");
|
|
||||||
if (!tab || tab.closing || !tab.parentNode || !tab.linkedBrowser ||
|
|
||||||
!tab.linkedBrowser.currentURI.equalsExceptRef(canonicalURI)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gBrowser.removeTab(tab);
|
|
||||||
}
|
|
||||||
Services.obs.addObserver(tabCloser, "captive-portal-login-abort", false);
|
|
||||||
Services.obs.addObserver(tabCloser, "captive-portal-login-success", false);
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -974,7 +974,6 @@ var gBrowserInit = {
|
||||||
AboutPrivateBrowsingListener.init();
|
AboutPrivateBrowsingListener.init();
|
||||||
TrackingProtection.init();
|
TrackingProtection.init();
|
||||||
RefreshBlocker.init();
|
RefreshBlocker.init();
|
||||||
CaptivePortalWatcher.init();
|
|
||||||
|
|
||||||
let mm = window.getGroupMessageManager("browsers");
|
let mm = window.getGroupMessageManager("browsers");
|
||||||
mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
|
mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
|
||||||
|
@ -1510,8 +1509,6 @@ var gBrowserInit = {
|
||||||
|
|
||||||
RefreshBlocker.uninit();
|
RefreshBlocker.uninit();
|
||||||
|
|
||||||
CaptivePortalWatcher.uninit();
|
|
||||||
|
|
||||||
gMenuButtonUpdateBadge.uninit();
|
gMenuButtonUpdateBadge.uninit();
|
||||||
|
|
||||||
gMenuButtonBadgeManager.uninit();
|
gMenuButtonBadgeManager.uninit();
|
||||||
|
@ -2743,16 +2740,12 @@ var BrowserOnClick = {
|
||||||
init: function () {
|
init: function () {
|
||||||
let mm = window.messageManager;
|
let mm = window.messageManager;
|
||||||
mm.addMessageListener("Browser:CertExceptionError", this);
|
mm.addMessageListener("Browser:CertExceptionError", this);
|
||||||
mm.addMessageListener("Browser:OpenCaptivePortalPage", this);
|
|
||||||
mm.addMessageListener("Browser:SiteBlockedError", this);
|
mm.addMessageListener("Browser:SiteBlockedError", this);
|
||||||
mm.addMessageListener("Browser:EnableOnlineMode", this);
|
mm.addMessageListener("Browser:EnableOnlineMode", this);
|
||||||
mm.addMessageListener("Browser:ResetSSLPreferences", this);
|
mm.addMessageListener("Browser:ResetSSLPreferences", this);
|
||||||
mm.addMessageListener("Browser:SSLErrorReportTelemetry", this);
|
mm.addMessageListener("Browser:SSLErrorReportTelemetry", this);
|
||||||
mm.addMessageListener("Browser:OverrideWeakCrypto", this);
|
mm.addMessageListener("Browser:OverrideWeakCrypto", this);
|
||||||
mm.addMessageListener("Browser:SSLErrorGoBack", this);
|
mm.addMessageListener("Browser:SSLErrorGoBack", this);
|
||||||
|
|
||||||
Services.obs.addObserver(this, "captive-portal-login-abort", false);
|
|
||||||
Services.obs.addObserver(this, "captive-portal-login-success", false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
uninit: function () {
|
uninit: function () {
|
||||||
|
@ -2764,20 +2757,6 @@ var BrowserOnClick = {
|
||||||
mm.removeMessageListener("Browser:SSLErrorReportTelemetry", this);
|
mm.removeMessageListener("Browser:SSLErrorReportTelemetry", this);
|
||||||
mm.removeMessageListener("Browser:OverrideWeakCrypto", this);
|
mm.removeMessageListener("Browser:OverrideWeakCrypto", this);
|
||||||
mm.removeMessageListener("Browser:SSLErrorGoBack", this);
|
mm.removeMessageListener("Browser:SSLErrorGoBack", this);
|
||||||
|
|
||||||
Services.obs.removeObserver(this, "captive-portal-login-abort");
|
|
||||||
Services.obs.removeObserver(this, "captive-portal-login-success");
|
|
||||||
},
|
|
||||||
|
|
||||||
observe: function(aSubject, aTopic, aData) {
|
|
||||||
switch (aTopic) {
|
|
||||||
case "captive-portal-login-abort":
|
|
||||||
case "captive-portal-login-success":
|
|
||||||
// Broadcast when a captive portal is freed so that error pages
|
|
||||||
// can refresh themselves.
|
|
||||||
window.messageManager.broadcastAsyncMessage("Browser:CaptivePortalFreed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
receiveMessage: function (msg) {
|
receiveMessage: function (msg) {
|
||||||
|
@ -2787,9 +2766,6 @@ var BrowserOnClick = {
|
||||||
msg.data.isTopFrame, msg.data.location,
|
msg.data.isTopFrame, msg.data.location,
|
||||||
msg.data.securityInfoAsString);
|
msg.data.securityInfoAsString);
|
||||||
break;
|
break;
|
||||||
case "Browser:OpenCaptivePortalPage":
|
|
||||||
CaptivePortalWatcher.ensureCaptivePortalTab();
|
|
||||||
break;
|
|
||||||
case "Browser:SiteBlockedError":
|
case "Browser:SiteBlockedError":
|
||||||
this.onAboutBlocked(msg.data.elementId, msg.data.reason,
|
this.onAboutBlocked(msg.data.elementId, msg.data.reason,
|
||||||
msg.data.isTopFrame, msg.data.location);
|
msg.data.isTopFrame, msg.data.location);
|
||||||
|
|
|
@ -264,9 +264,7 @@ function getSerializedSecurityInfo(docShell) {
|
||||||
var AboutNetAndCertErrorListener = {
|
var AboutNetAndCertErrorListener = {
|
||||||
init: function(chromeGlobal) {
|
init: function(chromeGlobal) {
|
||||||
addMessageListener("CertErrorDetails", this);
|
addMessageListener("CertErrorDetails", this);
|
||||||
addMessageListener("Browser:CaptivePortalFreed", this);
|
|
||||||
chromeGlobal.addEventListener('AboutNetErrorLoad', this, false, true);
|
chromeGlobal.addEventListener('AboutNetErrorLoad', this, false, true);
|
||||||
chromeGlobal.addEventListener('AboutNetErrorOpenCaptivePortal', this, false, true);
|
|
||||||
chromeGlobal.addEventListener('AboutNetErrorSetAutomatic', this, false, true);
|
chromeGlobal.addEventListener('AboutNetErrorSetAutomatic', this, false, true);
|
||||||
chromeGlobal.addEventListener('AboutNetErrorOverride', this, false, true);
|
chromeGlobal.addEventListener('AboutNetErrorOverride', this, false, true);
|
||||||
chromeGlobal.addEventListener('AboutNetErrorResetPreferences', this, false, true);
|
chromeGlobal.addEventListener('AboutNetErrorResetPreferences', this, false, true);
|
||||||
|
@ -289,9 +287,6 @@ var AboutNetAndCertErrorListener = {
|
||||||
case "CertErrorDetails":
|
case "CertErrorDetails":
|
||||||
this.onCertErrorDetails(msg);
|
this.onCertErrorDetails(msg);
|
||||||
break;
|
break;
|
||||||
case "Browser:CaptivePortalFreed":
|
|
||||||
this.onCaptivePortalFreed(msg);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -338,10 +333,6 @@ var AboutNetAndCertErrorListener = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onCaptivePortalFreed(msg) {
|
|
||||||
content.dispatchEvent(new content.CustomEvent("AboutNetErrorCaptivePortalFreed"));
|
|
||||||
},
|
|
||||||
|
|
||||||
handleEvent: function(aEvent) {
|
handleEvent: function(aEvent) {
|
||||||
if (!this.isAboutNetError && !this.isAboutCertError) {
|
if (!this.isAboutNetError && !this.isAboutCertError) {
|
||||||
return;
|
return;
|
||||||
|
@ -351,9 +342,6 @@ var AboutNetAndCertErrorListener = {
|
||||||
case "AboutNetErrorLoad":
|
case "AboutNetErrorLoad":
|
||||||
this.onPageLoad(aEvent);
|
this.onPageLoad(aEvent);
|
||||||
break;
|
break;
|
||||||
case "AboutNetErrorOpenCaptivePortal":
|
|
||||||
this.openCaptivePortalPage(aEvent);
|
|
||||||
break;
|
|
||||||
case "AboutNetErrorSetAutomatic":
|
case "AboutNetErrorSetAutomatic":
|
||||||
this.onSetAutomatic(aEvent);
|
this.onSetAutomatic(aEvent);
|
||||||
break;
|
break;
|
||||||
|
@ -384,11 +372,6 @@ var AboutNetAndCertErrorListener = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
openCaptivePortalPage: function(evt) {
|
|
||||||
sendAsyncMessage("Browser:OpenCaptivePortalPage");
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
onResetPreferences: function(evt) {
|
onResetPreferences: function(evt) {
|
||||||
sendAsyncMessage("Browser:ResetSSLPreferences");
|
sendAsyncMessage("Browser:ResetSSLPreferences");
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
<script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
|
<script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
|
||||||
|
|
||||||
<script type="application/javascript" src="chrome://browser/content/browser-addons.js"/>
|
<script type="application/javascript" src="chrome://browser/content/browser-addons.js"/>
|
||||||
<script type="application/javascript" src="chrome://browser/content/browser-captivePortal.js"/>
|
|
||||||
<script type="application/javascript" src="chrome://browser/content/browser-ctrlTab.js"/>
|
<script type="application/javascript" src="chrome://browser/content/browser-ctrlTab.js"/>
|
||||||
<script type="application/javascript" src="chrome://browser/content/browser-customization.js"/>
|
<script type="application/javascript" src="chrome://browser/content/browser-customization.js"/>
|
||||||
<script type="application/javascript" src="chrome://browser/content/browser-devedition.js"/>
|
<script type="application/javascript" src="chrome://browser/content/browser-devedition.js"/>
|
||||||
|
|
|
@ -11,7 +11,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource://gre/modules/PageThumbs.jsm");
|
Cu.import("resource://gre/modules/PageThumbs.jsm");
|
||||||
Cu.import("resource://gre/modules/BackgroundPageThumbs.jsm");
|
Cu.import("resource://gre/modules/BackgroundPageThumbs.jsm");
|
||||||
Cu.import("resource:///modules/DirectoryLinksProvider.jsm");
|
|
||||||
Cu.import("resource://gre/modules/NewTabUtils.jsm");
|
Cu.import("resource://gre/modules/NewTabUtils.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Rect",
|
XPCOMUtils.defineLazyModuleGetter(this, "Rect",
|
||||||
|
|
|
@ -287,8 +287,6 @@ var gPage = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryLinksProvider.reportSitesAction(sites, "view", lastIndex);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
maybeShowAutoMigrationUndoNotification() {
|
maybeShowAutoMigrationUndoNotification() {
|
||||||
|
|
|
@ -171,7 +171,7 @@ Site.prototype = {
|
||||||
// first check for end time, as it may modify the link
|
// first check for end time, as it may modify the link
|
||||||
this._checkLinkEndTime();
|
this._checkLinkEndTime();
|
||||||
// setup display variables
|
// setup display variables
|
||||||
let enhanced = gAllPages.enhanced && DirectoryLinksProvider.getEnhancedLink(this.link);
|
let enhanced = gAllPages.enhanced;
|
||||||
let url = this.url;
|
let url = this.url;
|
||||||
let title = enhanced && enhanced.title ? enhanced.title :
|
let title = enhanced && enhanced.title ? enhanced.title :
|
||||||
this.link.type == "history" ? this.link.baseDomain :
|
this.link.type == "history" ? this.link.baseDomain :
|
||||||
|
@ -244,7 +244,7 @@ Site.prototype = {
|
||||||
*/
|
*/
|
||||||
refreshThumbnail: function Site_refreshThumbnail() {
|
refreshThumbnail: function Site_refreshThumbnail() {
|
||||||
// Only enhance tiles if that feature is turned on
|
// Only enhance tiles if that feature is turned on
|
||||||
let link = gAllPages.enhanced && DirectoryLinksProvider.getEnhancedLink(this.link) ||
|
let link = gAllPages.enhanced ||
|
||||||
this.link;
|
this.link;
|
||||||
|
|
||||||
let thumbnail = this._querySelector(".newtab-thumbnail.thumbnail");
|
let thumbnail = this._querySelector(".newtab-thumbnail.thumbnail");
|
||||||
|
@ -387,12 +387,6 @@ Site.prototype = {
|
||||||
else if (button == 0) {
|
else if (button == 0) {
|
||||||
aEvent.preventDefault();
|
aEvent.preventDefault();
|
||||||
if (target.classList.contains("newtab-control-block")) {
|
if (target.classList.contains("newtab-control-block")) {
|
||||||
// Notify DirectoryLinksProvider of suggested tile block, this may
|
|
||||||
// affect if and how suggested tiles are recommended and needs to
|
|
||||||
// be reported before pages are updated inside block() call
|
|
||||||
if (this.link.targetedSite) {
|
|
||||||
DirectoryLinksProvider.handleSuggestedTileBlock();
|
|
||||||
}
|
|
||||||
this.block();
|
this.block();
|
||||||
action = "block";
|
action = "block";
|
||||||
}
|
}
|
||||||
|
@ -413,11 +407,6 @@ Site.prototype = {
|
||||||
action = "pin";
|
action = "pin";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report all link click actions
|
|
||||||
if (action) {
|
|
||||||
DirectoryLinksProvider.reportSitesAction(gGrid.sites, action, tileIndex);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -68,7 +68,6 @@ browser.jar:
|
||||||
* content/browser/browser.js (content/browser.js)
|
* content/browser/browser.js (content/browser.js)
|
||||||
* content/browser/browser.xul (content/browser.xul)
|
* content/browser/browser.xul (content/browser.xul)
|
||||||
content/browser/browser-addons.js (content/browser-addons.js)
|
content/browser/browser-addons.js (content/browser-addons.js)
|
||||||
content/browser/browser-captivePortal.js (content/browser-captivePortal.js)
|
|
||||||
content/browser/browser-ctrlTab.js (content/browser-ctrlTab.js)
|
content/browser/browser-ctrlTab.js (content/browser-ctrlTab.js)
|
||||||
content/browser/browser-customization.js (content/browser-customization.js)
|
content/browser/browser-customization.js (content/browser-customization.js)
|
||||||
content/browser/browser-data-submission-info-bar.js (content/browser-data-submission-info-bar.js)
|
content/browser/browser-data-submission-info-bar.js (content/browser-data-submission-info-bar.js)
|
||||||
|
|
|
@ -32,7 +32,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", "@mozilla.org/alerts-s
|
||||||
["ContentPrefServiceParent", "resource://gre/modules/ContentPrefServiceParent.jsm"],
|
["ContentPrefServiceParent", "resource://gre/modules/ContentPrefServiceParent.jsm"],
|
||||||
["ContentSearch", "resource:///modules/ContentSearch.jsm"],
|
["ContentSearch", "resource:///modules/ContentSearch.jsm"],
|
||||||
["DateTimePickerHelper", "resource://gre/modules/DateTimePickerHelper.jsm"],
|
["DateTimePickerHelper", "resource://gre/modules/DateTimePickerHelper.jsm"],
|
||||||
["DirectoryLinksProvider", "resource:///modules/DirectoryLinksProvider.jsm"],
|
|
||||||
["Feeds", "resource:///modules/Feeds.jsm"],
|
["Feeds", "resource:///modules/Feeds.jsm"],
|
||||||
["FileUtils", "resource://gre/modules/FileUtils.jsm"],
|
["FileUtils", "resource://gre/modules/FileUtils.jsm"],
|
||||||
["FormValidationHandler", "resource:///modules/FormValidationHandler.jsm"],
|
["FormValidationHandler", "resource:///modules/FormValidationHandler.jsm"],
|
||||||
|
@ -657,9 +656,7 @@ BrowserGlue.prototype = {
|
||||||
webrtcUI.init();
|
webrtcUI.init();
|
||||||
AboutHome.init();
|
AboutHome.init();
|
||||||
|
|
||||||
DirectoryLinksProvider.init();
|
|
||||||
NewTabUtils.init();
|
NewTabUtils.init();
|
||||||
NewTabUtils.links.addProvider(DirectoryLinksProvider);
|
|
||||||
AboutNewTab.init();
|
AboutNewTab.init();
|
||||||
|
|
||||||
NewTabMessages.init();
|
NewTabMessages.init();
|
||||||
|
|
|
@ -1,278 +0,0 @@
|
||||||
=============================================
|
|
||||||
Directory Links Architecture and Data Formats
|
|
||||||
=============================================
|
|
||||||
|
|
||||||
Directory links are enhancements to the new tab experience that combine content
|
|
||||||
Firefox already knows about from user browsing with external content. There are
|
|
||||||
3 kinds of links:
|
|
||||||
|
|
||||||
- directory links fill in additional tiles on the new tab page if there would
|
|
||||||
have been empty tiles because the user has a clean profile or cleared history
|
|
||||||
- suggested links are shown if certain triggering criteria matches the user's
|
|
||||||
browsing behavior, i.e., if the user has a top site that matches one of
|
|
||||||
several possible sites. E.g., only show a sports suggestion if the user has a
|
|
||||||
sport site as a top site
|
|
||||||
- enhanced links replace a matching user's visible history tile from the same
|
|
||||||
site but only the visual aspects: title, image, and rollover image
|
|
||||||
|
|
||||||
To power the above features, DirectoryLinksProvider module downloads, at most
|
|
||||||
once per 24 hours, the directory source links as JSON with enough data for
|
|
||||||
Firefox to determine what should be shown or not. This module also handles
|
|
||||||
reporting back data about the tiles via asynchronous pings that don't return
|
|
||||||
data from the server.
|
|
||||||
|
|
||||||
For the directory source and ping endpoints, the default preference values point
|
|
||||||
to Mozilla key-pinned servers with encryption. No cookies are set by the servers
|
|
||||||
and Firefox enforces this by making anonymous requests.
|
|
||||||
|
|
||||||
- default directory source endpoint:
|
|
||||||
https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%
|
|
||||||
- default directory ping endpoint: https://tiles.services.mozilla.com/v3/links/
|
|
||||||
|
|
||||||
|
|
||||||
Preferences
|
|
||||||
===========
|
|
||||||
|
|
||||||
There are two main preferences that control downloading links and reporting
|
|
||||||
metrics.
|
|
||||||
|
|
||||||
``browser.newtabpage.directory.source``
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
This endpoint tells Firefox where to download directory source file as a GET
|
|
||||||
request. It should return JSON of the appropriate format containing the relevant
|
|
||||||
links data. The value can be a data URI, e.g., an empty JSON object effectively
|
|
||||||
turns off remote downloading: ``data:text/plain,{}``
|
|
||||||
|
|
||||||
The preference value will have %LOCALE% and %CHANNEL% replaced by the
|
|
||||||
appropriate values for the build of Firefox, e.g.,
|
|
||||||
|
|
||||||
- directory source endpoint:
|
|
||||||
https://tiles.services.mozilla.com/v3/links/fetch/en-US/release
|
|
||||||
|
|
||||||
``browser.newtabpage.directory.ping``
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
This endpoint tells Firefox where to report Tiles metrics as a POST request. The
|
|
||||||
data is sent as a JSON blob. Setting it to empty effectively turns off reporting
|
|
||||||
of Tiles data.
|
|
||||||
|
|
||||||
A path segment will be appended to the endpoint of "view" or "click" depending
|
|
||||||
on the type of ping, e.g.,
|
|
||||||
|
|
||||||
- ``view`` ping endpoint: https://tiles.services.mozilla.com/v3/links/view
|
|
||||||
- ``click`` ping endpoint: https://tiles.services.mozilla.com/v3/links/click
|
|
||||||
|
|
||||||
|
|
||||||
Data Flow
|
|
||||||
=========
|
|
||||||
|
|
||||||
When Firefox starts, it checks for a cached directory source file. If one
|
|
||||||
exists, it checks for its timestamp to determine if a new file should be
|
|
||||||
downloaded.
|
|
||||||
|
|
||||||
If a directory source file needs to be downloaded, a GET request is made then
|
|
||||||
cacheed and unpacked the JSON into the different types of links. Various checks
|
|
||||||
filter out invalid links, e.g., those with http-hosted images or those that
|
|
||||||
don't fit the allowed suggestions.
|
|
||||||
|
|
||||||
When a new tab page is built, DirectoryLinksProvider module provides additional
|
|
||||||
link data that is combined with history link data to determine which links can
|
|
||||||
be displayed or not.
|
|
||||||
|
|
||||||
When a new tab page is shown, a ``view`` ping is sent with relevant tiles data.
|
|
||||||
Similarly, when the user clicks on various parts of tiles (to load the page,
|
|
||||||
pin, block, etc.), a ``click`` ping is sent with similar data. Both of these can
|
|
||||||
trigger downloading of fresh directory source links if 24 hours have elapsed
|
|
||||||
since last download.
|
|
||||||
|
|
||||||
Users can turn off the ping with in-new-tab-page controls.
|
|
||||||
|
|
||||||
As the new tab page is rendered, any images for tiles are downloaded if not
|
|
||||||
already cached. The default servers hosting the images are Mozilla CDN that
|
|
||||||
don't use cookies: https://tiles.cdn.mozilla.net/ and Firefox enforces that the
|
|
||||||
images come from mozilla.net or data URIs when using the default directory
|
|
||||||
source.
|
|
||||||
|
|
||||||
|
|
||||||
Source JSON Format
|
|
||||||
==================
|
|
||||||
|
|
||||||
Firefox expects links data in a JSON object with top level keys each providing
|
|
||||||
an array of tile objects. The keys correspond to the different types of links:
|
|
||||||
``directory``, ``suggested``, and ``enhanced``.
|
|
||||||
|
|
||||||
Example
|
|
||||||
-------
|
|
||||||
|
|
||||||
Below is an example directory source file::
|
|
||||||
|
|
||||||
{
|
|
||||||
"directory": [
|
|
||||||
{
|
|
||||||
"bgColor": "",
|
|
||||||
"directoryId": 498,
|
|
||||||
"enhancedImageURI": "https://tiles.cdn.mozilla.net/images/d11ba0b3095bb19d8092cd29be9cbb9e197671ea.28088.png",
|
|
||||||
"imageURI": "https://tiles.cdn.mozilla.net/images/1332a68badf11e3f7f69bf7364e79c0a7e2753bc.5316.png",
|
|
||||||
"title": "Mozilla Community",
|
|
||||||
"type": "affiliate",
|
|
||||||
"url": "http://contribute.mozilla.org/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"enhanced": [
|
|
||||||
{
|
|
||||||
"bgColor": "",
|
|
||||||
"directoryId": 776,
|
|
||||||
"enhancedImageURI": "https://tiles.cdn.mozilla.net/images/44a14fc405cebc299ead86514dff0e3735c8cf65.10814.png",
|
|
||||||
"imageURI": "https://tiles.cdn.mozilla.net/images/20e24aa2219ec7542cc8cf0fd79f0c81e16ebeac.11859.png",
|
|
||||||
"title": "TurboTax",
|
|
||||||
"type": "sponsored",
|
|
||||||
"url": "https://turbotax.intuit.com/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"suggested": [
|
|
||||||
{
|
|
||||||
"adgroup_name": "open-source browser",
|
|
||||||
"bgColor": "#cae1f4",
|
|
||||||
"check_inadjacency": true,
|
|
||||||
"directoryId": 702,
|
|
||||||
"explanation": "Suggested for %1$S enthusiasts who visit sites like %2$S",
|
|
||||||
"frecent_sites": [
|
|
||||||
"addons.mozilla.org",
|
|
||||||
"air.mozilla.org",
|
|
||||||
"blog.mozilla.org",
|
|
||||||
"bugzilla.mozilla.org",
|
|
||||||
"developer.mozilla.org",
|
|
||||||
"etherpad.mozilla.org",
|
|
||||||
"hacks.mozilla.org",
|
|
||||||
"hg.mozilla.org",
|
|
||||||
"mozilla.org",
|
|
||||||
"planet.mozilla.org",
|
|
||||||
"quality.mozilla.org",
|
|
||||||
"support.mozilla.org",
|
|
||||||
"treeherder.mozilla.org",
|
|
||||||
"wiki.mozilla.org"
|
|
||||||
],
|
|
||||||
"frequency_caps": {"daily": 3, "total": 10},
|
|
||||||
"imageURI": "https://tiles.cdn.mozilla.net/images/9ee2b265678f2775de2e4bf680df600b502e6038.3875.png",
|
|
||||||
"time_limits": {"start": "2014-01-01T00:00:00.000Z", "end": "2014-02-01T00:00:00.000Z"},
|
|
||||||
"title": "Thanks for testing!",
|
|
||||||
"type": "affiliate",
|
|
||||||
"url": "https://www.mozilla.com/firefox/tiles"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
Link Object
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Each link object has various values that Firefox uses to display a tile:
|
|
||||||
|
|
||||||
- ``url`` - string url for the page to be loaded when the tile is clicked. Only
|
|
||||||
https and http URLs are allowed.
|
|
||||||
- ``title`` - string that appears below the tile.
|
|
||||||
- ``type`` - string relationship of the link to Mozilla. Expected values:
|
|
||||||
affiliate, organic, sponsored.
|
|
||||||
- ``imageURI`` - string url for the tile image to show. Only https and data URIs
|
|
||||||
are allowed.
|
|
||||||
- ``enhancedImageURI`` - string url for the image to be shown before the user
|
|
||||||
hovers. Only https and data URIs are allowed.
|
|
||||||
- ``bgColor`` - string css color for additional fill background color.
|
|
||||||
- ``directoryId`` - id of the tile to be used during ping reporting
|
|
||||||
|
|
||||||
Suggested Link Object Extras
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
A suggested link has additional values:
|
|
||||||
|
|
||||||
- ``adgroup_name`` - string to override the hardcoded display name of the
|
|
||||||
triggering set of sites in Firefox.
|
|
||||||
- ``check_inadjacency`` - boolean if true prevents the suggested link from being
|
|
||||||
shown if the new tab page is showing a site from an inadjacency list.
|
|
||||||
- ``explanation`` - string to override the default explanation that appears
|
|
||||||
below a Suggested Tile. %1$S is replaced by the triggering adgroup name and
|
|
||||||
%2$S is replaced by the triggering site.
|
|
||||||
- ``frecent_sites`` - array of strings of the sites that can trigger showing a
|
|
||||||
Suggested Tile if the user has the site in one of the top 100 most-frecent
|
|
||||||
pages.
|
|
||||||
- ``frequency_caps`` - an object consisting of daily and total frequency caps
|
|
||||||
that limit the number of times a Suggested Tile can be shown in the new tab
|
|
||||||
per day and overall.
|
|
||||||
- ``time_limits`` - an object consisting of start and end timestamps specifying
|
|
||||||
when a Suggested Tile may start and has to stop showing in the newtab.
|
|
||||||
The timestamp is expected in ISO_8601 format: '2014-01-10T20:00:00.000Z'
|
|
||||||
|
|
||||||
The inadjacency list is packaged with Firefox as base64-encoded 1-way-hashed
|
|
||||||
sites that tend to have adult, gambling, alcohol, drug, and similar content.
|
|
||||||
Its location: chrome://browser/content/newtab/newTab.inadjacent.json
|
|
||||||
|
|
||||||
The preapproved arrays follow a policy for determining what topic grouping is
|
|
||||||
allowed as well as the composition of a grouping. The topics are broad
|
|
||||||
uncontroversial categories, e.g., Mobile Phone, News, Technology, Video Game,
|
|
||||||
Web Development. There are at least 5 sites within a grouping, and as many
|
|
||||||
popular sites relevant to the topic are included to avoid having one site be
|
|
||||||
clearly dominant. These requirements provide some deniability of which site
|
|
||||||
actually triggered a suggestion during ping reporting, so it's more difficult to
|
|
||||||
determine if a user has gone to a specific site.
|
|
||||||
|
|
||||||
|
|
||||||
Ping JSON Format
|
|
||||||
================
|
|
||||||
|
|
||||||
Firefox reports back an action and the state of tiles on the new tab page based
|
|
||||||
on the user opening a new tab or clicking a tile. The top level keys of the
|
|
||||||
ping:
|
|
||||||
|
|
||||||
- ``locale`` - string locale of the Firefox build
|
|
||||||
- ``tiles`` - array of tiles ping objects
|
|
||||||
|
|
||||||
An additional key at the top level indicates which action triggered the ping.
|
|
||||||
The value associated to the action key is the 0-based index into the tiles array
|
|
||||||
of which tile triggered the action. Valid actions: block, click, pin, sponsored,
|
|
||||||
sponsored_link, unpin, view. E.g., if the second tile is being clicked, the ping
|
|
||||||
will have ``"click": 1``
|
|
||||||
|
|
||||||
Example
|
|
||||||
-------
|
|
||||||
|
|
||||||
Below is an example ``click`` ping with 3 tiles: a pinned suggested tile
|
|
||||||
followed by a history tile and a directory tile. The first tile is being
|
|
||||||
blocked::
|
|
||||||
|
|
||||||
{
|
|
||||||
"locale": "en-US",
|
|
||||||
"tiles": [
|
|
||||||
{
|
|
||||||
"id": 702,
|
|
||||||
"pin": 1,
|
|
||||||
"past_impressions": {"total": 5, "daily": 1},
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
"id": 498,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"block": 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Tiles Ping Object
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Each tile of the new tab page is reported back as part of the ping with some or
|
|
||||||
none of the following optional values:
|
|
||||||
|
|
||||||
- ``id`` - id that was provided as part of the downloaded link object (for all
|
|
||||||
types of links: directory, suggested, enhanced); not present if the tile was
|
|
||||||
created from user behavior, e.g., visiting pages
|
|
||||||
- ``past_impressions`` - number of impressions (new tab "views") a suggested
|
|
||||||
tile was shown before it was clicked, pinned or blocked. Where the "total"
|
|
||||||
counter is the overall number of impressions accumulated prior to a click action,
|
|
||||||
and "daily" counter is the number impressions occurred on same calendar day of
|
|
||||||
a click. This infomration is submitted once per a suggested tile upon click,
|
|
||||||
pin or block
|
|
||||||
- ``pinned`` - 1 if the tile is pinned; not present otherwise
|
|
||||||
- ``pos`` - integer position if the tile is not in the natural order, e.g., a
|
|
||||||
pinned tile after an empty slot; not present otherwise
|
|
||||||
- ``score`` - integer truncated score based on the tile's frecency; not present
|
|
||||||
if 0
|
|
||||||
- ``url`` - empty string if it's an enhanced tile; not present otherwise
|
|
|
@ -282,7 +282,6 @@
|
||||||
@RESPATH@/components/saxparser.xpt
|
@RESPATH@/components/saxparser.xpt
|
||||||
@RESPATH@/browser/components/sessionstore.xpt
|
@RESPATH@/browser/components/sessionstore.xpt
|
||||||
@RESPATH@/components/services-crypto-component.xpt
|
@RESPATH@/components/services-crypto-component.xpt
|
||||||
@RESPATH@/components/captivedetect.xpt
|
|
||||||
@RESPATH@/browser/components/shellservice.xpt
|
@RESPATH@/browser/components/shellservice.xpt
|
||||||
@RESPATH@/components/shistory.xpt
|
@RESPATH@/components/shistory.xpt
|
||||||
@RESPATH@/components/spellchecker.xpt
|
@RESPATH@/components/spellchecker.xpt
|
||||||
|
@ -487,8 +486,6 @@
|
||||||
@RESPATH@/components/Weave.js
|
@RESPATH@/components/Weave.js
|
||||||
@RESPATH@/components/FxAccountsComponents.manifest
|
@RESPATH@/components/FxAccountsComponents.manifest
|
||||||
@RESPATH@/components/FxAccountsPush.js
|
@RESPATH@/components/FxAccountsPush.js
|
||||||
@RESPATH@/components/CaptivePortalDetectComponents.manifest
|
|
||||||
@RESPATH@/components/captivedetect.js
|
|
||||||
@RESPATH@/components/servicesComponents.manifest
|
@RESPATH@/components/servicesComponents.manifest
|
||||||
@RESPATH@/components/cryptoComponents.manifest
|
@RESPATH@/components/cryptoComponents.manifest
|
||||||
@RESPATH@/components/TelemetryStartup.js
|
@RESPATH@/components/TelemetryStartup.js
|
||||||
|
|
|
@ -695,17 +695,6 @@ decoder.noHWAcceleration.message = To improve video quality, you may need to ins
|
||||||
decoder.noPulseAudio.message = To play audio, you may need to install the required PulseAudio software.
|
decoder.noPulseAudio.message = To play audio, you may need to install the required PulseAudio software.
|
||||||
decoder.unsupportedLibavcodec.message = libavcodec may be vulnerable or is not supported, and should be updated to play video.
|
decoder.unsupportedLibavcodec.message = libavcodec may be vulnerable or is not supported, and should be updated to play video.
|
||||||
|
|
||||||
# LOCALIZATION NOTE (captivePortal.infoMessage,
|
|
||||||
# captivePortal.infoMessage2):
|
|
||||||
# Shown in a notification bar when we detect a captive portal is blocking network access
|
|
||||||
# and requires the user to log in before browsing. %1$S is replaced with brandShortName.
|
|
||||||
captivePortal.infoMessage = This network may require you to login to use the internet. %1$S has opened the login page for you.
|
|
||||||
captivePortal.infoMessage2 = This network may require you to login to use the internet.
|
|
||||||
# LOCALIZATION NOTE (captivePortal.showLoginPage):
|
|
||||||
# The label for a button shown in the info bar in all tabs except the login page tab.
|
|
||||||
# The button shows the portal login page tab when clicked.
|
|
||||||
captivePortal.showLoginPage = Show Login Page
|
|
||||||
|
|
||||||
permissions.remove.tooltip = Clear this permission and ask again
|
permissions.remove.tooltip = Clear this permission and ask again
|
||||||
|
|
||||||
# LOCALIZATION NOTE (aboutDialog.architecture.*):
|
# LOCALIZATION NOTE (aboutDialog.architecture.*):
|
||||||
|
|
|
@ -51,13 +51,6 @@
|
||||||
<p>&brandShortName; can’t load this page for some reason.</p>
|
<p>&brandShortName; can’t load this page for some reason.</p>
|
||||||
">
|
">
|
||||||
|
|
||||||
<!ENTITY captivePortal.title "Login to network">
|
|
||||||
<!ENTITY captivePortal.longDesc "
|
|
||||||
<p>This network may require you to login to access the internet.</p>
|
|
||||||
">
|
|
||||||
|
|
||||||
<!ENTITY openPortalLoginPage.label "Open Login Page">
|
|
||||||
|
|
||||||
<!ENTITY malformedURI.title "The address isn’t valid">
|
<!ENTITY malformedURI.title "The address isn’t valid">
|
||||||
<!ENTITY malformedURI.longDesc "
|
<!ENTITY malformedURI.longDesc "
|
||||||
<ul>
|
<ul>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,7 +16,6 @@ EXTRA_JS_MODULES += [
|
||||||
'ContentObservers.jsm',
|
'ContentObservers.jsm',
|
||||||
'ContentSearch.jsm',
|
'ContentSearch.jsm',
|
||||||
'ContentWebRTC.jsm',
|
'ContentWebRTC.jsm',
|
||||||
'DirectoryLinksProvider.jsm',
|
|
||||||
'E10SUtils.jsm',
|
'E10SUtils.jsm',
|
||||||
'Feeds.jsm',
|
'Feeds.jsm',
|
||||||
'FormSubmitObserver.jsm',
|
'FormSubmitObserver.jsm',
|
||||||
|
|
|
@ -16,10 +16,6 @@ body.certerror {
|
||||||
#f0d000 66%, #f0d000);
|
#f0d000 66%, #f0d000);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.captiveportal .title {
|
|
||||||
background-image: url("wifi.svg");
|
|
||||||
}
|
|
||||||
|
|
||||||
body.certerror .title {
|
body.certerror .title {
|
||||||
background-image: url("cert-error.svg");
|
background-image: url("cert-error.svg");
|
||||||
}
|
}
|
||||||
|
@ -39,13 +35,6 @@ button:disabled {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#certErrorAndCaptivePortalButtonContainer {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body:not(.neterror) #certErrorAndCaptivePortalButtonContainer {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
body:not(.neterror) #netErrorButtonContainer {
|
body:not(.neterror) #netErrorButtonContainer {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -64,14 +53,6 @@ body:not(.neterror) #netErrorButtonContainer {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.captiveportal #returnButton {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body:not(.captiveportal) #openPortalLoginPageButton {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#openPortalLoginPageButton {
|
#openPortalLoginPageButton {
|
||||||
margin-inline-start: 0;
|
margin-inline-start: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,6 @@
|
||||||
#endif
|
#endif
|
||||||
<preference id="pref.general.compatmode" name="general.useragent.compatMode" type="int"/>
|
<preference id="pref.general.compatmode" name="general.useragent.compatMode" type="int"/>
|
||||||
|
|
||||||
<preference id="pref.general.captiveportal" name="network.captive-portal-service.enabled" type="bool"/>
|
|
||||||
|
|
||||||
<!-- Network tab -->
|
<!-- Network tab -->
|
||||||
<preference id="browser.cache.disk.capacity" name="browser.cache.disk.capacity" type="int"/>
|
<preference id="browser.cache.disk.capacity" name="browser.cache.disk.capacity" type="int"/>
|
||||||
|
|
||||||
|
@ -181,7 +179,6 @@
|
||||||
</hbox>
|
</hbox>
|
||||||
</groupbox>
|
</groupbox>
|
||||||
#endif
|
#endif
|
||||||
<!-- User Agent compatibility -->
|
|
||||||
<groupbox id="UACompatGroup" orient="vertical">
|
<groupbox id="UACompatGroup" orient="vertical">
|
||||||
<caption label="&UACompatGroup.label;"/>
|
<caption label="&UACompatGroup.label;"/>
|
||||||
<hbox align="center">
|
<hbox align="center">
|
||||||
|
@ -195,15 +192,6 @@
|
||||||
</menulist>
|
</menulist>
|
||||||
</hbox>
|
</hbox>
|
||||||
</groupbox>
|
</groupbox>
|
||||||
|
|
||||||
<!-- Captive portal detection -->
|
|
||||||
<groupbox id="captivePortalGroup" orient="vertical">
|
|
||||||
<caption label="&captivePortalGroup.label;"/>
|
|
||||||
<checkbox id="captivePortalDetect"
|
|
||||||
label="&captivePortalDetect.label;"
|
|
||||||
preference="pref.general.captiveportal"/>
|
|
||||||
</groupbox>
|
|
||||||
|
|
||||||
</tabpanel>
|
</tabpanel>
|
||||||
|
|
||||||
<!-- Network -->
|
<!-- Network -->
|
||||||
|
|
|
@ -39,9 +39,6 @@
|
||||||
<!ENTITY UACompat.Gecko "Gecko Compatibility">
|
<!ENTITY UACompat.Gecko "Gecko Compatibility">
|
||||||
<!ENTITY UACompat.Firefox "Firefox Compatibility">
|
<!ENTITY UACompat.Firefox "Firefox Compatibility">
|
||||||
|
|
||||||
<!ENTITY captivePortalGroup.label "Captive portals">
|
|
||||||
<!ENTITY captivePortalDetect.label "Detect restricted network access">
|
|
||||||
|
|
||||||
<!ENTITY dataChoicesTab.label "Data Choices">
|
<!ENTITY dataChoicesTab.label "Data Choices">
|
||||||
|
|
||||||
<!ENTITY crashReporterSection.label "Crash Reporter">
|
<!ENTITY crashReporterSection.label "Crash Reporter">
|
||||||
|
|
|
@ -51,13 +51,6 @@
|
||||||
<p>&brandShortName; can’t load this page for some reason.</p>
|
<p>&brandShortName; can’t load this page for some reason.</p>
|
||||||
">
|
">
|
||||||
|
|
||||||
<!ENTITY captivePortal.title "Login to network">
|
|
||||||
<!ENTITY captivePortal.longDesc "
|
|
||||||
<p>This network may require you to login to access the internet.</p>
|
|
||||||
">
|
|
||||||
|
|
||||||
<!ENTITY openPortalLoginPage.label "Open Login Page">
|
|
||||||
|
|
||||||
<!ENTITY malformedURI.title "The address isn't valid">
|
<!ENTITY malformedURI.title "The address isn't valid">
|
||||||
<!ENTITY malformedURI.longDesc "
|
<!ENTITY malformedURI.longDesc "
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
#include "nsArray.h"
|
#include "nsArray.h"
|
||||||
#include "nsArrayUtils.h"
|
#include "nsArrayUtils.h"
|
||||||
#include "nsContentSecurityManager.h"
|
#include "nsContentSecurityManager.h"
|
||||||
#include "nsICaptivePortalService.h"
|
|
||||||
#include "nsIDOMStorage.h"
|
#include "nsIDOMStorage.h"
|
||||||
#include "nsIContentViewer.h"
|
#include "nsIContentViewer.h"
|
||||||
#include "nsIDocumentLoaderFactory.h"
|
#include "nsIDocumentLoaderFactory.h"
|
||||||
|
@ -5306,13 +5305,6 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
|
||||||
errorPageUrl.AppendASCII(manifestParam.get());
|
errorPageUrl.AppendASCII(manifestParam.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
|
|
||||||
int32_t cpsState;
|
|
||||||
if (cps && NS_SUCCEEDED(cps->GetState(&cpsState)) &&
|
|
||||||
cpsState == nsICaptivePortalService::LOCKED_PORTAL) {
|
|
||||||
errorPageUrl.AppendLiteral("&captive=true");
|
|
||||||
}
|
|
||||||
|
|
||||||
// netError.xhtml's getDescription only handles the "d" parameter at the
|
// netError.xhtml's getDescription only handles the "d" parameter at the
|
||||||
// end of the URL, so append it last.
|
// end of the URL, so append it last.
|
||||||
errorPageUrl.AppendLiteral("&d=");
|
errorPageUrl.AppendLiteral("&d=");
|
||||||
|
|
|
@ -52,7 +52,6 @@
|
||||||
#include "mozilla/layers/ImageBridgeChild.h"
|
#include "mozilla/layers/ImageBridgeChild.h"
|
||||||
#include "mozilla/layout/RenderFrameChild.h"
|
#include "mozilla/layout/RenderFrameChild.h"
|
||||||
#include "mozilla/net/NeckoChild.h"
|
#include "mozilla/net/NeckoChild.h"
|
||||||
#include "mozilla/net/CaptivePortalService.h"
|
|
||||||
#include "mozilla/plugins/PluginInstanceParent.h"
|
#include "mozilla/plugins/PluginInstanceParent.h"
|
||||||
#include "mozilla/plugins/PluginModuleParent.h"
|
#include "mozilla/plugins/PluginModuleParent.h"
|
||||||
#include "mozilla/widget/WidgetMessageUtils.h"
|
#include "mozilla/widget/WidgetMessageUtils.h"
|
||||||
|
@ -887,15 +886,13 @@ ContentChild::InitXPCOM()
|
||||||
StructuredCloneData initialData;
|
StructuredCloneData initialData;
|
||||||
OptionalURIParams userContentSheetURL;
|
OptionalURIParams userContentSheetURL;
|
||||||
|
|
||||||
int32_t captivePortalState;
|
SendGetXPCOMProcessAttributes(&isOffline, &isConnected,
|
||||||
SendGetXPCOMProcessAttributes(&isOffline, &isConnected, &captivePortalState,
|
|
||||||
&isLangRTL, &haveBidiKeyboards,
|
&isLangRTL, &haveBidiKeyboards,
|
||||||
&mAvailableDictionaries,
|
&mAvailableDictionaries,
|
||||||
&clipboardCaps, &domainPolicy, &initialData,
|
&clipboardCaps, &domainPolicy, &initialData,
|
||||||
&userContentSheetURL);
|
&userContentSheetURL);
|
||||||
RecvSetOffline(isOffline);
|
RecvSetOffline(isOffline);
|
||||||
RecvSetConnectivity(isConnected);
|
RecvSetConnectivity(isConnected);
|
||||||
RecvSetCaptivePortalState(captivePortalState);
|
|
||||||
RecvBidiKeyboardNotify(isLangRTL, haveBidiKeyboards);
|
RecvBidiKeyboardNotify(isLangRTL, haveBidiKeyboards);
|
||||||
|
|
||||||
// Create the CPOW manager as soon as possible.
|
// Create the CPOW manager as soon as possible.
|
||||||
|
@ -1816,21 +1813,6 @@ ContentChild::RecvSetConnectivity(const bool& connectivity)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
ContentChild::RecvSetCaptivePortalState(const int32_t& aState)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
|
|
||||||
if (!cps) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::net::CaptivePortalService *portal =
|
|
||||||
static_cast<mozilla::net::CaptivePortalService*>(cps.get());
|
|
||||||
portal->SetStateInChild(aState);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ContentChild::ActorDestroy(ActorDestroyReason why)
|
ContentChild::ActorDestroy(ActorDestroyReason why)
|
||||||
{
|
{
|
||||||
|
|
|
@ -341,7 +341,6 @@ public:
|
||||||
virtual bool RecvSetOffline(const bool& offline) override;
|
virtual bool RecvSetOffline(const bool& offline) override;
|
||||||
|
|
||||||
virtual bool RecvSetConnectivity(const bool& connectivity) override;
|
virtual bool RecvSetConnectivity(const bool& connectivity) override;
|
||||||
virtual bool RecvSetCaptivePortalState(const int32_t& state) override;
|
|
||||||
|
|
||||||
virtual bool RecvNotifyLayerAllocated(const dom::TabId& aTabId, const uint64_t& aLayersId) override;
|
virtual bool RecvNotifyLayerAllocated(const dom::TabId& aTabId, const uint64_t& aLayersId) override;
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,6 @@
|
||||||
#include "mozilla/StyleSheet.h"
|
#include "mozilla/StyleSheet.h"
|
||||||
#include "mozilla/StyleSheetInlines.h"
|
#include "mozilla/StyleSheetInlines.h"
|
||||||
#include "nsHostObjectProtocolHandler.h"
|
#include "nsHostObjectProtocolHandler.h"
|
||||||
#include "nsICaptivePortalService.h"
|
|
||||||
|
|
||||||
#include "nsIBidiKeyboard.h"
|
#include "nsIBidiKeyboard.h"
|
||||||
|
|
||||||
|
@ -493,7 +492,6 @@ static const char* sObserverTopics[] = {
|
||||||
"profile-before-change",
|
"profile-before-change",
|
||||||
NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
|
NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
|
||||||
NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
|
NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
|
||||||
NS_IPC_CAPTIVE_PORTAL_SET_STATE,
|
|
||||||
"memory-pressure",
|
"memory-pressure",
|
||||||
"child-gc-request",
|
"child-gc-request",
|
||||||
"child-cc-request",
|
"child-cc-request",
|
||||||
|
@ -2532,17 +2530,6 @@ ContentParent::Observe(nsISupports* aSubject,
|
||||||
if (!SendSetConnectivity(NS_LITERAL_STRING("true").Equals(aData))) {
|
if (!SendSetConnectivity(NS_LITERAL_STRING("true").Equals(aData))) {
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
} else if (!strcmp(aTopic, NS_IPC_CAPTIVE_PORTAL_SET_STATE)) {
|
|
||||||
nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
|
|
||||||
MOZ_ASSERT(cps, "Should QI to a captive portal service");
|
|
||||||
if (!cps) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
int32_t state;
|
|
||||||
cps->GetState(&state);
|
|
||||||
if (!SendSetCaptivePortalState(state)) {
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// listening for alert notifications
|
// listening for alert notifications
|
||||||
else if (!strcmp(aTopic, "alertfinished") ||
|
else if (!strcmp(aTopic, "alertfinished") ||
|
||||||
|
@ -2629,7 +2616,6 @@ ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
|
||||||
bool
|
bool
|
||||||
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||||
bool* aIsConnected,
|
bool* aIsConnected,
|
||||||
int32_t* aCaptivePortalState,
|
|
||||||
bool* aIsLangRTL,
|
bool* aIsLangRTL,
|
||||||
bool* aHaveBidiKeyboards,
|
bool* aHaveBidiKeyboards,
|
||||||
InfallibleTArray<nsString>* dictionaries,
|
InfallibleTArray<nsString>* dictionaries,
|
||||||
|
@ -2646,12 +2632,6 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||||
rv = io->GetConnectivity(aIsConnected);
|
rv = io->GetConnectivity(aIsConnected);
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
|
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
|
||||||
|
|
||||||
*aCaptivePortalState = nsICaptivePortalService::UNKNOWN;
|
|
||||||
nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
|
|
||||||
if (cps) {
|
|
||||||
cps->GetState(aCaptivePortalState);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
|
nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
|
||||||
|
|
||||||
*aIsLangRTL = false;
|
*aIsLangRTL = false;
|
||||||
|
|
|
@ -690,7 +690,6 @@ private:
|
||||||
virtual bool
|
virtual bool
|
||||||
RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||||
bool* aIsConnected,
|
bool* aIsConnected,
|
||||||
int32_t* aCaptivePortalState,
|
|
||||||
bool* aIsLangRTL,
|
bool* aIsLangRTL,
|
||||||
bool* aHaveBidiKeyboards,
|
bool* aHaveBidiKeyboards,
|
||||||
InfallibleTArray<nsString>* dictionaries,
|
InfallibleTArray<nsString>* dictionaries,
|
||||||
|
|
|
@ -361,7 +361,6 @@ child:
|
||||||
|
|
||||||
async SetOffline(bool offline);
|
async SetOffline(bool offline);
|
||||||
async SetConnectivity(bool connectivity);
|
async SetConnectivity(bool connectivity);
|
||||||
async SetCaptivePortalState(int32_t aState);
|
|
||||||
|
|
||||||
async NotifyVisited(URIParams uri);
|
async NotifyVisited(URIParams uri);
|
||||||
|
|
||||||
|
@ -554,7 +553,7 @@ parent:
|
||||||
sync GetProcessAttributes()
|
sync GetProcessAttributes()
|
||||||
returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
|
returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
|
||||||
sync GetXPCOMProcessAttributes()
|
sync GetXPCOMProcessAttributes()
|
||||||
returns (bool isOffline, bool isConnected, int32_t captivePortalState,
|
returns (bool isOffline, bool isConnected,
|
||||||
bool isLangRTL,
|
bool isLangRTL,
|
||||||
bool haveBidiKeyboards, nsString[] dictionaries,
|
bool haveBidiKeyboards, nsString[] dictionaries,
|
||||||
ClipboardCapabilities clipboardCaps,
|
ClipboardCapabilities clipboardCaps,
|
||||||
|
|
|
@ -532,12 +532,6 @@
|
||||||
'linux_use_gold_flags%': 0,
|
'linux_use_gold_flags%': 0,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
['OS=="android"', {
|
|
||||||
'enable_captive_portal_detection%': 0,
|
|
||||||
}, {
|
|
||||||
'enable_captive_portal_detection%': 1,
|
|
||||||
}],
|
|
||||||
|
|
||||||
# Enable Skia UI text drawing incrementally on different platforms.
|
# Enable Skia UI text drawing incrementally on different platforms.
|
||||||
# http://crbug.com/105550
|
# http://crbug.com/105550
|
||||||
#
|
#
|
||||||
|
@ -665,7 +659,6 @@
|
||||||
'test_isolation_outdir%': '<(test_isolation_outdir)',
|
'test_isolation_outdir%': '<(test_isolation_outdir)',
|
||||||
'enable_automation%': '<(enable_automation)',
|
'enable_automation%': '<(enable_automation)',
|
||||||
'enable_printing%': '<(enable_printing)',
|
'enable_printing%': '<(enable_printing)',
|
||||||
'enable_captive_portal_detection%': '<(enable_captive_portal_detection)',
|
|
||||||
'disable_ftp_support%': '<(disable_ftp_support)',
|
'disable_ftp_support%': '<(disable_ftp_support)',
|
||||||
'force_rlz_use_chrome_net%': '<(force_rlz_use_chrome_net)',
|
'force_rlz_use_chrome_net%': '<(force_rlz_use_chrome_net)',
|
||||||
'enable_task_manager%': '<(enable_task_manager)',
|
'enable_task_manager%': '<(enable_task_manager)',
|
||||||
|
@ -1782,9 +1775,7 @@
|
||||||
['enable_printing==1', {
|
['enable_printing==1', {
|
||||||
'defines': ['ENABLE_PRINTING=1'],
|
'defines': ['ENABLE_PRINTING=1'],
|
||||||
}],
|
}],
|
||||||
['enable_captive_portal_detection==1', {
|
|
||||||
'defines': ['ENABLE_CAPTIVE_PORTAL_DETECTION=1'],
|
|
||||||
}],
|
|
||||||
['disable_ftp_support==1', {
|
['disable_ftp_support==1', {
|
||||||
'defines': ['DISABLE_FTP_SUPPORT=1'],
|
'defines': ['DISABLE_FTP_SUPPORT=1'],
|
||||||
}],
|
}],
|
||||||
|
|
|
@ -28,7 +28,6 @@ DEFS_Debug := \
|
||||||
'-DENABLE_BACKGROUND=1' \
|
'-DENABLE_BACKGROUND=1' \
|
||||||
'-DENABLE_AUTOMATION=1' \
|
'-DENABLE_AUTOMATION=1' \
|
||||||
'-DENABLE_PRINTING=1' \
|
'-DENABLE_PRINTING=1' \
|
||||||
'-DENABLE_CAPTIVE_PORTAL_DETECTION=1' \
|
|
||||||
'-DWEBRTC_CHROMIUM_BUILD' \
|
'-DWEBRTC_CHROMIUM_BUILD' \
|
||||||
'-DWEBRTC_LINUX' \
|
'-DWEBRTC_LINUX' \
|
||||||
'-DWEBRTC_THREAD_RR' \
|
'-DWEBRTC_THREAD_RR' \
|
||||||
|
@ -118,7 +117,6 @@ DEFS_Release := \
|
||||||
'-DENABLE_BACKGROUND=1' \
|
'-DENABLE_BACKGROUND=1' \
|
||||||
'-DENABLE_AUTOMATION=1' \
|
'-DENABLE_AUTOMATION=1' \
|
||||||
'-DENABLE_PRINTING=1' \
|
'-DENABLE_PRINTING=1' \
|
||||||
'-DENABLE_CAPTIVE_PORTAL_DETECTION=1' \
|
|
||||||
'-DWEBRTC_CHROMIUM_BUILD' \
|
'-DWEBRTC_CHROMIUM_BUILD' \
|
||||||
'-DWEBRTC_LINUX' \
|
'-DWEBRTC_LINUX' \
|
||||||
'-DWEBRTC_THREAD_RR' \
|
'-DWEBRTC_THREAD_RR' \
|
||||||
|
|
|
@ -207,7 +207,6 @@
|
||||||
@BINPATH@/components/satchel.xpt
|
@BINPATH@/components/satchel.xpt
|
||||||
@BINPATH@/components/saxparser.xpt
|
@BINPATH@/components/saxparser.xpt
|
||||||
@BINPATH@/components/services-crypto-component.xpt
|
@BINPATH@/components/services-crypto-component.xpt
|
||||||
@BINPATH@/components/captivedetect.xpt
|
|
||||||
@BINPATH@/components/shistory.xpt
|
@BINPATH@/components/shistory.xpt
|
||||||
@BINPATH@/components/spellchecker.xpt
|
@BINPATH@/components/spellchecker.xpt
|
||||||
@BINPATH@/components/storage.xpt
|
@BINPATH@/components/storage.xpt
|
||||||
|
@ -369,9 +368,6 @@
|
||||||
@BINPATH@/components/PeerConnection.manifest
|
@BINPATH@/components/PeerConnection.manifest
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@BINPATH@/components/CaptivePortalDetectComponents.manifest
|
|
||||||
@BINPATH@/components/captivedetect.js
|
|
||||||
|
|
||||||
#ifdef MOZ_WEBSPEECH
|
#ifdef MOZ_WEBSPEECH
|
||||||
@BINPATH@/components/dom_webspeechsynth.xpt
|
@BINPATH@/components/dom_webspeechsynth.xpt
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4950,20 +4950,6 @@ pref("ui.touch_activation.duration_ms", 10);
|
||||||
// actions when the fifo is written to. Disable this in general.
|
// actions when the fifo is written to. Disable this in general.
|
||||||
pref("memory_info_dumper.watch_fifo.enabled", false);
|
pref("memory_info_dumper.watch_fifo.enabled", false);
|
||||||
|
|
||||||
// If minInterval is 0, the check will only happen
|
|
||||||
// when the service has a strong suspicion we are in a captive portal
|
|
||||||
pref("network.captive-portal-service.minInterval", 60000); // 60 seconds
|
|
||||||
pref("network.captive-portal-service.maxInterval", 1500000); // 25 minutes
|
|
||||||
// Every 10 checks, the delay is increased by a factor of 5
|
|
||||||
pref("network.captive-portal-service.backoffFactor", "5.0");
|
|
||||||
pref("network.captive-portal-service.enabled", false);
|
|
||||||
|
|
||||||
pref("captivedetect.canonicalURL", "http://detectportal.palemoon.org/success.txt");
|
|
||||||
pref("captivedetect.canonicalContent", "success\n");
|
|
||||||
pref("captivedetect.maxWaitingTime", 5000);
|
|
||||||
pref("captivedetect.pollingTime", 3000);
|
|
||||||
pref("captivedetect.maxRetryCount", 5);
|
|
||||||
|
|
||||||
#ifdef RELEASE_OR_BETA
|
#ifdef RELEASE_OR_BETA
|
||||||
pref("dom.forms.inputmode", false);
|
pref("dom.forms.inputmode", false);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -1,366 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "mozilla/net/CaptivePortalService.h"
|
|
||||||
#include "mozilla/Services.h"
|
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "nsIObserverService.h"
|
|
||||||
#include "nsServiceManagerUtils.h"
|
|
||||||
#include "nsXULAppAPI.h"
|
|
||||||
|
|
||||||
static const char16_t kInterfaceName[] = u"captive-portal-inteface";
|
|
||||||
|
|
||||||
static const char kOpenCaptivePortalLoginEvent[] = "captive-portal-login";
|
|
||||||
static const char kAbortCaptivePortalLoginEvent[] = "captive-portal-login-abort";
|
|
||||||
static const char kCaptivePortalLoginSuccessEvent[] = "captive-portal-login-success";
|
|
||||||
|
|
||||||
static const uint32_t kDefaultInterval = 60*1000; // check every 60 seconds
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace net {
|
|
||||||
|
|
||||||
static LazyLogModule gCaptivePortalLog("CaptivePortalService");
|
|
||||||
#undef LOG
|
|
||||||
#define LOG(args) MOZ_LOG(gCaptivePortalLog, mozilla::LogLevel::Debug, args)
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(CaptivePortalService, nsICaptivePortalService, nsIObserver,
|
|
||||||
nsISupportsWeakReference, nsITimerCallback,
|
|
||||||
nsICaptivePortalCallback)
|
|
||||||
|
|
||||||
CaptivePortalService::CaptivePortalService()
|
|
||||||
: mState(UNKNOWN)
|
|
||||||
, mStarted(false)
|
|
||||||
, mInitialized(false)
|
|
||||||
, mRequestInProgress(false)
|
|
||||||
, mEverBeenCaptive(false)
|
|
||||||
, mDelay(kDefaultInterval)
|
|
||||||
, mSlackCount(0)
|
|
||||||
, mMinInterval(kDefaultInterval)
|
|
||||||
, mMaxInterval(25*kDefaultInterval)
|
|
||||||
, mBackoffFactor(5.0)
|
|
||||||
{
|
|
||||||
mLastChecked = TimeStamp::Now();
|
|
||||||
}
|
|
||||||
|
|
||||||
CaptivePortalService::~CaptivePortalService()
|
|
||||||
{
|
|
||||||
LOG(("CaptivePortalService::~CaptivePortalService isParentProcess:%d\n",
|
|
||||||
XRE_GetProcessType() == GeckoProcessType_Default));
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
CaptivePortalService::PerformCheck()
|
|
||||||
{
|
|
||||||
LOG(("CaptivePortalService::PerformCheck mRequestInProgress:%d mInitialized:%d mStarted:%d\n",
|
|
||||||
mRequestInProgress, mInitialized, mStarted));
|
|
||||||
// Don't issue another request if last one didn't complete
|
|
||||||
if (mRequestInProgress || !mInitialized || !mStarted) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
||||||
nsresult rv;
|
|
||||||
if (!mCaptivePortalDetector) {
|
|
||||||
mCaptivePortalDetector =
|
|
||||||
do_GetService("@mozilla.org/toolkit/captive-detector;1", &rv);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
LOG(("Unable to get a captive portal detector\n"));
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(("CaptivePortalService::PerformCheck - Calling CheckCaptivePortal\n"));
|
|
||||||
mRequestInProgress = true;
|
|
||||||
mCaptivePortalDetector->CheckCaptivePortal(kInterfaceName, this);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
CaptivePortalService::RearmTimer()
|
|
||||||
{
|
|
||||||
LOG(("CaptivePortalService::RearmTimer\n"));
|
|
||||||
// Start a timer to recheck
|
|
||||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
||||||
if (mTimer) {
|
|
||||||
mTimer->Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have successfully determined the state, and we have never detected
|
|
||||||
// a captive portal, we don't need to keep polling, but will rely on events
|
|
||||||
// to trigger detection.
|
|
||||||
if (mState == NOT_CAPTIVE) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mTimer) {
|
|
||||||
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mTimer && mDelay > 0) {
|
|
||||||
LOG(("CaptivePortalService - Reloading timer with delay %u\n", mDelay));
|
|
||||||
return mTimer->InitWithCallback(this, mDelay, nsITimer::TYPE_ONE_SHOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
CaptivePortalService::Initialize()
|
|
||||||
{
|
|
||||||
if (mInitialized) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
mInitialized = true;
|
|
||||||
|
|
||||||
// Only the main process service should actually do anything. The service in
|
|
||||||
// the content process only mirrors the CP state in the main process.
|
|
||||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> observerService =
|
|
||||||
mozilla::services::GetObserverService();
|
|
||||||
if (observerService) {
|
|
||||||
observerService->AddObserver(this, kOpenCaptivePortalLoginEvent, true);
|
|
||||||
observerService->AddObserver(this, kAbortCaptivePortalLoginEvent, true);
|
|
||||||
observerService->AddObserver(this, kCaptivePortalLoginSuccessEvent, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(("Initialized CaptivePortalService\n"));
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
CaptivePortalService::Start()
|
|
||||||
{
|
|
||||||
if (!mInitialized) {
|
|
||||||
return NS_ERROR_NOT_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
|
||||||
// Doesn't do anything if called in the content process.
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mStarted) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mState == UNKNOWN, "Initial state should be UNKNOWN");
|
|
||||||
mStarted = true;
|
|
||||||
mEverBeenCaptive = false;
|
|
||||||
|
|
||||||
// Get the delay prefs
|
|
||||||
Preferences::GetUint("network.captive-portal-service.minInterval", &mMinInterval);
|
|
||||||
Preferences::GetUint("network.captive-portal-service.maxInterval", &mMaxInterval);
|
|
||||||
Preferences::GetFloat("network.captive-portal-service.backoffFactor", &mBackoffFactor);
|
|
||||||
|
|
||||||
LOG(("CaptivePortalService::Start min:%u max:%u backoff:%.2f\n",
|
|
||||||
mMinInterval, mMaxInterval, mBackoffFactor));
|
|
||||||
|
|
||||||
mSlackCount = 0;
|
|
||||||
mDelay = mMinInterval;
|
|
||||||
|
|
||||||
// When Start is called, perform a check immediately
|
|
||||||
PerformCheck();
|
|
||||||
RearmTimer();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
CaptivePortalService::Stop()
|
|
||||||
{
|
|
||||||
LOG(("CaptivePortalService::Stop\n"));
|
|
||||||
|
|
||||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
|
||||||
// Doesn't do anything when called in the content process.
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mStarted) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mTimer) {
|
|
||||||
mTimer->Cancel();
|
|
||||||
}
|
|
||||||
mTimer = nullptr;
|
|
||||||
mRequestInProgress = false;
|
|
||||||
mStarted = false;
|
|
||||||
if (mCaptivePortalDetector) {
|
|
||||||
mCaptivePortalDetector->Abort(kInterfaceName);
|
|
||||||
}
|
|
||||||
mCaptivePortalDetector = nullptr;
|
|
||||||
|
|
||||||
// Clear the state in case anyone queries the state while detection is off.
|
|
||||||
mState = UNKNOWN;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CaptivePortalService::SetStateInChild(int32_t aState)
|
|
||||||
{
|
|
||||||
// This should only be called in the content process, from ContentChild.cpp
|
|
||||||
// in order to mirror the captive portal state set in the chrome process.
|
|
||||||
MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default);
|
|
||||||
|
|
||||||
mState = aState;
|
|
||||||
mLastChecked = TimeStamp::Now();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// CaptivePortalService::nsICaptivePortalService
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
CaptivePortalService::GetState(int32_t *aState)
|
|
||||||
{
|
|
||||||
*aState = mState;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
CaptivePortalService::RecheckCaptivePortal()
|
|
||||||
{
|
|
||||||
LOG(("CaptivePortalService::RecheckCaptivePortal\n"));
|
|
||||||
|
|
||||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
|
||||||
// Doesn't do anything if called in the content process.
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is called for user activity. We need to reset the slack count,
|
|
||||||
// so the checks continue to be quite frequent.
|
|
||||||
mSlackCount = 0;
|
|
||||||
mDelay = mMinInterval;
|
|
||||||
|
|
||||||
PerformCheck();
|
|
||||||
RearmTimer();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
CaptivePortalService::GetLastChecked(uint64_t *aLastChecked)
|
|
||||||
{
|
|
||||||
double duration = (TimeStamp::Now() - mLastChecked).ToMilliseconds();
|
|
||||||
*aLastChecked = static_cast<uint64_t>(duration);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// CaptivePortalService::nsITimer
|
|
||||||
// This callback gets called every mDelay miliseconds
|
|
||||||
// It issues a checkCaptivePortal operation if one isn't already in progress
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
NS_IMETHODIMP
|
|
||||||
CaptivePortalService::Notify(nsITimer *aTimer)
|
|
||||||
{
|
|
||||||
LOG(("CaptivePortalService::Notify\n"));
|
|
||||||
MOZ_ASSERT(aTimer == mTimer);
|
|
||||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
||||||
|
|
||||||
PerformCheck();
|
|
||||||
|
|
||||||
// This is needed because we don't want to always make requests very often.
|
|
||||||
// Every 10 checks, we the delay is increased mBackoffFactor times
|
|
||||||
// to a maximum delay of mMaxInterval
|
|
||||||
mSlackCount++;
|
|
||||||
if (mSlackCount % 10 == 0) {
|
|
||||||
mDelay = mDelay * mBackoffFactor;
|
|
||||||
}
|
|
||||||
if (mDelay > mMaxInterval) {
|
|
||||||
mDelay = mMaxInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note - if mDelay is 0, the timer will not be rearmed.
|
|
||||||
RearmTimer();
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// CaptivePortalService::nsIObserver
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
NS_IMETHODIMP
|
|
||||||
CaptivePortalService::Observe(nsISupports *aSubject,
|
|
||||||
const char * aTopic,
|
|
||||||
const char16_t * aData)
|
|
||||||
{
|
|
||||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
|
||||||
// Doesn't do anything if called in the content process.
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(("CaptivePortalService::Observe() topic=%s\n", aTopic));
|
|
||||||
if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
|
|
||||||
// A redirect or altered content has been detected.
|
|
||||||
// The user needs to log in. We are in a captive portal.
|
|
||||||
mState = LOCKED_PORTAL;
|
|
||||||
mLastChecked = TimeStamp::Now();
|
|
||||||
mEverBeenCaptive = true;
|
|
||||||
} else if (!strcmp(aTopic, kCaptivePortalLoginSuccessEvent)) {
|
|
||||||
// The user has successfully logged in. We have connectivity.
|
|
||||||
mState = UNLOCKED_PORTAL;
|
|
||||||
mLastChecked = TimeStamp::Now();
|
|
||||||
mSlackCount = 0;
|
|
||||||
mDelay = mMinInterval;
|
|
||||||
|
|
||||||
RearmTimer();
|
|
||||||
} else if (!strcmp(aTopic, kAbortCaptivePortalLoginEvent)) {
|
|
||||||
// The login has been aborted
|
|
||||||
mState = UNKNOWN;
|
|
||||||
mLastChecked = TimeStamp::Now();
|
|
||||||
mSlackCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send notification so that the captive portal state is mirrored in the
|
|
||||||
// content process.
|
|
||||||
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
|
||||||
if (observerService) {
|
|
||||||
nsCOMPtr<nsICaptivePortalService> cps(this);
|
|
||||||
observerService->NotifyObservers(cps, NS_IPC_CAPTIVE_PORTAL_SET_STATE, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// CaptivePortalService::nsICaptivePortalCallback
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
NS_IMETHODIMP
|
|
||||||
CaptivePortalService::Prepare()
|
|
||||||
{
|
|
||||||
LOG(("CaptivePortalService::Prepare\n"));
|
|
||||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
||||||
// XXX: Finish preparation shouldn't be called until dns and routing is available.
|
|
||||||
if (mCaptivePortalDetector) {
|
|
||||||
mCaptivePortalDetector->FinishPreparation(kInterfaceName);
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
CaptivePortalService::Complete(bool success)
|
|
||||||
{
|
|
||||||
LOG(("CaptivePortalService::Complete(success=%d) mState=%d\n", success, mState));
|
|
||||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
||||||
mLastChecked = TimeStamp::Now();
|
|
||||||
|
|
||||||
// Note: this callback gets called when:
|
|
||||||
// 1. the request is completed, and content is valid (success == true)
|
|
||||||
// 2. when the request is aborted or times out (success == false)
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
if (mEverBeenCaptive) {
|
|
||||||
mState = UNLOCKED_PORTAL;
|
|
||||||
} else {
|
|
||||||
mState = NOT_CAPTIVE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mRequestInProgress = false;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace net
|
|
||||||
} // namespace mozilla
|
|
|
@ -1,70 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef CaptivePortalService_h_
|
|
||||||
#define CaptivePortalService_h_
|
|
||||||
|
|
||||||
#include "nsICaptivePortalService.h"
|
|
||||||
#include "nsICaptivePortalDetector.h"
|
|
||||||
#include "nsIObserver.h"
|
|
||||||
#include "nsWeakReference.h"
|
|
||||||
#include "nsITimer.h"
|
|
||||||
#include "nsCOMArray.h"
|
|
||||||
#include "mozilla/TimeStamp.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace net {
|
|
||||||
|
|
||||||
class CaptivePortalService
|
|
||||||
: public nsICaptivePortalService
|
|
||||||
, public nsIObserver
|
|
||||||
, public nsSupportsWeakReference
|
|
||||||
, public nsITimerCallback
|
|
||||||
, public nsICaptivePortalCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
NS_DECL_NSICAPTIVEPORTALSERVICE
|
|
||||||
NS_DECL_NSIOBSERVER
|
|
||||||
NS_DECL_NSITIMERCALLBACK
|
|
||||||
NS_DECL_NSICAPTIVEPORTALCALLBACK
|
|
||||||
|
|
||||||
CaptivePortalService();
|
|
||||||
nsresult Initialize();
|
|
||||||
nsresult Start();
|
|
||||||
nsresult Stop();
|
|
||||||
|
|
||||||
// This method is only called in the content process, in order to mirror
|
|
||||||
// the captive portal state in the parent process.
|
|
||||||
void SetStateInChild(int32_t aState);
|
|
||||||
private:
|
|
||||||
virtual ~CaptivePortalService();
|
|
||||||
nsresult PerformCheck();
|
|
||||||
nsresult RearmTimer();
|
|
||||||
|
|
||||||
nsCOMPtr<nsICaptivePortalDetector> mCaptivePortalDetector;
|
|
||||||
int32_t mState;
|
|
||||||
|
|
||||||
nsCOMPtr<nsITimer> mTimer;
|
|
||||||
bool mStarted;
|
|
||||||
bool mInitialized;
|
|
||||||
bool mRequestInProgress;
|
|
||||||
bool mEverBeenCaptive;
|
|
||||||
|
|
||||||
uint32_t mDelay;
|
|
||||||
int32_t mSlackCount;
|
|
||||||
|
|
||||||
uint32_t mMinInterval;
|
|
||||||
uint32_t mMaxInterval;
|
|
||||||
float mBackoffFactor;
|
|
||||||
|
|
||||||
// This holds a timestamp when the last time when the captive portal check
|
|
||||||
// has changed state.
|
|
||||||
mozilla::TimeStamp mLastChecked;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace net
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // CaptivePortalService_h_
|
|
|
@ -27,7 +27,6 @@ XPIDL_SOURCES += [
|
||||||
'nsICacheInfoChannel.idl',
|
'nsICacheInfoChannel.idl',
|
||||||
'nsICachingChannel.idl',
|
'nsICachingChannel.idl',
|
||||||
'nsICancelable.idl',
|
'nsICancelable.idl',
|
||||||
'nsICaptivePortalService.idl',
|
|
||||||
'nsIChannel.idl',
|
'nsIChannel.idl',
|
||||||
'nsIChannelEventSink.idl',
|
'nsIChannelEventSink.idl',
|
||||||
'nsIChannelWithDivertableParentListener.idl',
|
'nsIChannelWithDivertableParentListener.idl',
|
||||||
|
@ -172,7 +171,6 @@ EXPORTS.mozilla += [
|
||||||
]
|
]
|
||||||
|
|
||||||
EXPORTS.mozilla.net += [
|
EXPORTS.mozilla.net += [
|
||||||
'CaptivePortalService.h',
|
|
||||||
'ChannelDiverterChild.h',
|
'ChannelDiverterChild.h',
|
||||||
'ChannelDiverterParent.h',
|
'ChannelDiverterParent.h',
|
||||||
'Dashboard.h',
|
'Dashboard.h',
|
||||||
|
@ -185,7 +183,6 @@ EXPORTS.mozilla.net += [
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'ArrayBufferInputStream.cpp',
|
'ArrayBufferInputStream.cpp',
|
||||||
'BackgroundFileSaver.cpp',
|
'BackgroundFileSaver.cpp',
|
||||||
'CaptivePortalService.cpp',
|
|
||||||
'ChannelDiverterChild.cpp',
|
'ChannelDiverterChild.cpp',
|
||||||
'ChannelDiverterParent.cpp',
|
'ChannelDiverterParent.cpp',
|
||||||
'Dashboard.cpp',
|
'Dashboard.cpp',
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
|
||||||
|
|
||||||
[scriptable, uuid(b5fd5629-d04c-4138-9529-9311f291ecd4)]
|
|
||||||
interface nsICaptivePortalServiceCallback : nsISupports
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Invoke callbacks after captive portal detection finished.
|
|
||||||
*/
|
|
||||||
void complete(in bool success, in nsresult error);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service used for captive portal detection.
|
|
||||||
* The service is only active in the main process. It is also available in the
|
|
||||||
* content process, but only to mirror the captive portal state from the main
|
|
||||||
* process.
|
|
||||||
*/
|
|
||||||
[scriptable, uuid(bdbe0555-fc3d-4f7b-9205-c309ceb2d641)]
|
|
||||||
interface nsICaptivePortalService : nsISupports
|
|
||||||
{
|
|
||||||
const long UNKNOWN = 0;
|
|
||||||
const long NOT_CAPTIVE = 1;
|
|
||||||
const long UNLOCKED_PORTAL = 2;
|
|
||||||
const long LOCKED_PORTAL = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called from XPCOM to trigger a captive portal recheck.
|
|
||||||
* A network request will only be performed if no other checks are currently
|
|
||||||
* ongoing.
|
|
||||||
* Will not do anything if called in the content process.
|
|
||||||
*/
|
|
||||||
void recheckCaptivePortal();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the state of the captive portal.
|
|
||||||
*/
|
|
||||||
readonly attribute long state;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the time difference between NOW and the last time a request was
|
|
||||||
* completed in milliseconds.
|
|
||||||
*/
|
|
||||||
readonly attribute unsigned long long lastChecked;
|
|
||||||
};
|
|
||||||
|
|
||||||
%{C++
|
|
||||||
/**
|
|
||||||
* This observer notification will be emitted when the captive portal state
|
|
||||||
* changes. After receiving it, the ContentParent will send an IPC message
|
|
||||||
* to the ContentChild, which will set the state in the captive portal service
|
|
||||||
* in the child.
|
|
||||||
*/
|
|
||||||
#define NS_IPC_CAPTIVE_PORTAL_SET_STATE "ipc:network:captive-portal-set-state"
|
|
||||||
|
|
||||||
%}
|
|
|
@ -52,7 +52,6 @@
|
||||||
#include "mozilla/ipc/URIUtils.h"
|
#include "mozilla/ipc/URIUtils.h"
|
||||||
#include "mozilla/net/NeckoChild.h"
|
#include "mozilla/net/NeckoChild.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#include "mozilla/net/CaptivePortalService.h"
|
|
||||||
#include "ReferrerPolicy.h"
|
#include "ReferrerPolicy.h"
|
||||||
#include "nsContentSecurityManager.h"
|
#include "nsContentSecurityManager.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
@ -72,7 +71,6 @@ namespace net {
|
||||||
#define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
|
#define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
|
||||||
#define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size"
|
#define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size"
|
||||||
#define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed"
|
#define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed"
|
||||||
#define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled"
|
|
||||||
|
|
||||||
#define MAX_RECURSION_COUNT 50
|
#define MAX_RECURSION_COUNT 50
|
||||||
|
|
||||||
|
@ -209,8 +207,6 @@ nsIOService::Init()
|
||||||
else
|
else
|
||||||
NS_WARNING("failed to get error service");
|
NS_WARNING("failed to get error service");
|
||||||
|
|
||||||
InitializeCaptivePortalService();
|
|
||||||
|
|
||||||
// setup our bad port list stuff
|
// setup our bad port list stuff
|
||||||
for(int i=0; gBadPortList[i]; i++)
|
for(int i=0; gBadPortList[i]; i++)
|
||||||
mRestrictedPortList.AppendElement(gBadPortList[i]);
|
mRestrictedPortList.AppendElement(gBadPortList[i]);
|
||||||
|
@ -224,7 +220,6 @@ nsIOService::Init()
|
||||||
prefBranch->AddObserver(NECKO_BUFFER_CACHE_COUNT_PREF, this, true);
|
prefBranch->AddObserver(NECKO_BUFFER_CACHE_COUNT_PREF, this, true);
|
||||||
prefBranch->AddObserver(NECKO_BUFFER_CACHE_SIZE_PREF, this, true);
|
prefBranch->AddObserver(NECKO_BUFFER_CACHE_SIZE_PREF, this, true);
|
||||||
prefBranch->AddObserver(NETWORK_NOTIFY_CHANGED_PREF, this, true);
|
prefBranch->AddObserver(NETWORK_NOTIFY_CHANGED_PREF, this, true);
|
||||||
prefBranch->AddObserver(NETWORK_CAPTIVE_PORTAL_PREF, this, true);
|
|
||||||
PrefsChanged(prefBranch);
|
PrefsChanged(prefBranch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,22 +255,6 @@ nsIOService::~nsIOService()
|
||||||
gIOService = nullptr;
|
gIOService = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsIOService::InitializeCaptivePortalService()
|
|
||||||
{
|
|
||||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
|
||||||
// We only initalize a captive portal service in the main process
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
mCaptivePortalService = do_GetService(NS_CAPTIVEPORTAL_CID);
|
|
||||||
if (mCaptivePortalService) {
|
|
||||||
return static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsIOService::InitializeSocketTransportService()
|
nsIOService::InitializeSocketTransportService()
|
||||||
{
|
{
|
||||||
|
@ -356,63 +335,11 @@ NS_IMPL_ISUPPORTS(nsIOService,
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsIOService::RecheckCaptivePortal()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread");
|
|
||||||
if (mCaptivePortalService) {
|
|
||||||
mCaptivePortalService->RecheckCaptivePortal();
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan)
|
|
||||||
{
|
|
||||||
nsresult rv;
|
|
||||||
|
|
||||||
if (!mCaptivePortalService) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri;
|
|
||||||
rv = newChan->GetURI(getter_AddRefs(uri));
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCString host;
|
|
||||||
rv = uri->GetHost(host);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRNetAddr prAddr;
|
|
||||||
if (PR_StringToNetAddr(host.BeginReading(), &prAddr) != PR_SUCCESS) {
|
|
||||||
// The redirect wasn't to an IP literal, so there's probably no need
|
|
||||||
// to trigger the captive portal detection right now. It can wait.
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetAddr netAddr;
|
|
||||||
PRNetAddrToNetAddr(&prAddr, &netAddr);
|
|
||||||
if (IsIPAddrLocal(&netAddr)) {
|
|
||||||
// Redirects to local IP addresses are probably captive portals
|
|
||||||
mCaptivePortalService->RecheckCaptivePortal();
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsIOService::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
nsIOService::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
nsAsyncRedirectVerifyHelper *helper)
|
nsAsyncRedirectVerifyHelper *helper)
|
||||||
{
|
{
|
||||||
// If a redirect to a local network address occurs, then chances are we
|
|
||||||
// are in a captive portal, so we trigger a recheck.
|
|
||||||
RecheckCaptivePortalIfLocalRedirect(newChan);
|
|
||||||
|
|
||||||
// This is silly. I wish there was a simpler way to get at the global
|
// This is silly. I wish there was a simpler way to get at the global
|
||||||
// reference of the contentSecurityManager. But it lives in the XPCOM
|
// reference of the contentSecurityManager. But it lives in the XPCOM
|
||||||
// service registry.
|
// service registry.
|
||||||
|
@ -1138,15 +1065,6 @@ nsIOService::SetConnectivityInternal(bool aConnectivity)
|
||||||
}
|
}
|
||||||
mConnectivity = aConnectivity;
|
mConnectivity = aConnectivity;
|
||||||
|
|
||||||
if (mCaptivePortalService) {
|
|
||||||
if (aConnectivity && !xpc::AreNonLocalConnectionsDisabled()) {
|
|
||||||
// This will also trigger a captive portal check for the new network
|
|
||||||
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
|
|
||||||
} else {
|
|
||||||
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
||||||
if (!observerService) {
|
if (!observerService) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -1281,17 +1199,6 @@ nsIOService::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) {
|
|
||||||
bool captivePortalEnabled;
|
|
||||||
nsresult rv = prefs->GetBoolPref(NETWORK_CAPTIVE_PORTAL_PREF, &captivePortalEnabled);
|
|
||||||
if (NS_SUCCEEDED(rv) && mCaptivePortalService) {
|
|
||||||
if (captivePortalEnabled && !xpc::AreNonLocalConnectionsDisabled()) {
|
|
||||||
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
|
|
||||||
} else {
|
|
||||||
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1373,8 +1280,6 @@ nsIOService::NotifyWakeup()
|
||||||
(u"" NS_NETWORK_LINK_DATA_CHANGED));
|
(u"" NS_NETWORK_LINK_DATA_CHANGED));
|
||||||
}
|
}
|
||||||
|
|
||||||
RecheckCaptivePortal();
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1437,11 +1342,6 @@ nsIOService::Observe(nsISupports *subject,
|
||||||
|
|
||||||
SetOffline(true);
|
SetOffline(true);
|
||||||
|
|
||||||
if (mCaptivePortalService) {
|
|
||||||
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
|
|
||||||
mCaptivePortalService = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Break circular reference.
|
// Break circular reference.
|
||||||
mProxyService = nullptr;
|
mProxyService = nullptr;
|
||||||
} else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
|
} else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
|
||||||
|
@ -1609,8 +1509,6 @@ nsIOService::OnNetworkLinkEvent(const char *data)
|
||||||
bool isUp = true;
|
bool isUp = true;
|
||||||
if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
|
if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
|
||||||
// CHANGED means UP/DOWN didn't change
|
// CHANGED means UP/DOWN didn't change
|
||||||
// but the status of the captive portal may have changed.
|
|
||||||
RecheckCaptivePortal();
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
|
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
|
||||||
isUp = false;
|
isUp = false;
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "prtime.h"
|
#include "prtime.h"
|
||||||
#include "nsICaptivePortalService.h"
|
|
||||||
|
|
||||||
#define NS_N(x) (sizeof(x)/sizeof(*x))
|
#define NS_N(x) (sizeof(x)/sizeof(*x))
|
||||||
|
|
||||||
|
@ -94,8 +93,6 @@ public:
|
||||||
|
|
||||||
static bool BlockToplevelDataUriNavigations();
|
static bool BlockToplevelDataUriNavigations();
|
||||||
|
|
||||||
// Used to trigger a recheck of the captive portal status
|
|
||||||
nsresult RecheckCaptivePortal();
|
|
||||||
private:
|
private:
|
||||||
// These shouldn't be called directly:
|
// These shouldn't be called directly:
|
||||||
// - construct using GetInstance
|
// - construct using GetInstance
|
||||||
|
@ -113,9 +110,6 @@ private:
|
||||||
nsresult CacheProtocolHandler(const char *scheme,
|
nsresult CacheProtocolHandler(const char *scheme,
|
||||||
nsIProtocolHandler* hdlr);
|
nsIProtocolHandler* hdlr);
|
||||||
|
|
||||||
nsresult InitializeCaptivePortalService();
|
|
||||||
nsresult RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan);
|
|
||||||
|
|
||||||
// Prefs wrangling
|
// Prefs wrangling
|
||||||
void PrefsChanged(nsIPrefBranch *prefs, const char *pref = nullptr);
|
void PrefsChanged(nsIPrefBranch *prefs, const char *pref = nullptr);
|
||||||
void GetPrefBranch(nsIPrefBranch **);
|
void GetPrefBranch(nsIPrefBranch **);
|
||||||
|
@ -159,7 +153,6 @@ private:
|
||||||
nsCOMPtr<nsPISocketTransportService> mSocketTransportService;
|
nsCOMPtr<nsPISocketTransportService> mSocketTransportService;
|
||||||
nsCOMPtr<nsPIDNSService> mDNSService;
|
nsCOMPtr<nsPIDNSService> mDNSService;
|
||||||
nsCOMPtr<nsIProtocolProxyService2> mProxyService;
|
nsCOMPtr<nsIProtocolProxyService2> mProxyService;
|
||||||
nsCOMPtr<nsICaptivePortalService> mCaptivePortalService;
|
|
||||||
nsCOMPtr<nsINetworkLinkService> mNetworkLinkService;
|
nsCOMPtr<nsINetworkLinkService> mNetworkLinkService;
|
||||||
bool mNetworkLinkServiceInitialized;
|
bool mNetworkLinkServiceInitialized;
|
||||||
|
|
||||||
|
|
|
@ -470,17 +470,6 @@
|
||||||
{ 0xae, 0xcf, 0x05, 0xf8, 0xfa, 0xf0, 0x0c, 0x9b } \
|
{ 0xae, 0xcf, 0x05, 0xf8, 0xfa, 0xf0, 0x0c, 0x9b } \
|
||||||
}
|
}
|
||||||
|
|
||||||
// captive portal service implementing nsICaptivePortalService
|
|
||||||
#define NS_CAPTIVEPORTAL_CONTRACTID \
|
|
||||||
"@mozilla.org/network/captive-portal-service;1"
|
|
||||||
#define NS_CAPTIVEPORTAL_CID \
|
|
||||||
{ /* bdbe0555-fc3d-4f7b-9205-c309ceb2d641 */ \
|
|
||||||
0xbdbe0555, \
|
|
||||||
0xfc3d, \
|
|
||||||
0x4f7b, \
|
|
||||||
{ 0x92, 0x05, 0xc3, 0x09, 0xce, 0xb2, 0xd6, 0x41 } \
|
|
||||||
}
|
|
||||||
|
|
||||||
// service implementing nsIRequestContextService
|
// service implementing nsIRequestContextService
|
||||||
#define NS_REQUESTCONTEXTSERVICE_CONTRACTID \
|
#define NS_REQUESTCONTEXTSERVICE_CONTRACTID \
|
||||||
"@mozilla.org/network/request-context-service;1"
|
"@mozilla.org/network/request-context-service;1"
|
||||||
|
|
|
@ -150,13 +150,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(LoadContextInfoFactory)
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "mozilla/net/CaptivePortalService.h"
|
|
||||||
namespace mozilla {
|
|
||||||
namespace net {
|
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(CaptivePortalService)
|
|
||||||
} // namespace net
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#include "RequestContextService.h"
|
#include "RequestContextService.h"
|
||||||
typedef mozilla::net::RequestContextService RequestContextService;
|
typedef mozilla::net::RequestContextService RequestContextService;
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(RequestContextService, Init)
|
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(RequestContextService, Init)
|
||||||
|
@ -862,7 +855,6 @@ NS_DEFINE_NAMED_CID(NS_REDIRECTCHANNELREGISTRAR_CID);
|
||||||
NS_DEFINE_NAMED_CID(NS_CACHE_STORAGE_SERVICE_CID);
|
NS_DEFINE_NAMED_CID(NS_CACHE_STORAGE_SERVICE_CID);
|
||||||
NS_DEFINE_NAMED_CID(NS_NSILOADCONTEXTINFOFACTORY_CID);
|
NS_DEFINE_NAMED_CID(NS_NSILOADCONTEXTINFOFACTORY_CID);
|
||||||
NS_DEFINE_NAMED_CID(NS_NETWORKPREDICTOR_CID);
|
NS_DEFINE_NAMED_CID(NS_NETWORKPREDICTOR_CID);
|
||||||
NS_DEFINE_NAMED_CID(NS_CAPTIVEPORTAL_CID);
|
|
||||||
NS_DEFINE_NAMED_CID(NS_REQUESTCONTEXTSERVICE_CID);
|
NS_DEFINE_NAMED_CID(NS_REQUESTCONTEXTSERVICE_CID);
|
||||||
#ifdef BUILD_NETWORK_INFO_SERVICE
|
#ifdef BUILD_NETWORK_INFO_SERVICE
|
||||||
NS_DEFINE_NAMED_CID(NETWORKINFOSERVICE_CID);
|
NS_DEFINE_NAMED_CID(NETWORKINFOSERVICE_CID);
|
||||||
|
@ -1013,7 +1005,6 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = {
|
||||||
{ &kNS_CACHE_STORAGE_SERVICE_CID, false, nullptr, CacheStorageServiceConstructor },
|
{ &kNS_CACHE_STORAGE_SERVICE_CID, false, nullptr, CacheStorageServiceConstructor },
|
||||||
{ &kNS_NSILOADCONTEXTINFOFACTORY_CID, false, nullptr, LoadContextInfoFactoryConstructor },
|
{ &kNS_NSILOADCONTEXTINFOFACTORY_CID, false, nullptr, LoadContextInfoFactoryConstructor },
|
||||||
{ &kNS_NETWORKPREDICTOR_CID, false, nullptr, mozilla::net::Predictor::Create },
|
{ &kNS_NETWORKPREDICTOR_CID, false, nullptr, mozilla::net::Predictor::Create },
|
||||||
{ &kNS_CAPTIVEPORTAL_CID, false, nullptr, mozilla::net::CaptivePortalServiceConstructor },
|
|
||||||
{ &kNS_REQUESTCONTEXTSERVICE_CID, false, nullptr, RequestContextServiceConstructor },
|
{ &kNS_REQUESTCONTEXTSERVICE_CID, false, nullptr, RequestContextServiceConstructor },
|
||||||
#ifdef BUILD_NETWORK_INFO_SERVICE
|
#ifdef BUILD_NETWORK_INFO_SERVICE
|
||||||
{ &kNETWORKINFOSERVICE_CID, false, nullptr, nsNetworkInfoServiceConstructor },
|
{ &kNETWORKINFOSERVICE_CID, false, nullptr, nsNetworkInfoServiceConstructor },
|
||||||
|
@ -1169,7 +1160,6 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = {
|
||||||
{ NS_CACHE_STORAGE_SERVICE_CONTRACTID2, &kNS_CACHE_STORAGE_SERVICE_CID },
|
{ NS_CACHE_STORAGE_SERVICE_CONTRACTID2, &kNS_CACHE_STORAGE_SERVICE_CID },
|
||||||
{ NS_NSILOADCONTEXTINFOFACTORY_CONTRACTID, &kNS_NSILOADCONTEXTINFOFACTORY_CID },
|
{ NS_NSILOADCONTEXTINFOFACTORY_CONTRACTID, &kNS_NSILOADCONTEXTINFOFACTORY_CID },
|
||||||
{ NS_NETWORKPREDICTOR_CONTRACTID, &kNS_NETWORKPREDICTOR_CID },
|
{ NS_NETWORKPREDICTOR_CONTRACTID, &kNS_NETWORKPREDICTOR_CID },
|
||||||
{ NS_CAPTIVEPORTAL_CONTRACTID, &kNS_CAPTIVEPORTAL_CID },
|
|
||||||
{ NS_REQUESTCONTEXTSERVICE_CONTRACTID, &kNS_REQUESTCONTEXTSERVICE_CID },
|
{ NS_REQUESTCONTEXTSERVICE_CONTRACTID, &kNS_REQUESTCONTEXTSERVICE_CID },
|
||||||
#ifdef BUILD_NETWORK_INFO_SERVICE
|
#ifdef BUILD_NETWORK_INFO_SERVICE
|
||||||
{ NETWORKINFOSERVICE_CONTRACT_ID, &kNETWORKINFOSERVICE_CID },
|
{ NETWORKINFOSERVICE_CONTRACT_ID, &kNETWORKINFOSERVICE_CID },
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "nsICacheStorageService.h"
|
#include "nsICacheStorageService.h"
|
||||||
#include "nsICacheStorage.h"
|
#include "nsICacheStorage.h"
|
||||||
#include "nsICacheEntry.h"
|
#include "nsICacheEntry.h"
|
||||||
#include "nsICaptivePortalService.h"
|
|
||||||
#include "nsICryptoHash.h"
|
#include "nsICryptoHash.h"
|
||||||
#include "nsINetworkInterceptController.h"
|
#include "nsINetworkInterceptController.h"
|
||||||
#include "nsINSSErrorsService.h"
|
#include "nsINSSErrorsService.h"
|
||||||
|
@ -6491,13 +6490,6 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
|
||||||
MOZ_ASSERT(NS_IsMainThread(),
|
MOZ_ASSERT(NS_IsMainThread(),
|
||||||
"OnStopRequest should only be called from the main thread");
|
"OnStopRequest should only be called from the main thread");
|
||||||
|
|
||||||
// If this load failed because of a security error, it may be because we
|
|
||||||
// are in a captive portal - trigger an async check to make sure.
|
|
||||||
int32_t nsprError = -1 * NS_ERROR_GET_CODE(status);
|
|
||||||
if (mozilla::psm::IsNSSErrorCode(nsprError)) {
|
|
||||||
gIOService->RecheckCaptivePortal();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mTimingEnabled && request == mCachePump) {
|
if (mTimingEnabled && request == mCachePump) {
|
||||||
mCacheReadEnd = TimeStamp::Now();
|
mCacheReadEnd = TimeStamp::Now();
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,6 @@ user_pref("security.turn_off_all_security_so_that_viruses_can_take_over_this_com
|
||||||
// use an additional pref here to allow automation to use the "normal" behavior.
|
// use an additional pref here to allow automation to use the "normal" behavior.
|
||||||
user_pref("dom.use_xbl_scopes_for_remote_xul", true);
|
user_pref("dom.use_xbl_scopes_for_remote_xul", true);
|
||||||
|
|
||||||
user_pref("captivedetect.canonicalURL", "http://%(server)s/captive-detect/success.txt");
|
|
||||||
// Get network events.
|
// Get network events.
|
||||||
user_pref("network.activity.blipIntervalMilliseconds", 250);
|
user_pref("network.activity.blipIntervalMilliseconds", 250);
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
component {d9cd00ba-aa4d-47b1-8792-b1fe0cd35060} captivedetect.js
|
|
||||||
contract @mozilla.org/toolkit/captive-detector;1 {d9cd00ba-aa4d-47b1-8792-b1fe0cd35060}
|
|
|
@ -1,476 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
|
|
||||||
|
|
||||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
|
||||||
Cu.import('resource://gre/modules/Services.jsm');
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, "gSysMsgr",
|
|
||||||
"@mozilla.org/system-message-internal;1",
|
|
||||||
"nsISystemMessagesInternal");
|
|
||||||
|
|
||||||
const DEBUG = false; // set to true to show debug messages
|
|
||||||
|
|
||||||
const kCAPTIVEPORTALDETECTOR_CONTRACTID = '@mozilla.org/toolkit/captive-detector;1';
|
|
||||||
const kCAPTIVEPORTALDETECTOR_CID = Components.ID('{d9cd00ba-aa4d-47b1-8792-b1fe0cd35060}');
|
|
||||||
|
|
||||||
const kOpenCaptivePortalLoginEvent = 'captive-portal-login';
|
|
||||||
const kAbortCaptivePortalLoginEvent = 'captive-portal-login-abort';
|
|
||||||
const kCaptivePortalLoginSuccessEvent = 'captive-portal-login-success';
|
|
||||||
const kCaptivePortalCheckComplete = 'captive-portal-check-complete';
|
|
||||||
|
|
||||||
const kCaptivePortalSystemMessage = 'captive-portal';
|
|
||||||
|
|
||||||
function URLFetcher(url, timeout) {
|
|
||||||
let self = this;
|
|
||||||
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
|
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
|
||||||
xhr.open('GET', url, true);
|
|
||||||
// Prevent the request from reading from the cache.
|
|
||||||
xhr.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
|
||||||
// Prevent the request from writing to the cache.
|
|
||||||
xhr.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
|
|
||||||
// Prevent privacy leaks
|
|
||||||
xhr.channel.loadFlags |= Ci.nsIRequest.LOAD_ANONYMOUS;
|
|
||||||
// The Cache-Control header is only interpreted by proxies and the
|
|
||||||
// final destination. It does not help if a resource is already
|
|
||||||
// cached locally.
|
|
||||||
xhr.setRequestHeader("Cache-Control", "no-cache");
|
|
||||||
// HTTP/1.0 servers might not implement Cache-Control and
|
|
||||||
// might only implement Pragma: no-cache
|
|
||||||
xhr.setRequestHeader("Pragma", "no-cache");
|
|
||||||
|
|
||||||
xhr.timeout = timeout;
|
|
||||||
xhr.ontimeout = function () { self.ontimeout(); };
|
|
||||||
xhr.onerror = function () { self.onerror(); };
|
|
||||||
xhr.onreadystatechange = function(oEvent) {
|
|
||||||
if (xhr.readyState === 4) {
|
|
||||||
if (self._isAborted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (xhr.status === 200) {
|
|
||||||
self.onsuccess(xhr.responseText);
|
|
||||||
} else if (xhr.status) {
|
|
||||||
self.onredirectorerror(xhr.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
this._xhr = xhr;
|
|
||||||
}
|
|
||||||
|
|
||||||
URLFetcher.prototype = {
|
|
||||||
_isAborted: false,
|
|
||||||
ontimeout: function() {},
|
|
||||||
onerror: function() {},
|
|
||||||
abort: function() {
|
|
||||||
if (!this._isAborted) {
|
|
||||||
this._isAborted = true;
|
|
||||||
this._xhr.abort();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
function LoginObserver(captivePortalDetector) {
|
|
||||||
const LOGIN_OBSERVER_STATE_DETACHED = 0; /* Should not monitor network activity since no ongoing login procedure */
|
|
||||||
const LOGIN_OBSERVER_STATE_IDLE = 1; /* No network activity currently, waiting for a longer enough idle period */
|
|
||||||
const LOGIN_OBSERVER_STATE_BURST = 2; /* Network activity is detected, probably caused by a login procedure */
|
|
||||||
const LOGIN_OBSERVER_STATE_VERIFY_NEEDED = 3; /* Verifing network accessiblity is required after a long enough idle */
|
|
||||||
const LOGIN_OBSERVER_STATE_VERIFYING = 4; /* LoginObserver is probing if public network is available */
|
|
||||||
|
|
||||||
let state = LOGIN_OBSERVER_STATE_DETACHED;
|
|
||||||
|
|
||||||
let timer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer);
|
|
||||||
let activityDistributor = Cc['@mozilla.org/network/http-activity-distributor;1']
|
|
||||||
.getService(Ci.nsIHttpActivityDistributor);
|
|
||||||
let urlFetcher = null;
|
|
||||||
|
|
||||||
let waitForNetworkActivity = false;
|
|
||||||
|
|
||||||
let pageCheckingDone = function pageCheckingDone() {
|
|
||||||
if (state === LOGIN_OBSERVER_STATE_VERIFYING) {
|
|
||||||
urlFetcher = null;
|
|
||||||
// Finish polling the canonical site, switch back to idle state and
|
|
||||||
// waiting for next burst
|
|
||||||
state = LOGIN_OBSERVER_STATE_IDLE;
|
|
||||||
timer.initWithCallback(observer,
|
|
||||||
captivePortalDetector._pollingTime,
|
|
||||||
timer.TYPE_ONE_SHOT);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let checkPageContent = function checkPageContent() {
|
|
||||||
debug("checking if public network is available after the login procedure");
|
|
||||||
|
|
||||||
urlFetcher = new URLFetcher(captivePortalDetector._canonicalSiteURL,
|
|
||||||
captivePortalDetector._maxWaitingTime);
|
|
||||||
urlFetcher.ontimeout = pageCheckingDone;
|
|
||||||
urlFetcher.onerror = pageCheckingDone;
|
|
||||||
urlFetcher.onsuccess = function (content) {
|
|
||||||
if (captivePortalDetector.validateContent(content)) {
|
|
||||||
urlFetcher = null;
|
|
||||||
captivePortalDetector.executeCallback(true);
|
|
||||||
} else {
|
|
||||||
pageCheckingDone();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
urlFetcher.onredirectorerror = pageCheckingDone;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Public interface of LoginObserver
|
|
||||||
let observer = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHttpActivityObserver,
|
|
||||||
Ci.nsITimerCallback]),
|
|
||||||
|
|
||||||
attach: function attach() {
|
|
||||||
if (state === LOGIN_OBSERVER_STATE_DETACHED) {
|
|
||||||
activityDistributor.addObserver(this);
|
|
||||||
state = LOGIN_OBSERVER_STATE_IDLE;
|
|
||||||
timer.initWithCallback(this,
|
|
||||||
captivePortalDetector._pollingTime,
|
|
||||||
timer.TYPE_ONE_SHOT);
|
|
||||||
debug('attach HttpObserver for login activity');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
detach: function detach() {
|
|
||||||
if (state !== LOGIN_OBSERVER_STATE_DETACHED) {
|
|
||||||
if (urlFetcher) {
|
|
||||||
urlFetcher.abort();
|
|
||||||
urlFetcher = null;
|
|
||||||
}
|
|
||||||
activityDistributor.removeObserver(this);
|
|
||||||
timer.cancel();
|
|
||||||
state = LOGIN_OBSERVER_STATE_DETACHED;
|
|
||||||
debug('detach HttpObserver for login activity');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Treat all HTTP transactions as captive portal login activities.
|
|
||||||
*/
|
|
||||||
observeActivity: function observeActivity(aHttpChannel, aActivityType,
|
|
||||||
aActivitySubtype, aTimestamp,
|
|
||||||
aExtraSizeData, aExtraStringData) {
|
|
||||||
if (aActivityType === Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION
|
|
||||||
&& aActivitySubtype === Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_RESPONSE_COMPLETE) {
|
|
||||||
switch (state) {
|
|
||||||
case LOGIN_OBSERVER_STATE_IDLE:
|
|
||||||
case LOGIN_OBSERVER_STATE_VERIFY_NEEDED:
|
|
||||||
state = LOGIN_OBSERVER_STATE_BURST;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if login activity is finished according to HTTP burst.
|
|
||||||
*/
|
|
||||||
notify : function notify() {
|
|
||||||
switch (state) {
|
|
||||||
case LOGIN_OBSERVER_STATE_BURST:
|
|
||||||
// Wait while network stays idle for a short period
|
|
||||||
state = LOGIN_OBSERVER_STATE_VERIFY_NEEDED;
|
|
||||||
// Fall though to start polling timer
|
|
||||||
case LOGIN_OBSERVER_STATE_IDLE:
|
|
||||||
if (waitForNetworkActivity) {
|
|
||||||
timer.initWithCallback(this,
|
|
||||||
captivePortalDetector._pollingTime,
|
|
||||||
timer.TYPE_ONE_SHOT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// if we don't need to wait for network activity, just fall through
|
|
||||||
// to perform a captive portal check.
|
|
||||||
case LOGIN_OBSERVER_STATE_VERIFY_NEEDED:
|
|
||||||
// Polling the canonical website since network stays idle for a while
|
|
||||||
state = LOGIN_OBSERVER_STATE_VERIFYING;
|
|
||||||
checkPageContent();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return observer;
|
|
||||||
}
|
|
||||||
|
|
||||||
function CaptivePortalDetector() {
|
|
||||||
// Load preference
|
|
||||||
this._canonicalSiteURL = null;
|
|
||||||
this._canonicalSiteExpectedContent = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
this._canonicalSiteURL =
|
|
||||||
Services.prefs.getCharPref('captivedetect.canonicalURL');
|
|
||||||
this._canonicalSiteExpectedContent =
|
|
||||||
Services.prefs.getCharPref('captivedetect.canonicalContent');
|
|
||||||
} catch (e) {
|
|
||||||
debug('canonicalURL or canonicalContent not set.')
|
|
||||||
}
|
|
||||||
|
|
||||||
this._maxWaitingTime =
|
|
||||||
Services.prefs.getIntPref('captivedetect.maxWaitingTime');
|
|
||||||
this._pollingTime =
|
|
||||||
Services.prefs.getIntPref('captivedetect.pollingTime');
|
|
||||||
this._maxRetryCount =
|
|
||||||
Services.prefs.getIntPref('captivedetect.maxRetryCount');
|
|
||||||
debug('Load Prefs {site=' + this._canonicalSiteURL + ',content='
|
|
||||||
+ this._canonicalSiteExpectedContent + ',time=' + this._maxWaitingTime
|
|
||||||
+ "max-retry=" + this._maxRetryCount + '}');
|
|
||||||
|
|
||||||
// Create HttpObserver for monitoring the login procedure
|
|
||||||
this._loginObserver = LoginObserver(this);
|
|
||||||
|
|
||||||
this._nextRequestId = 0;
|
|
||||||
this._runningRequest = null;
|
|
||||||
this._requestQueue = []; // Maintain a progress table, store callbacks and the ongoing XHR
|
|
||||||
this._interfaceNames = {}; // Maintain names of the requested network interfaces
|
|
||||||
|
|
||||||
debug('CaptiveProtalDetector initiated, waiting for network connection established');
|
|
||||||
}
|
|
||||||
|
|
||||||
CaptivePortalDetector.prototype = {
|
|
||||||
classID: kCAPTIVEPORTALDETECTOR_CID,
|
|
||||||
classInfo: XPCOMUtils.generateCI({classID: kCAPTIVEPORTALDETECTOR_CID,
|
|
||||||
contractID: kCAPTIVEPORTALDETECTOR_CONTRACTID,
|
|
||||||
classDescription: 'Captive Portal Detector',
|
|
||||||
interfaces: [Ci.nsICaptivePortalDetector]}),
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalDetector]),
|
|
||||||
|
|
||||||
// nsICaptivePortalDetector
|
|
||||||
checkCaptivePortal: function checkCaptivePortal(aInterfaceName, aCallback) {
|
|
||||||
if (!this._canonicalSiteURL) {
|
|
||||||
throw Components.Exception('No canonical URL set up.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent multiple requests on a single network interface
|
|
||||||
if (this._interfaceNames[aInterfaceName]) {
|
|
||||||
throw Components.Exception('Do not allow multiple request on one interface: ' + aInterfaceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
let request = {interfaceName: aInterfaceName};
|
|
||||||
if (aCallback) {
|
|
||||||
let callback = aCallback.QueryInterface(Ci.nsICaptivePortalCallback);
|
|
||||||
request['callback'] = callback;
|
|
||||||
request['retryCount'] = 0;
|
|
||||||
}
|
|
||||||
this._addRequest(request);
|
|
||||||
},
|
|
||||||
|
|
||||||
abort: function abort(aInterfaceName) {
|
|
||||||
debug('abort for ' + aInterfaceName);
|
|
||||||
this._removeRequest(aInterfaceName);
|
|
||||||
},
|
|
||||||
|
|
||||||
finishPreparation: function finishPreparation(aInterfaceName) {
|
|
||||||
debug('finish preparation phase for interface "' + aInterfaceName + '"');
|
|
||||||
if (!this._runningRequest
|
|
||||||
|| this._runningRequest.interfaceName !== aInterfaceName) {
|
|
||||||
debug('invalid finishPreparation for ' + aInterfaceName);
|
|
||||||
throw Components.Exception('only first request is allowed to invoke |finishPreparation|');
|
|
||||||
}
|
|
||||||
|
|
||||||
this._startDetection();
|
|
||||||
},
|
|
||||||
|
|
||||||
cancelLogin: function cancelLogin(eventId) {
|
|
||||||
debug('login canceled by user for request "' + eventId + '"');
|
|
||||||
// Captive portal login procedure is canceled by user
|
|
||||||
if (this._runningRequest && this._runningRequest.hasOwnProperty('eventId')) {
|
|
||||||
let id = this._runningRequest.eventId;
|
|
||||||
if (eventId === id) {
|
|
||||||
this.executeCallback(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_applyDetection: function _applyDetection() {
|
|
||||||
debug('enter applyDetection('+ this._runningRequest.interfaceName + ')');
|
|
||||||
|
|
||||||
// Execute network interface preparation
|
|
||||||
if (this._runningRequest.hasOwnProperty('callback')) {
|
|
||||||
this._runningRequest.callback.prepare();
|
|
||||||
} else {
|
|
||||||
this._startDetection();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_startDetection: function _startDetection() {
|
|
||||||
debug('startDetection {site=' + this._canonicalSiteURL + ',content='
|
|
||||||
+ this._canonicalSiteExpectedContent + ',time=' + this._maxWaitingTime + '}');
|
|
||||||
let self = this;
|
|
||||||
|
|
||||||
let urlFetcher = new URLFetcher(this._canonicalSiteURL, this._maxWaitingTime);
|
|
||||||
|
|
||||||
let mayRetry = this._mayRetry.bind(this);
|
|
||||||
|
|
||||||
urlFetcher.ontimeout = mayRetry;
|
|
||||||
urlFetcher.onerror = mayRetry;
|
|
||||||
urlFetcher.onsuccess = function (content) {
|
|
||||||
if (self.validateContent(content)) {
|
|
||||||
self.executeCallback(true);
|
|
||||||
} else {
|
|
||||||
// Content of the canonical website has been overwrite
|
|
||||||
self._startLogin();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
urlFetcher.onredirectorerror = function (status) {
|
|
||||||
if (status >= 300 && status <= 399) {
|
|
||||||
// The canonical website has been redirected to an unknown location
|
|
||||||
self._startLogin();
|
|
||||||
} else {
|
|
||||||
mayRetry();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this._runningRequest['urlFetcher'] = urlFetcher;
|
|
||||||
},
|
|
||||||
|
|
||||||
_startLogin: function _startLogin() {
|
|
||||||
let id = this._allocateRequestId();
|
|
||||||
let details = {
|
|
||||||
type: kOpenCaptivePortalLoginEvent,
|
|
||||||
id: id,
|
|
||||||
url: this._canonicalSiteURL,
|
|
||||||
};
|
|
||||||
this._loginObserver.attach();
|
|
||||||
this._runningRequest['eventId'] = id;
|
|
||||||
this._sendEvent(kOpenCaptivePortalLoginEvent, details);
|
|
||||||
gSysMsgr.broadcastMessage(kCaptivePortalSystemMessage, {});
|
|
||||||
},
|
|
||||||
|
|
||||||
_mayRetry: function _mayRetry() {
|
|
||||||
if (this._runningRequest.retryCount++ < this._maxRetryCount) {
|
|
||||||
debug('retry-Detection: ' + this._runningRequest.retryCount + '/' + this._maxRetryCount);
|
|
||||||
this._startDetection();
|
|
||||||
} else {
|
|
||||||
this.executeCallback(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
executeCallback: function executeCallback(success) {
|
|
||||||
if (this._runningRequest) {
|
|
||||||
debug('callback executed');
|
|
||||||
if (this._runningRequest.hasOwnProperty('callback')) {
|
|
||||||
this._runningRequest.callback.complete(success);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only when the request has a event id and |success| is true
|
|
||||||
// do we need to notify the login-success event.
|
|
||||||
if (this._runningRequest.hasOwnProperty('eventId') && success) {
|
|
||||||
let details = {
|
|
||||||
type: kCaptivePortalLoginSuccessEvent,
|
|
||||||
id: this._runningRequest['eventId'],
|
|
||||||
};
|
|
||||||
this._sendEvent(kCaptivePortalLoginSuccessEvent, details);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue the following request
|
|
||||||
this._runningRequest['complete'] = true;
|
|
||||||
this._removeRequest(this._runningRequest.interfaceName);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_sendEvent: function _sendEvent(topic, details) {
|
|
||||||
debug('sendEvent "' + JSON.stringify(details) + '"');
|
|
||||||
Services.obs.notifyObservers(this,
|
|
||||||
topic,
|
|
||||||
JSON.stringify(details));
|
|
||||||
},
|
|
||||||
|
|
||||||
validateContent: function validateContent(content) {
|
|
||||||
debug('received content: ' + content);
|
|
||||||
let valid = content === this._canonicalSiteExpectedContent;
|
|
||||||
// We need a way to indicate that a check has been performed, and if we are
|
|
||||||
// still in a captive portal.
|
|
||||||
this._sendEvent(kCaptivePortalCheckComplete, !valid);
|
|
||||||
return valid;
|
|
||||||
},
|
|
||||||
|
|
||||||
_allocateRequestId: function _allocateRequestId() {
|
|
||||||
let newId = this._nextRequestId++;
|
|
||||||
return newId.toString();
|
|
||||||
},
|
|
||||||
|
|
||||||
_runNextRequest: function _runNextRequest() {
|
|
||||||
let nextRequest = this._requestQueue.shift();
|
|
||||||
if (nextRequest) {
|
|
||||||
this._runningRequest = nextRequest;
|
|
||||||
this._applyDetection();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_addRequest: function _addRequest(request) {
|
|
||||||
this._interfaceNames[request.interfaceName] = true;
|
|
||||||
this._requestQueue.push(request);
|
|
||||||
if (!this._runningRequest) {
|
|
||||||
this._runNextRequest();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_removeRequest: function _removeRequest(aInterfaceName) {
|
|
||||||
if (!this._interfaceNames[aInterfaceName]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete this._interfaceNames[aInterfaceName];
|
|
||||||
|
|
||||||
if (this._runningRequest
|
|
||||||
&& this._runningRequest.interfaceName === aInterfaceName) {
|
|
||||||
this._loginObserver.detach();
|
|
||||||
|
|
||||||
if (!this._runningRequest.complete) {
|
|
||||||
// Abort the user login procedure
|
|
||||||
if (this._runningRequest.hasOwnProperty('eventId')) {
|
|
||||||
let details = {
|
|
||||||
type: kAbortCaptivePortalLoginEvent,
|
|
||||||
id: this._runningRequest.eventId
|
|
||||||
};
|
|
||||||
this._sendEvent(kAbortCaptivePortalLoginEvent, details);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abort the ongoing HTTP request
|
|
||||||
if (this._runningRequest.hasOwnProperty('urlFetcher')) {
|
|
||||||
this._runningRequest.urlFetcher.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug('remove running request');
|
|
||||||
this._runningRequest = null;
|
|
||||||
|
|
||||||
// Continue next pending reqeust if the ongoing one has been aborted
|
|
||||||
this._runNextRequest();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a pending request has been aborted
|
|
||||||
for (let i = 0; i < this._requestQueue.length; i++) {
|
|
||||||
if (this._requestQueue[i].interfaceName == aInterfaceName) {
|
|
||||||
this._requestQueue.splice(i, 1);
|
|
||||||
|
|
||||||
debug('remove pending request #' + i + ', remaining ' + this._requestQueue.length);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
var debug;
|
|
||||||
if (DEBUG) {
|
|
||||||
debug = function (s) {
|
|
||||||
dump('-*- CaptivePortalDetector component: ' + s + '\n');
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
debug = function (s) {};
|
|
||||||
}
|
|
||||||
|
|
||||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([CaptivePortalDetector]);
|
|
|
@ -1,19 +0,0 @@
|
||||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
|
||||||
# vim: set filetype=python:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
|
||||||
|
|
||||||
XPIDL_SOURCES += [
|
|
||||||
'nsICaptivePortalDetector.idl',
|
|
||||||
]
|
|
||||||
|
|
||||||
XPIDL_MODULE = 'captivedetect'
|
|
||||||
|
|
||||||
EXTRA_COMPONENTS += [
|
|
||||||
'captivedetect.js',
|
|
||||||
'CaptivePortalDetectComponents.manifest',
|
|
||||||
]
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
|
||||||
|
|
||||||
[scriptable, uuid(593fdeec-6284-4de8-b416-8e63cbdc695e)]
|
|
||||||
interface nsICaptivePortalCallback : nsISupports
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Preparation for network interface before captive portal detection started.
|
|
||||||
*/
|
|
||||||
void prepare();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke callbacks after captive portal detection finished.
|
|
||||||
*/
|
|
||||||
void complete(in bool success);
|
|
||||||
};
|
|
||||||
|
|
||||||
[scriptable, uuid(2f827c5a-f551-477f-af09-71adbfbd854a)]
|
|
||||||
interface nsICaptivePortalDetector : nsISupports
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Perform captive portal detection on specific network interface.
|
|
||||||
* @param ifname The name of network interface, exception will be thrwon
|
|
||||||
* if the same interface has unfinished request.
|
|
||||||
* @param callback Callbacks when detection procedure starts and finishes.
|
|
||||||
*/
|
|
||||||
void checkCaptivePortal(in wstring ifname,
|
|
||||||
in nsICaptivePortalCallback callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abort captive portal detection for specific network interface
|
|
||||||
* due to system failure, callback will not be invoked.
|
|
||||||
* @param ifname The name of network interface.
|
|
||||||
*/
|
|
||||||
void abort(in wstring ifname);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel captive portal login procedure by user, callback will be invoked.
|
|
||||||
* @param eventId Login event id provided in |captive-portal-login| event.
|
|
||||||
*/
|
|
||||||
void cancelLogin(in wstring eventId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify prepare phase is finished, routing and dns must be ready for sending
|
|
||||||
* out XMLHttpRequest. this is callback for CaptivePortalDetector API user.
|
|
||||||
* @param ifname The name of network interface, must be unique.
|
|
||||||
*/
|
|
||||||
void finishPreparation(in wstring ifname);
|
|
||||||
};
|
|
|
@ -1,7 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
"extends": [
|
|
||||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
|
||||||
]
|
|
||||||
};
|
|
|
@ -1,49 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
||||||
|
|
||||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
|
||||||
Cu.import('resource://gre/modules/Services.jsm');
|
|
||||||
Cu.import('resource://testing-common/httpd.js');
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, 'gCaptivePortalDetector',
|
|
||||||
'@mozilla.org/toolkit/captive-detector;1',
|
|
||||||
'nsICaptivePortalDetector');
|
|
||||||
|
|
||||||
const kCanonicalSitePath = '/canonicalSite.html';
|
|
||||||
const kCanonicalSiteContent = 'true';
|
|
||||||
const kPrefsCanonicalURL = 'captivedetect.canonicalURL';
|
|
||||||
const kPrefsCanonicalContent = 'captivedetect.canonicalContent';
|
|
||||||
const kPrefsMaxWaitingTime = 'captivedetect.maxWaitingTime';
|
|
||||||
const kPrefsPollingTime = 'captivedetect.pollingTime';
|
|
||||||
|
|
||||||
var gServer;
|
|
||||||
var gServerURL;
|
|
||||||
|
|
||||||
function setupPrefs() {
|
|
||||||
let prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
|
||||||
.getService(Components.interfaces.nsIPrefService)
|
|
||||||
.QueryInterface(Components.interfaces.nsIPrefBranch);
|
|
||||||
prefs.setCharPref(kPrefsCanonicalURL, gServerURL + kCanonicalSitePath);
|
|
||||||
prefs.setCharPref(kPrefsCanonicalContent, kCanonicalSiteContent);
|
|
||||||
prefs.setIntPref(kPrefsMaxWaitingTime, 0);
|
|
||||||
prefs.setIntPref(kPrefsPollingTime, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_captivedetect_test(xhr_handler, fakeUIResponse, testfun)
|
|
||||||
{
|
|
||||||
gServer = new HttpServer();
|
|
||||||
gServer.registerPathHandler(kCanonicalSitePath, xhr_handler);
|
|
||||||
gServer.start(-1);
|
|
||||||
gServerURL = 'http://localhost:' + gServer.identity.primaryPort;
|
|
||||||
|
|
||||||
setupPrefs();
|
|
||||||
|
|
||||||
fakeUIResponse();
|
|
||||||
|
|
||||||
testfun();
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
|
|
||||||
var server;
|
|
||||||
var step = 0;
|
|
||||||
var loginFinished = false;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 200, 'OK');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache', false);
|
|
||||||
response.setHeader('Content-Type', 'text/plain', false);
|
|
||||||
if (loginFinished) {
|
|
||||||
response.write('true');
|
|
||||||
} else {
|
|
||||||
response.write('false');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login') {
|
|
||||||
do_throw('should not receive captive-portal-login event');
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_abort() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_throw('should not execute |complete| callback');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
gCaptivePortalDetector.abort(kInterfaceName);
|
|
||||||
gServer.stop(do_test_finished);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_abort);
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
|
|
||||||
var server;
|
|
||||||
var step = 0;
|
|
||||||
var loginFinished = false;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 200, 'OK');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache', false);
|
|
||||||
response.setHeader('Content-Type', 'text/plain', false);
|
|
||||||
if (loginFinished) {
|
|
||||||
response.write('true');
|
|
||||||
} else {
|
|
||||||
response.write('false');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
let requestId;
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login') {
|
|
||||||
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
|
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
|
||||||
xhr.open('GET', gServerURL + kCanonicalSitePath, true);
|
|
||||||
xhr.send();
|
|
||||||
loginFinished = true;
|
|
||||||
do_check_eq(++step, 2);
|
|
||||||
requestId = JSON.parse(data).id;
|
|
||||||
gCaptivePortalDetector.abort(kInterfaceName);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login-abort') {
|
|
||||||
do_check_eq(++step, 3);
|
|
||||||
do_check_eq(JSON.parse(data).id, requestId);
|
|
||||||
gServer.stop(do_test_finished);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login-abort', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_abort() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_throw('should not execute |complete| callback');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_abort);
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
const kOtherInterfaceName = 'ril';
|
|
||||||
|
|
||||||
var server;
|
|
||||||
var step = 0;
|
|
||||||
var loginFinished = false;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 200, 'OK');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache', false);
|
|
||||||
response.setHeader('Content-Type', 'text/plain', false);
|
|
||||||
if (loginFinished) {
|
|
||||||
response.write('true');
|
|
||||||
} else {
|
|
||||||
response.write('false');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login') {
|
|
||||||
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
|
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
|
||||||
xhr.open('GET', gServerURL + kCanonicalSitePath, true);
|
|
||||||
xhr.send();
|
|
||||||
loginFinished = true;
|
|
||||||
do_check_eq(++step, 3);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_multiple_requests_abort() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_throw('should not execute |complete| callback for ' + kInterfaceName);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let otherCallback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 2);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kOtherInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_check_eq(++step, 4);
|
|
||||||
do_check_true(success);
|
|
||||||
gServer.stop(do_test_finished);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kOtherInterfaceName, otherCallback);
|
|
||||||
gCaptivePortalDetector.abort(kInterfaceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_multiple_requests_abort);
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
const kOtherInterfaceName = 'ril';
|
|
||||||
|
|
||||||
var server;
|
|
||||||
var step = 0;
|
|
||||||
var loginFinished = false;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 200, 'OK');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache', false);
|
|
||||||
response.setHeader('Content-Type', 'text/plain', false);
|
|
||||||
if (loginFinished) {
|
|
||||||
response.write('true');
|
|
||||||
} else {
|
|
||||||
response.write('false');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login') {
|
|
||||||
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
|
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
|
||||||
xhr.open('GET', gServerURL + kCanonicalSitePath, true);
|
|
||||||
xhr.send();
|
|
||||||
loginFinished = true;
|
|
||||||
do_check_eq(++step, 2);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_abort() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_check_eq(++step, 3);
|
|
||||||
do_check_true(success);
|
|
||||||
gServer.stop(do_test_finished);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let otherCallback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_throw('should not execute |prepare| callback for ' + kOtherInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_throw('should not execute |complete| callback for ' + kInterfaceName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kOtherInterfaceName, otherCallback);
|
|
||||||
gCaptivePortalDetector.abort(kOtherInterfaceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_abort);
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
|
|
||||||
var server;
|
|
||||||
var step = 0;
|
|
||||||
var loginFinished = false;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 200, 'OK');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache', false);
|
|
||||||
response.setHeader('Content-Type', 'text/plain', false);
|
|
||||||
if (loginFinished) {
|
|
||||||
response.write('true');
|
|
||||||
} else {
|
|
||||||
response.write('false');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login') {
|
|
||||||
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
|
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
|
||||||
xhr.open('GET', gServerURL + kCanonicalSitePath, true);
|
|
||||||
xhr.send();
|
|
||||||
loginFinished = true;
|
|
||||||
do_check_eq(++step, 2);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login-success') {
|
|
||||||
do_check_eq(++step, 4);
|
|
||||||
gServer.stop(do_test_finished);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login-success', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_portal_found() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
// Since this is a synchronous callback, it must happen before
|
|
||||||
// 'captive-portal-login-success' is received.
|
|
||||||
// (Check captivedetect.js::executeCallback
|
|
||||||
do_check_eq(++step, 3);
|
|
||||||
do_check_true(success);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_portal_found);
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
|
|
||||||
var step = 0;
|
|
||||||
var loginFinished = false;
|
|
||||||
|
|
||||||
var gRedirectServer;
|
|
||||||
var gRedirectServerURL;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
if (loginFinished) {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 200, 'OK');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache', false);
|
|
||||||
response.setHeader('Content-Type', 'text/plain', false);
|
|
||||||
response.write('true');
|
|
||||||
} else {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 303, "See Other");
|
|
||||||
response.setHeader("Location", gRedirectServerURL, false);
|
|
||||||
response.setHeader("Content-Type", "text/html", false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login') {
|
|
||||||
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
|
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
|
||||||
xhr.open('GET', gServerURL + kCanonicalSitePath, true);
|
|
||||||
xhr.send();
|
|
||||||
loginFinished = true;
|
|
||||||
do_check_eq(++step, 2);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login-success') {
|
|
||||||
do_check_eq(++step, 4);
|
|
||||||
gServer.stop(function () {
|
|
||||||
gRedirectServer.stop(do_test_finished);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login-success', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_portal_found() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_check_eq(++step, 3);
|
|
||||||
do_check_true(success);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
gRedirectServer = new HttpServer();
|
|
||||||
gRedirectServer.start(-1);
|
|
||||||
gRedirectServerURL = 'http://localhost:' + gRedirectServer.identity.primaryPort;
|
|
||||||
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_portal_found);
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
|
|
||||||
var server;
|
|
||||||
var step = 0;
|
|
||||||
var attempt = 0;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
dump('HTTP activity\n');
|
|
||||||
response.setStatusLine(metadata.httpVersion, 200, 'OK');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache', false);
|
|
||||||
response.setHeader('Content-Type', 'text/plain', false);
|
|
||||||
response.write('true');
|
|
||||||
attempt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic == 'captive-portal-login') {
|
|
||||||
do_throw('should not receive captive-portal-login event');
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_portal_not_found() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_check_eq(++step, 2);
|
|
||||||
do_check_true(success);
|
|
||||||
do_check_eq(attempt, 1);
|
|
||||||
gServer.stop(function() { dump('server stop\n'); do_test_finished(); });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_portal_not_found);
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
|
|
||||||
var server;
|
|
||||||
var step = 0;
|
|
||||||
var loginFinished = false;
|
|
||||||
var attempt = 0;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 404, "Page not Found");
|
|
||||||
attempt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login') {
|
|
||||||
do_throw('should not receive captive-portal-login event');
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_portal_not_found() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_check_eq(++step, 2);
|
|
||||||
do_check_false(success);
|
|
||||||
do_check_eq(attempt, 6);
|
|
||||||
gServer.stop(do_test_finished);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_portal_not_found);
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
const kOtherInterfaceName = 'ril';
|
|
||||||
|
|
||||||
var server;
|
|
||||||
var step = 0;
|
|
||||||
var loginFinished = false;
|
|
||||||
var loginSuccessCount = 0;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 200, 'OK');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache', false);
|
|
||||||
response.setHeader('Content-Type', 'text/plain', false);
|
|
||||||
if (loginFinished) {
|
|
||||||
response.write('true');
|
|
||||||
} else {
|
|
||||||
response.write('false');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login') {
|
|
||||||
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
|
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
|
||||||
xhr.open('GET', gServerURL + kCanonicalSitePath, true);
|
|
||||||
xhr.send();
|
|
||||||
loginFinished = true;
|
|
||||||
do_check_eq(++step, 2);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login-success') {
|
|
||||||
loginSuccessCount++;
|
|
||||||
if (loginSuccessCount > 1) {
|
|
||||||
throw "We should only receive 'captive-portal-login-success' once";
|
|
||||||
}
|
|
||||||
do_check_eq(++step, 4);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login-success', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_multiple_requests() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_check_eq(++step, 3);
|
|
||||||
do_check_true(success);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let otherCallback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 5);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kOtherInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_check_eq(++step, 6);
|
|
||||||
do_check_true(success);
|
|
||||||
gServer.stop(do_test_finished);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kOtherInterfaceName, otherCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_multiple_requests);
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const kInterfaceName = 'wifi';
|
|
||||||
|
|
||||||
var server;
|
|
||||||
var step = 0;
|
|
||||||
|
|
||||||
function xhr_handler(metadata, response) {
|
|
||||||
response.setStatusLine(metadata.httpVersion, 200, 'OK');
|
|
||||||
response.setHeader('Cache-Control', 'no-cache', false);
|
|
||||||
response.setHeader('Content-Type', 'text/plain', false);
|
|
||||||
response.write('false');
|
|
||||||
}
|
|
||||||
|
|
||||||
function fakeUIResponse() {
|
|
||||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
|
||||||
if (topic === 'captive-portal-login') {
|
|
||||||
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
|
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
|
||||||
xhr.open('GET', gServerURL + kCanonicalSitePath, true);
|
|
||||||
xhr.send();
|
|
||||||
do_check_eq(++step, 2);
|
|
||||||
let details = JSON.parse(data);
|
|
||||||
gCaptivePortalDetector.cancelLogin(details.id);
|
|
||||||
}
|
|
||||||
}, 'captive-portal-login', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_cancel() {
|
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
let callback = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
|
|
||||||
prepare: function prepare() {
|
|
||||||
do_check_eq(++step, 1);
|
|
||||||
gCaptivePortalDetector.finishPreparation(kInterfaceName);
|
|
||||||
},
|
|
||||||
complete: function complete(success) {
|
|
||||||
do_check_eq(++step, 3);
|
|
||||||
do_check_false(success);
|
|
||||||
gServer.stop(do_test_finished);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
gCaptivePortalDetector.checkCaptivePortal(kInterfaceName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
run_captivedetect_test(xhr_handler, fakeUIResponse, test_cancel);
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
[DEFAULT]
|
|
||||||
head = head_setprefs.js
|
|
||||||
tail =
|
|
||||||
|
|
||||||
[test_captive_portal_not_found.js]
|
|
||||||
[test_captive_portal_not_found_404.js]
|
|
||||||
[test_captive_portal_found.js]
|
|
||||||
[test_captive_portal_found_303.js]
|
|
||||||
[test_abort.js]
|
|
||||||
[test_abort_during_user_login.js]
|
|
||||||
[test_user_cancel.js]
|
|
||||||
[test_multiple_requests.js]
|
|
||||||
[test_abort_ongoing_request.js]
|
|
||||||
[test_abort_pending_request.js]
|
|
||||||
|
|
|
@ -95,8 +95,6 @@ if CONFIG['MOZ_TOOLKIT_SEARCH']:
|
||||||
if CONFIG['MOZ_URL_CLASSIFIER']:
|
if CONFIG['MOZ_URL_CLASSIFIER']:
|
||||||
DIRS += ['url-classifier']
|
DIRS += ['url-classifier']
|
||||||
|
|
||||||
DIRS += ['captivedetect']
|
|
||||||
|
|
||||||
if CONFIG['OS_TARGET'] != 'Android':
|
if CONFIG['OS_TARGET'] != 'Android':
|
||||||
DIRS += ['terminator']
|
DIRS += ['terminator']
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user