Junk captive portal and directory ping

This commit is contained in:
Fedor 2019-03-12 19:35:44 +03:00
parent db6eb94ebb
commit 74bd1d375d
59 changed files with 6 additions and 3947 deletions

View File

@ -581,9 +581,6 @@ pref("mousewheel.with_win.action", 1);
pref("browser.xul.error_pages.enabled", true);
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
pref("network.manage-offline-status", true);

View File

@ -30,8 +30,6 @@
// e - the error code
// s - custom CSS class to allow alternate styling/favicons
// 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
// the URL (with the format from above). This is because
@ -59,10 +57,6 @@
return searchParams.get("d");
}
function isCaptive() {
return searchParams.get("captive") == "true";
}
function retryThis(buttonEl)
{
// Note: The application may wish to handle switching off "offline mode"
@ -166,11 +160,6 @@
{
var err = getErrorCode();
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
// defined, get the generic message
@ -193,10 +182,7 @@
sd.textContent = getDescription();
}
}
if (showCaptivePortalUI) {
initPageCaptivePortal();
return;
}
if (gIsCertError) {
initPageCertError();
return;
@ -289,29 +275,6 @@
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() {
document.body.className = "certerror";
document.title = document.getElementById("certErrorPageTitle").textContent;
@ -434,13 +397,11 @@
<body dir="&locale.dir;">
<!-- Contains an alternate page title set on page init for cert errors. -->
<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) -->
<div id="errorContainer">
<div id="errorTitlesContainer">
<h1 id="et_generic">&generic.title;</h1>
<h1 id="et_captivePortal">&captivePortal.title;</h1>
<h1 id="et_dnsNotFound">&dnsNotFound.title;</h1>
<h1 id="et_fileNotFound">&fileNotFound.title;</h1>
<h1 id="et_fileAccessDenied">&fileAccessDenied.title;</h1>
@ -470,7 +431,6 @@
</div>
<div id="errorDescriptionsContainer">
<div id="ed_generic">&generic.longDesc;</div>
<div id="ed_captivePortal">&captivePortal.longDesc;</div>
<div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div>
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
<div id="ed_fileAccessDenied">&fileAccessDenied.longDesc;</div>
@ -529,12 +489,6 @@
<button id="prefResetButton" class="primary" autocomplete="off">&prefReset.label;</button>
</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 id="netErrorButtonContainer" class="button-container">

View File

@ -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);
},
};

View File

@ -974,7 +974,6 @@ var gBrowserInit = {
AboutPrivateBrowsingListener.init();
TrackingProtection.init();
RefreshBlocker.init();
CaptivePortalWatcher.init();
let mm = window.getGroupMessageManager("browsers");
mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
@ -1510,8 +1509,6 @@ var gBrowserInit = {
RefreshBlocker.uninit();
CaptivePortalWatcher.uninit();
gMenuButtonUpdateBadge.uninit();
gMenuButtonBadgeManager.uninit();
@ -2743,16 +2740,12 @@ var BrowserOnClick = {
init: function () {
let mm = window.messageManager;
mm.addMessageListener("Browser:CertExceptionError", this);
mm.addMessageListener("Browser:OpenCaptivePortalPage", this);
mm.addMessageListener("Browser:SiteBlockedError", this);
mm.addMessageListener("Browser:EnableOnlineMode", this);
mm.addMessageListener("Browser:ResetSSLPreferences", this);
mm.addMessageListener("Browser:SSLErrorReportTelemetry", this);
mm.addMessageListener("Browser:OverrideWeakCrypto", 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 () {
@ -2764,20 +2757,6 @@ var BrowserOnClick = {
mm.removeMessageListener("Browser:SSLErrorReportTelemetry", this);
mm.removeMessageListener("Browser:OverrideWeakCrypto", 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) {
@ -2787,9 +2766,6 @@ var BrowserOnClick = {
msg.data.isTopFrame, msg.data.location,
msg.data.securityInfoAsString);
break;
case "Browser:OpenCaptivePortalPage":
CaptivePortalWatcher.ensureCaptivePortalTab();
break;
case "Browser:SiteBlockedError":
this.onAboutBlocked(msg.data.elementId, msg.data.reason,
msg.data.isTopFrame, msg.data.location);

View File

@ -264,9 +264,7 @@ function getSerializedSecurityInfo(docShell) {
var AboutNetAndCertErrorListener = {
init: function(chromeGlobal) {
addMessageListener("CertErrorDetails", this);
addMessageListener("Browser:CaptivePortalFreed", this);
chromeGlobal.addEventListener('AboutNetErrorLoad', this, false, true);
chromeGlobal.addEventListener('AboutNetErrorOpenCaptivePortal', this, false, true);
chromeGlobal.addEventListener('AboutNetErrorSetAutomatic', this, false, true);
chromeGlobal.addEventListener('AboutNetErrorOverride', this, false, true);
chromeGlobal.addEventListener('AboutNetErrorResetPreferences', this, false, true);
@ -289,9 +287,6 @@ var AboutNetAndCertErrorListener = {
case "CertErrorDetails":
this.onCertErrorDetails(msg);
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) {
if (!this.isAboutNetError && !this.isAboutCertError) {
return;
@ -351,9 +342,6 @@ var AboutNetAndCertErrorListener = {
case "AboutNetErrorLoad":
this.onPageLoad(aEvent);
break;
case "AboutNetErrorOpenCaptivePortal":
this.openCaptivePortalPage(aEvent);
break;
case "AboutNetErrorSetAutomatic":
this.onSetAutomatic(aEvent);
break;
@ -384,11 +372,6 @@ var AboutNetAndCertErrorListener = {
}
},
openCaptivePortalPage: function(evt) {
sendAsyncMessage("Browser:OpenCaptivePortalPage");
},
onResetPreferences: function(evt) {
sendAsyncMessage("Browser:ResetSSLPreferences");
},

View File

@ -11,7 +11,6 @@
<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-captivePortal.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-devedition.js"/>

View File

@ -11,7 +11,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PageThumbs.jsm");
Cu.import("resource://gre/modules/BackgroundPageThumbs.jsm");
Cu.import("resource:///modules/DirectoryLinksProvider.jsm");
Cu.import("resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Rect",

View File

@ -287,8 +287,6 @@ var gPage = {
}
}
}
DirectoryLinksProvider.reportSitesAction(sites, "view", lastIndex);
},
maybeShowAutoMigrationUndoNotification() {

View File

@ -171,7 +171,7 @@ Site.prototype = {
// first check for end time, as it may modify the link
this._checkLinkEndTime();
// setup display variables
let enhanced = gAllPages.enhanced && DirectoryLinksProvider.getEnhancedLink(this.link);
let enhanced = gAllPages.enhanced;
let url = this.url;
let title = enhanced && enhanced.title ? enhanced.title :
this.link.type == "history" ? this.link.baseDomain :
@ -244,7 +244,7 @@ Site.prototype = {
*/
refreshThumbnail: function Site_refreshThumbnail() {
// Only enhance tiles if that feature is turned on
let link = gAllPages.enhanced && DirectoryLinksProvider.getEnhancedLink(this.link) ||
let link = gAllPages.enhanced ||
this.link;
let thumbnail = this._querySelector(".newtab-thumbnail.thumbnail");
@ -387,12 +387,6 @@ Site.prototype = {
else if (button == 0) {
aEvent.preventDefault();
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();
action = "block";
}
@ -413,11 +407,6 @@ Site.prototype = {
action = "pin";
}
}
// Report all link click actions
if (action) {
DirectoryLinksProvider.reportSitesAction(gGrid.sites, action, tileIndex);
}
},
/**

View File

@ -68,7 +68,6 @@ browser.jar:
* content/browser/browser.js (content/browser.js)
* content/browser/browser.xul (content/browser.xul)
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-customization.js (content/browser-customization.js)
content/browser/browser-data-submission-info-bar.js (content/browser-data-submission-info-bar.js)

View File

@ -32,7 +32,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", "@mozilla.org/alerts-s
["ContentPrefServiceParent", "resource://gre/modules/ContentPrefServiceParent.jsm"],
["ContentSearch", "resource:///modules/ContentSearch.jsm"],
["DateTimePickerHelper", "resource://gre/modules/DateTimePickerHelper.jsm"],
["DirectoryLinksProvider", "resource:///modules/DirectoryLinksProvider.jsm"],
["Feeds", "resource:///modules/Feeds.jsm"],
["FileUtils", "resource://gre/modules/FileUtils.jsm"],
["FormValidationHandler", "resource:///modules/FormValidationHandler.jsm"],
@ -657,9 +656,7 @@ BrowserGlue.prototype = {
webrtcUI.init();
AboutHome.init();
DirectoryLinksProvider.init();
NewTabUtils.init();
NewTabUtils.links.addProvider(DirectoryLinksProvider);
AboutNewTab.init();
NewTabMessages.init();

View File

@ -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

View File

@ -282,7 +282,6 @@
@RESPATH@/components/saxparser.xpt
@RESPATH@/browser/components/sessionstore.xpt
@RESPATH@/components/services-crypto-component.xpt
@RESPATH@/components/captivedetect.xpt
@RESPATH@/browser/components/shellservice.xpt
@RESPATH@/components/shistory.xpt
@RESPATH@/components/spellchecker.xpt
@ -487,8 +486,6 @@
@RESPATH@/components/Weave.js
@RESPATH@/components/FxAccountsComponents.manifest
@RESPATH@/components/FxAccountsPush.js
@RESPATH@/components/CaptivePortalDetectComponents.manifest
@RESPATH@/components/captivedetect.js
@RESPATH@/components/servicesComponents.manifest
@RESPATH@/components/cryptoComponents.manifest
@RESPATH@/components/TelemetryStartup.js

View File

@ -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.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
# LOCALIZATION NOTE (aboutDialog.architecture.*):

View File

@ -51,13 +51,6 @@
<p>&brandShortName; cant 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 isnt valid">
<!ENTITY malformedURI.longDesc "
<ul>

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,6 @@ EXTRA_JS_MODULES += [
'ContentObservers.jsm',
'ContentSearch.jsm',
'ContentWebRTC.jsm',
'DirectoryLinksProvider.jsm',
'E10SUtils.jsm',
'Feeds.jsm',
'FormSubmitObserver.jsm',

View File

@ -16,10 +16,6 @@ body.certerror {
#f0d000 66%, #f0d000);
}
body.captiveportal .title {
background-image: url("wifi.svg");
}
body.certerror .title {
background-image: url("cert-error.svg");
}
@ -39,13 +35,6 @@ button:disabled {
display: none;
}
#certErrorAndCaptivePortalButtonContainer {
display: none;
}
body:not(.neterror) #certErrorAndCaptivePortalButtonContainer {
display: flex;
}
body:not(.neterror) #netErrorButtonContainer {
display: none;
@ -64,14 +53,6 @@ body:not(.neterror) #netErrorButtonContainer {
display: none;
}
body.captiveportal #returnButton {
display: none;
}
body:not(.captiveportal) #openPortalLoginPageButton {
display: none;
}
#openPortalLoginPageButton {
margin-inline-start: 0;
}

View File

@ -48,8 +48,6 @@
type="bool"/>
#endif
<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 -->
<preference id="browser.cache.disk.capacity" name="browser.cache.disk.capacity" type="int"/>
@ -181,7 +179,6 @@
</hbox>
</groupbox>
#endif
<!-- User Agent compatibility -->
<groupbox id="UACompatGroup" orient="vertical">
<caption label="&UACompatGroup.label;"/>
<hbox align="center">
@ -195,15 +192,6 @@
</menulist>
</hbox>
</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>
<!-- Network -->

View File

@ -39,9 +39,6 @@
<!ENTITY UACompat.Gecko "Gecko Compatibility">
<!ENTITY UACompat.Firefox "Firefox Compatibility">
<!ENTITY captivePortalGroup.label "Captive portals">
<!ENTITY captivePortalDetect.label "Detect restricted network access">
<!ENTITY dataChoicesTab.label "Data Choices">
<!ENTITY crashReporterSection.label "Crash Reporter">

View File

@ -51,13 +51,6 @@
<p>&brandShortName; cant 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.longDesc "
<ul>

View File

@ -43,7 +43,6 @@
#include "nsArray.h"
#include "nsArrayUtils.h"
#include "nsContentSecurityManager.h"
#include "nsICaptivePortalService.h"
#include "nsIDOMStorage.h"
#include "nsIContentViewer.h"
#include "nsIDocumentLoaderFactory.h"
@ -5306,13 +5305,6 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
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
// end of the URL, so append it last.
errorPageUrl.AppendLiteral("&d=");

View File

@ -52,7 +52,6 @@
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layout/RenderFrameChild.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/net/CaptivePortalService.h"
#include "mozilla/plugins/PluginInstanceParent.h"
#include "mozilla/plugins/PluginModuleParent.h"
#include "mozilla/widget/WidgetMessageUtils.h"
@ -887,15 +886,13 @@ ContentChild::InitXPCOM()
StructuredCloneData initialData;
OptionalURIParams userContentSheetURL;
int32_t captivePortalState;
SendGetXPCOMProcessAttributes(&isOffline, &isConnected, &captivePortalState,
SendGetXPCOMProcessAttributes(&isOffline, &isConnected,
&isLangRTL, &haveBidiKeyboards,
&mAvailableDictionaries,
&clipboardCaps, &domainPolicy, &initialData,
&userContentSheetURL);
RecvSetOffline(isOffline);
RecvSetConnectivity(isConnected);
RecvSetCaptivePortalState(captivePortalState);
RecvBidiKeyboardNotify(isLangRTL, haveBidiKeyboards);
// Create the CPOW manager as soon as possible.
@ -1816,21 +1813,6 @@ ContentChild::RecvSetConnectivity(const bool& connectivity)
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
ContentChild::ActorDestroy(ActorDestroyReason why)
{

View File

@ -341,7 +341,6 @@ public:
virtual bool RecvSetOffline(const bool& offline) 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;

View File

@ -170,7 +170,6 @@
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsICaptivePortalService.h"
#include "nsIBidiKeyboard.h"
@ -493,7 +492,6 @@ static const char* sObserverTopics[] = {
"profile-before-change",
NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
NS_IPC_CAPTIVE_PORTAL_SET_STATE,
"memory-pressure",
"child-gc-request",
"child-cc-request",
@ -2532,17 +2530,6 @@ ContentParent::Observe(nsISupports* aSubject,
if (!SendSetConnectivity(NS_LITERAL_STRING("true").Equals(aData))) {
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
else if (!strcmp(aTopic, "alertfinished") ||
@ -2629,7 +2616,6 @@ ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
bool
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsConnected,
int32_t* aCaptivePortalState,
bool* aIsLangRTL,
bool* aHaveBidiKeyboards,
InfallibleTArray<nsString>* dictionaries,
@ -2646,12 +2632,6 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
rv = io->GetConnectivity(aIsConnected);
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();
*aIsLangRTL = false;

View File

@ -690,7 +690,6 @@ private:
virtual bool
RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsConnected,
int32_t* aCaptivePortalState,
bool* aIsLangRTL,
bool* aHaveBidiKeyboards,
InfallibleTArray<nsString>* dictionaries,

View File

@ -361,7 +361,6 @@ child:
async SetOffline(bool offline);
async SetConnectivity(bool connectivity);
async SetCaptivePortalState(int32_t aState);
async NotifyVisited(URIParams uri);
@ -554,7 +553,7 @@ parent:
sync GetProcessAttributes()
returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
sync GetXPCOMProcessAttributes()
returns (bool isOffline, bool isConnected, int32_t captivePortalState,
returns (bool isOffline, bool isConnected,
bool isLangRTL,
bool haveBidiKeyboards, nsString[] dictionaries,
ClipboardCapabilities clipboardCaps,

View File

@ -532,12 +532,6 @@
'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.
# http://crbug.com/105550
#
@ -665,7 +659,6 @@
'test_isolation_outdir%': '<(test_isolation_outdir)',
'enable_automation%': '<(enable_automation)',
'enable_printing%': '<(enable_printing)',
'enable_captive_portal_detection%': '<(enable_captive_portal_detection)',
'disable_ftp_support%': '<(disable_ftp_support)',
'force_rlz_use_chrome_net%': '<(force_rlz_use_chrome_net)',
'enable_task_manager%': '<(enable_task_manager)',
@ -1782,9 +1775,7 @@
['enable_printing==1', {
'defines': ['ENABLE_PRINTING=1'],
}],
['enable_captive_portal_detection==1', {
'defines': ['ENABLE_CAPTIVE_PORTAL_DETECTION=1'],
}],
['disable_ftp_support==1', {
'defines': ['DISABLE_FTP_SUPPORT=1'],
}],

View File

@ -28,7 +28,6 @@ DEFS_Debug := \
'-DENABLE_BACKGROUND=1' \
'-DENABLE_AUTOMATION=1' \
'-DENABLE_PRINTING=1' \
'-DENABLE_CAPTIVE_PORTAL_DETECTION=1' \
'-DWEBRTC_CHROMIUM_BUILD' \
'-DWEBRTC_LINUX' \
'-DWEBRTC_THREAD_RR' \
@ -118,7 +117,6 @@ DEFS_Release := \
'-DENABLE_BACKGROUND=1' \
'-DENABLE_AUTOMATION=1' \
'-DENABLE_PRINTING=1' \
'-DENABLE_CAPTIVE_PORTAL_DETECTION=1' \
'-DWEBRTC_CHROMIUM_BUILD' \
'-DWEBRTC_LINUX' \
'-DWEBRTC_THREAD_RR' \

View File

@ -207,7 +207,6 @@
@BINPATH@/components/satchel.xpt
@BINPATH@/components/saxparser.xpt
@BINPATH@/components/services-crypto-component.xpt
@BINPATH@/components/captivedetect.xpt
@BINPATH@/components/shistory.xpt
@BINPATH@/components/spellchecker.xpt
@BINPATH@/components/storage.xpt
@ -369,9 +368,6 @@
@BINPATH@/components/PeerConnection.manifest
#endif
@BINPATH@/components/CaptivePortalDetectComponents.manifest
@BINPATH@/components/captivedetect.js
#ifdef MOZ_WEBSPEECH
@BINPATH@/components/dom_webspeechsynth.xpt
#endif

View File

@ -4950,20 +4950,6 @@ pref("ui.touch_activation.duration_ms", 10);
// actions when the fifo is written to. Disable this in general.
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
pref("dom.forms.inputmode", false);
#else

View File

@ -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

View File

@ -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_

View File

@ -27,7 +27,6 @@ XPIDL_SOURCES += [
'nsICacheInfoChannel.idl',
'nsICachingChannel.idl',
'nsICancelable.idl',
'nsICaptivePortalService.idl',
'nsIChannel.idl',
'nsIChannelEventSink.idl',
'nsIChannelWithDivertableParentListener.idl',
@ -172,7 +171,6 @@ EXPORTS.mozilla += [
]
EXPORTS.mozilla.net += [
'CaptivePortalService.h',
'ChannelDiverterChild.h',
'ChannelDiverterParent.h',
'Dashboard.h',
@ -185,7 +183,6 @@ EXPORTS.mozilla.net += [
UNIFIED_SOURCES += [
'ArrayBufferInputStream.cpp',
'BackgroundFileSaver.cpp',
'CaptivePortalService.cpp',
'ChannelDiverterChild.cpp',
'ChannelDiverterParent.cpp',
'Dashboard.cpp',

View File

@ -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"
%}

View File

@ -52,7 +52,6 @@
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/net/CaptivePortalService.h"
#include "ReferrerPolicy.h"
#include "nsContentSecurityManager.h"
#include "nsContentUtils.h"
@ -72,7 +71,6 @@ namespace net {
#define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
#define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size"
#define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed"
#define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled"
#define MAX_RECURSION_COUNT 50
@ -209,8 +207,6 @@ nsIOService::Init()
else
NS_WARNING("failed to get error service");
InitializeCaptivePortalService();
// setup our bad port list stuff
for(int i=0; gBadPortList[i]; 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_SIZE_PREF, this, true);
prefBranch->AddObserver(NETWORK_NOTIFY_CHANGED_PREF, this, true);
prefBranch->AddObserver(NETWORK_CAPTIVE_PORTAL_PREF, this, true);
PrefsChanged(prefBranch);
}
@ -260,22 +255,6 @@ nsIOService::~nsIOService()
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
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
nsIOService::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
uint32_t flags,
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
// reference of the contentSecurityManager. But it lives in the XPCOM
// service registry.
@ -1138,15 +1065,6 @@ nsIOService::SetConnectivityInternal(bool 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();
if (!observerService) {
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
@ -1373,8 +1280,6 @@ nsIOService::NotifyWakeup()
(u"" NS_NETWORK_LINK_DATA_CHANGED));
}
RecheckCaptivePortal();
return NS_OK;
}
@ -1437,11 +1342,6 @@ nsIOService::Observe(nsISupports *subject,
SetOffline(true);
if (mCaptivePortalService) {
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
mCaptivePortalService = nullptr;
}
// Break circular reference.
mProxyService = nullptr;
} else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
@ -1609,8 +1509,6 @@ nsIOService::OnNetworkLinkEvent(const char *data)
bool isUp = true;
if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
// CHANGED means UP/DOWN didn't change
// but the status of the captive portal may have changed.
RecheckCaptivePortal();
return NS_OK;
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
isUp = false;

View File

@ -21,7 +21,6 @@
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "prtime.h"
#include "nsICaptivePortalService.h"
#define NS_N(x) (sizeof(x)/sizeof(*x))
@ -94,8 +93,6 @@ public:
static bool BlockToplevelDataUriNavigations();
// Used to trigger a recheck of the captive portal status
nsresult RecheckCaptivePortal();
private:
// These shouldn't be called directly:
// - construct using GetInstance
@ -113,9 +110,6 @@ private:
nsresult CacheProtocolHandler(const char *scheme,
nsIProtocolHandler* hdlr);
nsresult InitializeCaptivePortalService();
nsresult RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan);
// Prefs wrangling
void PrefsChanged(nsIPrefBranch *prefs, const char *pref = nullptr);
void GetPrefBranch(nsIPrefBranch **);
@ -159,7 +153,6 @@ private:
nsCOMPtr<nsPISocketTransportService> mSocketTransportService;
nsCOMPtr<nsPIDNSService> mDNSService;
nsCOMPtr<nsIProtocolProxyService2> mProxyService;
nsCOMPtr<nsICaptivePortalService> mCaptivePortalService;
nsCOMPtr<nsINetworkLinkService> mNetworkLinkService;
bool mNetworkLinkServiceInitialized;

View File

@ -470,17 +470,6 @@
{ 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
#define NS_REQUESTCONTEXTSERVICE_CONTRACTID \
"@mozilla.org/network/request-context-service;1"

View File

@ -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"
typedef mozilla::net::RequestContextService RequestContextService;
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_NSILOADCONTEXTINFOFACTORY_CID);
NS_DEFINE_NAMED_CID(NS_NETWORKPREDICTOR_CID);
NS_DEFINE_NAMED_CID(NS_CAPTIVEPORTAL_CID);
NS_DEFINE_NAMED_CID(NS_REQUESTCONTEXTSERVICE_CID);
#ifdef BUILD_NETWORK_INFO_SERVICE
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_NSILOADCONTEXTINFOFACTORY_CID, false, nullptr, LoadContextInfoFactoryConstructor },
{ &kNS_NETWORKPREDICTOR_CID, false, nullptr, mozilla::net::Predictor::Create },
{ &kNS_CAPTIVEPORTAL_CID, false, nullptr, mozilla::net::CaptivePortalServiceConstructor },
{ &kNS_REQUESTCONTEXTSERVICE_CID, false, nullptr, RequestContextServiceConstructor },
#ifdef BUILD_NETWORK_INFO_SERVICE
{ &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_NSILOADCONTEXTINFOFACTORY_CONTRACTID, &kNS_NSILOADCONTEXTINFOFACTORY_CID },
{ NS_NETWORKPREDICTOR_CONTRACTID, &kNS_NETWORKPREDICTOR_CID },
{ NS_CAPTIVEPORTAL_CONTRACTID, &kNS_CAPTIVEPORTAL_CID },
{ NS_REQUESTCONTEXTSERVICE_CONTRACTID, &kNS_REQUESTCONTEXTSERVICE_CID },
#ifdef BUILD_NETWORK_INFO_SERVICE
{ NETWORKINFOSERVICE_CONTRACT_ID, &kNETWORKINFOSERVICE_CID },

View File

@ -20,7 +20,6 @@
#include "nsICacheStorageService.h"
#include "nsICacheStorage.h"
#include "nsICacheEntry.h"
#include "nsICaptivePortalService.h"
#include "nsICryptoHash.h"
#include "nsINetworkInterceptController.h"
#include "nsINSSErrorsService.h"
@ -6491,13 +6490,6 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
MOZ_ASSERT(NS_IsMainThread(),
"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) {
mCacheReadEnd = TimeStamp::Now();
}

View File

@ -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.
user_pref("dom.use_xbl_scopes_for_remote_xul", true);
user_pref("captivedetect.canonicalURL", "http://%(server)s/captive-detect/success.txt");
// Get network events.
user_pref("network.activity.blipIntervalMilliseconds", 250);

View File

@ -1,2 +0,0 @@
component {d9cd00ba-aa4d-47b1-8792-b1fe0cd35060} captivedetect.js
contract @mozilla.org/toolkit/captive-detector;1 {d9cd00ba-aa4d-47b1-8792-b1fe0cd35060}

View File

@ -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]);

View File

@ -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',
]

View File

@ -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);
};

View File

@ -1,7 +0,0 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
]
};

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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]

View File

@ -95,8 +95,6 @@ if CONFIG['MOZ_TOOLKIT_SEARCH']:
if CONFIG['MOZ_URL_CLASSIFIER']:
DIRS += ['url-classifier']
DIRS += ['captivedetect']
if CONFIG['OS_TARGET'] != 'Android':
DIRS += ['terminator']