Merge mozilla-central to tabcandy-central.

This commit is contained in:
Ian Gilman 2010-10-05 13:43:50 -07:00
Родитель 5e94b5bcb5 fe05954c74
Коммит 63becd4137
397 изменённых файлов: 16975 добавлений и 8804 удалений

Просмотреть файл

@ -120,9 +120,6 @@ export::
ifdef ENABLE_TESTS
# Additional makefile targets to call automated test suites
include $(topsrcdir)/testing/testsuite-targets.mk
else
# OS X Universal builds will want to call this, so stub it out
package-tests:
endif
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -73,10 +73,10 @@
var jar = getJar(rootDir);
if (jar) {
var tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path;
rootDir = "file://" + tmpdir.path + '/';
}
var url = rootDir + "/scroll.html#link1";
var url = rootDir + "scroll.html#link1";
var tabBrowser = document.getElementById("tabBrowser");
tabBrowser.loadURI(url);
}

Просмотреть файл

@ -39,7 +39,7 @@
}
var rootDir = getRootDirectory(window.location.href);
var href = rootDir.path + "/foo";
var href = rootDir.path + "foo";
// roles that can't live as nsHTMLLinkAccessibles
testValue("aria_menuitem_link", "");

Просмотреть файл

@ -1042,10 +1042,8 @@ pref("services.sync.prefs.sync.spellchecker.dictionary", true);
pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
#endif
// Disable the Error Console
// Disable the error console and inspector
pref("devtools.errorconsole.enabled", false);
// disable the Inspector
pref("devtools.inspector.enabled", false);
// Whether the character encoding menu is under the main Firefox button. This

Просмотреть файл

@ -147,7 +147,7 @@ toolbar[mode="icons"] > #reload-button[displaystop] {
}
#urlbar-progress {
-moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter");
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#urlbar-progress");
}
/* Some child nodes want to be ordered based on the locale's direction, while

Просмотреть файл

@ -1582,7 +1582,8 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
}
// Enable Error Console?
let consoleEnabled = gPrefService.getBoolPref("devtools.errorconsole.enabled");
// XXX Temporarily always-enabled, see bug 601201
let consoleEnabled = true || gPrefService.getBoolPref("devtools.errorconsole.enabled");
if (consoleEnabled) {
document.getElementById("javascriptConsole").hidden = false;
document.getElementById("key_errorConsole").removeAttribute("disabled");

Просмотреть файл

@ -23,11 +23,15 @@
}
.tab-label[pinned] {
display: none;
width: 0;
margin-left: 0 !important;
margin-right: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
}
.tab-stack {
vertical-align: middle; /* for pinned tabs */
vertical-align: top; /* for pinned tabs */
}
tabpanels {

Просмотреть файл

@ -590,7 +590,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this.$undoContainer = iQ("<div/>")
.addClass("undo")
.attr("type", "button")
.text("Undo Close Group")
.text(tabviewString("groupItem.undoCloseGroup"))
.appendTo("body");
let undoClose = iQ("<span/>")
.addClass("close")

Просмотреть файл

@ -355,7 +355,7 @@ function test9()
gBrowser.removeTab(tab, {animate: false});
// Next test
executeSoon(finish);
executeSoon(test10);
});
};
@ -372,3 +372,38 @@ function test9()
tab.linkedBrowser.loadURI(uri);
}
/**
* In this test, we check that the author defined error message is shown.
*/
function test10()
{
let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input x-moz-errormessage='foo' required id='i'><input id='s' type='submit'></form>";
let tab = gBrowser.addTab();
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
is(gInvalidFormPopup.firstChild.nodeValue, "foo",
"The panel should show the author defined error message");
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
executeSoon(finish);
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
gBrowser.contentDocument.getElementById('s').click();
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedTab.linkedBrowser.loadURI(uri);
}

Просмотреть файл

@ -11,8 +11,8 @@ function test()
// Now run the tests again and then close C.
// The test results does not matter, all this is just to exercise some code to
// catch assertions or crashes.
var uri = "chrome://mochikit/content/browser/" +
"browser/base/content/test/browser_tab_dragdrop2_frame1.xul";
var chromeroot = getRootDirectory(gTestPath);
var uri = chromeroot + "browser_tab_dragdrop2_frame1.xul";
let window_B = openDialog(location, "_blank", "chrome,all,dialog=no,left=200,top=200,width=200,height=200", uri);
window_B.addEventListener("load", function(aEvent) {
window_B.removeEventListener("load", arguments.callee, false);

Просмотреть файл

@ -951,4 +951,16 @@
]]></constructor>
</implementation>
</binding>
<binding id="urlbar-progress" extends="chrome://global/content/bindings/progressmeter.xml#progressmeter">
<handlers>
<handler event="transitionend"><![CDATA[
if (this.hasAttribute("slideback") || this.value > 0)
this.removeAttribute("slideback");
else
this.setAttribute("slideback", true);
]]></handler>
</handlers>
</binding>
</bindings>

Просмотреть файл

@ -531,8 +531,7 @@ nsBrowserContentHandler.prototype = {
}
if (cmdLine.handleFlag("silent", false))
cmdLine.preventDefault = true;
if (cmdLine.findFlag("private-toggle", false) >= 0 &&
cmdLine.state != cmdLine.STATE_INITIAL_LAUNCH)
if (cmdLine.findFlag("private-toggle", false) >= 0)
cmdLine.preventDefault = true;
var searchParam = cmdLine.handleFlagWithParam("search", false);

Просмотреть файл

@ -165,6 +165,10 @@ BrowserGlue.prototype = {
case "final-ui-startup":
this._onProfileStartup();
break;
case "browser-delayed-startup-finished":
this._onFirstWindowLoaded();
Services.obs.removeObserver(this, "browser-delayed-startup-finished");
break;
case "sessionstore-windows-restored":
this._onBrowserStartup();
break;
@ -260,6 +264,7 @@ BrowserGlue.prototype = {
os.addObserver(this, "xpcom-shutdown", false);
os.addObserver(this, "prefservice:after-app-defaults", false);
os.addObserver(this, "final-ui-startup", false);
os.addObserver(this, "browser-delayed-startup-finished", false);
os.addObserver(this, "sessionstore-windows-restored", false);
os.addObserver(this, "browser:purge-session-history", false);
os.addObserver(this, "quit-application-requested", false);
@ -347,6 +352,22 @@ BrowserGlue.prototype = {
Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
},
// the first browser window has finished initializing
_onFirstWindowLoaded: function BG__onFirstWindowLoaded() {
#ifdef XP_WIN
#ifndef WINCE
// For windows seven, initialize the jump list module.
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
if (WINTASKBAR_CONTRACTID in Cc &&
Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
let temp = {};
Cu.import("resource://gre/modules/WindowsJumpLists.jsm", temp);
temp.WinTaskbarJumpList.startup();
}
#endif
#endif
},
// profile shutdown handler (contains profile cleanup routines)
_onProfileShutdown: function BG__onProfileShutdown() {
#ifdef MOZ_UPDATER
@ -408,19 +429,6 @@ BrowserGlue.prototype = {
// been warned about them yet, open the plugins update page.
if (Services.prefs.getBoolPref(PREF_PLUGINS_NOTIFYUSER))
this._showPluginUpdatePage();
#ifdef XP_WIN
#ifndef WINCE
// For windows seven, initialize the jump list module.
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
if (WINTASKBAR_CONTRACTID in Cc &&
Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
let temp = {};
Cu.import("resource://gre/modules/WindowsJumpLists.jsm", temp);
temp.WinTaskbarJumpList.startup();
}
#endif
#endif
},
_onQuitRequest: function BG__onQuitRequest(aCancelQuit, aQuitType) {

Просмотреть файл

@ -43,9 +43,9 @@ function test() {
let jar = getJar(rootDir);
if (jar) {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path;
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
run_test_subset([
test_pane_visibility,

Просмотреть файл

@ -43,9 +43,9 @@ function test() {
let jar = getJar(rootDir);
if (jar) {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path;
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
run_test_subset([
test_historymode_retention("remember", undefined),

Просмотреть файл

@ -42,9 +42,9 @@ function test() {
let jar = getJar(rootDir);
if (jar) {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path;
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
run_test_subset([
test_custom_retention("rememberHistory", "remember"),

Просмотреть файл

@ -42,9 +42,9 @@ function test() {
let jar = getJar(rootDir);
if (jar) {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path;
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
run_test_subset([
test_custom_retention("acceptCookies", "remember"),

Просмотреть файл

@ -42,9 +42,9 @@ function test() {
let jar = getJar(rootDir);
if (jar) {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path;
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
run_test_subset([
test_locbar_suggestion_retention(-1, undefined),

Просмотреть файл

@ -42,9 +42,9 @@ function test() {
let jar = getJar(rootDir);
if (jar) {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path;
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
run_test_subset([
test_privatebrowsing_toggle,

Просмотреть файл

@ -42,9 +42,9 @@ function test() {
let jar = getJar(rootDir);
if (jar) {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path;
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
run_test_subset([
test_privatebrowsing_ui,

Просмотреть файл

@ -41,9 +41,9 @@ function test() {
let jar = getJar(rootDir);
if (jar) {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path;
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
run_test_subset([
// history mode should be initialized to remember

Просмотреть файл

@ -129,6 +129,9 @@ PrivateBrowsingService.prototype = {
// List of nsIXULWindows we are going to be closing during the transition
_windowsToClose: [],
// Whether private browsing has been turned on from the command line
_lastChangedByCommandLine: false,
// XPCOM registration
classID: Components.ID("{c31f4883-839b-45f6-82ad-a6a9bc5ad599}"),
@ -231,6 +234,9 @@ PrivateBrowsingService.prototype = {
// to be restored, do it now
if (!this._inPrivateBrowsing) {
this._currentStatus = STATE_WAITING_FOR_RESTORE;
if (!this._getBrowserWindow()) {
ss.init(null);
}
ss.setBrowserState(this._savedBrowserState);
this._savedBrowserState = null;
@ -273,6 +279,9 @@ PrivateBrowsingService.prototype = {
};
// Transition into private browsing mode
this._currentStatus = STATE_WAITING_FOR_RESTORE;
if (!this._getBrowserWindow()) {
ss.init(null);
}
ss.setBrowserState(JSON.stringify(privateBrowsingState));
}
}
@ -439,6 +448,10 @@ PrivateBrowsingService.prototype = {
if (aSubject.findFlag("private", false) >= 0) {
this.privateBrowsingEnabled = true;
this._autoStarted = true;
this._lastChangedByCommandLine = true;
}
else if (aSubject.findFlag("private-toggle", false) >= 0) {
this._lastChangedByCommandLine = true;
}
break;
case "sessionstore-browser-state-restored":
@ -458,6 +471,7 @@ PrivateBrowsingService.prototype = {
else if (aCmdLine.handleFlag("private-toggle", false)) {
this.privateBrowsingEnabled = !this.privateBrowsingEnabled;
this._autoStarted = false;
this._lastChangedByCommandLine = true;
}
},
@ -534,6 +548,7 @@ PrivateBrowsingService.prototype = {
} finally {
this._windowsToClose = [];
this._notifyIfTransitionComplete();
this._lastChangedByCommandLine = false;
}
},
@ -544,6 +559,13 @@ PrivateBrowsingService.prototype = {
return this._inPrivateBrowsing && this._autoStarted;
},
/**
* Whether the latest transition was initiated from the command line.
*/
get lastChangedByCommandLine() {
return this._lastChangedByCommandLine;
},
removeDataFromDomain: function PBS_removeDataFromDomain(aDomain)
{

Просмотреть файл

@ -106,6 +106,15 @@ nsPrivateBrowsingServiceWrapper::GetAutoStarted(PRBool *aAutoStarted)
return mPBService->GetAutoStarted(aAutoStarted);
}
NS_IMETHODIMP
nsPrivateBrowsingServiceWrapper::GetLastChangedByCommandLine(PRBool *aReason)
{
if (!aReason)
return NS_ERROR_NULL_POINTER;
JSStackGuard guard;
return mPBService->GetLastChangedByCommandLine(aReason);
}
NS_IMETHODIMP
nsPrivateBrowsingServiceWrapper::RemoveDataFromDomain(const nsACString & aDomain)
{

Просмотреть файл

@ -128,6 +128,8 @@ function test() {
is(browser.contentWindow.location, "about:", "The correct page has been loaded");
simulatePrivateCommandLineArgument();
is(pb.lastChangedByCommandLine, true,
"The status change reason should reflect the PB mode being set from the command line");
tab = gBrowser.selectedTab;
browser = gBrowser.getBrowserForTab(tab);
browser.addEventListener("load", function() {
@ -137,6 +139,8 @@ function test() {
"about:privatebrowsing should now be loaded");
simulatePrivateCommandLineArgument();
is(pb.lastChangedByCommandLine, true,
"The status change reason should reflect the PB mode being set from the command line");
tab = gBrowser.selectedTab;
browser = gBrowser.getBrowserForTab(tab);
browser.addEventListener("load", function() {

Просмотреть файл

@ -0,0 +1,250 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Private Browsing Tests.
*
* The Initial Developer of the Original Code is
* Ehsan Akhgari.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// This tests the private browsing service to make sure it implements its
// documented interface correctly.
// This test should run before the rest of private browsing service unit tests,
// hence the naming used for this file.
function do_test() {
// initialization
var os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
// the contract ID should be available
do_check_true(PRIVATEBROWSING_CONTRACT_ID in Cc);
// the interface should be available
do_check_true("nsIPrivateBrowsingService" in Ci);
// it should be possible to initialize the component
try {
var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
getService(Ci.nsIPrivateBrowsingService);
} catch (ex) {
LOG("exception thrown when trying to get the service: " + ex);
do_throw("private browsing service could not be initialized");
}
// private browsing should be turned off initially
do_check_false(pb.privateBrowsingEnabled);
// private browsing not auto-started
do_check_false(pb.autoStarted);
// and the status should have never been changed
do_check_eq(pb.lastChangedByCommandLine, false);
// it should be possible to toggle its status
pb.privateBrowsingEnabled = true;
do_check_true(pb.privateBrowsingEnabled);
do_check_false(pb.autoStarted);
do_check_eq(pb.lastChangedByCommandLine, false);
pb.privateBrowsingEnabled = false;
do_check_false(pb.privateBrowsingEnabled);
do_check_false(pb.autoStarted);
do_check_eq(pb.lastChangedByCommandLine, false);
// test the private-browsing notification
var observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == kPrivateBrowsingNotification)
this.data = aData;
},
data: null
};
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_eq(observer.data, kEnter);
pb.privateBrowsingEnabled = false;
do_check_eq(observer.data, kExit);
os.removeObserver(observer, kPrivateBrowsingNotification);
// make sure that setting the private browsing mode from within an observer throws
observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == kPrivateBrowsingNotification) {
try {
pb.privateBrowsingEnabled = (aData == kEnter);
do_throw("Setting privateBrowsingEnabled inside the " + aData +
" notification should throw");
} catch (ex) {
if (!("result" in ex && ex.result == Cr.NS_ERROR_FAILURE))
do_throw("Unexpected exception caught: " + ex);
}
}
}
};
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_true(pb.privateBrowsingEnabled); // the exception should not interfere with the mode change
pb.privateBrowsingEnabled = false;
do_check_false(pb.privateBrowsingEnabled); // the exception should not interfere with the mode change
os.removeObserver(observer, kPrivateBrowsingNotification);
// make sure that getting the private browsing mode from within an observer doesn't throw
observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == kPrivateBrowsingNotification) {
try {
var dummy = pb.privateBrowsingEnabled;
if (aData == kEnter)
do_check_true(dummy);
else if (aData == kExit)
do_check_false(dummy);
} catch (ex) {
do_throw("Unexpected exception caught: " + ex);
}
}
}
};
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_true(pb.privateBrowsingEnabled); // just a sanity check
pb.privateBrowsingEnabled = false;
do_check_false(pb.privateBrowsingEnabled); // just a sanity check
os.removeObserver(observer, kPrivateBrowsingNotification);
// check that the private-browsing-cancel-vote notification is sent before the
// private-browsing notification
observer = {
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case kPrivateBrowsingCancelVoteNotification:
case kPrivateBrowsingNotification:
this.notifications.push(aTopic + " " + aData);
}
},
notifications: []
};
os.addObserver(observer, kPrivateBrowsingCancelVoteNotification, false);
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_true(pb.privateBrowsingEnabled); // just a sanity check
pb.privateBrowsingEnabled = false;
do_check_false(pb.privateBrowsingEnabled); // just a sanity check
os.removeObserver(observer, kPrivateBrowsingNotification);
os.removeObserver(observer, kPrivateBrowsingCancelVoteNotification);
var reference_order = [
kPrivateBrowsingCancelVoteNotification + " " + kEnter,
kPrivateBrowsingNotification + " " + kEnter,
kPrivateBrowsingCancelVoteNotification + " " + kExit,
kPrivateBrowsingNotification + " " + kExit
];
do_check_eq(observer.notifications.join(","), reference_order.join(","));
// make sure that the private-browsing-cancel-vote notification can be used
// to cancel the mode switch
observer = {
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case kPrivateBrowsingCancelVoteNotification:
do_check_neq(aSubject, null);
try {
aSubject.QueryInterface(Ci.nsISupportsPRBool);
} catch (ex) {
do_throw("aSubject in " + kPrivateBrowsingCancelVoteNotification +
" should implement nsISupportsPRBool");
}
do_check_false(aSubject.data);
aSubject.data = true; // cancel the mode switch
// fall through
case kPrivateBrowsingNotification:
this.notifications.push(aTopic + " " + aData);
}
},
nextPhase: function() {
this.notifications.push("enter phase " + (++this._phase));
},
notifications: [],
_phase: 0
};
os.addObserver(observer, kPrivateBrowsingCancelVoteNotification, false);
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_false(pb.privateBrowsingEnabled); // should have been canceled
// temporarily disable the observer
os.removeObserver(observer, kPrivateBrowsingCancelVoteNotification);
observer.nextPhase();
pb.privateBrowsingEnabled = true; // this time, should enter successfully
do_check_true(pb.privateBrowsingEnabled); // should have been canceled
// re-enable the observer
os.addObserver(observer, kPrivateBrowsingCancelVoteNotification, false);
pb.privateBrowsingEnabled = false;
do_check_true(pb.privateBrowsingEnabled); // should have been canceled
os.removeObserver(observer, kPrivateBrowsingCancelVoteNotification);
observer.nextPhase();
pb.privateBrowsingEnabled = false; // this time, should exit successfully
do_check_false(pb.privateBrowsingEnabled);
os.removeObserver(observer, kPrivateBrowsingNotification);
reference_order = [
kPrivateBrowsingCancelVoteNotification + " " + kEnter,
"enter phase 1",
kPrivateBrowsingNotification + " " + kEnter,
kPrivateBrowsingCancelVoteNotification + " " + kExit,
"enter phase 2",
kPrivateBrowsingNotification + " " + kExit,
];
do_check_eq(observer.notifications.join(","), reference_order.join(","));
// make sure that the private browsing transition complete notification is
// raised correctly.
observer = {
observe: function(aSubject, aTopic, aData) {
this.notifications.push(aTopic + " " + aData);
},
notifications: []
};
os.addObserver(observer, kPrivateBrowsingNotification, false);
os.addObserver(observer, kPrivateBrowsingTransitionCompleteNotification, false);
pb.privateBrowsingEnabled = true;
pb.privateBrowsingEnabled = false;
os.removeObserver(observer, kPrivateBrowsingNotification);
os.removeObserver(observer, kPrivateBrowsingTransitionCompleteNotification);
reference_order = [
kPrivateBrowsingNotification + " " + kEnter,
kPrivateBrowsingTransitionCompleteNotification + " ",
kPrivateBrowsingNotification + " " + kExit,
kPrivateBrowsingTransitionCompleteNotification + " ",
];
do_check_eq(observer.notifications.join(","), reference_order.join(","));
}
// Support running tests on both the service itself and its wrapper
function run_test() {
run_test_on_all_services();
}

Просмотреть файл

@ -118,4 +118,6 @@ function do_test() {
do_check_true(pb.privateBrowsingEnabled);
// and should appear as auto-started!
do_check_true(pb.autoStarted);
// and should be coming from the command line!
do_check_eq(pb.lastChangedByCommandLine, true);
}

Просмотреть файл

@ -38,209 +38,8 @@
// This tests the private browsing service to make sure it implements its
// documented interface correctly.
// This test should run before the rest of private browsing service unit tests,
// hence the naming used for this file.
function run_test_on_service() {
// initialization
var os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
// the contract ID should be available
do_check_true(PRIVATEBROWSING_CONTRACT_ID in Cc);
// the interface should be available
do_check_true("nsIPrivateBrowsingService" in Ci);
// it should be possible to initialize the component
try {
var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
getService(Ci.nsIPrivateBrowsingService);
} catch (ex) {
LOG("exception thrown when trying to get the service: " + ex);
do_throw("private browsing service could not be initialized");
}
// private browsing should be turned off initially
do_check_false(pb.privateBrowsingEnabled);
// private browsing not auto-started
do_check_false(pb.autoStarted);
// it should be possible to toggle its status
pb.privateBrowsingEnabled = true;
do_check_true(pb.privateBrowsingEnabled);
do_check_false(pb.autoStarted);
pb.privateBrowsingEnabled = false;
do_check_false(pb.privateBrowsingEnabled);
do_check_false(pb.autoStarted);
// test the private-browsing notification
var observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == kPrivateBrowsingNotification)
this.data = aData;
},
data: null
};
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_eq(observer.data, kEnter);
pb.privateBrowsingEnabled = false;
do_check_eq(observer.data, kExit);
os.removeObserver(observer, kPrivateBrowsingNotification);
// make sure that setting the private browsing mode from within an observer throws
observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == kPrivateBrowsingNotification) {
try {
pb.privateBrowsingEnabled = (aData == kEnter);
do_throw("Setting privateBrowsingEnabled inside the " + aData +
" notification should throw");
} catch (ex) {
if (!("result" in ex && ex.result == Cr.NS_ERROR_FAILURE))
do_throw("Unexpected exception caught: " + ex);
}
}
}
};
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_true(pb.privateBrowsingEnabled); // the exception should not interfere with the mode change
pb.privateBrowsingEnabled = false;
do_check_false(pb.privateBrowsingEnabled); // the exception should not interfere with the mode change
os.removeObserver(observer, kPrivateBrowsingNotification);
// make sure that getting the private browsing mode from within an observer doesn't throw
observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == kPrivateBrowsingNotification) {
try {
var dummy = pb.privateBrowsingEnabled;
if (aData == kEnter)
do_check_true(dummy);
else if (aData == kExit)
do_check_false(dummy);
} catch (ex) {
do_throw("Unexpected exception caught: " + ex);
}
}
}
};
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_true(pb.privateBrowsingEnabled); // just a sanity check
pb.privateBrowsingEnabled = false;
do_check_false(pb.privateBrowsingEnabled); // just a sanity check
os.removeObserver(observer, kPrivateBrowsingNotification);
// check that the private-browsing-cancel-vote notification is sent before the
// private-browsing notification
observer = {
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case kPrivateBrowsingCancelVoteNotification:
case kPrivateBrowsingNotification:
this.notifications.push(aTopic + " " + aData);
}
},
notifications: []
};
os.addObserver(observer, kPrivateBrowsingCancelVoteNotification, false);
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_true(pb.privateBrowsingEnabled); // just a sanity check
pb.privateBrowsingEnabled = false;
do_check_false(pb.privateBrowsingEnabled); // just a sanity check
os.removeObserver(observer, kPrivateBrowsingNotification);
os.removeObserver(observer, kPrivateBrowsingCancelVoteNotification);
var reference_order = [
kPrivateBrowsingCancelVoteNotification + " " + kEnter,
kPrivateBrowsingNotification + " " + kEnter,
kPrivateBrowsingCancelVoteNotification + " " + kExit,
kPrivateBrowsingNotification + " " + kExit
];
do_check_eq(observer.notifications.join(","), reference_order.join(","));
// make sure that the private-browsing-cancel-vote notification can be used
// to cancel the mode switch
observer = {
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case kPrivateBrowsingCancelVoteNotification:
do_check_neq(aSubject, null);
try {
aSubject.QueryInterface(Ci.nsISupportsPRBool);
} catch (ex) {
do_throw("aSubject in " + kPrivateBrowsingCancelVoteNotification +
" should implement nsISupportsPRBool");
}
do_check_false(aSubject.data);
aSubject.data = true; // cancel the mode switch
// fall through
case kPrivateBrowsingNotification:
this.notifications.push(aTopic + " " + aData);
}
},
nextPhase: function() {
this.notifications.push("enter phase " + (++this._phase));
},
notifications: [],
_phase: 0
};
os.addObserver(observer, kPrivateBrowsingCancelVoteNotification, false);
os.addObserver(observer, kPrivateBrowsingNotification, false);
pb.privateBrowsingEnabled = true;
do_check_false(pb.privateBrowsingEnabled); // should have been canceled
// temporarily disable the observer
os.removeObserver(observer, kPrivateBrowsingCancelVoteNotification);
observer.nextPhase();
pb.privateBrowsingEnabled = true; // this time, should enter successfully
do_check_true(pb.privateBrowsingEnabled); // should have been canceled
// re-enable the observer
os.addObserver(observer, kPrivateBrowsingCancelVoteNotification, false);
pb.privateBrowsingEnabled = false;
do_check_true(pb.privateBrowsingEnabled); // should have been canceled
os.removeObserver(observer, kPrivateBrowsingCancelVoteNotification);
observer.nextPhase();
pb.privateBrowsingEnabled = false; // this time, should exit successfully
do_check_false(pb.privateBrowsingEnabled);
os.removeObserver(observer, kPrivateBrowsingNotification);
reference_order = [
kPrivateBrowsingCancelVoteNotification + " " + kEnter,
"enter phase 1",
kPrivateBrowsingNotification + " " + kEnter,
kPrivateBrowsingCancelVoteNotification + " " + kExit,
"enter phase 2",
kPrivateBrowsingNotification + " " + kExit,
];
do_check_eq(observer.notifications.join(","), reference_order.join(","));
// make sure that the private browsing transition complete notification is
// raised correctly.
observer = {
observe: function(aSubject, aTopic, aData) {
this.notifications.push(aTopic + " " + aData);
},
notifications: []
};
os.addObserver(observer, kPrivateBrowsingNotification, false);
os.addObserver(observer, kPrivateBrowsingTransitionCompleteNotification, false);
pb.privateBrowsingEnabled = true;
pb.privateBrowsingEnabled = false;
os.removeObserver(observer, kPrivateBrowsingNotification);
os.removeObserver(observer, kPrivateBrowsingTransitionCompleteNotification);
reference_order = [
kPrivateBrowsingNotification + " " + kEnter,
kPrivateBrowsingTransitionCompleteNotification + " ",
kPrivateBrowsingNotification + " " + kExit,
kPrivateBrowsingTransitionCompleteNotification + " ",
];
do_check_eq(observer.notifications.join(","), reference_order.join(","));
}
// Support running tests on both the service itself and its wrapper
function run_test() {
run_test_on_all_services();
PRIVATEBROWSING_CONTRACT_ID = "@mozilla.org/privatebrowsing;1";
load("do_test_0-privatebrowsing.js");
do_test();
}

Просмотреть файл

@ -0,0 +1,45 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Private Browsing Tests.
*
* The Initial Developer of the Original Code is
* Ehsan Akhgari.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// This tests the private browsing service to make sure it implements its
// documented interface correctly.
function run_test() {
PRIVATEBROWSING_CONTRACT_ID = "@mozilla.org/privatebrowsing-wrapper;1";
load("do_test_0-privatebrowsing.js");
do_test();
}

Просмотреть файл

@ -101,7 +101,7 @@ SessionStartup.prototype = {
// do not need to initialize anything in auto-started private browsing sessions
let pbs = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
if (pbs.autoStarted)
if (pbs.autoStarted || pbs.lastChangedByCommandLine)
return;
let prefBranch = Cc["@mozilla.org/preferences-service;1"].
@ -237,7 +237,12 @@ SessionStartup.prototype = {
aWindow.arguments[0] == defaultArgs)
aWindow.arguments[0] = null;
try {
Services.obs.removeObserver(this, "domwindowopened");
} catch (e) {
// This might throw if we're removing the observer multiple times,
// but this is safe to ignore.
}
},
/* ........ Public API ................*/

Просмотреть файл

@ -214,6 +214,9 @@ SessionStoreService.prototype = {
// The state from the previous session (after restoring pinned tabs)
_lastSessionState: null,
// Whether we've been initialized
_initialized: false,
/* ........ Public Getters .............. */
get canRestoreLastSession() {
@ -233,15 +236,7 @@ SessionStoreService.prototype = {
/**
* Initialize the component
*/
init: function sss_init(aWindow) {
if (!aWindow || this._loadState == STATE_RUNNING) {
// make sure that all browser windows which try to initialize
// SessionStore are really tracked by it
if (aWindow && (!aWindow.__SSi || !this._windows[aWindow.__SSi]))
this.onLoad(aWindow);
return;
}
initService: function() {
this._prefBranch = Services.prefs.getBranch("browser.");
this._prefBranch.QueryInterface(Ci.nsIPrefBranch2);
@ -354,6 +349,34 @@ SessionStoreService.prototype = {
this._prefBranch.getBoolPref("sessionstore.resume_session_once"))
this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
this._initialized = true;
},
/**
* Start tracking a window.
* Important note: despite its name, this function doesn't initialize
* the component!
*/
init: function sss_init(aWindow) {
if (!aWindow || this._loadState == STATE_RUNNING) {
// make sure that all browser windows which try to initialize
// SessionStore are really tracked by it
if (aWindow && (!aWindow.__SSi || !this._windows[aWindow.__SSi]))
this.onLoad(aWindow);
// If init is being called with a null window, it's possible that we
// just want to tell sessionstore that a session is live (as is the case
// with starting Firefox with -private, for example; see bug 568816),
// so we should mark the load state as running to make sure that
// things like setBrowserState calls will succeed in restoring the session.
if (!aWindow && this._loadState == STATE_STOPPED)
this._loadState = STATE_RUNNING;
return;
}
// Initialize the service if needed.
if (!this._initialized)
this.initService();
// As this is called at delayedStartup, restoration must be initiated here
this.onLoad(aWindow);
},
@ -3539,10 +3562,15 @@ SessionStoreService.prototype = {
function sss__resetTabRestoringState(aTab, aRestoreNextTab, aRestoreThisTab) {
let browser = aTab.linkedBrowser;
// Always delete the session history listener off the browser
delete browser.__SS_shistoryListener;
if (browser.__SS_restoring) {
// If the session history listener hasn't been detached, make sure we
// remove it and delete the reference.
if (browser.__SS_shistoryListener) {
browser.webNavigation.sessionHistory.
removeSHistoryListener(browser.__SS_shistoryListener);
delete browser.__SS_shistoryListener;
}
delete browser.__SS_restoring;
if (aRestoreNextTab) {
// this._tabsRestoringCount is decremented in restoreNextTab.
@ -3721,8 +3749,12 @@ let gRestoreTabsProgressListener = {
aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
delete aBrowser.__SS_restoring;
this.ss.restoreNextTab(true);
// We need to reset the tab before starting the next restore.
// _resetTabRestoringState will make sure we remove the session history
// listener and will call restoreNextTab.
let window = aBrowser.ownerDocument.defaultView;
let tab = window.gBrowser._getTabForContentWindow(aBrowser.contentWindow);
this.ss._resetTabRestoringState(tab, true, false);
}
}
}

Просмотреть файл

@ -577,7 +577,7 @@ function test_reload() {
if (loadCount == state.windows[0].tabs.length) {
window.gBrowser.removeTabsProgressListener(progressListener);
runNextTest();
test_reload2(state);
}
else {
// reload the next tab
@ -592,6 +592,62 @@ function test_reload() {
}
// This test shouldn't be added to tests. It will be called directly from
// test_reload. This guarantees that we're already in a tested restored state
// and we know what the state should be.
function test_reload2(aState) {
info("starting test_reload2");
let progressListener = {
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
test_reload2_progressCallback(aBrowser);
}
}
// Simulate a left mouse button click with no modifiers, which is what
// Command-R, or clicking reload does.
let fakeEvent = {
button: 0,
metaKey: false,
altKey: false,
ctrlKey: false,
shiftKey: false,
}
let loadCount = 0;
function test_reload2_progressCallback(aBrowser) {
loadCount++;
if (loadCount <= aState.windows[0].tabs.length) {
// double check that this tab was the right one
let expectedData = aState.windows[0].tabs[loadCount - 1].extData.uniq;
let tab;
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser)
tab = window.gBrowser.tabs[i];
}
is(ss.getTabValue(tab, "uniq"), expectedData,
"test_reload2: load " + loadCount + " - correct tab was reloaded");
if (loadCount == aState.windows[0].tabs.length) {
window.gBrowser.removeTabsProgressListener(progressListener);
runNextTest();
}
else {
// reload the next tab
window.gBrowser.selectTabAtIndex(loadCount);
BrowserReloadOrDuplicate(fakeEvent);
}
}
}
window.gBrowser.addTabsProgressListener(progressListener);
BrowserReloadOrDuplicate(fakeEvent);
}
function countTabs() {
let needsRestore = 0,
isRestoring = 0,

Просмотреть файл

@ -150,7 +150,7 @@ var tasksCfg = [
close: false, // no point
},
// Privacy mode
// Toggle the Private Browsing mode
{
get title() {
if (_privateBrowsingSvc.privateBrowsingEnabled)

Просмотреть файл

@ -1,3 +1,4 @@
tabview.groupItem.newTabButton=New tab
tabview.groupItem.defaultName=Name this tab group…
tabview.groupItem.undoCloseGroup=Undo Close Group
tabview.search.otherWindowTabs=Tabs from other windows

Просмотреть файл

@ -964,9 +964,18 @@ toolbar[iconsize="small"] #sync-button[status="active"] {
background-color: transparent;
}
.tab-progress[busy][stalled][value="0"],
#urlbar-progress[busy][stalled][value="0"] {
/* TODO: add connecting state (bug 596812) */
#urlbar-progress[value="0"] > .progress-remainder {
background-image: -moz-linear-gradient(left, rgba(255,255,255,0), rgb(255,255,255), rgba(255,255,255,0)) !important;
background-size: 10%;
background-repeat: no-repeat;
background-position: right;
-moz-transition-property: background-position;
-moz-transition-duration: 2s;
-moz-transition-timing-function: linear;
}
#urlbar-progress[value="0"][slideback] > .progress-remainder {
background-position: left;
}
.tab-progress > .progress-bar,

Просмотреть файл

@ -450,26 +450,26 @@ input.defaultName {
opacity: .70;
}
#otherresults{
#otherresults {
left: 0px;
bottom: 0px;
width: 100%;
height: 30px;
background-color: rgba(0,0,0,.3);
-moz-box-shadow: 0px -1px 0px rgba(255,255,255,.1), inset 0px 2px 5px rgba(0,0,0,.3);
box-shadow: 0px -1px 0px rgba(255,255,255,.1), inset 0px 2px 5px rgba(0,0,0,.3);
}
#otherresults .label{
#otherresults .label {
color: #999;
line-height:30px;
margin-left:5px;
line-height: 30px;
margin-left: 5px;
margin-right: 5px;
}
.inlineMatch{
.inlineMatch {
background-color: #EBEBEB;
border-radius: 0.4em;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
border: 1px solid rgba(255, 255, 255, 0.5);
padding-left: 3px;
padding-right: 3px;
@ -478,17 +478,17 @@ input.defaultName {
cursor: pointer;
}
.inlineMatch:hover{
.inlineMatch:hover {
opacity: 1.0;
}
.inlineMatch>img{
.inlineMatch > img {
margin-right: 5px;
position: relative;
top: 2px;
}
.inlineMatch>span{
max-width:200px;
.inlineMatch > span {
max-width: 200px;
height: 15px;
}

Просмотреть файл

@ -912,9 +912,18 @@ toolbar[mode="icons"] #zoom-in-button {
margin: -2px 0 -1px;
}
.tab-progress[busy][stalled][value="0"],
#urlbar-progress[busy][stalled][value="0"] {
/* TODO: add connecting state (bug 596812) */
#urlbar-progress[value="0"] > .progress-remainder {
background-image: -moz-linear-gradient(left, rgba(255,255,255,0), rgb(255,255,255), rgba(255,255,255,0)) !important;
background-size: 10%;
background-repeat: no-repeat;
background-position: right;
-moz-transition-property: background-position;
-moz-transition-duration: 2s;
-moz-transition-timing-function: linear;
}
#urlbar-progress[value="0"][slideback] > .progress-remainder {
background-position: left;
}
.tab-progress > .progress-bar,
@ -961,13 +970,8 @@ toolbar[mode="icons"] #zoom-in-button {
/* tab progress */
.tab-progress-container {
margin-top: -2px;
}
#tabbrowser-tabs[tabsontop="false"] > .tabbrowser-tab > .tab-stack > .tab-progress-container {
-moz-box-pack: end;
margin-bottom: -2px;
}
/* ----- AUTOCOMPLETE ----- */
@ -1549,6 +1553,11 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
font-weight: bold;
}
.tab-stack {
/* ensure stable tab height with and without toolbarbuttons on the tab bar */
height: 19px;
}
.tabbrowser-tab,
.tabs-newtab-button {
-moz-appearance: none;
@ -1565,7 +1574,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
-moz-border-left-colors: rgba(0,0,0,.04) rgba(0,0,0,.17) rgba(255,255,255,.1);
background-clip: padding-box;
text-align: center;
height: 24px;
background-image: url(chrome://browser/skin/tabbrowser/tab-bkgnd.png);
}

Просмотреть файл

@ -1098,9 +1098,18 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
background-color: transparent;
}
.tab-progress[busy][stalled][value="0"],
#urlbar-progress[busy][stalled][value="0"] {
/* TODO: add connecting state (bug 596812) */
#urlbar-progress[value="0"] > .progress-remainder {
background-image: -moz-linear-gradient(left, rgba(255,255,255,0), rgb(255,255,255), rgba(255,255,255,0)) !important;
background-size: 10%;
background-repeat: no-repeat;
background-position: right;
-moz-transition-property: background-position;
-moz-transition-duration: 2s;
-moz-transition-timing-function: linear;
}
#urlbar-progress[value="0"][slideback] > .progress-remainder {
background-position: left;
}
.tab-progress > .progress-bar,

Просмотреть файл

@ -461,3 +461,46 @@ input.defaultName {
.notMainMatch{
opacity: .70;
}
#otherresults {
left: 0px;
bottom: 0px;
width: 100%;
height: 30px;
background-color: rgba(0,0,0,.3);
box-shadow: 0px -1px 0px rgba(255,255,255,.1), inset 0px 2px 5px rgba(0,0,0,.3);
}
#otherresults .label {
color: #999;
line-height: 30px;
margin-left: 5px;
margin-right: 5px;
}
.inlineMatch {
background-color: #EBEBEB;
border-radius: 0.4em;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
border: 1px solid rgba(255, 255, 255, 0.5);
padding-left: 3px;
padding-right: 3px;
height: 20px;
margin-right: 5px;
cursor: pointer;
}
.inlineMatch:hover {
opacity: 1.0;
}
.inlineMatch > img {
margin-right: 5px;
position: relative;
top: 2px;
}
.inlineMatch > span {
max-width: 200px;
height: 15px;
}

Просмотреть файл

@ -121,8 +121,8 @@ postflight_all:
# A universal .dmg can now be produced by making in either architecture's
# INSTALLER_DIR.
# Now, repeat the process for the test package.
$(MAKE) -C $(OBJDIR_ARCH_1) UNIVERSAL_BINARY= package-tests
$(MAKE) -C $(OBJDIR_ARCH_2) UNIVERSAL_BINARY= package-tests
$(MAKE) -C $(OBJDIR_ARCH_1) UNIVERSAL_BINARY= CHROME_JAR= package-tests
$(MAKE) -C $(OBJDIR_ARCH_2) UNIVERSAL_BINARY= CHROME_JAR= package-tests
rm -rf $(DIST_UNI)/test-package-stage
# automation.py differs because it hardcodes a path to
# dist/bin. It doesn't matter which one we use.

Просмотреть файл

@ -111,4 +111,12 @@ public class ASMozStub extends android.app.Service {
System.exit(0);
}
public void SendToDataChannel(String strToSend)
{
if (runDataThrd.isAlive())
{
runDataThrd.SendToDataChannel(strToSend);
}
}
}

Просмотреть файл

@ -5,6 +5,7 @@
android:versionName="1.0" android:sharedUserId="org.mozilla.sharedID">
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
<activity android:name=".SUTAgentAndroid"
android:screenOrientation="nosensor"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -25,7 +26,7 @@
</application>
<uses-sdk android:minSdkVersion="5"/>
<uses-sdk android:minSdkVersion="5" android:targetSdkVersion="8"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
@ -59,4 +60,9 @@
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
<uses-permission android:name="android.permission.SET_TIME"></uses-permission>
</manifest>

Просмотреть файл

@ -55,12 +55,15 @@ public class DataWorkerThread extends Thread
private RunDataThread theParent = null;
private Socket socket = null;
boolean bListening = true;
PrintWriter out = null;
SimpleDateFormat sdf = null;
public DataWorkerThread(RunDataThread theParent, Socket workerSocket)
{
super("DataWorkerThread");
this.theParent = theParent;
this.socket = workerSocket;
this.sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
}
public void StopListening()
@ -68,6 +71,19 @@ public class DataWorkerThread extends Thread
bListening = false;
}
public void SendString(String strToSend)
{
if (this.out != null)
{
Calendar cal = Calendar.getInstance();
String strOut = sdf.format(cal.getTime());
strOut += " " + strToSend + "\r\n";
out.write(strOut);
out.flush();
}
}
private String readLine(BufferedInputStream in)
{
String sRet = "";
@ -135,13 +151,12 @@ public class DataWorkerThread extends Thread
{
OutputStream cmdOut = socket.getOutputStream();
InputStream cmdIn = socket.getInputStream();
PrintWriter out = new PrintWriter(cmdOut, true);
this.out = new PrintWriter(cmdOut, true);
BufferedInputStream in = new BufferedInputStream(cmdIn);
String inputLine, outputLine;
DoCommand dc = new DoCommand(theParent.svc);
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
sRet = sdf.format(cal.getTime());
sRet += " trace output";

Просмотреть файл

@ -60,7 +60,9 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
import java.util.Timer;
import java.util.zip.Adler32;
import java.util.zip.CheckedInputStream;
@ -95,6 +97,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Build;
import android.os.Debug;
import android.os.Environment;
import android.os.StatFs;
import android.os.SystemClock;
@ -113,9 +116,9 @@ public class DoCommand {
ContextWrapper contextWrapper = null;
String currentDir = "/";
String sErrorPrefix = "##AGENT-ERROR## ";
String sErrorPrefix = "##AGENT-WARNING## ";
private final String prgVersion = "SUTAgentAndroid Version 0.80";
private final String prgVersion = "SUTAgentAndroid Version 0.85";
public enum Command
{
@ -128,6 +131,7 @@ public class DoCommand {
OS ("os"),
ID ("id"),
UPTIME ("uptime"),
SETTIME ("settime"),
SYSTIME ("systime"),
SCREEN ("screen"),
MEMORY ("memory"),
@ -215,10 +219,18 @@ public class DoCommand {
strReturn = prgVersion;
break;
case CLOK:
strReturn = GetClok();
break;
case UPDT:
strReturn = StartUpdateOMatic(Argv[1], Argv[2]);
break;
case SETTIME:
strReturn = SetSystemTime(Argv[1], Argv[2], cmdOut);
break;
case CWD:
try {
strReturn = new java.io.File(currentDir).getCanonicalPath();
@ -244,7 +256,7 @@ public class DoCommand {
if (Argc == 2)
strReturn = GetAppRoot(Argv[1]);
else
strReturn = sErrorPrefix + "Wrong number of arguments for cd command!";
strReturn = sErrorPrefix + "Wrong number of arguments for getapproot command!";
break;
case TESTROOT:
@ -1929,6 +1941,84 @@ public class DoCommand {
return (sRet);
}
public String SetSystemTime(String sDate, String sTime, OutputStream out)
{
// Debug.waitForDebugger();
String sRet = "";
// Intent prgIntent = new Intent(android.provider.Settings.ACTION_DATE_SETTINGS);
// prgIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// contextWrapper.startActivity(prgIntent);
// 2010/09/22
// 15:41:00
// 0123456789012345678
if (((sDate != null) && (sTime != null)) &&
(sDate.contains("/") || sDate.contains(".")) &&
(sTime.contains(":")))
{
int year = Integer.parseInt(sDate.substring(0,4));
int month = Integer.parseInt(sDate.substring(5,7));
int day = Integer.parseInt(sDate.substring(8,10));
int hour = Integer.parseInt(sTime.substring(0,2));
int mins = Integer.parseInt(sTime.substring(3,5));
int secs = Integer.parseInt(sTime.substring(6,8));
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
cal.set(year, month - 1, day, hour, mins, secs);
long lMillisecs = cal.getTime().getTime();
// boolean bRet = SystemClock.setCurrentTimeMillis(lMillisecs);
String sM = Long.toString(lMillisecs);
// long lm = 1285175618316L;
String sTest = cal.getTime().toGMTString();
String sMillis = sM.substring(0, sM.length() - 3) + "." + sM.substring(sM.length() - 3);
String [] theArgs = new String [3];
theArgs[0] = "su";
theArgs[1] = "-c";
theArgs[2] = "date -u " + sMillis;
try
{
pProc = Runtime.getRuntime().exec(theArgs);
RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
outThrd.start();
outThrd.join(10000);
sRet = GetSystemTime();
}
catch (IOException e)
{
sRet = e.getMessage();
e.printStackTrace();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
sRet = "Invalid argument(s)";
}
return (sRet);
}
public String GetClok()
{
long lMillisecs = System.currentTimeMillis();
String sRet = "";
if (lMillisecs > 0)
sRet = Long.toString(lMillisecs);
return(sRet);
}
public String GetUptime()
{
String sRet = "";
@ -2140,6 +2230,9 @@ public class DoCommand {
try
{
// Tell all of the data channels we are rebooting
((ASMozStub)this.contextWrapper).SendToDataChannel("Rebooting ...");
pProc = Runtime.getRuntime().exec(theArgs);
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
outThrd.start();
@ -2551,6 +2644,9 @@ public class DoCommand {
"rebt - reboot device\n" +
"inst /path/filename.apk - install the referenced apk file\n" +
"uninst packagename - uninstall the referenced package\n" +
"updt pkgname pkgfile - unpdate the referenced package\n" +
"clok - the current device time expressed as the number of millisecs since epoch\n" +
"settime date time - sets the device date and time (YYYY/MM/DD HH:MM:SS)\n" +
"rebt - reboot device\n" +
"quit - disconnect SUTAgent\n" +
"exit - close SUTAgent\n" +

Просмотреть файл

@ -67,6 +67,19 @@ public class RunDataThread extends Thread
bListening = false;
}
public void SendToDataChannel(String strToSend)
{
int nNumWorkers = theWorkers.size();
for (int lcv = 0; lcv < nNumWorkers; lcv++)
{
if (theWorkers.get(lcv).isAlive())
{
theWorkers.get(lcv).SendString(strToSend);
}
}
return;
}
public void run() {
try {
SvrSocket.setSoTimeout(5000);

Просмотреть файл

@ -65,6 +65,7 @@ import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Debug;
import android.os.PowerManager;
import android.telephony.TelephonyManager;
import android.util.Log;
@ -134,6 +135,8 @@ public class SUTAgentAndroid extends Activity
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Debug.waitForDebugger();
// long lHeapSize = VMRuntime.getRuntime().getMinimumHeapSize();
// lHeapSize = 16000000;
// VMRuntime.getRuntime().setMinimumHeapSize(lHeapSize);

Просмотреть файл

@ -525,6 +525,7 @@ MOZ_ENABLE_XREMOTE = @MOZ_ENABLE_XREMOTE@
MOZ_ENABLE_DWRITE_FONT = @MOZ_ENABLE_DWRITE_FONT@
MOZ_ENABLE_D2D_SURFACE = @MOZ_ENABLE_D2D_SURFACE@
MOZ_ENABLE_D3D9_LAYER = @MOZ_ENABLE_D3D9_LAYER@
MOZ_ENABLE_D3D10_LAYER = @MOZ_ENABLE_D3D10_LAYER@
MOZ_GTK2_CFLAGS = @MOZ_GTK2_CFLAGS@
MOZ_GTK2_LIBS = @MOZ_GTK2_LIBS@

Просмотреть файл

@ -4958,6 +4958,7 @@ MOZ_XTF=1
MOZ_XUL=1
MOZ_ZIPWRITER=1
NS_PRINTING=1
MOZ_DISABLE_DOMCRYPTO=
NSS_DISABLE_DBM=
NECKO_WIFI=1
NECKO_COOKIES=1
@ -6611,6 +6612,13 @@ fi
AC_SUBST(MOZ_DISABLE_PARENTAL_CONTROLS)
dnl ========================================================
dnl = Disable DOMCrypto
dnl ========================================================
if test -n "$MOZ_DISABLE_DOMCRYPTO"; then
AC_DEFINE(MOZ_DISABLE_DOMCRYPTO)
fi
dnl ========================================================
dnl =
dnl = Module specific options
@ -8425,6 +8433,7 @@ if test "$MOZ_TREE_CAIRO"; then
fi
AC_CHECK_HEADER(d3d9.h, MOZ_ENABLE_D3D9_LAYER=1)
AC_CHECK_HEADER(d3d10.h, MOZ_ENABLE_D3D10_LAYER=1)
AC_TRY_COMPILE([#include <ddraw.h>], [int foo = DDLOCK_WAITNOTBUSY;], HAS_DDRAW=1, HAS_DDRAW=)
if test -z "$HAS_DDRAW"; then
@ -8474,6 +8483,7 @@ if test "$MOZ_TREE_CAIRO"; then
AC_SUBST(MOZ_ENABLE_DWRITE_FONT)
AC_SUBST(MOZ_ENABLE_D2D_SURFACE)
AC_SUBST(MOZ_ENABLE_D3D9_LAYER)
AC_SUBST(MOZ_ENABLE_D3D10_LAYER)
AC_SUBST(CAIRO_FT_CFLAGS)
AC_SUBST(HAS_OGLES)

Просмотреть файл

@ -155,7 +155,7 @@ NS_IMETHODIMP
nsCrossSiteListenerProxy::OnStartRequest(nsIRequest* aRequest,
nsISupports* aContext)
{
mRequestApproved = NS_SUCCEEDED(CheckRequestApproved(aRequest, PR_FALSE));
mRequestApproved = NS_SUCCEEDED(CheckRequestApproved(aRequest));
if (!mRequestApproved) {
if (nsXMLHttpRequest::sAccessControlCache) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
@ -219,8 +219,7 @@ IsValidHTTPToken(const nsCSubstring& aToken)
}
nsresult
nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest,
PRBool aIsRedirect)
nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
{
// Check if this was actually a cross domain request
if (!mHasBeenCrossSite) {
@ -241,21 +240,6 @@ nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest,
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
NS_ENSURE_TRUE(http, NS_ERROR_DOM_BAD_URI);
// Redirects aren't success-codes. But necko already checked that it was a
// valid redirect.
if (!aIsRedirect) {
PRBool succeeded;
rv = http->GetRequestSucceeded(&succeeded);
NS_ENSURE_SUCCESS(rv, rv);
if (!succeeded) {
PRUint32 responseStatus;
rv = http->GetResponseStatus(&responseStatus);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(mAllowedHTTPErrors.Contains(responseStatus),
NS_ERROR_DOM_BAD_URI);
}
}
// Check the Access-Control-Allow-Origin header
nsCAutoString allowedOriginHeader;
rv = http->GetResponseHeader(
@ -286,12 +270,20 @@ nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest,
}
if (mIsPreflight) {
PRBool succeeded;
rv = http->GetRequestSucceeded(&succeeded);
NS_ENSURE_SUCCESS(rv, rv);
if (!succeeded) {
return NS_ERROR_DOM_BAD_URI;
}
nsCAutoString headerVal;
// The "Access-Control-Allow-Methods" header contains a comma separated
// list of method names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Methods"),
headerVal);
PRBool foundMethod = mPreflightMethod.EqualsLiteral("GET") ||
mPreflightMethod.EqualsLiteral("HEAD") ||
mPreflightMethod.EqualsLiteral("POST");
nsCCharSeparatedTokenizer methodTokens(headerVal, ',');
while(methodTokens.hasMoreTokens()) {
@ -379,7 +371,7 @@ nsCrossSiteListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
{
nsresult rv;
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
rv = CheckRequestApproved(aOldChannel, PR_TRUE);
rv = CheckRequestApproved(aOldChannel);
if (NS_FAILED(rv)) {
if (nsXMLHttpRequest::sAccessControlCache) {
nsCOMPtr<nsIURI> oldURI;

Просмотреть файл

@ -84,14 +84,9 @@ public:
// Must be called at startup.
static void Startup();
void AllowHTTPResult(PRUint32 aResultCode)
{
mAllowedHTTPErrors.AppendElement(aResultCode);
}
private:
nsresult UpdateChannel(nsIChannel* aChannel);
nsresult CheckRequestApproved(nsIRequest* aRequest, PRBool aIsRedirect);
nsresult CheckRequestApproved(nsIRequest* aRequest);
nsCOMPtr<nsIStreamListener> mOuterListener;
nsCOMPtr<nsIPrincipal> mRequestingPrincipal;
@ -102,7 +97,6 @@ private:
PRBool mIsPreflight;
nsCString mPreflightMethod;
nsTArray<nsCString> mPreflightHeaders;
nsTArray<PRUint32> mAllowedHTTPErrors;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIChannel> mOldRedirectChannel;
nsCOMPtr<nsIChannel> mNewRedirectChannel;

Просмотреть файл

@ -59,6 +59,9 @@
#include "nsDOMError.h"
#include "nsIDOMWindow.h"
#include "nsPIDOMWindow.h"
#include "mozilla/AutoRestore.h"
using namespace mozilla;
// nsIDOMEventListener
nsresult
@ -263,6 +266,7 @@ nsDOMParser::ParseFromStream(nsIInputStream *stream,
// Tell the document to start loading
nsCOMPtr<nsIStreamListener> listener;
AutoRestore<PRPackedBool> restoreSyncLoop(mLoopingForSyncLoad);
mLoopingForSyncLoad = PR_TRUE;
// Have to pass PR_FALSE for reset here, else the reset will remove

Просмотреть файл

@ -587,6 +587,7 @@ GK_ATOM(mouseover, "mouseover")
GK_ATOM(mousethrough, "mousethrough")
GK_ATOM(mouseup, "mouseup")
GK_ATOM(moz_opaque, "moz-opaque")
GK_ATOM(x_moz_errormessage, "x-moz-errormessage")
GK_ATOM(msthemecompatible, "msthemecompatible")
GK_ATOM(multicol, "multicol")
GK_ATOM(multiple, "multiple")

Просмотреть файл

@ -1416,7 +1416,13 @@ nsXMLHttpRequest::GetResponseHeader(const nsACString& header,
nsACString& _retval)
{
nsresult rv = NS_OK;
_retval.Truncate();
_retval.SetIsVoid(PR_TRUE);
nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
if (!httpChannel) {
return NS_OK;
}
// See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
PRBool chrome = PR_FALSE; // default to false in case IsCapabilityEnabled fails
@ -1425,13 +1431,11 @@ nsXMLHttpRequest::GetResponseHeader(const nsACString& header,
(header.LowerCaseEqualsASCII("set-cookie") ||
header.LowerCaseEqualsASCII("set-cookie2"))) {
NS_WARNING("blocked access to response header");
_retval.SetIsVoid(PR_TRUE);
return NS_OK;
}
// Check for dangerous headers
if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
// Make sure we don't leak header information from denied cross-site
// requests.
if (mChannel) {
@ -1455,17 +1459,34 @@ nsXMLHttpRequest::GetResponseHeader(const nsACString& header,
}
}
if (!safeHeader) {
nsCAutoString headerVal;
// The "Access-Control-Expose-Headers" header contains a comma separated
// list of method names.
httpChannel->
GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"),
headerVal);
nsCCharSeparatedTokenizer exposeTokens(headerVal, ',');
while(exposeTokens.hasMoreTokens()) {
const nsDependentCSubstring& token = exposeTokens.nextToken();
if (token.IsEmpty()) {
continue;
}
if (!IsValidHTTPToken(token)) {
return NS_OK;
}
if (header.Equals(token, nsCaseInsensitiveCStringComparator())) {
safeHeader = PR_TRUE;
}
}
}
if (!safeHeader) {
return NS_OK;
}
}
nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
if (httpChannel) {
rv = httpChannel->GetResponseHeader(header, _retval);
}
if (rv == NS_ERROR_NOT_AVAILABLE) {
// Means no header
_retval.SetIsVoid(PR_TRUE);
@ -1586,8 +1607,6 @@ nsXMLHttpRequest::GetCurrentHttpChannel()
nsresult
nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
{
nsresult rv;
// First check if cross-site requests are enabled
if ((mState & XML_HTTP_REQUEST_XSITEENABLED)) {
return NS_OK;
@ -1611,24 +1630,10 @@ nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
httpChannel->GetRequestMethod(method);
if (!mACUnsafeHeaders.IsEmpty() ||
HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)) ||
(mUpload && mUpload->HasListeners())) {
mState |= XML_HTTP_REQUEST_NEED_AC_PREFLIGHT;
}
else if (method.LowerCaseEqualsLiteral("post")) {
nsCAutoString contentTypeHeader;
httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
contentTypeHeader);
nsCAutoString contentType, charset;
rv = NS_ParseContentType(contentTypeHeader, contentType, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (!contentType.LowerCaseEqualsLiteral("text/plain")) {
mState |= XML_HTTP_REQUEST_NEED_AC_PREFLIGHT;
}
}
else if (!method.LowerCaseEqualsLiteral("get") &&
!method.LowerCaseEqualsLiteral("head")) {
(mUpload && mUpload->HasListeners()) ||
(!method.LowerCaseEqualsLiteral("get") &&
!method.LowerCaseEqualsLiteral("post") &&
!method.LowerCaseEqualsLiteral("head"))) {
mState |= XML_HTTP_REQUEST_NEED_AC_PREFLIGHT;
}
@ -2488,7 +2493,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
// ignore the necessary headers for an empty Content-Type.
nsCOMPtr<nsIUploadChannel2> uploadChannel2(do_QueryInterface(httpChannel));
// This assertion will fire if buggy extensions are installed
NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel");
NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel2");
if (uploadChannel2) {
uploadChannel2->ExplicitSetUploadStream(postDataStream, contentType,
-1, method, PR_FALSE);
@ -2508,6 +2513,23 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
}
}
if (httpChannel) {
nsCAutoString contentTypeHeader;
rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
contentTypeHeader);
if (NS_SUCCEEDED(rv)) {
nsCAutoString contentType, charset;
rv = NS_ParseContentType(contentTypeHeader, contentType, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (!contentType.LowerCaseEqualsLiteral("text/plain") &&
!contentType.LowerCaseEqualsLiteral("application/x-www-form-urlencoded") &&
!contentType.LowerCaseEqualsLiteral("multipart/form-data")) {
mACUnsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
}
}
}
// Reset responseBody
mResponseBody.Truncate();
mResponseBodyUnicode.SetIsVoid(PR_TRUE);
@ -2765,8 +2787,10 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
// Check for dangerous cross-site headers
PRBool safeHeader = !!(mState & XML_HTTP_REQUEST_XSITEENABLED);
if (!safeHeader) {
// Content-Type isn't always safe, but we'll deal with it in Send()
const char *kCrossOriginSafeHeaders[] = {
"accept", "accept-language", "content-type"
"accept", "accept-language", "content-language", "content-type",
"last-event-id"
};
for (i = 0; i < NS_ARRAY_LENGTH(kCrossOriginSafeHeaders); ++i) {
if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {

Просмотреть файл

@ -260,6 +260,7 @@ _TEST_FILES1 = test_bug5141.html \
test_bug505783.html \
test_bug457746.html \
test_bug587931.html \
test_bug592829.html \
test_bug518104.html \
bug457746.sjs \
test_CrossSiteXHR.html \

Просмотреть файл

@ -43,17 +43,10 @@ window.addEventListener("message", function(e) {
}, false);
}
}
xhr.onload = function () {
res.status = xhr.status;
res.statusText = xhr.statusText;
res.responseXML = xhr.responseXML ?
(new XMLSerializer()).serializeToString(xhr.responseXML) :
null;
res.responseText = xhr.responseText;
post(e, res);
};
xhr.onerror = function () {
xhr.onload = xhr.onerror = function (event) {
if (event.type == "error") {
res.didFail = true;
}
res.status = xhr.status;
try {
res.statusText = xhr.statusText;
@ -63,6 +56,13 @@ window.addEventListener("message", function(e) {
(new XMLSerializer()).serializeToString(xhr.responseXML) :
null;
res.responseText = xhr.responseText;
res.responseHeaders = {};
for (responseHeader in req.responseHeaders) {
res.responseHeaders[responseHeader] =
xhr.getResponseHeader(responseHeader);
}
post(e, res);
}

Просмотреть файл

@ -101,6 +101,13 @@ function handleRequest(request, response)
query.allowHeaders = hops[query.hop-1].allowHeaders;
}
if (!isPreflight && query.status) {
response.setStatusLine(null, query.status, query.statusMessage);
}
if (isPreflight && query.preflightStatus) {
response.setStatusLine(null, query.preflightStatus, "preflight status");
}
if (query.allowOrigin && (!isPreflight || !query.noAllowPreflight))
response.setHeader("Access-Control-Allow-Origin", query.allowOrigin);
@ -117,6 +124,17 @@ function handleRequest(request, response)
if (query.allowMethods)
response.setHeader("Access-Control-Allow-Methods", query.allowMethods);
}
else {
if (query.responseHeaders) {
let responseHeaders = eval(query.responseHeaders);
for (let responseHeader in responseHeaders) {
response.setHeader(responseHeader, responseHeaders[responseHeader]);
}
}
if (query.exposeHeaders)
response.setHeader("Access-Control-Expose-Headers", query.exposeHeaders);
}
if (query.hop && query.hop < hops.length) {
newURL = hops[query.hop].server +

Просмотреть файл

@ -43,299 +43,541 @@ function runTest() {
origin = "http://example.org";
yield;
passTests = [{ method: "GET",
tests = [// Plain request
{ pass: 1,
method: "GET",
noAllowPreflight: 1,
},
{ method: "GET",
headers: { "Content-Type": "baz/bin",
// Default allowed headers
{ pass: 1,
method: "GET",
headers: { "Content-Type": "text/plain",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
{ method: "GET",
{ pass: 0,
method: "GET",
headers: { "Content-Type": "foo/bar",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
// Custom headers
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "X-My-Header",
},
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header": "secondValue" },
allowHeaders: "x-my-header, long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header",
},
{ pass: 1,
method: "GET",
headers: { "x-my%-header": "myValue" },
allowHeaders: "x-my%-header",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "" },
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "y-my-header",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header y-my-header",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, y-my-header z",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, y-my-he(ader",
},
{ pass: 0,
method: "GET",
headers: { "myheader": "" },
allowMethods: "myheader",
},
// Multiple custom headers
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue",
"third-header": "thirdValue" },
allowHeaders: "x-my-header, second-header, third-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue",
"third-header": "thirdValue" },
allowHeaders: "x-my-header,second-header,third-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue",
"third-header": "thirdValue" },
allowHeaders: "x-my-header ,second-header ,third-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue",
"third-header": "thirdValue" },
allowHeaders: "x-my-header , second-header , third-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue" },
allowHeaders: ", x-my-header, , ,, second-header, , ",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue" },
allowHeaders: "x-my-header, second-header, unused-header",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "X-My-Header",
},
{ method: "GET",
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue",
"long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header": "secondValue" },
allowHeaders: "x-my-header, long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header",
"y-my-header": "secondValue" },
allowHeaders: "x-my-header",
},
{ method: "GET",
headers: { "x-my%-header": "myValue" },
allowHeaders: "x-my%-header",
{ pass: 0,
method: "GET",
headers: { "x-my-header": "",
"y-my-header": "" },
allowHeaders: "x-my-header",
},
{ method: "HEAD",
// HEAD requests
{ pass: 1,
method: "HEAD",
noAllowPreflight: 1,
},
{ method: "HEAD",
headers: { "Content-Type": "baz/bin",
// HEAD with safe headers
{ pass: 1,
method: "HEAD",
headers: { "Content-Type": "text/plain",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
{ method: "POST",
{ pass: 0,
method: "HEAD",
headers: { "Content-Type": "foo/bar",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
// HEAD with custom headers
{ pass: 1,
method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ pass: 0,
method: "HEAD",
headers: { "x-my-header": "myValue" },
},
{ pass: 0,
method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "",
},
{ pass: 0,
method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "y-my-header",
},
{ pass: 0,
method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header y-my-header",
},
// POST tests
{ pass: 1,
method: "POST",
body: "hi there",
noAllowPreflight: 1,
},
{ method: "POST",
{ pass: 1,
method: "POST",
},
{ method: "POST",
{ pass: 1,
method: "POST",
noAllowPreflight: 1,
},
// POST with standard headers
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
noAllowPreflight: 1,
},
{ method: "POST",
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "multipart/form-data" },
noAllowPreflight: 1,
},
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
noAllowPreflight: 1,
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar" },
},
{ method: "POST",
{ pass: 0,
method: "POST",
headers: { "Content-Type": "foo/bar" },
},
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
{ method: "POST",
// POST with custom headers
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Accept": "foo/bar",
"Accept-Language": "sv-SE",
"x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "POST",
{ pass: 1,
method: "POST",
headers: { "Content-Type": "text/plain",
"x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "POST",
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain",
"x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar",
"x-my-header": "myValue" },
allowHeaders: "x-my-header, content-type",
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar" },
noAllowPreflight: 1,
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar",
"x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "POST",
{ pass: 1,
method: "POST",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "POST",
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, $_%",
},
{ method: "DELETE",
// Other methods
{ pass: 1,
method: "DELETE",
allowMethods: "DELETE",
},
{ method: "DELETE",
allowMethods: "POST, PUT, DELETE",
},
{ method: "DELETE",
allowMethods: "POST, DELETE, PUT",
},
{ method: "DELETE",
allowMethods: "DELETE, POST, PUT",
},
{ method: "DELETE",
allowMethods: "POST ,PUT ,DELETE",
},
{ method: "DELETE",
allowMethods: "POST,PUT,DELETE",
},
{ method: "DELETE",
allowMethods: "POST , PUT , DELETE",
},
{ method: "DELETE",
allowMethods: " ,, PUT ,, , , DELETE , ,",
},
{ method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
uploadProgress: "uploadprogress",
},
{ method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
uploadProgress: "progress",
},
];
failTests = [{ method: "GET",
headers: { "x-my-header": "myValue" },
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "y-my-header",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header y-my-header",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, y-my-header z",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, y-my-he(ader",
},
{ method: "GET",
headers: { "x-my-header": "myValue",
"y-my-header": "secondValue" },
allowHeaders: "x-my-header",
},
{ method: "GET",
headers: { "x-my-header": "" },
},
{ method: "GET",
headers: { "x-my-header": "",
"y-my-header": "" },
allowHeaders: "x-my-header",
},
{ method: "GET",
headers: { "myheader": "" },
allowMethods: "myheader",
},
{ method: "HEAD",
headers: { "x-my-header": "myValue" },
},
{ method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "",
},
{ method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "y-my-header",
},
{ method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header y-my-header",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowHeaders: "DELETE",
},
{ method: "POST",
noAllowPreflight: 1,
{ pass: 0,
method: "DELETE",
},
{ method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar" },
noAllowPreflight: 1,
},
{ method: "DELETE",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "",
},
{ method: "DELETE",
{ pass: 1,
method: "DELETE",
allowMethods: "POST, PUT, DELETE",
},
{ pass: 1,
method: "DELETE",
allowMethods: "POST, DELETE, PUT",
},
{ pass: 1,
method: "DELETE",
allowMethods: "DELETE, POST, PUT",
},
{ pass: 1,
method: "DELETE",
allowMethods: "POST ,PUT ,DELETE",
},
{ pass: 1,
method: "DELETE",
allowMethods: "POST,PUT,DELETE",
},
{ pass: 1,
method: "DELETE",
allowMethods: "POST , PUT , DELETE",
},
{ pass: 1,
method: "DELETE",
allowMethods: " ,, PUT ,, , , DELETE , ,",
},
{ pass: 0,
method: "DELETE",
allowMethods: "PUT",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "DELETEZ",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "DELETE PUT",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "DELETE, PUT Z",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "DELETE, PU(T",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "PUT DELETE",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "PUT Z, DELETE",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "PU(T, DELETE",
},
{ method: "MYMETHOD",
{ pass: 0,
method: "MYMETHOD",
allowMethods: "myMethod",
},
{ method: "PUT",
{ pass: 0,
method: "PUT",
allowMethods: "put",
},
{ method: "POST",
// Progress events
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
noAllowPreflight: 1,
uploadProgress: "uploadprogress",
},
{ method: "POST",
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
noAllowPreflight: 1,
uploadProgress: "progress",
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
uploadProgress: "uploadprogress",
noAllowPreflight: 1,
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
uploadProgress: "progress",
noAllowPreflight: 1,
},
// Status messages
{ pass: 1,
method: "GET",
noAllowPreflight: 1,
status: 404,
statusMessage: "nothin' here",
},
{ pass: 1,
method: "GET",
noAllowPreflight: 1,
status: 401,
statusMessage: "no can do",
},
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar" },
allowHeaders: "content-type",
status: 500,
statusMessage: "server boo",
},
{ pass: 1,
method: "GET",
noAllowPreflight: 1,
status: 200,
statusMessage: "Yes!!",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "header value" },
allowHeaders: "x-my-header",
preflightStatus: 400
},
{ pass: 1,
method: "GET",
headers: { "x-my-header": "header value" },
allowHeaders: "x-my-header",
preflightStatus: 200
},
// exposed headers
{ pass: 1,
method: "GET",
responseHeaders: { "x-my-header": "x header" },
exposeHeaders: "x-my-header",
expectedResponseHeaders: ["x-my-header"],
},
{ pass: 0,
method: "GET",
origin: "http://invalid",
responseHeaders: { "x-my-header": "x header" },
exposeHeaders: "x-my-header",
expectedResponseHeaders: [],
},
{ pass: 1,
method: "GET",
responseHeaders: { "x-my-header": "x header" },
expectedResponseHeaders: [],
},
{ pass: 1,
method: "GET",
responseHeaders: { "x-my-header": "x header" },
exposeHeaders: "x-my-header y",
expectedResponseHeaders: [],
},
{ pass: 1,
method: "GET",
responseHeaders: { "x-my-header": "x header" },
exposeHeaders: "y x-my-header",
expectedResponseHeaders: [],
},
{ pass: 1,
method: "GET",
responseHeaders: { "x-my-header": "x header" },
exposeHeaders: "x-my-header, y-my-header z",
expectedResponseHeaders: [],
},
{ pass: 1,
method: "GET",
responseHeaders: { "x-my-header": "x header" },
exposeHeaders: "x-my-header, y-my-hea(er",
expectedResponseHeaders: [],
},
{ pass: 1,
method: "GET",
responseHeaders: { "x-my-header": "x header",
"y-my-header": "y header" },
exposeHeaders: " , ,,y-my-header,z-my-header, ",
expectedResponseHeaders: ["y-my-header"],
},
];
if (!runPreflightTests) {
passTests = failTests = [];
tests = [];
}
for each(test in passTests) {
req = {
url: baseURL + "&allowOrigin=" + escape(origin) +
"&origin=" + escape(origin) +
"&requestMethod=" + test.method,
for each(test in tests) {
var req = {
url: baseURL + "allowOrigin=" + escape(test.origin || origin),
method: test.method,
headers: test.headers,
uploadProgress: test.uploadProgress,
body: test.body,
responseHeaders: test.responseHeaders,
};
if (test.pass) {
req.url += "&origin=" + escape(origin) +
"&requestMethod=" + test.method;
}
if (test.noAllowPreflight)
req.url += "&noAllowPreflight";
if ("headers" in test) {
if (test.pass && "headers" in test) {
function isUnsafeHeader(name) {
lName = name.toLowerCase();
return lName != "accept" &&
lName != "accept-language" &&
(lName != "content-type" ||
["text/plain",
"multipart/form-data",
"application/x-www-form-urlencoded"]
.indexOf(test.headers[name].toLowerCase()) == -1);
}
req.url += "&headers=" + escape(test.headers.toSource());
reqHeaders =
escape([name for (name in test.headers)].map(String.toLowerCase).filter(function(name)
name != "content-type" &&
name != "accept" &&
name != "accept-language").sort().join(","));
escape([name for (name in test.headers)]
.filter(isUnsafeHeader)
.map(String.toLowerCase)
.sort()
.join(","));
req.url += reqHeaders ? "&requestHeaders=" + reqHeaders : "";
}
if ("allowHeaders" in test)
@ -344,15 +586,31 @@ function runTest() {
req.url += "&allowMethods=" + escape(test.allowMethods);
if (test.body)
req.url += "&body=" + escape(test.body);
if (test.status) {
req.url += "&status=" + test.status;
req.url += "&statusMessage=" + escape(test.statusMessage);
}
if (test.preflightStatus)
req.url += "&preflightStatus=" + test.preflightStatus;
if (test.responseHeaders)
req.url += "&responseHeaders=" + escape(test.responseHeaders.toSource());
if (test.exposeHeaders)
req.url += "&exposeHeaders=" + escape(test.exposeHeaders);
loaderWindow.postMessage(req.toSource(), origin);
res = eval(yield);
if (test.pass) {
is(res.didFail, false,
"shouldn't have failed in test for " + test.toSource());
if (test.status) {
is(res.status, test.status, "wrong status in test for " + test.toSource());
is(res.statusText, test.statusMessage, "wrong status text for " + test.toSource());
}
else {
is(res.status, 200, "wrong status in test for " + test.toSource());
is(res.statusText, "OK", "wrong status text for " + test.toSource());
}
if (test.method !== "HEAD") {
is(res.responseXML, "<res>hello pass</res>",
"wrong responseXML in test for " + test.toSource());
@ -371,28 +629,22 @@ function runTest() {
"opening,rs1,sending,rs1,loadstart,rs2,rs4,load",
"wrong responseText in test for " + test.toSource());
}
if (test.responseHeaders) {
for (header in test.responseHeaders) {
if (test.expectedResponseHeaders.indexOf(header) == -1) {
is(res.responseHeaders[header], null,
"wrong response header (" + header + ") in test for " +
test.toSource());
}
for each(test in failTests) {
req = {
url: baseURL + "allowOrigin=" + escape(origin),
method: test.method,
headers: test.headers,
uploadProgress: test.uploadProgress,
body: test.body,
};
if (test.noAllowPreflight)
req.url += "&noAllowPreflight";
if ("allowHeaders" in test)
req.url += "&allowHeaders=" + escape(test.allowHeaders);
if ("allowMethods" in test)
req.url += "&allowMethods=" + escape(test.allowMethods);
loaderWindow.postMessage(req.toSource(), origin);
res = eval(yield);
else {
is(res.responseHeaders[header], test.responseHeaders[header],
"wrong response header (" + header + ") in test for " +
test.toSource());
}
}
}
}
else {
is(res.didFail, true,
"should have failed in test for " + test.toSource());
is(res.status, 0, "wrong status in test for " + test.toSource());
@ -406,8 +658,15 @@ function runTest() {
"wrong events in test for " + test.toSource());
is(res.progressEvents, 0,
"wrong events in test for " + test.toSource());
if (test.responseHeaders) {
for (header in test.responseHeaders) {
is(res.responseHeaders[header], null,
"wrong response header (" + header + ") in test for " +
test.toSource());
}
}
}
}
// Test cookie behavior
tests = [{ pass: 1,

Просмотреть файл

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=592829
-->
<head>
<title>Test for Bug 592829</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=592829">Mozilla Bug 592829</a>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 592829 **/
// NOTE! It's imperative that we don't call .init() here. Otherwise we're not
// testing what happens if parsing fails.
// If we ever change how DOMParser initilization works, just update this code
// to create a DOMParser which is not allowed to parse XUL.
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var isXUL = true;
try {
var x =
Components.classes["@mozilla.org/xmlextras/domparser;1"]
.getService(Components.interfaces.nsIDOMParser)
.parseFromString('<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>', "text/xml");
isXUL = x.documentElement.namespaceURI ==
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
}
catch (ex) {
isXUL = false;
}
is(isXUL, false, "We didn't create XUL and we didn't crash!");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -46,8 +46,6 @@ class nsIURI;
#define NS_FORM_METHOD_GET 0
#define NS_FORM_METHOD_POST 1
#define NS_FORM_METHOD_PUT 2
#define NS_FORM_METHOD_DELETE 3
#define NS_FORM_ENCTYPE_URLENCODED 0
#define NS_FORM_ENCTYPE_MULTIPART 1
#define NS_FORM_ENCTYPE_TEXTPLAIN 2

Просмотреть файл

@ -41,8 +41,6 @@
static const nsAttrValue::EnumTable kFormMethodTable[] = {
{ "get", NS_FORM_METHOD_GET },
{ "post", NS_FORM_METHOD_POST },
{ "put", NS_FORM_METHOD_PUT },
{ "delete", NS_FORM_METHOD_DELETE },
{ 0 }
};
// Default method is 'get'.

Просмотреть файл

@ -508,19 +508,6 @@ public:
*/
NS_HIDDEN_(nsresult) GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsAString& aResult);
/**
* Helper method for NS_IMPL_ENUM_ATTR_DEFAULT_VALUE.
* Gets the enum value string of an attribute and using a default value if
* the attribute is missing or the string is an invalid enum value.
*
* @param aType the name of the attribute.
* @param aDefault the default value if the attribute is missing or invalid.
* @param aResult string corresponding to the value [out].
*/
NS_HIDDEN_(nsresult) GetEnumAttr(nsIAtom* aAttr,
const char* aDefault,
nsAString& aResult);
/**
* Returns the current disabled state of the element.
*/
@ -714,6 +701,19 @@ protected:
*/
NS_HIDDEN_(nsresult) GetURIListAttr(nsIAtom* aAttr, nsAString& aResult);
/**
* Helper method for NS_IMPL_ENUM_ATTR_DEFAULT_VALUE.
* Gets the enum value string of an attribute and using a default value if
* the attribute is missing or the string is an invalid enum value.
*
* @param aType the name of the attribute.
* @param aDefault the default value if the attribute is missing or invalid.
* @param aResult string corresponding to the value [out].
*/
NS_HIDDEN_(nsresult) GetEnumAttr(nsIAtom* aAttr,
const char* aDefault,
nsAString& aResult);
/**
* Locates the nsIEditor associated with this node. In general this is
* equivalent to GetEditorInternal(), but for designmode or contenteditable,

Просмотреть файл

@ -898,25 +898,11 @@ nsHTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission)
getter_AddRefs(postDataStream));
NS_ENSURE_SUBMIT_SUCCESS(rv);
nsAutoString method;
if (originatingElement &&
originatingElement->HasAttr(kNameSpaceID_None,
nsGkAtoms::formmethod)) {
if (!originatingElement->IsHTML()) {
return NS_ERROR_UNEXPECTED;
}
static_cast<nsGenericHTMLElement*>(originatingElement)->
GetEnumAttr(nsGkAtoms::formmethod, kFormDefaultMethod->tag, method);
} else {
GetEnumAttr(nsGkAtoms::method, kFormDefaultMethod->tag, method);
}
rv = linkHandler->OnLinkClickSync(this, actionURI,
target.get(),
postDataStream, nsnull,
getter_AddRefs(docShell),
getter_AddRefs(mSubmittingRequest),
NS_LossyConvertUTF16toASCII(method).get());
getter_AddRefs(mSubmittingRequest));
NS_ENSURE_SUBMIT_SUCCESS(rv);
}

Просмотреть файл

@ -973,7 +973,6 @@ nsresult nsHTMLMediaElement::LoadResource(nsIURI* aURI)
listener = crossSiteListener;
NS_ENSURE_TRUE(crossSiteListener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
crossSiteListener->AllowHTTPResult(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE);
} else {
rv = nsContentUtils::GetSecurityManager()->
CheckLoadURIWithPrincipal(NodePrincipal(),

Просмотреть файл

@ -78,7 +78,16 @@ nsIConstraintValidation::GetValidationMessage(nsAString& aValidationMessage)
aValidationMessage.Truncate();
if (IsCandidateForConstraintValidation() && !IsValid()) {
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR)) {
nsCOMPtr<nsIContent> content = do_QueryInterface(this);
NS_ASSERTION(content, "This class should be inherited by HTML elements only!");
nsAutoString authorMessage;
content->GetAttr(kNameSpaceID_None, nsGkAtoms::x_moz_errormessage,
authorMessage);
if (!authorMessage.IsEmpty()) {
aValidationMessage.Assign(authorMessage);
} else if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR)) {
aValidationMessage.Assign(mCustomValidity);
} else if (GetValidityState(VALIDITY_STATE_TOO_LONG)) {
GetValidationMessage(aValidationMessage, VALIDITY_STATE_TOO_LONG);

Просмотреть файл

@ -1,8 +0,0 @@
function handleRequest(request, response)
{
// Redirect to another domain.
// Using 307 to keep the method.
response.setStatusLine(null, 307, "Temp");
response.setHeader("Location",
"http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs");
}

Просмотреть файл

@ -1,5 +0,0 @@
function handleRequest(request, response)
{
// Send the HTTP method.
response.write(request.method);
}

Просмотреть файл

@ -212,11 +212,6 @@ _TEST_FILES = \
test_bug590353-1.html \
test_bug590353-2.html \
test_bug593689.html \
test_bug583288-1.html \
test_bug583288-2.html \
test_bug583288-3.html \
583288_submit_server.sjs \
583288_redirect_server.sjs \
test_bug555840.html \
test_bug561636.html \
test_bug556013.html \
@ -235,6 +230,7 @@ _TEST_FILES = \
test_bug557087-4.html \
test_bug557087-5.html \
test_bug557087-6.html \
test_bug600155.html \
$(NULL)
libs:: $(_TEST_FILES)

Просмотреть файл

@ -1,143 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=583288
-->
<head>
<title>Test for Bug 583288</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload='runTests();'>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=583288">Mozilla Bug 583288</a>
<p id="display"></p>
<style>
iframe { width: 70px; height: 40px;}
</style>
<!--<div id="content" style="display: none">-->
<div id="content">
<iframe name='get' id='get'></iframe>
<iframe name='post' id='post'></iframe>
<iframe name='put' id='put'></iframe>
<iframe name='del' id='del'></iframe>
<iframe name='get2' id='get2'></iframe>
<iframe name='post2' id='post2'></iframe>
<iframe name='put2' id='put2'></iframe>
<iframe name='del2' id='del2'></iframe>
<form action="583288_submit_server.sjs" target='get' method='get'>
</form>
<form action="583288_submit_server.sjs" target='post' method='post'>
</form>
<form action="583288_submit_server.sjs" target='put' method='put'>
</form>
<form action="583288_submit_server.sjs" target='del' method='delete'>
</form>
<form action="583288_submit_server.sjs">
<input type='submit' id='iget' value='get' formtarget='get2' formmethod='get'>
</form>
<form action="583288_submit_server.sjs">
<input type='submit' id='ipost' value='post' formtarget='post2' formmethod='post'>
</form>
<form action="583288_submit_server.sjs">
<input type='submit' id='iput' value='put' formtarget='put2' formmethod='put'>
</form>
<form action="583288_submit_server.sjs">
<input type='submit' id='idel' value='delete' formtarget='del2' formmethod='delete'>
</form>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 583288 **/
SimpleTest.waitForExplicitFinish();
var gTestResults = {
get: "GET",
get2: "GET",
post: "POST",
post2: "POST",
put: "PUT",
put2: "PUT",
del: "DELETE",
del2: "DELETE",
};
var gPendingLoad = 0; // Has to be set after depending on the frames number.
function runTests()
{
// We add a load event for the frames which will be called when the forms
// will be submitted.
var frames = [ document.getElementById('get'),
document.getElementById('get2'),
document.getElementById('post'),
document.getElementById('post2'),
document.getElementById('put'),
document.getElementById('put2'),
document.getElementById('del'),
document.getElementById('del2'),
];
gPendingLoad = frames.length;
for (var i=0; i<frames.length; ++i) {
frames[i].setAttribute('onload', "frameLoaded(this);");
}
// The four first forms can be submitted with .submit().
for (var i=0; i<4; ++i) {
document.forms[i].submit();
}
/**
* We are going to focus each element before interacting with them so we are
* sure they will be visible in the iframe.
* Considering we are using synthesizeKey that may be not required.
*
* Focusing the first element (id='iget') is launching the tests.
*/
document.getElementById('iget').addEventListener('focus', function(aEvent) {
aEvent.target.removeEventListener('focus', arguments.callee, false);
synthesizeKey("VK_RETURN", {});
document.getElementById('ipost').focus();
}, false);
document.getElementById('ipost').addEventListener('focus', function(aEvent) {
aEvent.target.removeEventListener('focus', arguments.callee, false);
synthesizeKey("VK_RETURN", {});
document.getElementById('iput').focus();
}, false);
document.getElementById('iput').addEventListener('focus', function(aEvent) {
aEvent.target.removeEventListener('focus', arguments.callee, false);
synthesizeKey("VK_RETURN", {});
document.getElementById('idel').focus();
}, false);
document.getElementById('idel').addEventListener('focus', function(aEvent) {
aEvent.target.removeEventListener('focus', arguments.callee, false);
synthesizeKey("VK_RETURN", {});
}, false);
document.getElementById('iget').focus();
}
function frameLoaded(aFrame) {
// Check if formaction/action has the correct behavior.
is(aFrame.contentDocument.documentElement.textContent, gTestResults[aFrame.name],
"the method used during the form submission should be " +
gTestResults[aFrame.name]);
if (--gPendingLoad == 0) {
SimpleTest.finish();
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,99 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=583288
-->
<head>
<title>Test for Bug 583288</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload='runTests();'>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=583288">Mozilla Bug 583288</a>
<p id="display"></p>
<style>
iframe { width: 70px; height: 40px;}
</style>
<!--<div id="content" style="display: none">-->
<div id="content">
<iframe name='get' id='get'></iframe>
<iframe name='post' id='post'></iframe>
<iframe name='put' id='put'></iframe>
<iframe name='del' id='del'></iframe>
<form action="http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs" target='get' method='get'>
</form>
<form action="http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs" target='post' method='post'>
</form>
<form action="http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs" target='put' method='put'>
</form>
<form action="http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs" target='del' method='delete'>
</form>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 583288 **/
SimpleTest.waitForExplicitFinish();
var gLoaded = 0;
function runTests()
{
// We add a load event for the frames which will be called when the forms
// will be submitted.
var frames = [ document.getElementById('get'),
document.getElementById('post'),
document.getElementById('put'),
document.getElementById('del'),
];
for (var i=0; i<2; ++i) {
frames[i].setAttribute('onload', "frameShouldLoad();");
}
for (var i=2; i<4; ++i) {
frames[i].setAttribute('onload', "frameShouldNotLoad();");
}
// The four forms can be submitted with .submit().
// Submitting those which should be blocked so we can considering if the the
// last ones are submitted, that means the firsts were blocked.
for (var i=3; i>=0; --i) {
document.forms[i].submit();
}
// After the two first succefull submissions, we are going to stop the test.
// The expected successfull submissions have been requested at the end so we
// expect them at the end. So if the two firsts ones didn't show up, we are
// assuming they have been blocked.
// Unfortunately, it doesn't sound like there is a better way to test that.
// The worst thing that can happen here is to have a random green (if the
// first two submissions were not blocked but came after the last two).
}
function frameShouldLoad() {
ok(true, "The form submission should succeed.");
if (++gLoaded == 2) {
finished();
}
}
function frameShouldNotLoad() {
ok(false, "The form submission should have been blocked");
if (++gLoaded == 2) {
finished();
}
}
function finished()
{
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,85 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=583288
-->
<head>
<title>Test for Bug 583288</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload='runTests();'>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=583288">Mozilla Bug 583288</a>
<p id="display"></p>
<style>
iframe { width: 70px; height: 40px;}
</style>
<!--<div id="content" style="display: none">-->
<div id="content">
<iframe name='get' id='get'></iframe>
<iframe name='post' id='post'></iframe>
<iframe name='put' id='put'></iframe>
<iframe name='del' id='del'></iframe>
<form action="583288_redirect_server.sjs" target='get' method='get'>
</form>
<form action="583288_redirect_server.sjs" target='post' method='post'>
</form>
<form action="583288_redirect_server.sjs" target='put' method='put'>
</form>
<form action="583288_redirect_server.sjs" target='del' method='delete'>
</form>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 583288 **/
SimpleTest.waitForExplicitFinish();
var gTestResults = {
get: "GET",
post: "POST",
put: "",
del: "",
};
var gPendingLoad = 0; // Has to be set after depending on the frames number.
function runTests()
{
// We add a load event for the frames which will be called when the forms
// will be submitted.
var frames = [ document.getElementById('get'),
document.getElementById('post'),
document.getElementById('put'),
document.getElementById('del'),
];
gPendingLoad = frames.length;
for (var i=0; i<gPendingLoad; ++i) {
frames[i].setAttribute('onload', "frameLoaded(this);");
}
// The four forms can be submitted with .submit().
for (var i=0; i<4; ++i) {
document.forms[i].submit();
}
}
function frameLoaded(aFrame) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
is(aFrame.contentDocument.documentElement.textContent, gTestResults[aFrame.name],
"cross-origin submission with redirection should work");
if (--gPendingLoad == 0) {
SimpleTest.finish();
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -30,9 +30,11 @@ var methodTestData = [
// Default value.
[ "get" ],
// Valid values.
[ "get", "post", "put", "delete" ],
[ "get", "post" ],
// Invalid values.
[ "", " ", "foo" ],
// TODO values, see bug 583289 and bug 583288.
[ "delete", "put" ],
];
function checkAttribute(form, attrName, idlName, data)

Просмотреть файл

@ -0,0 +1,45 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=600155
-->
<head>
<title>Test for Bug 600155</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=600155">Mozilla Bug 600155</a>
<p id="display"></p>
<div id='content' style='display:none;'>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 600155 **/
var subjectForConstraintValidation = [ "button", "input", "select", "textarea" ];
var content = document.getElementById('content');
for each (var eName in subjectForConstraintValidation) {
var e = document.createElement(eName);
content.appendChild(e);
e.setAttribute("x-moz-errormessage", "foo");
if ("required" in e) {
e.required = true;
} else {
e.setCustomValidity("bar");
}
// At this point, the element is invalid.
is(e.validationMessage, "foo",
"the validation message should be the author one");
content.removeChild(e);
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -449,7 +449,6 @@ nsresult nsMediaChannelStream::OpenChannel(nsIStreamListener** aStreamListener)
listener = crossSiteListener;
NS_ENSURE_TRUE(crossSiteListener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
crossSiteListener->AllowHTTPResult(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE);
} else {
nsresult rv = nsContentUtils::GetSecurityManager()->
CheckLoadURIWithPrincipal(element->NodePrincipal(),

Просмотреть файл

@ -871,15 +871,14 @@ nsXMLContentSink::GetCurrentContent()
if (mContentStack.Length() == 0) {
return nsnull;
}
return GetCurrentStackNode().mContent;
return GetCurrentStackNode()->mContent;
}
StackNode &
StackNode*
nsXMLContentSink::GetCurrentStackNode()
{
PRInt32 count = mContentStack.Length();
NS_ASSERTION(count > 0, "Bogus Length()");
return mContentStack[count-1];
return count != 0 ? &mContentStack[count-1] : nsnull;
}
@ -1116,11 +1115,14 @@ nsXMLContentSink::HandleEndElement(const PRUnichar *aName,
FlushText();
StackNode & sn = GetCurrentStackNode();
StackNode* sn = GetCurrentStackNode();
if (!sn) {
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIContent> content;
sn.mContent.swap(content);
PRUint32 numFlushed = sn.mNumFlushed;
sn->mContent.swap(content);
PRUint32 numFlushed = sn->mNumFlushed;
PopContent();
NS_ASSERTION(content, "failed to pop content");

Просмотреть файл

@ -148,7 +148,7 @@ protected:
nsresult AddContentAsLeaf(nsIContent *aContent);
nsIContent* GetCurrentContent();
StackNode & GetCurrentStackNode();
StackNode* GetCurrentStackNode();
nsresult PushContent(nsIContent *aContent);
void PopContent();
PRBool HaveNotifiedForCurrentContent() const;

Просмотреть файл

@ -1412,8 +1412,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
nsnull, // No SHEntry
aFirstParty,
nsnull, // No nsIDocShell
nsnull, // No nsIRequest
nsnull); // Use default HTTP method
nsnull); // No nsIRequest
}
NS_IMETHODIMP
@ -4096,7 +4095,7 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
return InternalLoad(errorPageURI, nsnull, nsnull,
INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nsnull, nsnull,
nsnull, nsnull, LOAD_ERROR_PAGE,
nsnull, PR_TRUE, nsnull, nsnull, nsnull);
nsnull, PR_TRUE, nsnull, nsnull);
}
@ -4160,8 +4159,7 @@ nsDocShell::Reload(PRUint32 aReloadFlags)
nsnull, // No SHEntry
PR_TRUE,
nsnull, // No nsIDocShell
nsnull, // No nsIRequest
nsnull); // Use default HTTP method
nsnull); // No nsIRequest
}
@ -5871,7 +5869,7 @@ nsDocShell::OnLocationChange(nsIWebProgress * aProgress,
return NS_OK;
}
nsresult
void
nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
nsIChannel* aNewChannel,
PRUint32 aRedirectFlags,
@ -5880,44 +5878,13 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
"Calling OnRedirectStateChange when there is no redirect");
if (!(aStateFlags & STATE_IS_DOCUMENT))
return NS_OK; // not a toplevel document
return; // not a toplevel document
nsCOMPtr<nsIURI> oldURI, newURI;
aOldChannel->GetURI(getter_AddRefs(oldURI));
aNewChannel->GetURI(getter_AddRefs(newURI));
if (!oldURI || !newURI) {
return NS_OK;
}
// HTTP channel with unsafe methods should not be redirected to a cross-domain.
if (!ChannelIsSafeHTTPMethod(aNewChannel)) {
// This code is very similar to the code of nsSameOriginChecker in
// nsContentUtils but we can't use nsSameOriginChecker because it
// needs to use a channel callback (which we already use).
// If nsSameOriginChecker happens to not use a channel callback
// anymore, this code would be a good candidate for refactoring.
nsCOMPtr<nsIPrincipal> oldPrincipal;
nsresult rv;
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
rv = secMan->GetChannelPrincipal(aOldChannel,
getter_AddRefs(oldPrincipal));
NS_ENSURE_SUCCESS(rv, NS_OK);
NS_ASSERTION(oldPrincipal, "oldPrincipal should not be null!");
nsCOMPtr<nsIURI> newOriginalURI;
aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
rv = oldPrincipal->CheckMayLoad(newURI, PR_FALSE);
if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
rv = oldPrincipal->CheckMayLoad(newOriginalURI, PR_FALSE);
}
// The requested tried to be redirected, we have to cancel it.
NS_ENSURE_SUCCESS(rv, rv);
return;
}
// Below a URI visit is saved (see AddURIVisit method doc).
@ -5968,8 +5935,6 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
mLoadType = LOAD_NORMAL_REPLACE;
SetHistoryEntry(&mLSHE, nsnull);
}
return NS_OK;
}
NS_IMETHODIMP
@ -6341,8 +6306,7 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
nsnull, // No SHEntry
PR_TRUE, // first party site
nsnull, // No nsIDocShell
nsnull, // No nsIRequest
nsnull); // Use default HTTP method
nsnull); // No nsIRequest
}
else {
DisplayLoadError(aStatus, url, nsnull, aChannel);
@ -7784,7 +7748,7 @@ public:
return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags,
nsnull, mTypeHint.get(),
mPostData, mHeadersData, mLoadType,
mSHEntry, mFirstParty, nsnull, nsnull, nsnull);
mSHEntry, mFirstParty, nsnull, nsnull);
}
private:
@ -7818,8 +7782,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
nsISHEntry * aSHEntry,
PRBool aFirstParty,
nsIDocShell** aDocShell,
nsIRequest** aRequest,
const char* aHttpMethod)
nsIRequest** aRequest)
{
nsresult rv = NS_OK;
@ -8021,8 +7984,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
aSHEntry,
aFirstParty,
aDocShell,
aRequest,
aHttpMethod);
aRequest);
if (rv == NS_ERROR_NO_CONTENT) {
// XXXbz except we never reach this code!
if (isNewWindow) {
@ -8457,8 +8419,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
aDocShell, getter_AddRefs(req),
(aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
(aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
aHttpMethod);
(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0);
if (req && aRequest)
NS_ADDREF(*aRequest = req);
@ -8539,8 +8500,7 @@ nsDocShell::DoURILoad(nsIURI * aURI,
nsIRequest ** aRequest,
PRBool aIsNewWindowTarget,
PRBool aBypassClassifier,
PRBool aForceAllowCookies,
const char* aHttpMethod)
PRBool aForceAllowCookies)
{
nsresult rv;
nsCOMPtr<nsIURILoader> uriLoader;
@ -8723,20 +8683,6 @@ nsDocShell::DoURILoad(nsIURI * aURI,
// Referrer is currenly only set for link clicks here.
httpChannel->SetReferrer(aReferrerURI);
}
// If a specific HTTP method has been requested, set it.
if (aHttpMethod) {
// Tell the cache it _has_ to open a cache entry.
PRUint32 loadFlags;
if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) {
channel->SetLoadFlags(loadFlags | nsICachingChannel::FORCE_OPEN_CACHE_ENTRY);
}
// The method name have to be correct.
// Otherwise SetRequestMethod will return a failure.
rv = httpChannel->SetRequestMethod(nsDependentCString(aHttpMethod));
NS_ENSURE_SUCCESS(rv, rv);
}
}
//
// Set the owner of the channel, but only for channels that can't
@ -8787,14 +8733,6 @@ nsDocShell::DoURILoad(nsIURI * aURI,
}
}
// If a specific HTTP channel has been set and it is not a safe method,
// we should prevent cross-origin requests.
if (aHttpMethod && ownerPrincipal && !ChannelIsSafeHTTPMethod(channel)) {
if (NS_FAILED(ownerPrincipal->CheckMayLoad(aURI, PR_FALSE))) {
return NS_OK;
}
}
nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
if (scriptChannel) {
// Allow execution against our context if the principals match
@ -10006,8 +9944,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, PRUint32 aLoadType)
aEntry, // SHEntry
PR_TRUE,
nsnull, // No nsIDocShell
nsnull, // No nsIRequest
nsnull); // Use default HTTP method
nsnull); // No nsIRequest
return rv;
}
@ -10420,7 +10357,6 @@ NS_IMETHODIMP nsDocShell::MakeEditable(PRBool inWaitForUriLoad)
return mEditorData->MakeEditable(inWaitForUriLoad);
}
/* static */
bool
nsDocShell::ChannelIsPost(nsIChannel* aChannel)
{
@ -10434,21 +10370,6 @@ nsDocShell::ChannelIsPost(nsIChannel* aChannel)
return method.Equals("POST");
}
/* static */
bool
nsDocShell::ChannelIsSafeHTTPMethod(nsIChannel* aChannel)
{
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
if (!httpChannel) {
return true;
}
nsCAutoString method;
httpChannel->GetRequestMethod(method);
return method.Equals("GET") || method.Equals("POST") ||
method.Equals("HEAD");
}
void
nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
nsIURI** aURI,
@ -11379,8 +11300,7 @@ nsDocShell::OnLinkClickSync(nsIContent *aContent,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
nsIDocShell** aDocShell,
nsIRequest** aRequest,
const char* aHttpMethod)
nsIRequest** aRequest)
{
// Initialize the DocShell / Request
if (aDocShell) {
@ -11456,8 +11376,7 @@ nsDocShell::OnLinkClickSync(nsIContent *aContent,
nsnull, // No SHEntry
PR_TRUE, // first party site
aDocShell, // DocShell out-param
aRequest, // Request out-param
aHttpMethod); // HTTP Method
aRequest); // Request out-param
if (NS_SUCCEEDED(rv)) {
DispatchPings(aContent, referer);
}

Просмотреть файл

@ -243,8 +243,7 @@ public:
nsIInputStream* aPostDataStream = 0,
nsIInputStream* aHeadersDataStream = 0,
nsIDocShell** aDocShell = 0,
nsIRequest** aRequest = 0,
const char* aHttpMethod = 0);
nsIRequest** aRequest = 0);
NS_IMETHOD OnOverLink(nsIContent* aContent,
nsIURI* aURI,
const PRUnichar* aTargetSpec);
@ -326,8 +325,7 @@ protected:
nsIRequest ** aRequest,
PRBool aIsNewWindowTarget,
PRBool aBypassClassifier,
PRBool aForceAllowCookies,
const char* aHttpMethod);
PRBool aForceAllowCookies);
NS_IMETHOD AddHeadersToChannel(nsIInputStream * aHeadersData,
nsIChannel * aChannel);
virtual nsresult DoChannelLoad(nsIChannel * aChannel,
@ -436,7 +434,7 @@ protected:
// overridden from nsDocLoader, this provides more information than the
// normal OnStateChange with flags STATE_REDIRECTING
virtual nsresult OnRedirectStateChange(nsIChannel* aOldChannel,
virtual void OnRedirectStateChange(nsIChannel* aOldChannel,
nsIChannel* aNewChannel,
PRUint32 aRedirectFlags,
PRUint32 aStateFlags);
@ -449,17 +447,7 @@ protected:
*
* @return True iff channel is an HTTP post.
*/
static bool ChannelIsPost(nsIChannel* aChannel);
/**
* Helper function that determines if the HTTP channel has a safe method
*
* @param aChannel The channel to test
*
* @return Whether the channel has a safe HTTP method.
* @note Will return true if the channel isn't an HTTP channel.
*/
static bool ChannelIsSafeHTTPMethod(nsIChannel* aChannel);
bool ChannelIsPost(nsIChannel* aChannel);
/**
* Helper function that finds the last URI and its transition flags for a

Просмотреть файл

@ -71,7 +71,7 @@ interface nsIPrincipal;
interface nsIWebBrowserPrint;
interface nsIVariant;
[scriptable, uuid(0e1e1ee5-5baa-4e27-98af-3197d70d0304)]
[scriptable, uuid(74470127-87eb-4f79-8293-1616fe9cb689)]
interface nsIDocShell : nsISupports
{
/**
@ -155,10 +155,6 @@ interface nsIDocShell : nsISupports
* @param aLoadFlags - Flags to modify load behaviour. Flags are defined
* in nsIWebNavigation.
* @param aSHEntry - Active Session History entry (if loading from SH)
* @param firstParty -
* @param aDocShell -
* @param aRequest -
* @param aHttpMethod - Force the HTTP channel to use a specific HTTP method
*/
[noscript]void internalLoad(in nsIURI aURI,
in nsIURI aReferrer,
@ -172,8 +168,7 @@ interface nsIDocShell : nsISupports
in nsISHEntry aSHEntry,
in boolean firstParty,
out nsIDocShell aDocShell,
out nsIRequest aRequest,
in string aHttpMethod);
out nsIRequest aRequest);
/**
* Do either a history.pushState() or history.replaceState() operation,

Просмотреть файл

@ -14,7 +14,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=428288
<p id="display"></p>
<div id="content" style="display: none">
<iframe name="target"></iframe>
<a id="crashy" target="target" href="http://www.mozilla.com">crash me</a>
<a id="crashy" target="target" href="about:blank">crash me</a>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">

Просмотреть файл

@ -104,7 +104,9 @@
#include "nsIHTMLDocument.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMHTMLElement.h"
#ifndef MOZ_DISABLE_DOMCRYPTO
#include "nsIDOMCrypto.h"
#endif
#include "nsIDOMDocument.h"
#include "nsIDOM3Document.h"
#include "nsIDOMNSDocument.h"
@ -391,10 +393,10 @@ static PRBool gDOMWindowDumpEnabled = PR_FALSE;
static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
#ifndef MOZ_DISABLE_DOMCRYPTO
static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
#endif
static const char sPopStatePrefStr[] = "browser.history.allowPopState";
static PRBool
@ -1652,12 +1654,12 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
JSContext *cx = (JSContext *)scx->GetNativeContext();
#ifndef MOZ_DISABLE_DOMCRYPTO
// clear smartcard events, our document has gone away.
if (mCrypto) {
mCrypto->SetEnableSmartCardEvents(PR_FALSE);
}
#endif
if (!mDocument) {
// First document load.
@ -3091,6 +3093,9 @@ nsGlobalWindow::RevokeBlobURL(const nsAString& aURL)
NS_IMETHODIMP
nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
{
#ifdef MOZ_DISABLE_DOMCRYPTO
return NS_ERROR_NOT_IMPLEMENTED;
#else
FORWARD_TO_OUTER(GetCrypto, (aCrypto), NS_ERROR_NOT_INITIALIZED);
if (!mCrypto) {
@ -3100,6 +3105,7 @@ nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
NS_IF_ADDREF(*aCrypto = mCrypto);
return NS_OK;
#endif
}
NS_IMETHODIMP

Просмотреть файл

@ -86,7 +86,9 @@
#include "nsIScriptSecurityManager.h"
#include "nsIEventListenerManager.h"
#include "nsIDOMDocument.h"
#ifndef MOZ_DISABLE_DOMCRYPTO
#include "nsIDOMCrypto.h"
#endif
#include "nsIPrincipal.h"
#include "nsPluginArray.h"
#include "nsMimeTypeArray.h"
@ -142,6 +144,10 @@ class nsRunnable;
class nsDOMOfflineResourceList;
class nsGeolocation;
#ifdef MOZ_DISABLE_DOMCRYPTO
class nsIDOMCrypto;
#endif
extern nsresult
NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
PRBool *aIsInterval,
@ -845,9 +851,9 @@ protected:
nsString mDefaultStatus;
// index 0->language_id 1, so index MAX-1 == language_id MAX
nsGlobalWindowObserver* mObserver;
#ifndef MOZ_DISABLE_DOMCRYPTO
nsCOMPtr<nsIDOMCrypto> mCrypto;
#endif
nsCOMPtr<nsIDOMStorage> mLocalStorage;
nsCOMPtr<nsIDOMStorage> mSessionStorage;

Просмотреть файл

@ -57,6 +57,8 @@
#include "nsServiceManagerUtils.h"
#include "nsXULAppAPI.h"
#include "nsWeakReference.h"
#include "nsIScriptError.h"
#include "nsIConsoleService.h"
#include "History.h"
#include "nsDocShellCID.h"
@ -112,6 +114,59 @@ private:
nsString mData;
};
class ConsoleListener : public nsIConsoleListener
{
public:
ConsoleListener(ContentChild* aChild)
: mChild(aChild) {}
NS_DECL_ISUPPORTS
NS_DECL_NSICONSOLELISTENER
private:
ContentChild* mChild;
friend class ContentChild;
};
NS_IMPL_ISUPPORTS1(ConsoleListener, nsIConsoleListener)
NS_IMETHODIMP
ConsoleListener::Observe(nsIConsoleMessage* aMessage)
{
if (!mChild)
return NS_OK;
nsCOMPtr<nsIScriptError> scriptError = do_QueryInterface(aMessage);
if (scriptError) {
nsString msg, sourceName, sourceLine;
nsXPIDLCString category;
PRUint32 lineNum, colNum, flags;
nsresult rv = scriptError->GetErrorMessage(msg);
NS_ENSURE_SUCCESS(rv, rv);
rv = scriptError->GetSourceName(sourceName);
NS_ENSURE_SUCCESS(rv, rv);
rv = scriptError->GetSourceLine(sourceLine);
NS_ENSURE_SUCCESS(rv, rv);
rv = scriptError->GetCategory(getter_Copies(category));
NS_ENSURE_SUCCESS(rv, rv);
rv = scriptError->GetLineNumber(&lineNum);
NS_ENSURE_SUCCESS(rv, rv);
rv = scriptError->GetColumnNumber(&colNum);
NS_ENSURE_SUCCESS(rv, rv);
rv = scriptError->GetFlags(&flags);
NS_ENSURE_SUCCESS(rv, rv);
mChild->SendScriptError(msg, sourceName, sourceLine,
lineNum, colNum, flags, category);
return NS_OK;
}
nsXPIDLString msg;
nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
NS_ENSURE_SUCCESS(rv, rv);
mChild->SendConsoleMessage(msg);
return NS_OK;
}
ContentChild* ContentChild::sSingleton;
@ -146,6 +201,20 @@ ContentChild::Init(MessageLoop* aIOLoop,
return true;
}
void
ContentChild::InitXPCOM()
{
nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
if (!svc) {
NS_WARNING("Couldn't acquire console service");
return;
}
mConsoleListener = new ConsoleListener(this);
if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
NS_WARNING("Couldn't register console listener for child process");
}
PBrowserChild*
ContentChild::AllocPBrowser(const PRUint32& aChromeFlags)
{
@ -253,6 +322,13 @@ ContentChild::ActorDestroy(ActorDestroyReason why)
#endif
mAlertObservers.Clear();
nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
if (svc) {
svc->UnregisterListener(mConsoleListener);
mConsoleListener->mChild = nsnull;
}
XRE_ShutdownChildProcess();
}

Просмотреть файл

@ -43,6 +43,7 @@
#include "mozilla/dom/PContentChild.h"
#include "nsTArray.h"
#include "nsIConsoleListener.h"
struct ChromePackage;
class nsIObserver;
@ -54,6 +55,7 @@ namespace dom {
class AlertObserver;
class PrefObserver;
class ConsoleListener;
class ContentChild : public PContentChild
{
@ -64,6 +66,7 @@ public:
bool Init(MessageLoop* aIOLoop,
base::ProcessHandle aParentHandle,
IPC::Channel* aChannel);
void InitXPCOM();
static ContentChild* GetSingleton() {
NS_ASSERTION(sSingleton, "not initialized");
@ -124,6 +127,7 @@ private:
nsTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
nsTArray<nsAutoPtr<PrefObserver> > mPrefObservers;
nsRefPtr<ConsoleListener> mConsoleListener;
bool mDead;
static ContentChild* sSingleton;

Просмотреть файл

@ -60,6 +60,9 @@
#include "nsIAlertsService.h"
#include "nsToolkitCompsCID.h"
#include "nsIDOMGeoGeolocation.h"
#include "nsIConsoleService.h"
#include "nsIScriptError.h"
#include "nsConsoleMessage.h"
#include "mozilla/dom/ExternalHelperAppParent.h"
@ -547,5 +550,40 @@ ContentParent::HandleEvent(nsIDOMGeoPosition* postion)
return NS_OK;
}
bool
ContentParent::RecvConsoleMessage(const nsString& aMessage)
{
nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
if (!svc)
return true;
nsRefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage.get()));
svc->LogMessage(msg);
return true;
}
bool
ContentParent::RecvScriptError(const nsString& aMessage,
const nsString& aSourceName,
const nsString& aSourceLine,
const PRUint32& aLineNumber,
const PRUint32& aColNumber,
const PRUint32& aFlags,
const nsCString& aCategory)
{
nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
if (!svc)
return true;
nsCOMPtr<nsIScriptError> msg(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
nsresult rv = msg->Init(aMessage.get(), aSourceName.get(), aSourceLine.get(),
aLineNumber, aColNumber, aFlags, aCategory.get());
if (NS_FAILED(rv))
return true;
svc->LogMessage(msg);
return true;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -157,6 +157,15 @@ private:
virtual bool RecvGeolocationStart();
virtual bool RecvGeolocationStop();
virtual bool RecvConsoleMessage(const nsString& aMessage);
virtual bool RecvScriptError(const nsString& aMessage,
const nsString& aSourceName,
const nsString& aSourceLine,
const PRUint32& aLineNumber,
const PRUint32& aColNumber,
const PRUint32& aFlags,
const nsCString& aCategory);
mozilla::Monitor mMonitor;
GeckoChildProcessHost* mSubprocess;

Просмотреть файл

@ -53,6 +53,7 @@ ContentProcess::Init()
ParentHandle(),
IOThreadChild::channel());
mXREEmbed.Start();
mContent.InitXPCOM();
return true;
}

Просмотреть файл

@ -80,6 +80,7 @@ LOCAL_INCLUDES += \
-I$(topsrcdir)/uriloader/exthandler \
-I$(srcdir)/../../netwerk/base/src \
-I$(srcdir)/../src/base \
-I$(srcdir)/../../xpcom/base \
$(NULL)
DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'

Просмотреть файл

@ -91,6 +91,26 @@ parent:
sync SyncMessage(nsString aMessage, nsString aJSON)
returns (nsString[] retval);
/**
* The IME sequence number (seqno) parameter is used to make sure
* that a notification is discarded if it arrives at the chrome process
* too late. If the notification is late and we accept it, we will have
* an out-of-date view of the content process, which means events that we
* dispatch based on this out-of-date view will be wrong also.
* (see Bug 599550 and Bug 591047 comments 44, 50, and 54)
*
* Chrome increments seqno and includes it in each IME event sent to
* content, and content sends its current seqno back to chrome with each
* notification. A notification is up-to-date only if the content
* seqno is the same as the current chrome seqno, meaning no additional
* event was sent to content before the notification was received
*
* On blur, chrome returns the current seqno to content, and content
* uses it to discard subsequent events until the content seqno and
* chrome seqno-on-blur match again. These events, meant for the blurred
* textfield, are discarded to prevent events going to the wrong target
*/
/**
* Notifies chrome that there is a focus change involving an editable
* object (input, textarea, document, contentEditable. etc.)
@ -98,9 +118,10 @@ parent:
* focus PR_TRUE if editable object is receiving focus
* PR_FALSE if losing focus
* preference Native widget preference for IME updates
* seqno Current seqno value on the chrome side
*/
sync NotifyIMEFocus(PRBool focus)
returns (nsIMEUpdatePreference preference);
returns (nsIMEUpdatePreference preference, PRUint32 seqno);
/**
* Notifies chrome that there has been a change in text content
@ -120,10 +141,11 @@ parent:
* Notifies chrome that there has been a change in selection
* Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
*
* seqno Current seqno value on the content side
* anchor Offset where the selection started
* focus Offset where the caret is
*/
NotifyIMESelection(PRUint32 anchor, PRUint32 focus);
NotifyIMESelection(PRUint32 seqno, PRUint32 anchor, PRUint32 focus);
/**
* Notifies chrome to refresh its text cache

Просмотреть файл

@ -115,6 +115,11 @@ parent:
GeolocationStart();
GeolocationStop();
ConsoleMessage(nsString message);
ScriptError(nsString message, nsString sourceName, nsString sourceLine,
PRUint32 lineNumber, PRUint32 colNumber, PRUint32 flags,
nsCString category);
both:
AsyncMessage(nsString aMessage, nsString aJSON);

Просмотреть файл

@ -317,12 +317,14 @@ TabParent::RecvAsyncMessage(const nsString& aMessage,
bool
TabParent::RecvNotifyIMEFocus(const PRBool& aFocus,
nsIMEUpdatePreference* aPreference)
nsIMEUpdatePreference* aPreference,
PRUint32* aSeqno)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget)
return true;
*aSeqno = mIMESeqno;
mIMETabParent = aFocus ? this : nsnull;
mIMESelectionAnchor = 0;
mIMESelectionFocus = 0;
@ -355,16 +357,19 @@ TabParent::RecvNotifyIMETextChange(const PRUint32& aStart,
}
bool
TabParent::RecvNotifyIMESelection(const PRUint32& aAnchor,
TabParent::RecvNotifyIMESelection(const PRUint32& aSeqno,
const PRUint32& aAnchor,
const PRUint32& aFocus)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget)
return true;
if (aSeqno == mIMESeqno) {
mIMESelectionAnchor = aAnchor;
mIMESelectionFocus = aFocus;
widget->OnIMESelectionChange();
}
return true;
}
@ -444,12 +449,13 @@ TabParent::HandleQueryContentEvent(nsQueryContentEvent& aEvent)
}
bool
TabParent::SendCompositionEvent(const nsCompositionEvent& event)
TabParent::SendCompositionEvent(nsCompositionEvent& event)
{
mIMEComposing = event.message == NS_COMPOSITION_START;
mIMECompositionStart = PR_MIN(mIMESelectionAnchor, mIMESelectionFocus);
if (mIMECompositionEnding)
return true;
event.seqno = ++mIMESeqno;
return PBrowserParent::SendCompositionEvent(event);
}
@ -461,7 +467,7 @@ TabParent::SendCompositionEvent(const nsCompositionEvent& event)
* here and pass the text as the EndIMEComposition return value
*/
bool
TabParent::SendTextEvent(const nsTextEvent& event)
TabParent::SendTextEvent(nsTextEvent& event)
{
if (mIMECompositionEnding) {
mIMECompositionText = event.theText;
@ -476,14 +482,16 @@ TabParent::SendTextEvent(const nsTextEvent& event)
mIMESelectionAnchor = mIMESelectionFocus =
mIMECompositionStart + event.theText.Length();
event.seqno = ++mIMESeqno;
return PBrowserParent::SendTextEvent(event);
}
bool
TabParent::SendSelectionEvent(const nsSelectionEvent& event)
TabParent::SendSelectionEvent(nsSelectionEvent& event)
{
mIMESelectionAnchor = event.mOffset + (event.mReversed ? event.mLength : 0);
mIMESelectionFocus = event.mOffset + (!event.mReversed ? event.mLength : 0);
event.seqno = ++mIMESeqno;
return PBrowserParent::SendSelectionEvent(event);
}

Просмотреть файл

@ -92,11 +92,13 @@ public:
virtual bool RecvAsyncMessage(const nsString& aMessage,
const nsString& aJSON);
virtual bool RecvNotifyIMEFocus(const PRBool& aFocus,
nsIMEUpdatePreference* aPreference);
nsIMEUpdatePreference* aPreference,
PRUint32* aSeqno);
virtual bool RecvNotifyIMETextChange(const PRUint32& aStart,
const PRUint32& aEnd,
const PRUint32& aNewEnd);
virtual bool RecvNotifyIMESelection(const PRUint32& aAnchor,
virtual bool RecvNotifyIMESelection(const PRUint32& aSeqno,
const PRUint32& aAnchor,
const PRUint32& aFocus);
virtual bool RecvNotifyIMETextHint(const nsString& aText);
virtual bool RecvEndIMEComposition(const PRBool& aCancel,
@ -179,9 +181,9 @@ public:
static TabParent *GetIMETabParent() { return mIMETabParent; }
bool HandleQueryContentEvent(nsQueryContentEvent& aEvent);
bool SendCompositionEvent(const nsCompositionEvent& event);
bool SendTextEvent(const nsTextEvent& event);
bool SendSelectionEvent(const nsSelectionEvent& event);
bool SendCompositionEvent(nsCompositionEvent& event);
bool SendTextEvent(nsTextEvent& event);
bool SendSelectionEvent(nsSelectionEvent& event);
protected:
bool ReceiveMessage(const nsString& aMessage,
PRBool aSync,
@ -232,6 +234,7 @@ protected:
// Compositions in almost all cases are small enough for nsAutoString
nsAutoString mIMECompositionText;
PRUint32 mIMECompositionStart;
PRUint32 mIMESeqno;
private:
already_AddRefed<nsFrameLoader> GetFrameLoader() const;

Просмотреть файл

@ -142,7 +142,7 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
#ifdef MOZ_X11
, mFlash10Quirks(PR_FALSE)
#endif
#if (MOZ_PLATFORM_MAEMO == 5)
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
, mMaemoImageRendering(PR_FALSE)
#endif
{
@ -303,7 +303,7 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
#endif
return NPERR_NO_ERROR;
#if (MOZ_PLATFORM_MAEMO == 5)
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
case NPNVSupportsWindowlessLocal: {
#ifdef MOZ_WIDGET_QT
const char *graphicsSystem = PR_GetEnv("MOZ_QT_GRAPHICSSYSTEM");
@ -2052,7 +2052,7 @@ PluginInstanceChild::CreateOptSurface(void)
mIsTransparent ? gfxASurface::ImageFormatARGB32 :
gfxASurface::ImageFormatRGB24;
#if (MOZ_PLATFORM_MAEMO == 5)
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
// On Maemo 5, we must send the Visibility event to activate the plugin
if (mMaemoImageRendering) {
NPEvent pluginEvent;
@ -2128,7 +2128,7 @@ PluginInstanceChild::MaybeCreatePlatformHelperSurface(void)
mDoAlphaExtraction = mIsTransparent;
}
} else if (mCurrentSurface->GetType() == gfxASurface::SurfaceTypeImage) {
#if (MOZ_PLATFORM_MAEMO == 5)
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
if (mMaemoImageRendering) {
// No helper surface needed, when mMaemoImageRendering is TRUE.
// we can rendering directly into image memory
@ -2206,7 +2206,7 @@ PluginInstanceChild::UpdateWindowAttributes(PRBool aForceSetWindow)
needWindowUpdate = PR_TRUE;
}
}
#if (MOZ_PLATFORM_MAEMO == 5)
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
else if (curSurface && curSurface->GetType() == gfxASurface::SurfaceTypeImage
&& mMaemoImageRendering) {
// For maemo5 we need to setup window/colormap to 0
@ -2254,7 +2254,7 @@ PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
{
UpdateWindowAttributes();
#ifdef MOZ_X11
#if (MOZ_PLATFORM_MAEMO == 5)
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
// On maemo5 we do support Image rendering NPAPI
if (mMaemoImageRendering &&
aSurface->GetType() == gfxASurface::SurfaceTypeImage) {
@ -2337,7 +2337,7 @@ PluginInstanceChild::PaintRectToSurface(const nsIntRect& aRect,
}
if (renderSurface->GetType() != gfxASurface::SurfaceTypeXlib) {
// On X11 we can paint to non Xlib surface only with HelperSurface
#if (MOZ_PLATFORM_MAEMO == 5)
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
// Don't use mHelperSurface if surface is image and mMaemoImageRendering is TRUE
if (!mMaemoImageRendering ||
renderSurface->GetType() != gfxASurface::SurfaceTypeImage)

Просмотреть файл

@ -482,7 +482,7 @@ private:
// Used with windowless flash plugin only, see bug 574583
PRPackedBool mFlash10Quirks;
#endif
#if (MOZ_PLATFORM_MAEMO == 5)
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
// Maemo5 Flash does not remember WindowlessLocal state
// we should listen for NPP values negotiation and remember it
PRPackedBool mMaemoImageRendering;

Просмотреть файл

@ -3,8 +3,14 @@
<head>
<title>postMessage chrome message receiver</title>
<script type="application/javascript">
var gPrePath = "";
function receiveMessage(evt)
{
if (evt.data.substring(0,9) == "chrome://") {
gPrePath = evt.data;
respond("path-is-set");
} else {
// Content cannot post to chrome without privileges
window.parent.postMessage("SHOULD NOT GET THIS!", "*");
@ -16,13 +22,14 @@
msg += " unexpected-untrusted-event";
if (evt.type !== "message")
msg += " wrong-type(" + evt.type + ")";
if (evt.origin !== "chrome://mochikit")
if (evt.origin !== gPrePath)
msg += " wrong-origin(" + evt.origin + ")";
if (evt.data !== "post-to-content")
msg += " wrong-message(" + evt.data + ")";
respond(msg);
}
}
function respond(msg)
{

Просмотреть файл

@ -45,6 +45,10 @@ function messageReceiver(evt)
switch (evt.data)
{
case "path-is-set":
chromePathIsSet(evt);
break;
case "post-to-self":
checkSelf(evt);
break;
@ -73,11 +77,16 @@ function checkSelf(evt)
is(evt.origin, prepath, "wrong origin for chrome: URL");
is(evt.source, null, "chrome posters get a null source, for security");
window.frames.contentDomain.postMessage(prepath, "*");
}
function chromePathIsSet(evt)
{
window.frames.contentDomain.postMessage("post-to-content",
"http://example.org");
}
/*************
* RECEIVERS *
*************/

Просмотреть файл

@ -0,0 +1,106 @@
/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alex Pakhotin <alexp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.widget.RemoteViews;
public class AlertNotification
extends Notification
{
Context mContext;
int mId;
int mIcon;
String mTitle;
boolean mProgressStyle;
NotificationManager mNotificationManager;
public AlertNotification(Context aContext, int aNotificationId, int aIcon, String aTitle, long aWhen) {
super(aIcon, aTitle, aWhen);
mContext = aContext;
mIcon = aIcon;
mTitle = aTitle;
mProgressStyle = false;
mId = aNotificationId;
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
}
public boolean isProgressStyle() {
return mProgressStyle;
}
public void show() {
mNotificationManager.notify(mId, this);
}
public void updateProgress(String aAlertText, long aProgress, long aProgressMax) {
if (!mProgressStyle) {
// Custom view
int layout = aAlertText.length() > 0 ? R.layout.notification_progress_text : R.layout.notification_progress;
RemoteViews view = new RemoteViews("org.mozilla." + GeckoApp.mAppContext.getAppName(), layout);
view.setImageViewResource(R.id.notificationImage, mIcon);
view.setTextViewText(R.id.notificationTitle, mTitle);
contentView = view;
flags |= FLAG_ONGOING_EVENT;
mProgressStyle = true;
}
String text;
if (aAlertText.length() > 0) {
text = aAlertText;
} else {
int percent = 0;
if (aProgressMax > 0)
percent = (int)(100 * aProgress / aProgressMax);
text = percent + "%";
}
contentView.setTextViewText(R.id.notificationText, text);
contentView.setProgressBar(R.id.notificationProgressbar, (int)aProgressMax, (int)aProgress, false);
// Update the notification
mNotificationManager.notify(mId, this);
}
}

Просмотреть файл

@ -20,7 +20,7 @@
android:label="@MOZ_APP_DISPLAYNAME@"
android:configChanges="keyboard|keyboardHidden|orientation|mcc|mnc"
android:windowSoftInputMode="stateUnspecified|adjustResize"
android:launchMode="singleTop">
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

Просмотреть файл

@ -42,7 +42,6 @@ import java.util.*;
import java.util.zip.*;
import java.nio.*;
import java.nio.channels.FileChannel;
import java.util.concurrent.*;
import android.os.*;
import android.app.*;
@ -55,7 +54,6 @@ import android.widget.*;
import android.hardware.*;
import android.util.*;
import android.net.*;
abstract public class GeckoApp
extends Activity
@ -374,40 +372,6 @@ abstract public class GeckoApp
unpackFile(zip, buf, entry, entry.getName());
}
}
ZipEntry componentsList = zip.getEntry("components/components.manifest");
if (componentsList == null) {
Log.i("GeckoAppJava", "Can't find components.manifest!");
return;
}
listStream = new BufferedInputStream(zip.getInputStream(componentsList));
StreamTokenizer tkn = new StreamTokenizer(new InputStreamReader(listStream));
String line = "components/";
int status;
boolean addnext = false;
tkn.eolIsSignificant(true);
do {
status = tkn.nextToken();
switch (status) {
case StreamTokenizer.TT_WORD:
if (tkn.sval.equals("binary-component"))
addnext = true;
else if (addnext) {
line += tkn.sval;
addnext = false;
}
break;
case StreamTokenizer.TT_NUMBER:
break;
case StreamTokenizer.TT_EOF:
case StreamTokenizer.TT_EOL:
unpackFile(zip, buf, null, line);
line = "components/";
break;
}
} while (status != StreamTokenizer.TT_EOF);
}
private void unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry,
@ -541,64 +505,4 @@ abstract public class GeckoApp
if (statusCode == 0)
System.exit(0);
}
static final int FILE_PICKER_REQUEST = 1;
private SynchronousQueue<String> mFilePickerResult = new SynchronousQueue();
public String showFilePicker() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
GeckoApp.this.
startActivityForResult(
Intent.createChooser(intent,"choose a file"),
FILE_PICKER_REQUEST);
String filePickerResult = "";
try {
filePickerResult = mFilePickerResult.take();
} catch (InterruptedException e) {
Log.i("GeckoApp", "error: " + e);
}
return filePickerResult;
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
String filePickerResult = "";
if (data != null && resultCode == RESULT_OK) {
try {
ContentResolver cr = getContentResolver();
Uri uri = data.getData();
String mimeType = cr.getType(uri);
String fileExt = "." +
mimeType.substring(mimeType.lastIndexOf('/') + 1);
File file =
File.createTempFile("tmp_" +
(int)Math.floor(1000 * Math.random()),
fileExt,
new File("/data/data/org.mozilla." +
getAppName()));
FileOutputStream fos = new FileOutputStream(file);
InputStream is = cr.openInputStream(uri);
byte[] buf = new byte[4096];
int len = is.read(buf);
while (len != -1) {
fos.write(buf, 0, len);
len = is.read(buf);
}
fos.close();
filePickerResult = file.getAbsolutePath();
}catch (Exception e) {
Log.e("GeckoApp", "error : "+ e);
}
}
try {
mFilePickerResult.put(filePickerResult);
} catch (InterruptedException e) {
Log.i("GeckoApp", "error: " + e);
}
}
}

Просмотреть файл

@ -41,6 +41,7 @@ import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.nio.*;
import java.lang.reflect.*;
import android.os.*;
import android.app.*;
@ -73,6 +74,8 @@ class GeckoAppShell
static private boolean gRestartScheduled = false;
static private final Timer mIMETimer = new Timer();
static private final HashMap<Integer, AlertNotification>
mAlertNotifications = new HashMap<Integer, AlertNotification>();
static private final int NOTIFY_IME_RESETINPUTSTATE = 0;
static private final int NOTIFY_IME_SETOPENSTATE = 1;
@ -407,10 +410,11 @@ class GeckoAppShell
}
static boolean openUriExternal(String aUriSpec, String aMimeType, String aPackageName,
String aClassName, String aAction) {
String aClassName, String aAction, String aTitle) {
Intent intent = getIntentForActionString(aAction);
if (aAction.equalsIgnoreCase(Intent.ACTION_SEND)) {
intent.putExtra(Intent.EXTRA_TEXT, aUriSpec);
intent.putExtra(Intent.EXTRA_SUBJECT, aTitle);
if (aMimeType != null && aMimeType.length() > 0)
intent.setType(aMimeType);
} else if (aMimeType.length() > 0) {
@ -446,31 +450,36 @@ class GeckoAppShell
cm.setText(text);
}
static void showAlertNotification(String imageUrl, String alertTitle, String alertText,
String alertCookie, String alertName) {
public static void showAlertNotification(String aImageUrl, String aAlertTitle, String aAlertText,
String aAlertCookie, String aAlertName) {
Log.i("GeckoAppJava", "GeckoAppShell.showAlertNotification\n" +
"- image = '" + imageUrl + "'\n" +
"- title = '" + alertTitle + "'\n" +
"- text = '" + alertText +"'\n" +
"- cookie = '" + alertCookie +"'\n" +
"- name = '" + alertName + "'");
"- image = '" + aImageUrl + "'\n" +
"- title = '" + aAlertTitle + "'\n" +
"- text = '" + aAlertText +"'\n" +
"- cookie = '" + aAlertCookie +"'\n" +
"- name = '" + aAlertName + "'");
int icon = R.drawable.icon; // Just use the app icon by default
Uri imageUri = Uri.parse(imageUrl);
Uri imageUri = Uri.parse(aImageUrl);
String scheme = imageUri.getScheme();
if ("drawable".equals(scheme)) {
String resource = imageUri.getSchemeSpecificPart();
if ("//alertdownloads".equals(resource))
icon = R.drawable.alertdownloads;
else if ("//alertaddons".equals(resource))
icon = R.drawable.alertaddons;
resource = resource.substring(resource.lastIndexOf('/') + 1);
try {
Class drawableClass = R.drawable.class;
Field f = drawableClass.getField(resource);
icon = f.getInt(null);
} catch (Exception e) {} // just means the resource doesn't exist
}
int notificationID = alertName.hashCode();
int notificationID = aAlertName.hashCode();
Notification notification = new Notification(icon, alertTitle, System.currentTimeMillis());
// Remove the old notification with the same ID, if any
removeNotification(notificationID);
AlertNotification notification = new AlertNotification(GeckoApp.mAppContext,
notificationID, icon, aAlertTitle, System.currentTimeMillis());
// The intent to launch when the user clicks the expanded notification
Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CLICK);
@ -478,11 +487,11 @@ class GeckoAppShell
"org.mozilla." + GeckoApp.mAppContext.getAppName() + ".NotificationHandler");
// Put the strings into the intent as an URI "alert:<name>#<cookie>"
Uri dataUri = Uri.fromParts("alert", alertName, alertCookie);
Uri dataUri = Uri.fromParts("alert", aAlertName, aAlertCookie);
notificationIntent.setData(dataUri);
PendingIntent contentIntent = PendingIntent.getActivity(GeckoApp.mAppContext, 0, notificationIntent, 0);
notification.setLatestEventInfo(GeckoApp.mAppContext, alertTitle, alertText, contentIntent);
notification.setLatestEventInfo(GeckoApp.mAppContext, aAlertTitle, aAlertText, contentIntent);
// The intent to execute when the status entry is deleted by the user with the "Clear All Notifications" button
Intent clearNotificationIntent = new Intent(GeckoApp.ACTION_ALERT_CLEAR);
@ -493,24 +502,51 @@ class GeckoAppShell
PendingIntent pendingClearIntent = PendingIntent.getActivity(GeckoApp.mAppContext, 0, clearNotificationIntent, 0);
notification.deleteIntent = pendingClearIntent;
// Show the notification
NotificationManager notificationManager = (NotificationManager)
GeckoApp.mAppContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationID, notification);
mAlertNotifications.put(notificationID, notification);
notification.show();
Log.i("GeckoAppJava", "Created notification ID " + notificationID);
}
public static void handleNotification(String action, String alertName, String alertCookie) {
if (GeckoApp.ACTION_ALERT_CLICK.equals(action)) {
Log.i("GeckoAppJava", "GeckoAppShell.handleNotification: callObserver(alertclickcallback)");
callObserver(alertName, "alertclickcallback", alertCookie);
public static void alertsProgressListener_OnProgress(String aAlertName, long aProgress, long aProgressMax, String aAlertText) {
Log.i("GeckoAppJava", "GeckoAppShell.alertsProgressListener_OnProgress\n" +
"- name = '" + aAlertName +"', " +
"progress = " + aProgress +" / " + aProgressMax + ", text = '" + aAlertText + "'");
int notificationID = aAlertName.hashCode();
AlertNotification notification = mAlertNotifications.get(notificationID);
if (notification != null)
notification.updateProgress(aAlertText, aProgress, aProgressMax);
}
Log.i("GeckoAppJava", "GeckoAppShell.handleNotification: callObserver(alertfinished)");
callObserver(alertName, "alertfinished", alertCookie);
removeObserver(alertName);
public static void handleNotification(String aAction, String aAlertName, String aAlertCookie) {
int notificationID = aAlertName.hashCode();
if (GeckoApp.ACTION_ALERT_CLICK.equals(aAction)) {
Log.i("GeckoAppJava", "GeckoAppShell.handleNotification: callObserver(alertclickcallback)");
callObserver(aAlertName, "alertclickcallback", aAlertCookie);
AlertNotification notification = mAlertNotifications.get(notificationID);
if (notification != null && notification.isProgressStyle()) {
// When clicked, keep the notification, if it displays a progress
return;
}
public static String showFilePicker() {
return GeckoApp.mAppContext.showFilePicker();
}
callObserver(aAlertName, "alertfinished", aAlertCookie);
removeObserver(aAlertName);
removeNotification(notificationID);
}
private static void removeNotification(int notificationID) {
mAlertNotifications.remove(notificationID);
NotificationManager notificationManager = (NotificationManager)
GeckoApp.mAppContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(notificationID);
}
}

Просмотреть файл

@ -49,6 +49,7 @@ JAVAFILES = \
GeckoEvent.java \
GeckoSurfaceView.java \
GeckoInputConnection.java \
AlertNotification.java \
$(NULL)
PROCESSEDJAVAFILES = \
@ -97,14 +98,9 @@ ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon48.png
ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon64.png
endif
RES_DRAWABLE = \
res/drawable/alertaddons.png \
res/drawable/alertdownloads.png \
$(NULL)
RES_DRAWABLE_HDPI = \
res/drawable-hdpi/alertaddons.png \
res/drawable-hdpi/alertdownloads.png \
RES_LAYOUT = \
res/layout/notification_progress.xml \
res/layout/notification_progress_text.xml
$(NULL)
NATIVE_LIBS = $(shell cat $(DIST)/bin/dependentlibs.list) libxpcom.so libnssckbi.so libfreebl3.so libmozutils.so
@ -168,18 +164,22 @@ res/drawable-hdpi/icon.png: $(MOZ_APP_ICON)
$(NSINSTALL) -D res/drawable-hdpi
cp $(ICON_PATH_HDPI) $@
$(RES_DRAWABLE):
ifdef MOZ_ANDROID_DRAWABLES
RES_DRAWABLE = $(addprefix res/drawable/,$(notdir $(MOZ_ANDROID_DRAWABLES)))
$(RES_DRAWABLE): $(addprefix $(topsrcdir)/,$(MOZ_ANDROID_DRAWABLES))
$(NSINSTALL) -D res/drawable
cp $(topsrcdir)/mobile/app/android/drawable/* res/drawable/
$(NSINSTALL) $^ res/drawable/
endif
$(RES_DRAWABLE_HDPI):
$(NSINSTALL) -D res/drawable-hdpi
cp $(topsrcdir)/mobile/app/android/drawable-hdpi/* res/drawable-hdpi/
$(RES_LAYOUT): $(subst res/,$(srcdir)/resources/,$(RES_LAYOUT))
$(NSINSTALL) -D res/layout
$(NSINSTALL) $(srcdir)/resources/layout/* res/layout/
R.java: $(MOZ_APP_ICON) $(RES_DRAWABLE) $(RES_DRAWABLE_HDPI) res/values/strings.xml $(LOCALIZED_STRINGS_XML) AndroidManifest.xml
R.java: $(MOZ_APP_ICON) $(RES_LAYOUT) $(RES_DRAWABLE) res/values/strings.xml $(LOCALIZED_STRINGS_XML) AndroidManifest.xml
$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -J . --custom-package org.mozilla.gecko
gecko.ap_: AndroidManifest.xml res/drawable/icon.png res/drawable-hdpi/icon.png $(RES_DRAWABLE) $(RES_DRAWABLE_HDPI) res/values/strings.xml $(LOCALIZED_STRINGS_XML)
gecko.ap_: AndroidManifest.xml res/drawable/icon.png res/drawable-hdpi/icon.png $(RES_LAYOUT) $(RES_DRAWABLE) res/values/strings.xml $(LOCALIZED_STRINGS_XML)
$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
libs/armeabi/%: $(DIST)/lib/%

Просмотреть файл

@ -82,12 +82,13 @@ public class NotificationHandler
Log.i("GeckoAppJava", "Handle notification ID " + notificationID);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.cancel(notificationID);
if (App.mAppContext != null) {
// This should call the observer, if any
App.mAppContext.handleNotification(action, alertName, alertCookie);
} else {
// The app is not running, just cancel this notification
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.cancel(notificationID);
}
if (App.ACTION_ALERT_CLICK.equals(action)) {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше