Merge mozilla-inbound to mozilla-central r=merge a=merge

This commit is contained in:
Andreea Pavel 2018-01-04 23:28:19 +02:00
Родитель 212980366d fe43092e2e
Коммит 25357802c6
66 изменённых файлов: 1880 добавлений и 2011 удалений

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

@ -185,3 +185,4 @@ tasks:
taskId: {$eval: 'taskId'}
input: {$eval: 'input'}
parameters: {$eval: 'parameters'}
- tasks_for: '${tasks_for}'

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

@ -68,6 +68,9 @@ var whitelist = [
platforms: ["macosx"]},
{file: "chrome://global/locale/printProgress.dtd", platforms: ["macosx"]},
// toolkit/content/aboutRights-unbranded.xhtml doesn't use aboutRights.css
{file: "chrome://global/skin/aboutRights.css", skipUnofficial: true},
// devtools/client/inspector/bin/dev-server.js
{file: "chrome://devtools/content/inspector/markup/markup.xhtml",
isFromDevTools: true},
@ -75,6 +78,9 @@ var whitelist = [
// Kept for add-on compatibility, should be removed in bug 851471.
{file: "chrome://mozapps/skin/downloads/downloadIcon.png"},
// SpiderMonkey parser API, currently unused in browser/ and toolkit/
{file: "resource://gre/modules/reflect.jsm"},
// extensions/pref/autoconfig/src/nsReadConfig.cpp
{file: "resource://gre/defaults/autoconfig/prefcalls.js"},
@ -132,8 +138,8 @@ var whitelist = [
platforms: ["linux", "macosx"]},
// Bug 1316187
{file: "chrome://global/content/customizeToolbar.xul"},
// Bug 1343837
{file: "chrome://global/content/findUtils.js"},
// Bug 1356031 (only used by devtools)
{file: "chrome://global/skin/icons/error-16.png"},
// Bug 1348362
{file: "chrome://global/skin/icons/warning-64.png", platforms: ["linux"]},
// Bug 1348525
@ -164,11 +170,20 @@ var whitelist = [
{file: "resource://gre/modules/Manifest.jsm"},
// Bug 1351097
{file: "resource://gre/modules/accessibility/AccessFu.jsm"},
// Bug 1356043
{file: "resource://gre/modules/PerfMeasurement.jsm"},
// Bug 1356045
{file: "chrome://global/content/test-ipc.xul"},
// Bug 1356036
{file: "resource://gre/modules/PerformanceWatcher-content.js"},
{file: "resource://gre/modules/PerformanceWatcher.jsm"},
// Bug 1378173 (warning: still used by devtools)
{file: "resource://gre/modules/Promise.jsm"},
];
whitelist = new Set(whitelist.filter(item =>
("isFromDevTools" in item) == isDevtools &&
(!item.skipNightly || !AppConstants.NIGHTLY_BUILD) &&
(!item.skipUnofficial || !AppConstants.MOZILLA_OFFICIAL) &&
(!item.platforms || item.platforms.includes(AppConstants.platform))
).map(item => item.file));
@ -198,6 +213,8 @@ for (let entry of ignorableWhitelist) {
}
if (!isDevtools) {
// services/sync/modules/main.js
whitelist.add("resource://services-sync/service.js");
// services/sync/modules/service.js
for (let module of ["addons.js", "bookmarks.js", "forms.js", "history.js",
"passwords.js", "prefs.js", "tabs.js",
@ -217,9 +234,17 @@ var gChromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIChromeRegistry);
var gChromeMap = new Map();
var gOverrideMap = new Map();
var gReferencesFromCode = new Set();
var gComponentsSet = new Set();
// In this map when the value is a Set of URLs, the file is referenced if any
// of the files in the Set is referenced.
// When the value is null, the file is referenced unconditionally.
// When the value is a string, "whitelist-direct" means that we have not found
// any reference in the code, but have a matching whitelist entry for this file.
// "whitelist" means that the file is indirectly whitelisted, ie. a whitelisted
// file causes this file to be referenced.
var gReferencesFromCode = new Map();
var resHandler = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
var gResourceMap = [];
@ -254,7 +279,7 @@ function parseManifest(manifestUri) {
Services.io.newURI(argv[0]).specIgnoringRef);
}
} else if (type == "category" && gInterestingCategories.has(argv[0])) {
gReferencesFromCode.add(argv[2]);
gReferencesFromCode.set(argv[2], null);
} else if (type == "resource") {
trackResourcePrefix(argv[0]);
} else if (type == "component") {
@ -264,6 +289,42 @@ function parseManifest(manifestUri) {
});
}
function addCodeReference(url, fromURI) {
let from = convertToCodeURI(fromURI.spec);
// Ignore self references.
if (url == from)
return;
let ref;
if (gReferencesFromCode.has(url)) {
ref = gReferencesFromCode.get(url);
if (ref === null)
return;
} else {
// Mark any file referenced by a 'features' bootstrap.js file as
// unconditionally referenced. The features folder is only in
// resource://app/ for non-packaged builds.
if (/resource:\/\/app\/features\/[^/]+\/bootstrap\.js/.test(from)) {
gReferencesFromCode.set(url, null);
return;
}
ref = new Set();
gReferencesFromCode.set(url, ref);
}
ref.add(from);
}
function listCodeReferences(refs) {
let refList = [];
if (refs) {
for (let ref of refs) {
refList.push(ref);
}
}
return refList.join(",");
}
function parseCSSFile(fileUri) {
return fetchFile(fileUri.spec).then(data => {
for (let line of data.split("\n")) {
@ -273,7 +334,7 @@ function parseCSSFile(fileUri) {
let importMatch = line.match(/@import ['"]?([^'"]*)['"]?/);
if (importMatch && importMatch[1]) {
let url = Services.io.newURI(importMatch[1], null, fileUri).spec;
gReferencesFromCode.add(convertToCodeURI(url));
addCodeReference(convertToCodeURI(url), fileUri);
}
continue;
}
@ -288,7 +349,7 @@ function parseCSSFile(fileUri) {
try {
url = Services.io.newURI(url, null, fileUri).specIgnoringRef;
gReferencesFromCode.add(convertToCodeURI(url));
addCodeReference(convertToCodeURI(url), fileUri);
} catch (e) {
ok(false, "unexpected error while resolving this URI: " + url);
}
@ -302,7 +363,7 @@ function parseCodeFile(fileUri) {
let baseUri;
for (let line of data.split("\n")) {
let urls =
line.match(/["'`]chrome:\/\/[a-zA-Z0-9 -]+\/(content|skin|locale)\/[^"'` ]*["'`]/g);
line.match(/["'`]chrome:\/\/[a-zA-Z0-9-]+\/(content|skin|locale)\/[^"'` ]*["'`]/g);
if (!urls) {
urls = line.match(/["']resource:\/\/[^"']+["']/g);
if (urls && isDevtools &&
@ -317,7 +378,7 @@ function parseCodeFile(fileUri) {
let match = line.match("(?:src|href)=[\"']([^$&\"']+)");
if (match && match[1]) {
let url = Services.io.newURI(match[1], null, fileUri).spec;
gReferencesFromCode.add(convertToCodeURI(url));
addCodeReference(convertToCodeURI(url), fileUri);
}
if (isDevtools) {
@ -337,7 +398,7 @@ function parseCodeFile(fileUri) {
path = path.replace(rule[0], rule[1]);
if (!/\.(properties|js|jsm|json|css)$/.test(path))
path += ".js";
gReferencesFromCode.add(path);
addCodeReference(path, fileUri);
break;
}
}
@ -351,7 +412,7 @@ function parseCodeFile(fileUri) {
if (!/\.(properties|js|jsm|json|css)$/.test(url))
url += ".js";
if (url.startsWith("resource://")) {
gReferencesFromCode.add(url);
addCodeReference(url, fileUri);
} else {
// if we end up with a chrome:// url here, it's likely because
// a baseURI to a resource:// path has been defined in another
@ -383,7 +444,7 @@ function parseCodeFile(fileUri) {
!/\.(properties|js|jsm|json|css)$/.test(url))
url += ".js";
gReferencesFromCode.add(url);
addCodeReference(url, fileUri);
}
}
});
@ -458,10 +519,9 @@ function findChromeUrlsFromArray(array, prefix) {
}
// Only keep strings that look like real chrome or resource urls.
if (/chrome:\/\/[a-zA-Z09 -]+\/(content|skin|locale)\//.test(string) ||
/resource:\/\/gre.*\.[a-z]+/.test(string) ||
string.startsWith("resource://content-accessible/"))
gReferencesFromCode.add(string);
if (/chrome:\/\/[a-zA-Z09-]+\/(content|skin|locale)\//.test(string) ||
/resource:\/\/[a-zA-Z09-]*\/.*\.[a-z]+/.test(string))
gReferencesFromCode.set(string, null);
}
}
@ -526,34 +586,94 @@ add_task(async function checkAllTheFiles() {
"resource://devtools-client-shared/",
"resource://app/modules/devtools",
"resource://gre/modules/devtools"];
let hasDevtoolsPrefix =
uri => devtoolsPrefixes.some(prefix => uri.startsWith(prefix));
let chromeFiles = [];
for (let uri of uris) {
uri = convertToCodeURI(uri.spec);
if ((uri.startsWith("chrome://") || uri.startsWith("resource://")) &&
isDevtools == devtoolsPrefixes.some(prefix => uri.startsWith(prefix)))
isDevtools == hasDevtoolsPrefix(uri))
chromeFiles.push(uri);
}
let isUnreferenced =
file => !gReferencesFromCode.has(file) &&
!gExceptionPaths.some(e => file.startsWith(e)) &&
(!gOverrideMap.has(file) || isUnreferenced(gOverrideMap.get(file)));
if (isDevtools) {
// chrome://devtools/skin/devtools-browser.css is included from browser.xul
gReferencesFromCode.set("chrome://browser/content/browser.xul", null);
// devtools' css is currently included from browser.css, see bug 1204810.
gReferencesFromCode.set("chrome://browser/skin/browser.css", null);
}
let notWhitelisted = file => {
if (!whitelist.has(file))
return true;
whitelist.delete(file);
return false;
let isUnreferenced = file => {
if (gExceptionPaths.some(e => file.startsWith(e)))
return false;
if (gReferencesFromCode.has(file)) {
let refs = gReferencesFromCode.get(file);
if (refs === null)
return false;
for (let ref of refs) {
if (ref.endsWith("!/bootstrap.js"))
return false;
if (isDevtools) {
if (ref.startsWith("resource://app/components/") ||
(file.startsWith("chrome://") && ref.startsWith("resource://")))
return false;
}
if (gReferencesFromCode.has(ref)) {
let refType = gReferencesFromCode.get(ref);
if (refType === null || // unconditionally referenced
refType == "whitelist" || refType == "whitelist-direct")
return false;
}
}
}
return !gOverrideMap.has(file) || isUnreferenced(gOverrideMap.get(file));
};
let unreferencedFiles = chromeFiles.filter(f => {
let rv = isUnreferenced(f);
if (rv && f.startsWith("resource://app/"))
rv = isUnreferenced(f.replace("resource://app/", "resource:///"));
if (rv && /^resource:\/\/(?:app|gre)\/components\/[^/]+\.js$/.test(f))
rv = !gComponentsSet.has(f.replace(/.*\//, ""));
return rv;
}).filter(notWhitelisted).sort();
let unreferencedFiles = chromeFiles;
let removeReferenced = useWhitelist => {
let foundReference = false;
unreferencedFiles = unreferencedFiles.filter(f => {
let rv = isUnreferenced(f);
if (rv && f.startsWith("resource://app/"))
rv = isUnreferenced(f.replace("resource://app/", "resource:///"));
if (rv && /^resource:\/\/(?:app|gre)\/components\/[^/]+\.js$/.test(f))
rv = !gComponentsSet.has(f.replace(/.*\//, ""));
if (!rv) {
foundReference = true;
if (useWhitelist) {
info("indirectly whitelisted file: " + f + " used from " +
listCodeReferences(gReferencesFromCode.get(f)));
}
gReferencesFromCode.set(f, useWhitelist ? "whitelist" : null);
}
return rv;
});
return foundReference;
};
// First filter out the files that are referenced.
while (removeReferenced(false)) {
// As long as removeReferenced returns true, some files have been marked
// as referenced, so we need to run it again.
}
// Marked as referenced the files that have been explicitly whitelisted.
unreferencedFiles = unreferencedFiles.filter(file => {
if (whitelist.has(file)) {
whitelist.delete(file);
gReferencesFromCode.set(file, "whitelist-direct");
return false;
}
return true;
});
// Run the process again, this time when more files are marked as referenced,
// it's a consequence of the whitelist.
while (removeReferenced(true)) {
// As long as removeReferenced returns true, we need to run it again.
}
unreferencedFiles.sort();
if (isDevtools) {
// Bug 1351878 - handle devtools resource files
@ -585,7 +705,16 @@ add_task(async function checkAllTheFiles() {
is(unreferencedFiles.length, 0, "there should be no unreferenced files");
for (let file of unreferencedFiles) {
ok(false, "unreferenced file: " + file);
let refs = gReferencesFromCode.get(file);
if (refs === undefined) {
ok(false, "unreferenced file: " + file);
} else {
let refList = listCodeReferences(refs);
let msg = "file only referenced from unreferenced files: " + file;
if (refList)
msg += " referenced from " + refList;
ok(false, msg);
}
}
for (let file of whitelist) {
@ -595,7 +724,7 @@ add_task(async function checkAllTheFiles() {
ok(false, "unused whitelist entry: " + file);
}
for (let file of gReferencesFromCode) {
for (let [file, refs] of gReferencesFromCode) {
if (isDevtools != devtoolsPrefixes.some(prefix => file.startsWith(prefix)))
continue;
@ -605,11 +734,16 @@ add_task(async function checkAllTheFiles() {
let pathParts =
file.match("chrome://([^/]+)/content/([^/.]+)\.xul") ||
file.match("chrome://([^/]+)/skin/([^/.]+)\.css");
if (!pathParts || pathParts[1] != pathParts[2]) {
// TODO: bug 1349010 - add a whitelist and make this reliable enough
// that we could make the test fail when this catches something new.
info("missing file with code reference: " + file);
}
if (pathParts && pathParts[1] == pathParts[2])
continue;
// TODO: bug 1349010 - add a whitelist and make this reliable enough
// that we could make the test fail when this catches something new.
let refList = listCodeReferences(refs);
let msg = "missing file: " + file;
if (refList)
msg += " referenced from " + refList;
info(msg);
}
}
});

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

@ -7,13 +7,18 @@ add_task(async function() {
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri);
let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri);
let updates = 0;
function countUpdates(event) { updates++; }
let updates = [];
function countUpdates(event) { updates.push((new Error()).stack); }
let updater = document.getElementById("editMenuCommandSetAll");
updater.addEventListener("commandupdate", countUpdates, true);
await BrowserTestUtils.switchTab(gBrowser, tab1);
is(updates, 1, "only one command update per tab switch");
is(updates.length, 1, "only one command update per tab switch");
if (updates.length > 1) {
for (let stack of updates) {
info("Update stack:\n" + stack);
}
}
updater.removeEventListener("commandupdate", countUpdates, true);
await BrowserTestUtils.removeTab(tab1);

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

@ -105,13 +105,14 @@ build_binutils() {
../binutils-$binutils_version/configure --prefix=${prefix-/tools/gcc}/ $binutils_configure_flags
make $make_flags
make install $make_flags DESTDIR=$root_dir
export PATH=$root_dir/${prefix-/tools/gcc}/bin:$PATH
popd
}
build_gcc() {
mkdir $root_dir/gcc-objdir
pushd $root_dir/gcc-objdir
../gcc-$gcc_version/configure --prefix=${prefix-/tools/gcc} --enable-languages=c,c++ --disable-nls --disable-gnu-unique-object --enable-__cxa_atexit --with-arch-32=pentiumpro
../gcc-$gcc_version/configure --prefix=${prefix-/tools/gcc} --enable-languages=c,c++ --disable-nls --disable-gnu-unique-object --enable-__cxa_atexit --with-arch-32=pentiumpro --disable-initfini-array
make $make_flags
make $make_flags install DESTDIR=$root_dir

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

@ -153,6 +153,10 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::Console',
},
'ConsoleInstance': {
'implicitJSContext': ['clear', 'count', 'groupEnd', 'time', 'timeEnd'],
},
'ConvolverNode': {
'implicitJSContext': [ 'buffer' ],
},

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

@ -1150,12 +1150,12 @@ WebGLContext::ClearBackbufferIfNeeded()
void
WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
{
const size_t maxWebGLContexts = gfxPrefs::WebGLMaxContexts();
size_t maxWebGLContextsPerPrincipal = gfxPrefs::WebGLMaxContextsPerPrincipal();
const auto maxWebGLContexts = gfxPrefs::WebGLMaxContexts();
auto maxWebGLContextsPerPrincipal = gfxPrefs::WebGLMaxContextsPerPrincipal();
// maxWebGLContextsPerPrincipal must be less than maxWebGLContexts
MOZ_ASSERT(maxWebGLContextsPerPrincipal < maxWebGLContexts);
maxWebGLContextsPerPrincipal = std::min(maxWebGLContextsPerPrincipal, maxWebGLContexts - 1);
MOZ_ASSERT(maxWebGLContextsPerPrincipal <= maxWebGLContexts);
maxWebGLContextsPerPrincipal = std::min(maxWebGLContextsPerPrincipal, maxWebGLContexts);
if (!NS_IsMainThread()) {
// XXX mtseng: bug 709490, WebGLMemoryTracker is not thread safe.
@ -1220,12 +1220,12 @@ WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
}
if (numContextsThisPrincipal > maxWebGLContextsPerPrincipal) {
GenerateWarning("Exceeded %zu live WebGL contexts for this principal, losing the "
GenerateWarning("Exceeded %u live WebGL contexts for this principal, losing the "
"least recently used one.", maxWebGLContextsPerPrincipal);
MOZ_ASSERT(oldestContextThisPrincipal); // if we reach this point, this can't be null
const_cast<WebGLContext*>(oldestContextThisPrincipal)->LoseContext();
} else if (numContexts > maxWebGLContexts) {
GenerateWarning("Exceeded %zu live WebGL contexts, losing the least "
GenerateWarning("Exceeded %u live WebGL contexts, losing the least "
"recently used one.", maxWebGLContexts);
MOZ_ASSERT(oldestContext); // if we reach this point, this can't be null
const_cast<WebGLContext*>(oldestContext)->LoseContext();

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

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/Console.h"
#include "mozilla/dom/ConsoleInstance.h"
#include "mozilla/dom/ConsoleBinding.h"
#include "mozilla/dom/BlobBinding.h"
@ -663,9 +664,11 @@ private:
class ConsoleProfileRunnable final : public ConsoleRunnable
{
public:
ConsoleProfileRunnable(Console* aConsole, const nsAString& aAction,
ConsoleProfileRunnable(Console* aConsole, Console::MethodName aName,
const nsAString& aAction,
const Sequence<JS::Value>& aArguments)
: ConsoleRunnable(aConsole)
, mName(aName)
, mAction(aAction)
, mArguments(aArguments)
{
@ -746,13 +749,14 @@ private:
}
}
mConsole->ProfileMethodInternal(aCx, mAction, arguments);
mConsole->ProfileMethodInternal(aCx, mName, mAction, arguments);
}
virtual void
ReleaseData() override
{}
Console::MethodName mName;
nsString mAction;
// This is a reference of the sequence of arguments we receive from the DOM
@ -770,12 +774,14 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Console)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Console)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsoleEventNotifier)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDumpFunction)
tmp->Shutdown();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Console)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsoleEventNotifier)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDumpFunction)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Console)
@ -816,6 +822,9 @@ Console::Console(nsPIDOMWindowInner* aWindow)
: mWindow(aWindow)
, mOuterID(0)
, mInnerID(0)
, mDumpToStdout(false)
, mChromeInstance(false)
, mMaxLogLevel(ConsoleLogLevel::All)
, mStatus(eUnknown)
, mCreationTimeStamp(TimeStamp::Now())
{
@ -950,13 +959,6 @@ METHOD(Debug, "debug")
METHOD(Table, "table")
METHOD(Trace, "trace")
/* static */ void
Console::Clear(const GlobalObject& aGlobal)
{
const Sequence<JS::Value> data;
Method(aGlobal, MethodClear, NS_LITERAL_STRING("clear"), data);
}
// Displays an interactive listing of all the properties of an object.
METHOD(Dir, "dir");
METHOD(Dirxml, "dirxml");
@ -964,6 +966,15 @@ METHOD(Dirxml, "dirxml");
METHOD(Group, "group")
METHOD(GroupCollapsed, "groupCollapsed")
#undef METHOD
/* static */ void
Console::Clear(const GlobalObject& aGlobal)
{
const Sequence<JS::Value> data;
Method(aGlobal, MethodClear, NS_LITERAL_STRING("clear"), data);
}
/* static */ void
Console::GroupEnd(const GlobalObject& aGlobal)
{
@ -987,15 +998,27 @@ Console::TimeEnd(const GlobalObject& aGlobal, const nsAString& aLabel)
Console::StringMethod(const GlobalObject& aGlobal, const nsAString& aLabel,
MethodName aMethodName, const nsAString& aMethodString)
{
JSContext* cx = aGlobal.Context();
RefPtr<Console> console = GetConsole(aGlobal);
if (!console) {
return;
}
ClearException ce(cx);
console->StringMethodInternal(aGlobal.Context(), aLabel, aMethodName,
aMethodString);
}
void
Console::StringMethodInternal(JSContext* aCx, const nsAString& aLabel,
MethodName aMethodName,
const nsAString& aMethodString)
{
ClearException ce(aCx);
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(cx, &data);
SequenceRooter<JS::Value> rooter(aCx, &data);
JS::Rooted<JS::Value> value(cx);
if (!dom::ToJSValue(cx, aLabel, &value)) {
JS::Rooted<JS::Value> value(aCx);
if (!dom::ToJSValue(aCx, aLabel, &value)) {
return;
}
@ -1003,7 +1026,7 @@ Console::StringMethod(const GlobalObject& aGlobal, const nsAString& aLabel,
return;
}
Method(aGlobal, aMethodName, aMethodString, data);
MethodInternal(aCx, aMethodName, aMethodString, data);
}
/* static */ void
@ -1027,18 +1050,20 @@ Console::TimeStamp(const GlobalObject& aGlobal,
/* static */ void
Console::Profile(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData)
{
ProfileMethod(aGlobal, NS_LITERAL_STRING("profile"), aData);
ProfileMethod(aGlobal, MethodProfile, NS_LITERAL_STRING("profile"), aData);
}
/* static */ void
Console::ProfileEnd(const GlobalObject& aGlobal,
const Sequence<JS::Value>& aData)
{
ProfileMethod(aGlobal, NS_LITERAL_STRING("profileEnd"), aData);
ProfileMethod(aGlobal, MethodProfileEnd, NS_LITERAL_STRING("profileEnd"),
aData);
}
/* static */ void
Console::ProfileMethod(const GlobalObject& aGlobal, const nsAString& aAction,
Console::ProfileMethod(const GlobalObject& aGlobal, MethodName aName,
const nsAString& aAction,
const Sequence<JS::Value>& aData)
{
RefPtr<Console> console = GetConsole(aGlobal);
@ -1047,22 +1072,40 @@ Console::ProfileMethod(const GlobalObject& aGlobal, const nsAString& aAction,
}
JSContext* cx = aGlobal.Context();
console->ProfileMethodInternal(cx, aAction, aData);
console->ProfileMethodInternal(cx, aName, aAction, aData);
}
bool
Console::IsEnabled(JSContext* aCx) const
{
// Console is always enabled if it is a custom Chrome-Only instance.
if (mChromeInstance) {
return true;
}
// Make all Console API no-op if DevTools aren't enabled.
return nsContentUtils::DevToolsEnabled(aCx);
}
void
Console::ProfileMethodInternal(JSContext* aCx, const nsAString& aAction,
Console::ProfileMethodInternal(JSContext* aCx, MethodName aMethodName,
const nsAString& aAction,
const Sequence<JS::Value>& aData)
{
// Make all Console API no-op if DevTools aren't enabled.
if (!nsContentUtils::DevToolsEnabled(aCx)) {
if (!IsEnabled(aCx)) {
return;
}
if (!ShouldProceed(aMethodName)) {
return;
}
MaybeExecuteDumpFunction(aCx, aAction, aData);
if (!NS_IsMainThread()) {
// Here we are in a worker thread.
RefPtr<ConsoleProfileRunnable> runnable =
new ConsoleProfileRunnable(this, aAction, aData);
new ConsoleProfileRunnable(this, aMethodName, aAction, aData);
runnable->Dispatch(aCx);
return;
@ -1207,10 +1250,14 @@ Console::MethodInternal(JSContext* aCx, MethodName aMethodName,
const nsAString& aMethodString,
const Sequence<JS::Value>& aData)
{
// Make all Console API no-op if DevTools aren't enabled.
if (!nsContentUtils::DevToolsEnabled(aCx)) {
if (!IsEnabled(aCx)) {
return;
}
if (!ShouldProceed(aMethodName)) {
return;
}
AssertIsOnOwningThread();
RefPtr<ConsoleCallData> callData(new ConsoleCallData());
@ -1321,9 +1368,19 @@ Console::MethodInternal(JSContext* aCx, MethodName aMethodName,
}
}
// Before processing this CallData differently, it's time to call the dump
// function.
if (aMethodName == MethodTrace) {
MaybeExecuteDumpFunctionForTrace(aCx, stack);
} else {
MaybeExecuteDumpFunction(aCx, aMethodString, aData);
}
if (NS_IsMainThread()) {
if (mWindow) {
callData->SetIDs(mOuterID, mInnerID);
} else if (!mPassedInnerID.IsEmpty()) {
callData->SetIDs(NS_LITERAL_STRING("jsm"), mPassedInnerID);
} else {
nsAutoString filename;
if (callData->mTopStackFrame.isSome()) {
@ -1492,6 +1549,7 @@ Console::PopulateConsoleNotificationInTheTargetScope(JSContext* aCx,
event.mInnerID.Value().SetAsUnsignedLongLong() = 0;
}
event.mConsoleID = mConsoleID;
event.mLevel = aData->mMethodString;
event.mFilename = frame.mFilename;
@ -2537,5 +2595,197 @@ Console::MonotonicTimer(JSContext* aCx, MethodName aMethodName,
return true;
}
/* static */ already_AddRefed<ConsoleInstance>
Console::CreateInstance(const GlobalObject& aGlobal,
const ConsoleInstanceOptions& aOptions)
{
RefPtr<ConsoleInstance> console = new ConsoleInstance(aOptions);
return console.forget();
}
void
Console::MaybeExecuteDumpFunction(JSContext* aCx,
const nsAString& aMethodName,
const Sequence<JS::Value>& aData)
{
if (!mDumpFunction && !mDumpToStdout) {
return;
}
nsAutoString message;
message.AssignLiteral("console.");
message.Append(aMethodName);
message.AppendLiteral(": ");
if (!mDumpPrefix.IsEmpty()) {
message.Append(mDumpPrefix);
message.AppendLiteral(": ");
}
for (uint32_t i = 0; i < aData.Length(); ++i) {
JS::Rooted<JS::Value> v(aCx, aData[i]);
JS::Rooted<JSString*> jsString(aCx, JS_ValueToSource(aCx, v));
if (!jsString) {
continue;
}
nsAutoJSString string;
if (NS_WARN_IF(!string.init(aCx, jsString))) {
return;
}
if (i != 0) {
message.AppendLiteral(" ");
}
message.Append(string);
}
message.AppendLiteral("\n");
ExecuteDumpFunction(message);
}
void
Console::MaybeExecuteDumpFunctionForTrace(JSContext* aCx, nsIStackFrame* aStack)
{
if (!aStack || (!mDumpFunction && !mDumpToStdout)) {
return;
}
nsAutoString message;
message.AssignLiteral("console.trace:\n");
if (!mDumpPrefix.IsEmpty()) {
message.Append(mDumpPrefix);
message.AppendLiteral(": ");
}
nsCOMPtr<nsIStackFrame> stack(aStack);
while (stack) {
nsAutoString filename;
nsresult rv = stack->GetFilename(aCx, filename);
NS_ENSURE_SUCCESS_VOID(rv);
message.Append(filename);
message.AppendLiteral(" ");
int32_t lineNumber;
rv = stack->GetLineNumber(aCx, &lineNumber);
NS_ENSURE_SUCCESS_VOID(rv);
message.AppendInt(lineNumber);
message.AppendLiteral(" ");
nsAutoString functionName;
rv = stack->GetName(aCx, functionName);
NS_ENSURE_SUCCESS_VOID(rv);
message.Append(filename);
message.AppendLiteral("\n");
nsCOMPtr<nsIStackFrame> caller;
rv = stack->GetCaller(aCx, getter_AddRefs(caller));
NS_ENSURE_SUCCESS_VOID(rv);
if (!caller) {
rv = stack->GetAsyncCaller(aCx, getter_AddRefs(caller));
NS_ENSURE_SUCCESS_VOID(rv);
}
stack.swap(caller);
}
message.AppendLiteral("\n");
ExecuteDumpFunction(message);
}
void
Console::ExecuteDumpFunction(const nsAString& aMessage)
{
if (mDumpFunction) {
IgnoredErrorResult rv;
mDumpFunction->Call(aMessage, rv);
return;
}
NS_ConvertUTF16toUTF8 str(aMessage);
MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug, ("%s", str.get()));
#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", str.get());
#endif
fputs(str.get(), stdout);
fflush(stdout);
}
bool
Console::ShouldProceed(MethodName aName) const
{
return WebIDLLogLevelToInteger(mMaxLogLevel) <=
InternalLogLevelToInteger(aName);
}
uint32_t
Console::WebIDLLogLevelToInteger(ConsoleLogLevel aLevel) const
{
switch (aLevel) {
case ConsoleLogLevel::All: return 0;
case ConsoleLogLevel::Debug: return 2;
case ConsoleLogLevel::Log: return 3;
case ConsoleLogLevel::Info: return 3;
case ConsoleLogLevel::Clear: return 3;
case ConsoleLogLevel::Trace: return 3;
case ConsoleLogLevel::TimeEnd: return 3;
case ConsoleLogLevel::Time: return 3;
case ConsoleLogLevel::Group: return 3;
case ConsoleLogLevel::GroupEnd: return 3;
case ConsoleLogLevel::Profile: return 3;
case ConsoleLogLevel::ProfileEnd: return 3;
case ConsoleLogLevel::Dir: return 3;
case ConsoleLogLevel::Dirxml: return 3;
case ConsoleLogLevel::Warn: return 4;
case ConsoleLogLevel::Error: return 5;
case ConsoleLogLevel::Off: return UINT32_MAX;
default:
MOZ_CRASH("ConsoleLogLevel is out of sync with the Console implementation!");
return 0;
}
return 0;
}
uint32_t
Console::InternalLogLevelToInteger(MethodName aName) const
{
switch (aName) {
case MethodLog: return 3;
case MethodInfo: return 3;
case MethodWarn: return 4;
case MethodError: return 5;
case MethodException: return 5;
case MethodDebug: return 2;
case MethodTable: return 3;
case MethodTrace: return 3;
case MethodDir: return 3;
case MethodDirxml: return 3;
case MethodGroup: return 3;
case MethodGroupCollapsed: return 3;
case MethodGroupEnd: return 3;
case MethodTime: return 3;
case MethodTimeEnd: return 3;
case MethodTimeStamp: return 3;
case MethodAssert: return 3;
case MethodCount: return 3;
case MethodClear: return 3;
case MethodProfile: return 3;
case MethodProfileEnd: return 3;
default:
MOZ_CRASH("MethodName is out of sync with the Console implementation!");
return 0;
}
return 0;
}
} // namespace dom
} // namespace mozilla

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

@ -7,8 +7,7 @@
#ifndef mozilla_dom_Console_h
#define mozilla_dom_Console_h
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/ConsoleBinding.h"
#include "mozilla/JSObjectHolder.h"
#include "mozilla/TimeStamp.h"
#include "nsCycleCollectionParticipant.h"
@ -21,17 +20,18 @@
class nsIConsoleAPIStorage;
class nsIPrincipal;
class nsIStackFrame;
namespace mozilla {
namespace dom {
class AnyCallback;
class ConsoleCallData;
class ConsoleInstance;
class ConsoleInstanceDumpCallback;
class ConsoleRunnable;
class ConsoleCallDataRunnable;
class ConsoleProfileRunnable;
struct ConsoleTimerError;
struct ConsoleStackEntry;
class Console final : public nsIObserver
, public nsSupportsWeakReference
@ -114,6 +114,10 @@ public:
static void
Clear(const GlobalObject& aGlobal);
static already_AddRefed<ConsoleInstance>
CreateInstance(const GlobalObject& aGlobal,
const ConsoleInstanceOptions& aOptions);
void
ClearStorage();
@ -154,7 +158,9 @@ private:
MethodTimeStamp,
MethodAssert,
MethodCount,
MethodClear
MethodClear,
MethodProfile,
MethodProfileEnd,
};
static already_AddRefed<Console>
@ -164,11 +170,12 @@ private:
GetConsoleInternal(const GlobalObject& aGlobal, ErrorResult &aRv);
static void
ProfileMethod(const GlobalObject& aGlobal, const nsAString& aAction,
const Sequence<JS::Value>& aData);
ProfileMethod(const GlobalObject& aGlobal, MethodName aName,
const nsAString& aAction, const Sequence<JS::Value>& aData);
void
ProfileMethodInternal(JSContext* aCx, const nsAString& aAction,
ProfileMethodInternal(JSContext* aCx, MethodName aName,
const nsAString& aAction,
const Sequence<JS::Value>& aData);
static void
@ -183,6 +190,10 @@ private:
StringMethod(const GlobalObject& aGlobal, const nsAString& aLabel,
MethodName aMethodName, const nsAString& aMethodString);
void
StringMethodInternal(JSContext* aCx, const nsAString& aLabel,
MethodName aMethodName, const nsAString& aMethodString);
// This method must receive aCx and aArguments in the same JSCompartment.
void
ProcessCallData(JSContext* aCx,
@ -376,6 +387,28 @@ private:
const Sequence<JS::Value>& aData,
DOMHighResTimeStamp* aTimeStamp);
void
MaybeExecuteDumpFunction(JSContext* aCx, const nsAString& aMethodName,
const Sequence<JS::Value>& aData);
void
MaybeExecuteDumpFunctionForTrace(JSContext* aCx, nsIStackFrame* aStack);
void
ExecuteDumpFunction(const nsAString& aMessage);
bool
IsEnabled(JSContext* aCx) const;
bool
ShouldProceed(MethodName aName) const;
uint32_t
WebIDLLogLevelToInteger(ConsoleLogLevel aLevel) const;
uint32_t
InternalLogLevelToInteger(MethodName aName) const;
// All these nsCOMPtr are touched on main thread only.
nsCOMPtr<nsPIDOMWindowInner> mWindow;
nsCOMPtr<nsIConsoleAPIStorage> mStorage;
@ -406,6 +439,15 @@ private:
uint64_t mOuterID;
uint64_t mInnerID;
// Set only by ConsoleInstance:
nsString mConsoleID;
nsString mPassedInnerID;
RefPtr<ConsoleInstanceDumpCallback> mDumpFunction;
bool mDumpToStdout;
nsString mDumpPrefix;
bool mChromeInstance;
ConsoleLogLevel mMaxLogLevel;
enum {
eUnknown,
eInitialized,
@ -417,6 +459,7 @@ private:
mozilla::TimeStamp mCreationTimeStamp;
friend class ConsoleCallData;
friend class ConsoleInstance;
friend class ConsoleRunnable;
friend class ConsoleCallDataRunnable;
friend class ConsoleProfileRunnable;

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

@ -0,0 +1,188 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/ConsoleInstance.h"
#include "mozilla/dom/ConsoleBinding.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ConsoleInstance, mConsole)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ConsoleInstance)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ConsoleInstance)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ConsoleInstance)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_END
namespace {
ConsoleLogLevel
PrefToValue(const nsCString& aPref)
{
if (!NS_IsMainThread()) {
NS_WARNING("Console.maxLogLevelPref is not supported on workers!");
return ConsoleLogLevel::All;
}
nsAutoCString value;
nsresult rv = Preferences::GetCString(aPref.get(), value);
if (NS_WARN_IF(NS_FAILED(rv))) {
return ConsoleLogLevel::All;
}
int index = FindEnumStringIndexImpl(value.get(), value.Length(),
ConsoleLogLevelValues::strings);
if (NS_WARN_IF(index < 0)) {
return ConsoleLogLevel::All;
}
MOZ_ASSERT(index < (int)ConsoleLogLevel::EndGuard_);
return static_cast<ConsoleLogLevel>(index);
}
} // anonymous
ConsoleInstance::ConsoleInstance(const ConsoleInstanceOptions& aOptions)
: mConsole(new Console(nullptr))
{
mConsole->mConsoleID = aOptions.mConsoleID;
mConsole->mPassedInnerID = aOptions.mInnerID;
if (aOptions.mDump.WasPassed()) {
mConsole->mDumpFunction = &aOptions.mDump.Value();
} else {
// For historical reasons, ConsoleInstance prints messages on stdout.
mConsole->mDumpToStdout = true;
}
mConsole->mDumpPrefix = aOptions.mPrefix;
// Let's inform that this is a custom instance.
mConsole->mChromeInstance = true;
if (aOptions.mMaxLogLevel.WasPassed()) {
mConsole->mMaxLogLevel = aOptions.mMaxLogLevel.Value();
}
if (!aOptions.mMaxLogLevelPref.IsEmpty()) {
mConsole->mMaxLogLevel =
PrefToValue(NS_ConvertUTF16toUTF8(aOptions.mMaxLogLevelPref));
}
}
ConsoleInstance::~ConsoleInstance()
{}
JSObject*
ConsoleInstance::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return ConsoleInstanceBinding::Wrap(aCx, this, aGivenProto);
}
#define METHOD(name, string) \
void \
ConsoleInstance::name(JSContext* aCx, const Sequence<JS::Value>& aData) \
{ \
mConsole->MethodInternal(aCx, Console::Method##name, \
NS_LITERAL_STRING(string), aData); \
}
METHOD(Log, "log")
METHOD(Info, "info")
METHOD(Warn, "warn")
METHOD(Error, "error")
METHOD(Exception, "exception")
METHOD(Debug, "debug")
METHOD(Table, "table")
METHOD(Trace, "trace")
METHOD(Dir, "dir");
METHOD(Dirxml, "dirxml");
METHOD(Group, "group")
METHOD(GroupCollapsed, "groupCollapsed")
#undef METHOD
void
ConsoleInstance::GroupEnd(JSContext* aCx)
{
const Sequence<JS::Value> data;
mConsole->MethodInternal(aCx, Console::MethodGroupEnd,
NS_LITERAL_STRING("groupEnd"), data);
}
void
ConsoleInstance::Time(JSContext* aCx, const nsAString& aLabel)
{
mConsole->StringMethodInternal(aCx, aLabel, Console::MethodTime,
NS_LITERAL_STRING("time"));
}
void
ConsoleInstance::TimeEnd(JSContext* aCx, const nsAString& aLabel)
{
mConsole->StringMethodInternal(aCx, aLabel, Console::MethodTimeEnd,
NS_LITERAL_STRING("timeEnd"));
}
void
ConsoleInstance::TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData)
{
ClearException ce(aCx);
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(aCx, &data);
if (aData.isString() && !data.AppendElement(aData, fallible)) {
return;
}
mConsole->MethodInternal(aCx, Console::MethodTimeStamp,
NS_LITERAL_STRING("timeStamp"), data);
}
void
ConsoleInstance::Profile(JSContext* aCx, const Sequence<JS::Value>& aData)
{
mConsole->ProfileMethodInternal(aCx, Console::MethodProfile,
NS_LITERAL_STRING("profile"), aData);
}
void
ConsoleInstance::ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData)
{
mConsole->ProfileMethodInternal(aCx, Console::MethodProfileEnd,
NS_LITERAL_STRING("profileEnd"), aData);
}
void
ConsoleInstance::Assert(JSContext* aCx, bool aCondition,
const Sequence<JS::Value>& aData)
{
if (!aCondition) {
mConsole->MethodInternal(aCx, Console::MethodAssert,
NS_LITERAL_STRING("assert"), aData);
}
}
void
ConsoleInstance::Count(JSContext* aCx, const nsAString& aLabel)
{
mConsole->StringMethodInternal(aCx, aLabel, Console::MethodCount,
NS_LITERAL_STRING("count"));
}
void
ConsoleInstance::Clear(JSContext* aCx)
{
const Sequence<JS::Value> data;
mConsole->MethodInternal(aCx, Console::MethodClear,
NS_LITERAL_STRING("clear"), data);
}
} // namespace dom
} // namespace mozilla

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

@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_ConsoleInstance_h
#define mozilla_dom_ConsoleInstance_h
#include "mozilla/dom/Console.h"
namespace mozilla {
namespace dom {
class ConsoleInstance final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ConsoleInstance)
explicit ConsoleInstance(const ConsoleInstanceOptions& aOptions);
// WebIDL methods
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
nsPIDOMWindowInner* GetParentObject() const
{
return nullptr;
}
void
Log(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Info(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Warn(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Error(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Exception(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Debug(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Table(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Trace(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Dir(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Dirxml(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Group(JSContext* aCx, const Sequence<JS::Value>& aData);
void
GroupCollapsed(JSContext* aCx, const Sequence<JS::Value>& aData);
void
GroupEnd(JSContext* aCx);
void
Time(JSContext* aCx, const nsAString& aLabel);
void
TimeEnd(JSContext* aCx, const nsAString& aLabel);
void
TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData);
void
Profile(JSContext* aCx, const Sequence<JS::Value>& aData);
void
ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Assert(JSContext* aCx, bool aCondition, const Sequence<JS::Value>& aData);
void
Count(JSContext* aCx, const nsAString& aLabel);
void
Clear(JSContext* aCx);
private:
~ConsoleInstance();
RefPtr<Console> mConsole;
};
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_ConsoleInstance_h

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

@ -23,10 +23,12 @@ EXPORTS.mozilla += [
EXPORTS.mozilla.dom += [
'Console.h',
'ConsoleInstance.h',
]
UNIFIED_SOURCES += [
'Console.cpp',
'ConsoleInstance.cpp',
'ConsoleReportCollector.cpp',
]

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

@ -5,7 +5,23 @@
this.EXPORTED_SYMBOLS = [ "ConsoleTest" ];
this.ConsoleTest = {
go: function() {
go: function(dumpFunction) {
console.log("Hello world!");
console.createInstance().log("Hello world!");
let c = console.createInstance({
consoleID: "wow",
innerID: "CUSTOM INNER",
dump: dumpFunction,
prefix: "_PREFIX_",
});
c.log("Hello world!");
c.trace("Hello world!");
console.createInstance({ innerID: "LEVEL", maxLogLevel: "off" }).log("Invisible!");
console.createInstance({ innerID: "LEVEL", maxLogLevel: "all" }).log("Hello world!");
console.createInstance({ innerID: "LEVEL", maxLogLevelPref: "foo.pref" }).log("Invisible!");
console.createInstance({ innerID: "LEVEL", maxLogLevelPref: "pref.test.console" }).log("Hello world!");
}
};

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

@ -17,18 +17,45 @@
const JSM = "chrome://mochitests/content/chrome/dom/console/tests/console.jsm";
let dumpCalled = 0;
function dumpFunction(msg) {
ok(msg.indexOf("_PREFIX_") != -1, "we have a prefix");
dump("Message received: " + msg); // Just for debugging
dumpCalled++;
}
function consoleListener() {
SpecialPowers.addObserver(this, "console-api-log-event");
}
consoleListener.prototype = {
count: 0,
observe: function(aSubject, aTopic, aData) {
if (aTopic == "console-api-log-event") {
var obj = aSubject.wrappedJSObject;
if (obj.innerID == JSM) {
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
is (obj.arguments[0], "Hello world!", "Message matches");
is(obj.arguments[0], "Hello world!", "Message matches");
is(obj.consoleID, "", "No consoleID for console API");
// We want to see 2 messages from this innerID, the first is generated
// by console.log, the second one from createInstance().log();
++this.count;
} else if (obj.innerID == "CUSTOM INNER") {
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
is(obj.arguments[0], "Hello world!", "Message matches");
is(obj.consoleID, "wow", "consoleID is set by consoleInstance");
++this.count;
} else if (obj.innerID == "LEVEL") {
// Nothing special... just we don't want to see 'invisible' messages.
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
is(obj.arguments[0], "Hello world!", "Message matches");
++this.count;
}
if (this.count == 4) {
is(dumpCalled, 2, "Dump has been called!");
SpecialPowers.removeObserver(this, "console-api-log-event");
SimpleTest.finish();
}
@ -38,9 +65,11 @@ consoleListener.prototype = {
function test() {
SimpleTest.waitForExplicitFinish();
var cl = new consoleListener();
Components.utils.import(JSM);
ConsoleTest.go();
SpecialPowers.pushPrefEnv({set: [["pref.test.console", "log"]]}).then(() => {
var cl = new consoleListener();
Components.utils.import(JSM);
ConsoleTest.go(dumpFunction);
});
}
]]>

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

@ -12,6 +12,10 @@
ClassString="Console",
ProtoObjectHack]
namespace console {
// NOTE: if you touch this namespace, remember to update the ConsoleInstance
// interface as well!
// Logging
void assert(optional boolean condition = false, any... data);
void clear();
@ -45,12 +49,16 @@ namespace console {
[ChromeOnly]
const boolean IS_NATIVE_CONSOLE = true;
[ChromeOnly, NewObject]
ConsoleInstance createInstance(optional ConsoleInstanceOptions options);
};
// This is used to propagate console events to the observers.
dictionary ConsoleEvent {
(unsigned long long or DOMString) ID;
(unsigned long long or DOMString) innerID;
DOMString consoleID = "";
DOMString addonId = "";
DOMString level = "";
DOMString filename = "";
@ -109,3 +117,72 @@ dictionary ConsoleCounter {
dictionary ConsoleCounterError {
DOMString error = "maxCountersExceeded";
};
[ChromeOnly,
Exposed=(Window,Worker,WorkerDebugger,Worklet,System)]
// This is basically a copy of the console namespace.
interface ConsoleInstance {
// Logging
void assert(optional boolean condition = false, any... data);
void clear();
void count(optional DOMString label = "default");
void debug(any... data);
void error(any... data);
void info(any... data);
void log(any... data);
void table(any... data); // FIXME: The spec is still unclear about this.
void trace(any... data);
void warn(any... data);
void dir(any... data); // FIXME: This doesn't follow the spec yet.
void dirxml(any... data);
// Grouping
void group(any... data);
void groupCollapsed(any... data);
void groupEnd();
// Timing
void time(optional DOMString label = "default");
void timeEnd(optional DOMString label = "default");
// Mozilla only or Webcompat methods
void _exception(any... data);
void timeStamp(optional any data);
void profile(any... data);
void profileEnd(any... data);
};
callback ConsoleInstanceDumpCallback = void (DOMString message);
enum ConsoleLogLevel {
"all", "debug", "log", "info", "clear", "trace", "timeEnd", "time", "group",
"groupEnd", "profile", "profileEnd", "dir", "dirxml", "warn", "error", "off"
};
dictionary ConsoleInstanceOptions {
// An optional function to intercept all strings written to stdout.
ConsoleInstanceDumpCallback dump;
// An optional prefix string to be printed before the actual logged message.
DOMString prefix = "";
// An ID representing the source of the message. Normally the inner ID of a
// DOM window.
DOMString innerID = "";
// String identified for the console, this will be passed through the console
// notifications.
DOMString consoleID = "";
// Identifier that allows to filter which messages are logged based on their
// log level.
ConsoleLogLevel maxLogLevel;
// String pref name which contains the level to use for maxLogLevel. If the
// pref doesn't exist, gets removed or it is used in workers, the maxLogLevel
// will default to the value passed to this constructor (or "all" if it wasn't
// specified).
DOMString maxLogLevelPref = "";
};

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

@ -746,8 +746,8 @@ private:
DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);
DECL_GFX_PREF(Live, "webgl.force-index-validation", WebGLForceIndexValidation, int32_t, 0);
DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false);
DECL_GFX_PREF(Once, "webgl.max-contexts", WebGLMaxContexts, uint32_t, 32);
DECL_GFX_PREF(Once, "webgl.max-contexts-per-principal", WebGLMaxContextsPerPrincipal, uint32_t, 16);
DECL_GFX_PREF(Live, "webgl.max-contexts", WebGLMaxContexts, uint32_t, 32);
DECL_GFX_PREF(Live, "webgl.max-contexts-per-principal", WebGLMaxContextsPerPrincipal, uint32_t, 16);
DECL_GFX_PREF(Live, "webgl.max-warnings-per-context", WebGLMaxWarningsPerContext, uint32_t, 32);
DECL_GFX_PREF(Live, "webgl.min_capability_mode", WebGLMinCapabilityMode, bool, false);
DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false);

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

@ -0,0 +1,8 @@
// |jit-test| --arm-asm-nop-fill=1
var code = "(module ";
for (var i = 0; i < 100; i++)
code += "(func (param i32) (result i32) (i32.add (i32.const 1) (get_local 0))) ";
code += ")";
var buf = wasmTextToBinary(code);
WebAssembly.compile(buf);

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

@ -72,7 +72,7 @@ static_assert(!IsPointer<IsPointerTest>::value,
static_assert(IsPointer<IsPointerTest*>::value,
"IsPointerTest* is a pointer");
static_assert(!IsPointer<bool(IsPointerTest::*)()>::value,
"bool(IsPointerTest::*) not a pointer");
"bool(IsPointerTest::*)() not a pointer");
static_assert(!IsPointer<void(IsPointerTest::*)(void)>::value,
"void(IsPointerTest::*)(void) not a pointer");

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

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIArray;
interface nsIPrincipal;
%{C++
namespace mozilla {
@ -12,6 +13,13 @@ class TimeStamp;
native TimeStamp(mozilla::TimeStamp);
[scriptable, uuid(c2d9e95b-9cc9-4f47-9ef6-1de0cf7ebc75)]
interface nsIServerTiming : nsISupports {
[must_use] readonly attribute ACString name;
[must_use] readonly attribute double duration;
[must_use] readonly attribute ACString description;
};
// All properties return zero if the value is not available
[scriptable, uuid(ca63784d-959c-4c3a-9a59-234a2a520de0)]
interface nsITimedChannel : nsISupports {
@ -100,4 +108,6 @@ interface nsITimedChannel : nsISupports {
// If this attribute is false, this resource MUST NOT be reported in resource timing.
[noscript] attribute boolean reportResourceTiming;
readonly attribute nsIArray serverTiming;
};

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

@ -179,9 +179,10 @@ HttpBackgroundChannelChild::RecvOnTransportAndData(
IPCResult
HttpBackgroundChannelChild::RecvOnStopRequest(
const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming,
const TimeStamp& aLastActiveTabOptHit)
const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming,
const TimeStamp& aLastActiveTabOptHit,
const nsHttpHeaderArray& aResponseTrailers)
{
LOG(("HttpBackgroundChannelChild::RecvOnStopRequest [this=%p]\n", this));
MOZ_ASSERT(OnSocketThread());
@ -200,18 +201,22 @@ HttpBackgroundChannelChild::RecvOnStopRequest(
static_cast<uint32_t>(aChannelStatus)));
mQueuedRunnables.AppendElement(
NewRunnableMethod<const nsresult, const ResourceTimingStruct, const TimeStamp>(
NewRunnableMethod<const nsresult,
const ResourceTimingStruct,
const TimeStamp,
const nsHttpHeaderArray>(
"HttpBackgroundChannelChild::RecvOnStopRequest",
this,
&HttpBackgroundChannelChild::RecvOnStopRequest,
aChannelStatus,
aTiming,
aLastActiveTabOptHit));
aLastActiveTabOptHit,
aResponseTrailers));
return IPC_OK();
}
mChannelChild->ProcessOnStopRequest(aChannelStatus, aTiming);
mChannelChild->ProcessOnStopRequest(aChannelStatus, aTiming, aResponseTrailers);
return IPC_OK();
}

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

@ -49,7 +49,8 @@ protected:
IPCResult RecvOnStopRequest(const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming,
const TimeStamp& aLastActiveTabOptHit) override;
const TimeStamp& aLastActiveTabOptHit,
const nsHttpHeaderArray& aResponseTrailers) override;
IPCResult RecvOnProgress(const int64_t& aProgress,
const int64_t& aProgressMax) override;

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

@ -220,7 +220,8 @@ HttpBackgroundChannelParent::OnTransportAndData(
bool
HttpBackgroundChannelParent::OnStopRequest(const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming)
const ResourceTimingStruct& aTiming,
const nsHttpHeaderArray& aResponseTrailers)
{
LOG(("HttpBackgroundChannelParent::OnStopRequest [this=%p "
"status=%" PRIx32 "]\n", this, static_cast<uint32_t>(aChannelStatus)));
@ -233,12 +234,15 @@ HttpBackgroundChannelParent::OnStopRequest(const nsresult& aChannelStatus,
if (!IsOnBackgroundThread()) {
MutexAutoLock lock(mBgThreadMutex);
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod<const nsresult, const ResourceTimingStruct>(
NewRunnableMethod<const nsresult,
const ResourceTimingStruct,
const nsHttpHeaderArray>(
"net::HttpBackgroundChannelParent::OnStopRequest",
this,
&HttpBackgroundChannelParent::OnStopRequest,
aChannelStatus,
aTiming),
aTiming,
aResponseTrailers),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
@ -249,7 +253,7 @@ HttpBackgroundChannelParent::OnStopRequest(const nsresult& aChannelStatus,
// See the child code for why we do this.
TimeStamp lastActTabOpt = nsHttp::GetLastActiveTabLoadOptimizationHit();
return SendOnStopRequest(aChannelStatus, aTiming, lastActTabOpt);
return SendOnStopRequest(aChannelStatus, aTiming, lastActTabOpt, aResponseTrailers);
}
bool

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

@ -52,7 +52,8 @@ public:
// To send OnStopRequest message over background channel.
bool OnStopRequest(const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming);
const ResourceTimingStruct& aTiming,
const nsHttpHeaderArray& aResponseTrailers);
// To send OnProgress message over background channel.
bool OnProgress(const int64_t& aProgress,

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

@ -34,6 +34,7 @@
#include "nsIStreamConverterService.h"
#include "nsCRT.h"
#include "nsContentUtils.h"
#include "nsIMutableArray.h"
#include "nsIScriptSecurityManager.h"
#include "nsIObserverService.h"
#include "nsProxyRelease.h"
@ -65,6 +66,7 @@
#include "nsIDOMWindowUtils.h"
#include "nsHttpChannel.h"
#include "nsRedirectHistoryEntry.h"
#include "nsServerTiming.h"
#include <algorithm>
#include "HttpBaseChannel.h"
@ -4450,5 +4452,46 @@ HttpBaseChannel::CallTypeSniffers(void *aClosure, const uint8_t *aData,
}
}
template <class T>
static void
ParseServerTimingHeader(const nsAutoPtr<T> &aHeader,
nsIMutableArray* aOutput)
{
if (!aHeader) {
return;
}
nsAutoCString serverTimingHeader;
Unused << aHeader->GetHeader(nsHttp::Server_Timing, serverTimingHeader);
if (serverTimingHeader.IsEmpty()) {
return;
}
ServerTimingParser parser(serverTimingHeader);
parser.Parse();
nsTArray<nsCOMPtr<nsIServerTiming>> array = parser.TakeServerTimingHeaders();
for (const auto &data : array) {
aOutput->AppendElement(data);
}
}
NS_IMETHODIMP
HttpBaseChannel::GetServerTiming(nsIArray **aServerTiming)
{
NS_ENSURE_ARG_POINTER(aServerTiming);
nsTArray<nsCOMPtr<nsIServerTiming>> data;
nsresult rv = NS_OK;
nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
ParseServerTimingHeader(mResponseHead, array);
ParseServerTimingHeader(mResponseTrailers, array);
array.forget(aServerTiming);
return NS_OK;
}
} // namespace net
} // namespace mozilla

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

@ -339,6 +339,7 @@ public:
nsHttpResponseHead * GetResponseHead() const { return mResponseHead; }
nsHttpRequestHead * GetRequestHead() { return &mRequestHead; }
nsHttpHeaderArray * GetResponseTrailers() const { return mResponseTrailers; }
const NetAddr& GetSelfAddr() { return mSelfAddr; }
const NetAddr& GetPeerAddr() { return mPeerAddr; }
@ -520,6 +521,7 @@ protected:
nsCOMPtr<nsIInputStream> mUploadStream;
nsCOMPtr<nsIRunnable> mUploadCloneableCallback;
nsAutoPtr<nsHttpResponseHead> mResponseHead;
nsAutoPtr<nsHttpHeaderArray> mResponseTrailers;
RefPtr<nsHttpConnectionInfo> mConnectionInfo;
nsCOMPtr<nsIProxyInfo> mProxyInfo;
nsCOMPtr<nsISupports> mSecurityInfo;

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

@ -979,28 +979,33 @@ class StopRequestEvent : public NeckoTargetChannelEvent<HttpChannelChild>
public:
StopRequestEvent(HttpChannelChild* child,
const nsresult& channelStatus,
const ResourceTimingStruct& timing)
const ResourceTimingStruct& timing,
const nsHttpHeaderArray& aResponseTrailers)
: NeckoTargetChannelEvent<HttpChannelChild>(child)
, mChannelStatus(channelStatus)
, mTiming(timing) {}
, mTiming(timing)
, mResponseTrailers(aResponseTrailers) {}
void Run() { mChild->OnStopRequest(mChannelStatus, mTiming); }
void Run() { mChild->OnStopRequest(mChannelStatus, mTiming, mResponseTrailers); }
private:
nsresult mChannelStatus;
ResourceTimingStruct mTiming;
nsHttpHeaderArray mResponseTrailers;
};
void
HttpChannelChild::ProcessOnStopRequest(const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming)
const ResourceTimingStruct& aTiming,
const nsHttpHeaderArray& aResponseTrailers)
{
LOG(("HttpChannelChild::ProcessOnStopRequest [this=%p]\n", this));
MOZ_ASSERT(OnSocketThread());
MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
"Should not be receiving any more callbacks from parent!");
mEventQ->RunOrEnqueue(new StopRequestEvent(this, aChannelStatus, aTiming),
mEventQ->RunOrEnqueue(new StopRequestEvent(this, aChannelStatus,
aTiming, aResponseTrailers),
mDivertingToParent);
}
@ -1036,7 +1041,8 @@ HttpChannelChild::MaybeDivertOnStop(const nsresult& aChannelStatus)
void
HttpChannelChild::OnStopRequest(const nsresult& channelStatus,
const ResourceTimingStruct& timing)
const ResourceTimingStruct& timing,
const nsHttpHeaderArray& aResponseTrailers)
{
LOG(("HttpChannelChild::OnStopRequest [this=%p status=%" PRIx32 "]\n",
this, static_cast<uint32_t>(channelStatus)));
@ -1089,6 +1095,8 @@ HttpChannelChild::OnStopRequest(const nsresult& channelStatus,
mCacheReadStart = timing.cacheReadStart;
mCacheReadEnd = timing.cacheReadEnd;
mResponseTrailers = new nsHttpHeaderArray(aResponseTrailers);
DoPreOnStopRequest(channelStatus);
{ // We must flush the queue before we Send__delete__

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

@ -242,7 +242,8 @@ private:
const uint32_t& aCount,
const nsCString& aData);
void ProcessOnStopRequest(const nsresult& aStatusCode,
const ResourceTimingStruct& aTiming);
const ResourceTimingStruct& aTiming,
const nsHttpHeaderArray& aResponseTrailers);
void ProcessOnProgress(const int64_t& aProgress, const int64_t& aProgressMax);
void ProcessOnStatus(const nsresult& aStatus);
void ProcessFlushedForDiversion();
@ -415,7 +416,9 @@ private:
const uint64_t& offset,
const uint32_t& count,
const nsCString& data);
void OnStopRequest(const nsresult& channelStatus, const ResourceTimingStruct& timing);
void OnStopRequest(const nsresult& channelStatus,
const ResourceTimingStruct& timing,
const nsHttpHeaderArray& aResponseTrailers);
void MaybeDivertOnStop(const nsresult& aChannelStatus);
void OnProgress(const int64_t& progress, const int64_t& progressMax);
void OnStatus(const nsresult& status);

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

@ -1596,12 +1596,16 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
httpChannelImpl->SetWarningReporter(nullptr);
}
nsHttpHeaderArray *responseTrailer = mChannel->GetResponseTrailers();
// Either IPC channel is closed or background channel
// is ready to send OnStopRequest.
MOZ_ASSERT(mIPCClosed || mBgParent);
if (mIPCClosed ||
!mBgParent || !mBgParent->OnStopRequest(aStatusCode, timing)) {
!mBgParent ||
!mBgParent->OnStopRequest(aStatusCode, timing,
responseTrailer ? *responseTrailer : nsHttpHeaderArray())) {
return NS_ERROR_UNEXPECTED;
}

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

@ -895,6 +895,12 @@ NullHttpChannel::GetReportResourceTiming(bool* _retval) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NullHttpChannel::GetServerTiming(nsIArray **aServerTiming)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
#define IMPL_TIMING_ATTR(name) \
NS_IMETHODIMP \
NullHttpChannel::Get##name##Time(PRTime* _retval) { \

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

@ -11,6 +11,7 @@ include PURLClassifierInfo;
include "mozilla/net/NeckoMessageUtils.h";
using class nsHttpHeaderArray from "nsHttpHeaderArray.h";
using struct mozilla::net::ResourceTimingStruct from "mozilla/net/TimingStruct.h";
namespace mozilla {
@ -36,8 +37,10 @@ child:
uint32_t count,
nsCString data);
async OnStopRequest(nsresult channelStatus, ResourceTimingStruct timing,
TimeStamp lastActiveTabOptimization);
async OnStopRequest(nsresult channelStatus,
ResourceTimingStruct timing,
TimeStamp lastActiveTabOptimization,
nsHttpHeaderArray responseTrailers);
async OnProgress(int64_t progress, int64_t progressMax);

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

@ -45,6 +45,7 @@ EXPORTS.mozilla.net += [
'HttpChannelChild.h',
'HttpChannelParent.h',
'HttpInfo.h',
'nsServerTiming.h',
'NullHttpChannel.h',
'PHttpChannelParams.h',
'PSpdyPush.h',
@ -95,6 +96,7 @@ UNIFIED_SOURCES += [
'nsHttpRequestHead.cpp',
'nsHttpResponseHead.cpp',
'nsHttpTransaction.cpp',
'nsServerTiming.cpp',
'NullHttpChannel.cpp',
'NullHttpTransaction.cpp',
'TunnelUtils.cpp',

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

@ -19,6 +19,7 @@
#include "nsICacheEntry.h"
#include "nsIRequest.h"
#include <errno.h>
#include <functional>
namespace mozilla {
namespace net {
@ -603,127 +604,235 @@ void EnsureBuffer(UniquePtr<uint8_t[]> &buf, uint32_t newSize,
{
localEnsureBuffer<uint8_t> (buf, newSize, preserve, objSize);
}
///
static bool
IsTokenSymbol(signed char chr) {
if (chr < 33 || chr == 127 ||
chr == '(' || chr == ')' || chr == '<' || chr == '>' ||
chr == '@' || chr == ',' || chr == ';' || chr == ':' ||
chr == '"' || chr == '/' || chr == '[' || chr == ']' ||
chr == '?' || chr == '=' || chr == '{' || chr == '}' || chr == '\\') {
return false;
}
return true;
}
ParsedHeaderPair::ParsedHeaderPair(const char *name, int32_t nameLen,
const char *val, int32_t valLen,
bool isQuotedValue)
: mName(nsDependentCSubstring(nullptr, 0u))
, mValue(nsDependentCSubstring(nullptr, 0u))
, mIsQuotedValue(isQuotedValue)
{
if (nameLen > 0) {
mName.Rebind(name, name + nameLen);
}
if (valLen > 0) {
if (mIsQuotedValue) {
RemoveQuotedStringEscapes(val, valLen);
mValue.Rebind(mUnquotedValue.BeginWriting(), mUnquotedValue.Length());
} else {
mValue.Rebind(val, val + valLen);
}
}
}
void
ParsedHeaderValueList::Tokenize(char *input, uint32_t inputLen, char **token,
uint32_t *tokenLen, bool *foundEquals, char **next)
ParsedHeaderPair::RemoveQuotedStringEscapes(const char *val, int32_t valLen)
{
if (foundEquals) {
*foundEquals = false;
}
if (next) {
*next = nullptr;
}
if (inputLen < 1 || !input || !token) {
return;
}
bool foundFirst = false;
bool inQuote = false;
bool foundToken = false;
*token = input;
*tokenLen = inputLen;
for (uint32_t index = 0; !foundToken && index < inputLen; ++index) {
// strip leading cruft
if (!foundFirst &&
(input[index] == ' ' || input[index] == '"' || input[index] == '\t')) {
(*token)++;
} else {
foundFirst = true;
mUnquotedValue.Truncate();
const char *c = val;
for (int32_t i = 0; i < valLen; ++i) {
if (c[i] == '\\' && c[i + 1]) {
++i;
}
mUnquotedValue.Append(c[i]);
}
}
static
void Tokenize(const char *input, uint32_t inputLen, const char token,
const std::function<void(const char *, uint32_t)>& consumer)
{
auto trimWhitespace =
[] (const char *in, uint32_t inLen, const char **out, uint32_t *outLen) {
*out = in;
*outLen = inLen;
if (inLen == 0) {
return;
}
// Trim leading space
while (nsCRT::IsAsciiSpace(**out)) {
(*out)++;
--(*outLen);
}
// Trim tailing space
for (const char *i = *out + *outLen - 1; i >= *out; --i) {
if (!nsCRT::IsAsciiSpace(*i)) {
break;
}
--(*outLen);
}
};
const char *first = input;
bool inQuote = false;
const char *result = nullptr;
uint32_t resultLen = 0;
for (uint32_t index = 0; index < inputLen; ++index) {
if (inQuote && input[index] == '\\' && input[index + 1]) {
index++;
continue;
}
if (input[index] == '"') {
inQuote = !inQuote;
continue;
}
if (inQuote) {
continue;
}
if (input[index] == '=' || input[index] == ';') {
*tokenLen = (input + index) - *token;
if (next && ((index + 1) < inputLen)) {
*next = input + index + 1;
}
foundToken = true;
if (foundEquals && input[index] == '=') {
*foundEquals = true;
}
break;
if (input[index] == token) {
trimWhitespace(first, (input + index) - first,
&result, &resultLen);
consumer(result, resultLen);
first = input + index + 1;
}
}
if (!foundToken) {
*tokenLen = (input + inputLen) - *token;
}
// strip trailing cruft
for (char *index = *token + *tokenLen - 1; index >= *token; --index) {
if (*index != ' ' && *index != '\t' && *index != '"') {
break;
}
--(*tokenLen);
if (*index == '"') {
break;
}
}
trimWhitespace(first, (input + inputLen) - first,
&result, &resultLen);
consumer(result, resultLen);
}
ParsedHeaderValueList::ParsedHeaderValueList(char *t, uint32_t len)
ParsedHeaderValueList::ParsedHeaderValueList(const char *t,
uint32_t len,
bool allowInvalidValue)
{
char *name = nullptr;
uint32_t nameLen = 0;
char *value = nullptr;
uint32_t valueLen = 0;
char *next = nullptr;
bool foundEquals;
while (t) {
Tokenize(t, len, &name, &nameLen, &foundEquals, &next);
if (next) {
len -= next - t;
}
t = next;
if (foundEquals && t) {
Tokenize(t, len, &value, &valueLen, nullptr, &next);
if (next) {
len -= next - t;
}
t = next;
}
mValues.AppendElement(ParsedHeaderPair(name, nameLen, value, valueLen));
value = name = nullptr;
valueLen = nameLen = 0;
next = nullptr;
if (!len) {
return;
}
ParsedHeaderValueList *self = this;
auto consumer = [=] (const char *output, uint32_t outputLength) {
self->ParseNameAndValue(output, allowInvalidValue);
};
Tokenize(t, len, ';', consumer);
}
ParsedHeaderValueListList::ParsedHeaderValueListList(const nsCString &fullHeader)
void
ParsedHeaderValueList::ParseNameAndValue(const char *input, bool allowInvalidValue)
{
const char *nameStart = input;
const char *nameEnd = nullptr;
const char *valueStart = input;
const char *valueEnd = nullptr;
bool isQuotedString = false;
bool invalidValue = false;
for (; *input && *input != ';' && *input != ',' &&
!nsCRT::IsAsciiSpace(*input) && *input != '='; input++)
;
nameEnd = input;
if (!(nameEnd - nameStart)) {
return;
}
// Check whether param name is a valid token.
for (const char *c = nameStart; c < nameEnd; c++) {
if (!IsTokenSymbol(*c)) {
nameEnd = c;
break;
}
}
if (!(nameEnd - nameStart)) {
return;
}
while (nsCRT::IsAsciiSpace(*input)) {
++input;
}
if (!*input || *input++ != '=') {
mValues.AppendElement(ParsedHeaderPair(nameStart, nameEnd - nameStart,
nullptr, 0, false));
return;
}
while (nsCRT::IsAsciiSpace(*input)) {
++input;
}
if (*input != '"') {
// The value is a token, not a quoted string.
valueStart = input;
for (valueEnd = input;
*valueEnd && !nsCRT::IsAsciiSpace (*valueEnd) &&
*valueEnd != ';' && *valueEnd != ',';
valueEnd++)
;
input = valueEnd;
if (!allowInvalidValue) {
for (const char *c = valueStart; c < valueEnd; c++) {
if (!IsTokenSymbol(*c)) {
valueEnd = c;
break;
}
}
}
} else {
bool foundQuotedEnd = false;
isQuotedString = true;
++input;
valueStart = input;
for (valueEnd = input; *valueEnd; ++valueEnd) {
if (*valueEnd == '\\' && *(valueEnd + 1)) {
++valueEnd;
}
else if (*valueEnd == '"') {
foundQuotedEnd = true;
break;
}
}
if (!foundQuotedEnd) {
invalidValue = true;
}
input = valueEnd;
// *valueEnd != null means that *valueEnd is quote character.
if (*valueEnd) {
input++;
}
}
if (invalidValue) {
valueEnd = valueStart;
}
mValues.AppendElement(ParsedHeaderPair(nameStart, nameEnd - nameStart,
valueStart, valueEnd - valueStart,
isQuotedString));
}
ParsedHeaderValueListList::ParsedHeaderValueListList(const nsCString &fullHeader,
bool allowInvalidValue)
: mFull(fullHeader)
{
char *t = mFull.BeginWriting();
uint32_t len = mFull.Length();
char *last = t;
bool inQuote = false;
for (uint32_t index = 0; index < len; ++index) {
if (t[index] == '"') {
inQuote = !inQuote;
continue;
}
if (inQuote) {
continue;
}
if (t[index] == ',') {
mValues.AppendElement(ParsedHeaderValueList(last, (t + index) - last));
last = t + index + 1;
}
}
if (!inQuote) {
mValues.AppendElement(ParsedHeaderValueList(last, (t + len) - last));
}
auto &values = mValues;
auto consumer =
[&values, allowInvalidValue] (const char *output, uint32_t outputLength) {
values.AppendElement(ParsedHeaderValueList(output,
outputLength,
allowInvalidValue));
};
Tokenize(mFull.BeginReading(), mFull.Length(), ',', consumer);
}
} // namespace net

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

@ -266,42 +266,50 @@ class ParsedHeaderPair
{
public:
ParsedHeaderPair(const char *name, int32_t nameLen,
const char *val, int32_t valLen)
{
if (nameLen > 0) {
mName.Rebind(name, name + nameLen);
}
if (valLen > 0) {
mValue.Rebind(val, val + valLen);
}
}
const char *val, int32_t valLen, bool isQuotedValue);
ParsedHeaderPair(ParsedHeaderPair const &copy)
: mName(copy.mName)
, mValue(copy.mValue)
, mUnquotedValue(copy.mUnquotedValue)
, mIsQuotedValue(copy.mIsQuotedValue)
{
if (mIsQuotedValue) {
mValue.Rebind(mUnquotedValue.BeginReading(), mUnquotedValue.Length());
}
}
nsDependentCSubstring mName;
nsDependentCSubstring mValue;
private:
nsCString mUnquotedValue;
bool mIsQuotedValue;
void RemoveQuotedStringEscapes(const char *val, int32_t valLen);
};
class ParsedHeaderValueList
{
public:
ParsedHeaderValueList(char *t, uint32_t len);
ParsedHeaderValueList(const char *t, uint32_t len, bool allowInvalidValue);
nsTArray<ParsedHeaderPair> mValues;
private:
void ParsePair(char *t, uint32_t len);
void Tokenize(char *input, uint32_t inputLen, char **token,
uint32_t *tokenLen, bool *foundEquals, char **next);
void ParseNameAndValue(const char *input, bool allowInvalidValue);
};
class ParsedHeaderValueListList
{
public:
explicit ParsedHeaderValueListList(const nsCString &txt);
// RFC 7231 section 3.2.6 defines the syntax of the header field values.
// |allowInvalidValue| indicates whether the rule will be used to check
// the input text.
// Note that ParsedHeaderValueListList is currently used to parse
// Alt-Svc and Server-Timing header. |allowInvalidValue| is set to true
// when parsing Alt-Svc for historical reasons.
explicit ParsedHeaderValueListList(const nsCString &txt,
bool allowInvalidValue = true);
nsTArray<ParsedHeaderValueList> mValues;
private:

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

@ -74,6 +74,7 @@ HTTP_ATOM(Range, "Range")
HTTP_ATOM(Referer, "Referer")
HTTP_ATOM(Retry_After, "Retry-After")
HTTP_ATOM(Server, "Server")
HTTP_ATOM(Server_Timing, "Server-Timing")
HTTP_ATOM(Service_Worker_Allowed, "Service-Worker-Allowed")
HTTP_ATOM(Set_Cookie, "Set-Cookie")
HTTP_ATOM(Set_Cookie2, "Set-Cookie2")

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

@ -7213,6 +7213,8 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
Unused << mCacheEntry->SetNetworkTimes(onStartTime, onStopTime);
}
mResponseTrailers = mTransaction->TakeResponseTrailers();
// at this point, we're done with the transaction
mTransactionTimings = mTransaction->Timings();
mTransaction = nullptr;

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

@ -120,7 +120,17 @@ nsHttpChunkedDecoder::ParseChunkRemaining(char *buf,
if (!mTrailers) {
mTrailers = new nsHttpHeaderArray();
}
Unused << mTrailers->ParseHeaderLine(nsDependentCSubstring(buf, count));
nsHttpAtom hdr = {0};
nsAutoCString headerNameOriginal;
nsAutoCString val;
if (NS_SUCCEEDED(mTrailers->ParseHeaderLine(nsDependentCSubstring(buf, count),
&hdr, &headerNameOriginal, &val))) {
if (hdr == nsHttp::Server_Timing) {
Unused << mTrailers->SetHeaderFromNet(hdr, headerNameOriginal,
val, true);
}
}
}
else {
mWaitEOF = false;

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

@ -6,6 +6,7 @@
#ifndef nsHttpChunkedDecoder_h__
#define nsHttpChunkedDecoder_h__
#include "nsAutoPtr.h"
#include "nsError.h"
#include "nsString.h"
#include "nsHttpHeaderArray.h"
@ -29,11 +30,9 @@ public:
uint32_t *contentRead,
uint32_t *contentRemaining);
nsHttpHeaderArray *Trailers() { return mTrailers; }
nsHttpHeaderArray *Trailers() { return mTrailers.get(); }
nsHttpHeaderArray *TakeTrailers() { nsHttpHeaderArray *h = mTrailers;
mTrailers = nullptr;
return h; }
nsHttpHeaderArray *TakeTrailers() { return mTrailers.forget(); }
uint32_t GetChunkRemaining() { return mChunkRemaining; }
@ -43,11 +42,11 @@ private:
uint32_t *countRead);
private:
nsHttpHeaderArray *mTrailers;
uint32_t mChunkRemaining;
nsCString mLineBuf; // may hold a partial line
bool mReachedEOF;
bool mWaitEOF;
nsAutoPtr<nsHttpHeaderArray> mTrailers;
uint32_t mChunkRemaining;
nsCString mLineBuf; // may hold a partial line
bool mReachedEOF;
bool mWaitEOF;
};
} // namespace net

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

@ -136,6 +136,8 @@ nsHttpTransaction::nsHttpTransaction()
, mReportedResponseHeader(false)
, mForTakeResponseHead(nullptr)
, mResponseHeadTaken(false)
, mForTakeResponseTrailers(nullptr)
, mResponseTrailersTaken(false)
, mTopLevelOuterContentWindowId(0)
, mSubmittedRatePacing(false)
, mPassedRatePacing(false)
@ -486,6 +488,18 @@ nsHttpTransaction::TakeResponseHead()
return head;
}
nsHttpHeaderArray *
nsHttpTransaction::TakeResponseTrailers()
{
MOZ_ASSERT(!mResponseTrailersTaken, "TakeResponseTrailers called 2x");
// Lock TakeResponseTrailers() against main thread
MutexAutoLock lock(*nsHttp::GetLock());
mResponseTrailersTaken = true;
return mForTakeResponseTrailers.forget();
}
void
nsHttpTransaction::SetProxyConnectFailed()
{
@ -1776,6 +1790,11 @@ nsHttpTransaction::HandleContent(char *buf,
// check for end-of-file
if ((mContentRead == mContentLength) ||
(mChunkedDecoder && mChunkedDecoder->ReachedEOF())) {
MutexAutoLock lock(*nsHttp::GetLock());
mForTakeResponseTrailers = mChunkedDecoder
? mChunkedDecoder->TakeTrailers()
: nullptr;
// the transaction is done with a complete response.
mTransactionDone = true;
mResponseIsComplete = true;

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

@ -30,6 +30,7 @@ class nsIRequestContext;
namespace mozilla { namespace net {
class nsHttpChunkedDecoder;
class nsHttpHeaderArray;
class nsHttpRequestHead;
class nsHttpResponseHead;
@ -104,6 +105,10 @@ public:
// will drop any reference to the response headers after this call.
nsHttpResponseHead *TakeResponseHead();
// Called to take ownership of the trailer headers.
// Returning null if there is no trailer.
nsHttpHeaderArray *TakeResponseTrailers();
// Provides a thread safe reference of the connection
// nsHttpTransaction::Connection should only be used on the socket thread
already_AddRefed<nsAHttpConnection> GetConnectionReference();
@ -377,6 +382,8 @@ private:
// protected by nsHttp::GetLock()
nsHttpResponseHead *mForTakeResponseHead;
bool mResponseHeadTaken;
nsAutoPtr<nsHttpHeaderArray> mForTakeResponseTrailers;
bool mResponseTrailersTaken;
// The time when the transaction was submitted to the Connection Manager
TimeStamp mPendingTime;

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

@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsServerTiming.h"
NS_IMPL_ISUPPORTS(nsServerTiming, nsIServerTiming)
NS_IMETHODIMP
nsServerTiming::GetName(nsACString &aName)
{
aName.Assign(mName);
return NS_OK;
}
NS_IMETHODIMP
nsServerTiming::GetDuration(double *aDuration)
{
*aDuration = mDuration;
return NS_OK;
}
NS_IMETHODIMP
nsServerTiming::GetDescription(nsACString &aDescription)
{
aDescription.Assign(mDescription);
return NS_OK;
}
namespace mozilla {
namespace net {
static double
ParseDouble(const nsACString& aString)
{
nsresult rv;
double val = PromiseFlatCString(aString).ToDouble(&rv);
return NS_FAILED(rv) ? 0.0f : val;
}
void
ServerTimingParser::Parse()
{
// https://w3c.github.io/server-timing/#the-server-timing-header-field
// Server-Timing = #server-timing-metric
// server-timing-metric = metric-name *( OWS ";" OWS server-timing-param )
// metric-name = token
// server-timing-param = server-timing-param-name OWS "=" OWS server-timing-param-value
// server-timing-param-name = token
// server-timing-param-value = token / quoted-string
ParsedHeaderValueListList parsedHeader(mValue, false);
for (uint32_t index = 0; index < parsedHeader.mValues.Length(); ++index) {
if (parsedHeader.mValues[index].mValues.IsEmpty()) {
continue;
}
// According to spec, the first ParsedHeaderPair's name is metric-name.
RefPtr<nsServerTiming> timingHeader = new nsServerTiming();
mServerTimingHeaders.AppendElement(timingHeader);
timingHeader->SetName(parsedHeader.mValues[index].mValues[0].mName);
if (parsedHeader.mValues[index].mValues.Length() == 1) {
continue;
}
// Try to find duration and description from the rest ParsedHeaderPairs.
bool foundDuration = false;
bool foundDescription = false;
for (uint32_t pairIndex = 1;
pairIndex < parsedHeader.mValues[index].mValues.Length();
++pairIndex) {
nsDependentCSubstring &currentName =
parsedHeader.mValues[index].mValues[pairIndex].mName;
nsDependentCSubstring &currentValue =
parsedHeader.mValues[index].mValues[pairIndex].mValue;
// We should only take the value from the first
// occurrence of server-timing-param-name ("dur" and "desc").
if (currentName.LowerCaseEqualsASCII("dur") &&
currentValue.BeginReading() &&
!foundDuration) {
timingHeader->SetDuration(ParseDouble(currentValue));
foundDuration = true;
} else if (currentName.LowerCaseEqualsASCII("desc") &&
!currentValue.IsEmpty() &&
!foundDescription) {
timingHeader->SetDescription(currentValue);
foundDescription = true;
}
if (foundDuration && foundDescription) {
break;
}
}
}
}
nsTArray<nsCOMPtr<nsIServerTiming>>&&
ServerTimingParser::TakeServerTimingHeaders()
{
return Move(mServerTimingHeaders);
}
} // namespace net
} // namespace mozilla

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

@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsServerTiming_h__
#define nsServerTiming_h__
#include "nsITimedChannel.h"
#include "nsString.h"
#include "nsTArray.h"
class nsServerTiming final : public nsIServerTiming
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISERVERTIMING
nsServerTiming() = default;
void SetName(const nsACString &aName)
{
mName = aName;
}
void SetDuration(double aDuration)
{
mDuration = aDuration;
}
void SetDescription(const nsACString &aDescription)
{
mDescription = aDescription;
}
private:
virtual ~nsServerTiming() = default;
nsCString mName;
double mDuration;
nsCString mDescription;
};
namespace mozilla {
namespace net {
class ServerTimingParser
{
public:
explicit ServerTimingParser(const nsCString &value)
: mValue(value)
{}
void Parse();
nsTArray<nsCOMPtr<nsIServerTiming>>&& TakeServerTimingHeaders();
private:
nsCString mValue;
nsTArray<nsCOMPtr<nsIServerTiming>> mServerTimingHeaders;
};
} // namespace net
} // namespace mozilla
#endif

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

@ -0,0 +1,232 @@
#include "gtest/gtest.h"
#include "mozilla/Unused.h"
#include "mozilla/net/nsServerTiming.h"
#include <string>
#include <vector>
void testServerTimingHeader(const char* headerValue,
std::vector<std::vector<std::string>> expectedResults)
{
nsAutoCString header(headerValue);
ServerTimingParser parser(header);
parser.Parse();
nsTArray<nsCOMPtr<nsIServerTiming>> results = parser.TakeServerTimingHeaders();
ASSERT_EQ(results.Length(), expectedResults.size());
unsigned i = 0;
for (const auto& header : results) {
std::vector<std::string> expectedResult(expectedResults[i++]);
nsCString name;
mozilla::Unused << header->GetName(name);
ASSERT_TRUE(name.Equals(expectedResult[0].c_str()));
double duration;
mozilla::Unused << header->GetDuration(&duration);
ASSERT_EQ(duration, atof(expectedResult[1].c_str()));
nsCString description;
mozilla::Unused << header->GetDescription(description);
ASSERT_TRUE(description.Equals(expectedResult[2].c_str()));
}
}
TEST(TestServerTimingHeader, HeaderParsing) {
// Test cases below are copied from
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/network/HTTPParsersTest.cpp
testServerTimingHeader("", {});
testServerTimingHeader("metric", {{"metric", "0", ""}});
testServerTimingHeader("metric;dur", {{"metric", "0", ""}});
testServerTimingHeader("metric;dur=123.4", {{"metric", "123.4", ""}});
testServerTimingHeader("metric;dur=\"123.4\"", {{"metric", "123.4", ""}});
testServerTimingHeader("metric;desc", {{"metric", "0", ""}});
testServerTimingHeader("metric;desc=description",
{{"metric", "0", "description"}});
testServerTimingHeader("metric;desc=\"description\"",
{{"metric", "0", "description"}});
testServerTimingHeader("metric;dur;desc", {{"metric", "0", ""}});
testServerTimingHeader("metric;dur=123.4;desc", {{"metric", "123.4", ""}});
testServerTimingHeader("metric;dur;desc=description",
{{"metric", "0", "description"}});
testServerTimingHeader("metric;dur=123.4;desc=description",
{{"metric", "123.4", "description"}});
testServerTimingHeader("metric;desc;dur", {{"metric", "0", ""}});
testServerTimingHeader("metric;desc;dur=123.4", {{"metric", "123.4", ""}});
testServerTimingHeader("metric;desc=description;dur",
{{"metric", "0", "description"}});
testServerTimingHeader("metric;desc=description;dur=123.4",
{{"metric", "123.4", "description"}});
// special chars in name
testServerTimingHeader("aB3!#$%&'*+-.^_`|~",
{{"aB3!#$%&'*+-.^_`|~", "0", ""}});
// delimiter chars in quoted description
testServerTimingHeader("metric;desc=\"descr;,=iption\";dur=123.4",
{{"metric", "123.4", "descr;,=iption"}});
// whitespace
testServerTimingHeader("metric ; ", {{"metric", "0", ""}});
testServerTimingHeader("metric , ", {{"metric", "0", ""}});
testServerTimingHeader("metric ; dur = 123.4 ; desc = description",
{{"metric", "123.4", "description"}});
testServerTimingHeader("metric ; desc = description ; dur = 123.4",
{{"metric", "123.4", "description"}});
// multiple entries
testServerTimingHeader(
"metric1;dur=12.3;desc=description1,metric2;dur=45.6;"
"desc=description2,metric3;dur=78.9;desc=description3",
{{"metric1", "12.3", "description1"},
{"metric2", "45.6", "description2"},
{"metric3", "78.9", "description3"}});
testServerTimingHeader("metric1,metric2 ,metric3, metric4 , metric5",
{{"metric1", "0", ""},
{"metric2", "0", ""},
{"metric3", "0", ""},
{"metric4", "0", ""},
{"metric5", "0", ""}});
// quoted-strings
// metric;desc=\ --> ''
testServerTimingHeader("metric;desc=\\", {{"metric", "0", ""}});
// metric;desc=" --> ''
testServerTimingHeader("metric;desc=\"", {{"metric", "0", ""}});
// metric;desc=\\ --> ''
testServerTimingHeader("metric;desc=\\\\", {{"metric", "0", ""}});
// metric;desc=\" --> ''
testServerTimingHeader("metric;desc=\\\"", {{"metric", "0", ""}});
// metric;desc="\ --> ''
testServerTimingHeader("metric;desc=\"\\", {{"metric", "0", ""}});
// metric;desc="" --> ''
testServerTimingHeader("metric;desc=\"\"", {{"metric", "0", ""}});
// metric;desc=\\\ --> ''
testServerTimingHeader("metric;desc=\\\\\\", {{"metric", "0", ""}});
// metric;desc=\\" --> ''
testServerTimingHeader("metric;desc=\\\\\"", {{"metric", "0", ""}});
// metric;desc=\"\ --> ''
testServerTimingHeader("metric;desc=\\\"\\", {{"metric", "0", ""}});
// metric;desc=\"" --> ''
testServerTimingHeader("metric;desc=\\\"\"", {{"metric", "0", ""}});
// metric;desc="\\ --> ''
testServerTimingHeader("metric;desc=\"\\\\", {{"metric", "0", ""}});
// metric;desc="\" --> ''
testServerTimingHeader("metric;desc=\"\\\"", {{"metric", "0", ""}});
// metric;desc=""\ --> ''
testServerTimingHeader("metric;desc=\"\"\\", {{"metric", "0", ""}});
// metric;desc=""" --> ''
testServerTimingHeader("metric;desc=\"\"\"", {{"metric", "0", ""}});
// metric;desc=\\\\ --> ''
testServerTimingHeader("metric;desc=\\\\\\\\", {{"metric", "0", ""}});
// metric;desc=\\\" --> ''
testServerTimingHeader("metric;desc=\\\\\\\"", {{"metric", "0", ""}});
// metric;desc=\\"\ --> ''
testServerTimingHeader("metric;desc=\\\\\"\\", {{"metric", "0", ""}});
// metric;desc=\\"" --> ''
testServerTimingHeader("metric;desc=\\\\\"\"", {{"metric", "0", ""}});
// metric;desc=\"\\ --> ''
testServerTimingHeader("metric;desc=\\\"\\\\", {{"metric", "0", ""}});
// metric;desc=\"\" --> ''
testServerTimingHeader("metric;desc=\\\"\\\"", {{"metric", "0", ""}});
// metric;desc=\""\ --> ''
testServerTimingHeader("metric;desc=\\\"\"\\", {{"metric", "0", ""}});
// metric;desc=\""" --> ''
testServerTimingHeader("metric;desc=\\\"\"\"", {{"metric", "0", ""}});
// metric;desc="\\\ --> ''
testServerTimingHeader("metric;desc=\"\\\\\\", {{"metric", "0", ""}});
// metric;desc="\\" --> '\'
testServerTimingHeader("metric;desc=\"\\\\\"", {{"metric", "0", "\\"}});
// metric;desc="\"\ --> ''
testServerTimingHeader("metric;desc=\"\\\"\\", {{"metric", "0", ""}});
// metric;desc="\"" --> '"'
testServerTimingHeader("metric;desc=\"\\\"\"", {{"metric", "0", "\""}});
// metric;desc=""\\ --> ''
testServerTimingHeader("metric;desc=\"\"\\\\", {{"metric", "0", ""}});
// metric;desc=""\" --> ''
testServerTimingHeader("metric;desc=\"\"\\\"", {{"metric", "0", ""}});
// metric;desc="""\ --> ''
testServerTimingHeader("metric;desc=\"\"\"\\", {{"metric", "0", ""}});
// metric;desc="""" --> ''
testServerTimingHeader("metric;desc=\"\"\"\"", {{"metric", "0", ""}});
// duplicate entry names
testServerTimingHeader(
"metric;dur=12.3;desc=description1,metric;dur=45.6;"
"desc=description2",
{{"metric", "12.3", "description1"}, {"metric", "45.6", "description2"}});
// non-numeric durations
testServerTimingHeader("metric;dur=foo", {{"metric", "0", ""}});
testServerTimingHeader("metric;dur=\"foo\"", {{"metric", "0", ""}});
// unrecognized param names
testServerTimingHeader(
"metric;foo=bar;desc=description;foo=bar;dur=123.4;foo=bar",
{{"metric", "123.4", "description"}});
// duplicate param names
testServerTimingHeader("metric;dur=123.4;dur=567.8",
{{"metric", "123.4", ""}});
testServerTimingHeader("metric;desc=description1;desc=description2",
{{"metric", "0", "description1"}});
testServerTimingHeader("metric;dur=foo;dur=567.8", {{"metric", "", ""}});
// unspecified param values
testServerTimingHeader("metric;dur;dur=123.4", {{"metric", "123.4", ""}});
testServerTimingHeader("metric;desc;desc=description",
{{"metric", "0", "description"}});
// param name case
testServerTimingHeader("metric;DuR=123.4;DeSc=description",
{{"metric", "123.4", "description"}});
// nonsense
testServerTimingHeader("metric=foo;dur;dur=123.4,metric2",
{{"metric", "123.4", ""}, {"metric2", "0", ""}});
testServerTimingHeader("metric\"foo;dur;dur=123.4,metric2",
{{"metric", "", ""}});
// nonsense - return zero entries
testServerTimingHeader(" ", {});
testServerTimingHeader("=", {});
testServerTimingHeader("[", {});
testServerTimingHeader("]", {});
testServerTimingHeader(";", {});
testServerTimingHeader(",", {});
testServerTimingHeader("=;", {});
testServerTimingHeader(";=", {});
testServerTimingHeader("=,", {});
testServerTimingHeader(",=", {});
testServerTimingHeader(";,", {});
testServerTimingHeader(",;", {});
testServerTimingHeader("=;,", {});
// Invalid token
testServerTimingHeader("met=ric", {{"met", "0", ""}});
testServerTimingHeader("met ric", {{"met", "0", ""}});
testServerTimingHeader("met[ric", {{"met", "0", ""}});
testServerTimingHeader("met]ric", {{"met", "0", ""}});
testServerTimingHeader("metric;desc=desc=123, metric2",
{{"metric", "0", "desc"}, {"metric2", "0", ""}});
testServerTimingHeader("met ric;desc=de sc , metric2",
{{"met", "0", "de"}, {"metric2", "0", ""}});
// test cases from https://w3c.github.io/server-timing/#examples
testServerTimingHeader(" miss, ,db;dur=53, app;dur=47.2 ",
{{"miss", "0", ""}, {"db", "53", ""}, {"app", "47.2", ""}});
testServerTimingHeader(" customView, dc;desc=atl ",
{{"customView", "0", ""}, {"dc", "0", "atl"}});
testServerTimingHeader(" total;dur=123.4 ",
{{"total", "123.4", ""}});
// test cases for comma in quoted string
testServerTimingHeader(" metric ; desc=\"descr\\\"\\\";,=iption\";dur=123.4",
{{"metric", "123.4", "descr\"\";,=iption"}});
testServerTimingHeader(" metric2;dur=\"123.4\";;desc=\",;\\\",;,\";;, metric ; desc = \" \\\", ;\\\" \"; dur=123.4,",
{{"metric2", "123.4", ",;\",;,"}, {"metric", "123.4", " \", ;\" "}});
}

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

@ -12,6 +12,7 @@ UNIFIED_SOURCES += [
'TestPartiallySeekableInputStream.cpp',
'TestProtocolProxyService.cpp',
'TestReadStreamToString.cpp',
'TestServerTimingHeader.cpp',
'TestStandardURL.cpp',
'TestURIMutator.cpp',
]

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

@ -0,0 +1,84 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
// HTTP Server-Timing header test
//
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyGetter(this, "URL", function() {
return "http://localhost:" + httpServer.identity.primaryPort + "/content";
});
let httpServer = null;
function make_and_open_channel(url, callback) {
let chan = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
chan.asyncOpen2(new ChannelListener(callback, null, CL_ALLOW_UNKNOWN_CL));
}
var respnseServerTiming = [{metric:"metric", duration:"123.4", description:"description"},
{metric:"metric2", duration:"456.78", description:"description1"}];
var trailerServerTiming = [{metric:"metric3", duration:"789.11", description:"description2"},
{metric:"metric4", duration:"1112.13", description:"description3"}];
function createServerTimingHeader(headerData) {
var header = "";
for (var i = 0; i < headerData.length; i++) {
header += "Server-Timing:" + headerData[i].metric + ";" +
"dur=" + headerData[i].duration + ";" +
"desc=" + headerData[i].description + "\r\n";
}
return header;
}
function contentHandler(metadata, response)
{
var body = "c\r\ndata reached\r\n3\r\nhej\r\n0\r\n";
response.seizePower();
response.write("HTTP/1.1 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write(createServerTimingHeader(respnseServerTiming));
response.write("Transfer-Encoding: chunked\r\n");
response.write("\r\n");
response.write(body);
response.write(createServerTimingHeader(trailerServerTiming));
response.write("\r\n");
response.finish();
}
function run_test()
{
httpServer = new HttpServer();
httpServer.registerPathHandler("/content", contentHandler);
httpServer.start(-1);
do_test_pending();
make_and_open_channel(URL, readServerContent);
}
function checkServerTimingContent(headers) {
var expectedResult = respnseServerTiming.concat(trailerServerTiming);
Assert.equal(headers.length, expectedResult.length);
for (var i = 0; i < expectedResult.length; i++) {
let header = headers.queryElementAt(i, Ci.nsIServerTiming);
Assert.equal(header.name, expectedResult[i].metric);
Assert.equal(header.description, expectedResult[i].description);
Assert.equal(header.duration, parseFloat(expectedResult[i].duration));
}
}
function readServerContent(request, buffer)
{
let channel = request.QueryInterface(Ci.nsITimedChannel);
let headers = channel.serverTiming.QueryInterface(Ci.nsIArray);
checkServerTimingContent(headers);
httpServer.stop(do_test_finished);
}

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

@ -410,3 +410,4 @@ skip-if = os == "android"
[test_tls_flags.js]
[test_uri_mutator.js]
[test_bug1411316_http1.js]
[test_header_Server_Timing.js]

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

@ -14,7 +14,6 @@
#include "nsISupports.h"
#include "nsRDFBaseDataSources.h"
#include "nsRDFBuiltInDataSources.h"
#include "nsFileSystemDataSource.h"
#include "nsRDFCID.h"
#include "nsIComponentManager.h"
#include "rdf.h"
@ -66,7 +65,6 @@ MAKE_CTOR(RDFContentSink,RDFContentSink,RDFContentSink)
MAKE_CTOR(RDFDefaultResource,DefaultResource,RDFResource)
NS_DEFINE_NAMED_CID(NS_RDFCOMPOSITEDATASOURCE_CID);
NS_DEFINE_NAMED_CID(NS_RDFFILESYSTEMDATASOURCE_CID);
NS_DEFINE_NAMED_CID(NS_RDFINMEMORYDATASOURCE_CID);
NS_DEFINE_NAMED_CID(NS_RDFXMLDATASOURCE_CID);
NS_DEFINE_NAMED_CID(NS_RDFDEFAULTRESOURCE_CID);
@ -81,7 +79,6 @@ NS_DEFINE_NAMED_CID(NS_LOCALSTORE_CID);
static const mozilla::Module::CIDEntry kRDFCIDs[] = {
{ &kNS_RDFCOMPOSITEDATASOURCE_CID, false, nullptr, CreateNewRDFCompositeDataSource },
{ &kNS_RDFFILESYSTEMDATASOURCE_CID, false, nullptr, FileSystemDataSource::Create },
{ &kNS_RDFINMEMORYDATASOURCE_CID, false, nullptr, NS_NewRDFInMemoryDataSource },
{ &kNS_RDFXMLDATASOURCE_CID, false, nullptr, CreateNewRDFXMLDataSource },
{ &kNS_RDFDEFAULTRESOURCE_CID, false, nullptr, CreateNewRDFDefaultResource },
@ -97,7 +94,6 @@ static const mozilla::Module::CIDEntry kRDFCIDs[] = {
static const mozilla::Module::ContractIDEntry kRDFContracts[] = {
{ NS_RDF_DATASOURCE_CONTRACTID_PREFIX "composite-datasource", &kNS_RDFCOMPOSITEDATASOURCE_CID },
{ NS_RDF_DATASOURCE_CONTRACTID_PREFIX "files", &kNS_RDFFILESYSTEMDATASOURCE_CID },
{ NS_RDF_DATASOURCE_CONTRACTID_PREFIX "in-memory-datasource", &kNS_RDFINMEMORYDATASOURCE_CID },
{ NS_RDF_DATASOURCE_CONTRACTID_PREFIX "xml-datasource", &kNS_RDFXMLDATASOURCE_CID },
{ NS_RDF_RESOURCE_FACTORY_CONTRACTID, &kNS_RDFDEFAULTRESOURCE_CID },

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

@ -9,7 +9,6 @@ EXPORTS += [
]
UNIFIED_SOURCES += [
'nsFileSystemDataSource.cpp',
'nsLocalStore.cpp',
]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,79 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsFileSystemDataSource_h__
#define nsFileSystemDataSource_h__
#include "nsIRDFDataSource.h"
#include "nsIRDFLiteral.h"
#include "nsIRDFResource.h"
#include "nsIRDFService.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "mozilla/Attributes.h"
#if defined(XP_UNIX) || defined(XP_WIN)
#define USE_NC_EXTENSION
#endif
class FileSystemDataSource final : public nsIRDFDataSource
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRDFDATASOURCE
static nsresult Create(nsISupports* aOuter,
const nsIID& aIID, void **aResult);
nsresult Init();
private:
FileSystemDataSource() { }
~FileSystemDataSource() { }
// helper methods
bool isFileURI(nsIRDFResource* aResource);
bool isDirURI(nsIRDFResource* aSource);
nsresult GetVolumeList(nsISimpleEnumerator **aResult);
nsresult GetFolderList(nsIRDFResource *source, bool allowHidden, bool onlyFirst, nsISimpleEnumerator **aResult);
nsresult GetName(nsIRDFResource *source, nsIRDFLiteral** aResult);
nsresult GetURL(nsIRDFResource *source, bool *isFavorite, nsIRDFLiteral** aResult);
nsresult GetFileSize(nsIRDFResource *source, nsIRDFInt** aResult);
nsresult GetLastMod(nsIRDFResource *source, nsIRDFDate** aResult);
nsCOMPtr<nsIRDFService> mRDFService;
// pseudo-constants
nsCOMPtr<nsIRDFResource> mNC_FileSystemRoot;
nsCOMPtr<nsIRDFResource> mNC_Child;
nsCOMPtr<nsIRDFResource> mNC_Name;
nsCOMPtr<nsIRDFResource> mNC_URL;
nsCOMPtr<nsIRDFResource> mNC_Icon;
nsCOMPtr<nsIRDFResource> mNC_Length;
nsCOMPtr<nsIRDFResource> mNC_IsDirectory;
nsCOMPtr<nsIRDFResource> mWEB_LastMod;
nsCOMPtr<nsIRDFResource> mNC_FileSystemObject;
nsCOMPtr<nsIRDFResource> mNC_pulse;
nsCOMPtr<nsIRDFResource> mRDF_InstanceOf;
nsCOMPtr<nsIRDFResource> mRDF_type;
nsCOMPtr<nsIRDFLiteral> mLiteralTrue;
nsCOMPtr<nsIRDFLiteral> mLiteralFalse;
#ifdef USE_NC_EXTENSION
nsresult GetExtension(nsIRDFResource *source, nsIRDFLiteral** aResult);
nsCOMPtr<nsIRDFResource> mNC_extension;
#endif
#ifdef XP_WIN
bool isValidFolder(nsIRDFResource *source);
nsresult getIEFavoriteURL(nsIRDFResource *source, nsString aFileURL, nsIRDFLiteral **urlLiteral);
nsCOMPtr<nsIRDFResource> mNC_IEFavoriteObject;
nsCOMPtr<nsIRDFResource> mNC_IEFavoriteFolder;
nsCString ieFavoritesDir;
#endif
};
#endif // nsFileSystemDataSource_h__

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

@ -177,7 +177,8 @@ config = {
'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"]
},
"jsreftest": {
'options':["--extra-profile-file=tests/jsreftest/tests/user.js"],
'options':["--extra-profile-file=tests/jsreftest/tests/user.js",
"--suite=jstestbrowser"],
'tests': ["tests/jsreftest/tests/jstests.list"]
},
"reftest": {

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

@ -201,7 +201,8 @@ config = {
'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"]
},
"jsreftest": {
'options':["--extra-profile-file=tests/jsreftest/tests/user.js"],
'options':["--extra-profile-file=tests/jsreftest/tests/user.js",
"--suite=jstestbrowser"],
'tests': ["tests/jsreftest/tests/jstests.list"]
},
"reftest": {

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

@ -189,7 +189,8 @@ config = {
'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"]
},
"jsreftest": {
'options':["--extra-profile-file=tests/jsreftest/tests/user.js"],
'options':["--extra-profile-file=tests/jsreftest/tests/user.js",
"--suite=jstestbrowser"],
'tests': ["tests/jsreftest/tests/jstests.list"]
},
"reftest": {

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

@ -31,6 +31,7 @@ class VerifyToolsMixin(object):
self.verify_suites = {}
self.verify_downloaded = False
self.reftest_test_dir = None
self.jsreftest_test_dir = None
def _find_misc_tests(self, dirs, changed_files):
manifests = [
@ -51,7 +52,6 @@ class VerifyToolsMixin(object):
ref_manifests = [
(os.path.join(dirs['abs_reftest_dir'], 'tests', 'layout', 'reftests', 'reftest.list'), 'reftest'),
(os.path.join(dirs['abs_reftest_dir'], 'tests', 'testing', 'crashtest', 'crashtests.list'), 'crashtest'),
# TODO (os.path.join(dirs['abs_test_install_dir'], 'jsreftest', 'tests', 'jstests.list'), 'jstestbrowser'),
]
sys.path.append(dirs['abs_reftest_dir'])
import manifest
@ -63,6 +63,26 @@ class VerifyToolsMixin(object):
tests_by_path.update({os.path.relpath(t,self.reftest_test_dir):(suite,None) for t in man.files})
self.info("Verification updated with manifest %s" % path)
suite = 'jsreftest'
self.jsreftest_test_dir = os.path.join(dirs['abs_test_install_dir'], 'jsreftest', 'tests')
path = os.path.join(self.jsreftest_test_dir, 'jstests.list')
if os.path.exists(path):
man = manifest.ReftestManifest()
man.load(path)
for t in man.files:
# expect manifest test to look like:
# ".../tests/jsreftest/tests/jsreftest.html?test=test262/.../some_test.js"
# while the test is in mercurial at:
# js/src/tests/test262/.../some_test.js
epos = t.find('=')
if epos > 0:
relpath = t[epos+1:]
relpath = os.path.join('js', 'src', 'tests', relpath)
tests_by_path.update({relpath:(suite,None)})
else:
self.warning("unexpected jsreftest test format: %s" % str(t))
self.info("Verification updated with manifest %s" % path)
# for each changed file, determine if it is a test file, and what suite it is in
for file in changed_files:
# manifest paths use os.sep (like backslash on Windows) but
@ -191,10 +211,17 @@ class VerifyToolsMixin(object):
# otherwise, run once for each file in requested suite
references = re.compile(r"(-ref|-noref|-noref.)\.")
files = []
jsreftest_extra_dir = os.path.join('js', 'src', 'tests')
# For some suites, the test path needs to be updated before passing to
# the test harness.
for file in self.verify_suites.get(suite):
if (self.config.get('verify_category') != "web-platform" and
suite in ['reftest', 'crashtest']):
file = os.path.join(self.reftest_test_dir, file)
elif (self.config.get('verify_category') != "web-platform" and
suite == 'jsreftest'):
file = os.path.relpath(file, jsreftest_extra_dir)
file = os.path.join(self.jsreftest_test_dir, file)
files.append(file)
for file in files:
if self.config.get('verify_category') == "web-platform":

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

@ -1,2 +0,0 @@
[instantiation-error-3.html]
disabled: bug 1426195

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

@ -1,5 +0,0 @@
[module-in-xhtml.xhtml]
type: testharness
[module script in XHTML documents should be evaluated.]
expected: FAIL

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

@ -28,4 +28,4 @@
<script type="module" src="./cycle-unresolvable-a.js"
onerror="unreachable()" onload="log.push(2)"></script>
<script type="module" src="./cycle-unresolvable.js"
onerror="unreachable()" onload="log.push(3)" async></script>
onerror="unreachable()" onload="log.push(3)"></script>

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

@ -10,7 +10,11 @@
window.evaluated_module_script = true;
</script>
<script>
test(() => assert_true(window.evaluated_module_script), "module script in XHTML documents should be evaluated.");
var test = async_test("module script in XHTML documents should be evaluated.");
window.addEventListener("load", () => {
test.step(() => { assert_true(window.evaluated_module_script); });
test.done();
});
</script>
</body>
</html>

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

@ -1,106 +0,0 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/Services.jsm");
var gFindBundle;
function nsFindInstData() {}
nsFindInstData.prototype =
{
// set the next three attributes on your object to override the defaults
browser: null,
get rootSearchWindow() { return this._root || this.window.content; },
set rootSearchWindow(val) { this._root = val; },
get currentSearchWindow() {
if (this._current)
return this._current;
var focusedWindow = this.window.document.commandDispatcher.focusedWindow;
if (!focusedWindow || focusedWindow == this.window)
focusedWindow = this.window.content;
return focusedWindow;
},
set currentSearchWindow(val) { this._current = val; },
get webBrowserFind() { return this.browser.webBrowserFind; },
init() {
var findInst = this.webBrowserFind;
// set up the find to search the focussedWindow, bounded by the content window.
var findInFrames = findInst.QueryInterface(Components.interfaces.nsIWebBrowserFindInFrames);
findInFrames.rootSearchFrame = this.rootSearchWindow;
findInFrames.currentSearchFrame = this.currentSearchWindow;
// always search in frames for now. We could add a checkbox to the dialog for this.
findInst.searchFrames = true;
},
window,
_root: null,
_current: null
};
// browser is the <browser> element
// rootSearchWindow is the window to constrain the search to (normally window.content)
// currentSearchWindow is the frame to start searching (can be, and normally, rootSearchWindow)
function findInPage(findInstData) {
// is the dialog up already?
if ("findDialog" in window && window.findDialog)
window.findDialog.focus();
else {
findInstData.init();
window.findDialog = window.openDialog("chrome://global/content/finddialog.xul", "_blank", "chrome,resizable=no,dependent=yes", findInstData);
}
}
function findAgainInPage(findInstData, reverse) {
if ("findDialog" in window && window.findDialog)
window.findDialog.focus();
else {
// get the find service, which stores global find state, and init the
// nsIWebBrowser find with it. We don't assume that there was a previous
// Find that set this up.
var findService = Components.classes["@mozilla.org/find/find_service;1"]
.getService(Components.interfaces.nsIFindService);
var searchString = findService.searchString;
if (searchString.length == 0) {
// no previous find text
findInPage(findInstData);
return;
}
findInstData.init();
var findInst = findInstData.webBrowserFind;
findInst.searchString = searchString;
findInst.matchCase = findService.matchCase;
findInst.wrapFind = findService.wrapFind;
findInst.entireWord = findService.entireWord;
findInst.findBackwards = findService.findBackwards ^ reverse;
var found = findInst.findNext();
if (!found) {
if (!gFindBundle)
gFindBundle = document.getElementById("findBundle");
Services.prompt.alert(window, gFindBundle.getString("notFoundTitle"), gFindBundle.getString("notFoundWarning"));
}
// Reset to normal value, otherwise setting can get changed in find dialog
findInst.findBackwards = findService.findBackwards;
}
}
function canFindAgainInPage() {
var findService = Components.classes["@mozilla.org/find/find_service;1"]
.getService(Components.interfaces.nsIFindService);
return (findService.searchString.length > 0);
}

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

@ -1,144 +0,0 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Defined in dialog.xml.
/* globals moveToAlertPosition */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/FormHistory.jsm");
var dialog; // Quick access to document/form elements.
var gFindInst; // nsIWebBrowserFind that we're going to use
var gFindInstData; // use this to update the find inst data
function initDialogObject() {
// Create dialog object and initialize.
dialog = {};
dialog.findKey = document.getElementById("dialog.findKey");
dialog.caseSensitive = document.getElementById("dialog.caseSensitive");
dialog.wrap = document.getElementById("dialog.wrap");
dialog.find = document.getElementById("btnFind");
dialog.up = document.getElementById("radioUp");
dialog.down = document.getElementById("radioDown");
dialog.rg = dialog.up.radioGroup;
dialog.bundle = null;
// Move dialog to center, if it not been shown before
var windowElement = document.getElementById("findDialog");
if (!windowElement.hasAttribute("screenX") || !windowElement.hasAttribute("screenY")) {
sizeToContent();
moveToAlertPosition();
}
}
function fillDialog() {
// get the find service, which stores global find state
var findService = Components.classes["@mozilla.org/find/find_service;1"]
.getService(Components.interfaces.nsIFindService);
// Set initial dialog field contents. Use the gFindInst attributes first,
// this is necessary for window.find()
dialog.findKey.value = gFindInst.searchString ? gFindInst.searchString : findService.searchString;
dialog.caseSensitive.checked = gFindInst.matchCase ? gFindInst.matchCase : findService.matchCase;
dialog.wrap.checked = gFindInst.wrapFind ? gFindInst.wrapFind : findService.wrapFind;
var findBackwards = gFindInst.findBackwards ? gFindInst.findBackwards : findService.findBackwards;
if (findBackwards)
dialog.rg.selectedItem = dialog.up;
else
dialog.rg.selectedItem = dialog.down;
}
function saveFindData() {
// get the find service, which stores global find state
var findService = Components.classes["@mozilla.org/find/find_service;1"]
.getService(Components.interfaces.nsIFindService);
// Set data attributes per user input.
findService.searchString = dialog.findKey.value;
findService.matchCase = dialog.caseSensitive.checked;
findService.wrapFind = dialog.wrap.checked;
findService.findBackwards = dialog.up.selected;
}
function onLoad() {
initDialogObject();
// get the find instance
var arg0 = window.arguments[0];
// If the dialog was opened from window.find(),
// arg0 will be an instance of nsIWebBrowserFind
if (arg0 instanceof Components.interfaces.nsIWebBrowserFind) {
gFindInst = arg0;
} else {
gFindInstData = arg0;
gFindInst = gFindInstData.webBrowserFind;
}
fillDialog();
doEnabling();
if (dialog.findKey.value)
dialog.findKey.select();
dialog.findKey.focus();
}
function onUnload() {
window.opener.findDialog = 0;
}
function onAccept() {
if (gFindInstData && gFindInst != gFindInstData.webBrowserFind) {
gFindInstData.init();
gFindInst = gFindInstData.webBrowserFind;
}
// Transfer dialog contents to the find service.
saveFindData();
updateFormHistory();
// set up the find instance
gFindInst.searchString = dialog.findKey.value;
gFindInst.matchCase = dialog.caseSensitive.checked;
gFindInst.wrapFind = dialog.wrap.checked;
gFindInst.findBackwards = dialog.up.selected;
// Search.
var result = gFindInst.findNext();
if (!result) {
if (!dialog.bundle)
dialog.bundle = document.getElementById("findBundle");
Services.prompt.alert(window, dialog.bundle.getString("notFoundTitle"),
dialog.bundle.getString("notFoundWarning"));
dialog.findKey.select();
dialog.findKey.focus();
}
return false;
}
function doEnabling() {
dialog.find.disabled = !dialog.findKey.value;
}
function updateFormHistory() {
if (window.opener.PrivateBrowsingUtils &&
window.opener.PrivateBrowsingUtils.isWindowPrivate(window.opener) ||
!dialog.findKey.value)
return;
if (FormHistory.enabled) {
FormHistory.update({
op: "bump",
fieldname: "find-dialog",
value: dialog.findKey.value
}, {
handleError(aError) {
Components.utils.reportError("Saving find to form history failed: " +
aError.message);
}
});
}
}

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

@ -1,58 +0,0 @@
<?xml version="1.0"?> <!-- -*- Mode: HTML -*- -->
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://global/locale/finddialog.dtd">
<dialog id="findDialog"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
orient="horizontal"
windowtype="findInPage"
onload="onLoad();"
onunload="onUnload();"
ondialogaccept="return onAccept();"
buttons="accept,cancel"
title="&findDialog.title;"
persist="screenX screenY">
<script type="application/javascript" src="chrome://global/content/finddialog.js"/>
<stringbundle id="findBundle" src="chrome://global/locale/finddialog.properties"/>
<hbox>
<vbox>
<hbox align="center">
<label value="&findField.label;" accesskey="&findField.accesskey;" control="dialog.findKey"/>
<textbox id="dialog.findKey" flex="1"
type="autocomplete"
autocompletesearch="form-history"
autocompletesearchparam="find-dialog"
oninput="doEnabling();"/>
</hbox>
<hbox align="center">
<vbox>
<checkbox id="dialog.caseSensitive" label="&caseSensitiveCheckbox.label;" accesskey="&caseSensitiveCheckbox.accesskey;"/>
<checkbox id="dialog.wrap" label="&wrapCheckbox.label;" accesskey="&wrapCheckbox.accesskey;" checked="true"/>
</vbox>
<groupbox orient="horizontal">
<caption label="&direction.label;"/>
<radiogroup orient="horizontal">
<radio id="radioUp" label="&up.label;" accesskey="&up.accesskey;"/>
<radio id="radioDown" label="&down.label;" accesskey="&down.accesskey;" selected="true"/>
</radiogroup>
</groupbox>
</hbox>
</vbox>
<vbox>
<button id="btnFind" label="&findButton.label;" accesskey="&findButton.accesskey;"
dlgtype="accept" icon="find"/>
#ifdef XP_UNIX
<button label="&closeButton.label;" icon="close" dlgtype="cancel"/>
#else
<button label="&cancelButton.label;" icon="cancel" dlgtype="cancel"/>
#endif
</vbox>
</hbox>
</dialog>

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

@ -49,9 +49,6 @@ toolkit.jar:
#ifndef MOZ_FENNEC
content/global/editMenuOverlay.js
* content/global/editMenuOverlay.xul
content/global/finddialog.js
* content/global/finddialog.xul
content/global/findUtils.js
#endif
content/global/filepicker.properties
content/global/globalOverlay.js

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

@ -263,9 +263,6 @@ with Files('direction*'):
with Files('edit*'):
BUG_COMPONENT = ('Toolkit', 'XUL Widgets')
with Files('*find*'):
BUG_COMPONENT = ('Toolkit', 'Find Toolbar')
with Files('globalOverlay.*'):
BUG_COMPONENT = ('Toolkit', 'General')

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

@ -1111,6 +1111,7 @@ timepicker {
/*********** findbar ************/
findbar {
-moz-binding: url('chrome://global/content/bindings/findbar.xml#findbar');
overflow-x: hidden;
}
.findbar-textbox {

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

@ -1,22 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!-- extracted from finddialog.xul -->
<!ENTITY findDialog.title "Find in This Page">
<!ENTITY findField.label "Find what:">
<!ENTITY findField.accesskey "n">
<!ENTITY caseSensitiveCheckbox.label "Match case">
<!ENTITY caseSensitiveCheckbox.accesskey "c">
<!ENTITY wrapCheckbox.label "Wrap">
<!ENTITY wrapCheckbox.accesskey "W">
<!ENTITY findButton.label "Find Next">
<!ENTITY findButton.accesskey "F">
<!ENTITY cancelButton.label "Cancel">
<!ENTITY closeButton.label "Close">
<!ENTITY up.label "Up">
<!ENTITY up.accesskey "U">
<!ENTITY down.label "Down">
<!ENTITY down.accesskey "D">
<!ENTITY direction.label "Direction">

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

@ -1,6 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
notFoundWarning=The text you entered was not found.
notFoundTitle=Find

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

@ -54,8 +54,6 @@
#ifndef MOZ_FENNEC
locale/@AB_CD@/global/findbar.dtd (%chrome/global/findbar.dtd)
locale/@AB_CD@/global/findbar.properties (%chrome/global/findbar.properties)
locale/@AB_CD@/global/finddialog.dtd (%chrome/global/finddialog.dtd)
locale/@AB_CD@/global/finddialog.properties (%chrome/global/finddialog.properties)
#endif
locale/@AB_CD@/global/globalKeys.dtd (%chrome/global/globalKeys.dtd)
locale/@AB_CD@/global/intl.css (%chrome/global/intl.css)

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

@ -23,14 +23,3 @@ dialog {
font: menu;
}
/*XXX - belongs to toolkit/content/finddialog.xul: */
#findDialog,
#findDialog > menu,
#findDialog > groupbox {
font: menu !important;
}
#dialog\.caseSensitive {
margin-top: 8px;
}