mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
99886e5bda
@ -63,7 +63,8 @@ function runTests()
|
||||
method: "display",
|
||||
code: error4,
|
||||
result: error4 + openComment + "Exception: Node cannot be inserted " +
|
||||
"at the specified point in the hierarchy\n@1" + closeComment,
|
||||
"at the specified point in the hierarchy\n@" +
|
||||
scratchpad.uniqueName + ":1:0" + closeComment,
|
||||
label: "Alternative format error display output"
|
||||
},
|
||||
{
|
||||
@ -100,7 +101,8 @@ function runTests()
|
||||
method: "run",
|
||||
code: error4,
|
||||
result: error4 + openComment + "Exception: Node cannot be inserted " +
|
||||
"at the specified point in the hierarchy\n@1" + closeComment,
|
||||
"at the specified point in the hierarchy\n@" +
|
||||
scratchpad.uniqueName + ":1:0" + closeComment,
|
||||
label: "Alternative format error run output"
|
||||
}];
|
||||
|
||||
|
@ -20,6 +20,11 @@ page {
|
||||
-moz-user-select: text;
|
||||
}
|
||||
|
||||
treecol {
|
||||
/* override the * rule to let the treecol be sortable */
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
caption {
|
||||
-moz-appearance: none;
|
||||
margin: 0;
|
||||
|
@ -73,7 +73,7 @@ FFmpegRuntimeLinker::Link()
|
||||
Unlink();
|
||||
|
||||
sLinkStatus = LinkStatus_FAILED;
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -5,7 +5,6 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
const kSearchEngineID = "browser_urifixup_search_engine";
|
||||
const kTest
|
||||
const kSearchEngineURL = "http://example.com/?search={searchTerms}";
|
||||
Services.search.addEngineWithDetails(kSearchEngineID, "", "", "", "get",
|
||||
kSearchEngineURL);
|
||||
|
@ -20,23 +20,12 @@ var gDevUrl = "http://dev.url";
|
||||
function handleRequest(request, response) {
|
||||
var query = getQuery(request);
|
||||
|
||||
response.setHeader("Access-Control-Allow-Origin", "*", false);
|
||||
|
||||
var packageSize = ("packageSize" in query) ? query.packageSize : 0;
|
||||
var appName = ("appName" in query) ? query.appName : gAppName;
|
||||
var devName = ("devName" in query) ? query.devName : gDevName;
|
||||
var devUrl = ("devUrl" in query) ? query.devUrl : gDevUrl;
|
||||
// allowCancel just means deliver the file slowly so we have time to cancel it
|
||||
var allowCancel = "allowCancel" in query;
|
||||
var getPackage = "getPackage" in query;
|
||||
var alreadyDeferred = Number(getState("alreadyDeferred"));
|
||||
|
||||
if (allowCancel && getPackage && !alreadyDeferred) {
|
||||
// Only do this for the actual package delivery.
|
||||
response.processAsync();
|
||||
// And to avoid timer problems, only do this once.
|
||||
setState("alreadyDeferred", "1");
|
||||
}
|
||||
|
||||
response.setHeader("Access-Control-Allow-Origin", "*", false);
|
||||
|
||||
// If this is a version update, update state, prepare the manifest,
|
||||
// the application package and return.
|
||||
@ -47,8 +36,7 @@ function handleRequest(request, response) {
|
||||
var packageName = "test_packaged_app_" + packageVersion + ".zip";
|
||||
|
||||
setState("packageName", packageName);
|
||||
var packagePath = "/" + gBasePath + "file_packaged_app.sjs?" +
|
||||
(allowCancel?"allowCancel&": "") + "getPackage=" +
|
||||
var packagePath = "/" + gBasePath + "file_packaged_app.sjs?getPackage=" +
|
||||
packageName;
|
||||
setState("packagePath", packagePath);
|
||||
|
||||
@ -96,19 +84,11 @@ function handleRequest(request, response) {
|
||||
response.setHeader("Etag", etag, false);
|
||||
|
||||
// Serve the application package corresponding to the requested app version.
|
||||
if (getPackage) {
|
||||
if ("getPackage" in query) {
|
||||
var resource = readFile(packageName, true);
|
||||
response.setHeader("Content-Type",
|
||||
"Content-Type: application/java-archive", false);
|
||||
if (allowCancel && !alreadyDeferred) {
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(function (aTimer) {
|
||||
response.write(resource);
|
||||
response.finish();
|
||||
}, 3000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
} else {
|
||||
response.write(resource);
|
||||
}
|
||||
response.write(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -57,17 +57,13 @@ var PackagedTestHelper = (function PackagedTestHelper() {
|
||||
finish();
|
||||
}
|
||||
|
||||
function setAppVersion(aVersion, aCb, aDontUpdatePackage, aAllowCancel) {
|
||||
function setAppVersion(aVersion, aCb, aDontUpdatePackage) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
var dontUpdate = "";
|
||||
var allowCancel = "";
|
||||
if (aDontUpdatePackage) {
|
||||
dontUpdate = "&dontUpdatePackage=1";
|
||||
}
|
||||
if (aAllowCancel) {
|
||||
allowCancel= "&allowCancel=1";
|
||||
}
|
||||
var url = gSJS + "?setVersion=" + aVersion + dontUpdate + allowCancel;
|
||||
var url = gSJS + "?setVersion=" + aVersion + dontUpdate;
|
||||
xhr.addEventListener("load", function() {
|
||||
is(xhr.responseText, "OK", "setAppVersion OK");
|
||||
aCb();
|
||||
|
@ -34,7 +34,7 @@ function checkAppInstallError(aMiniManifestURL, aExpectedError) {
|
||||
req.onerror = function(evt) {
|
||||
var error = evt.target.error.name;
|
||||
if (error == aExpectedError) {
|
||||
info("Got expected " + aExpectedError);
|
||||
ok(true, "Got expected " + aExpectedError);
|
||||
PackagedTestHelper.next();
|
||||
} else {
|
||||
ok(false, "Got unexpected " + error);
|
||||
@ -46,7 +46,7 @@ function checkAppInstallError(aMiniManifestURL, aExpectedError) {
|
||||
function checkUninstallApp(aApp) {
|
||||
var req = navigator.mozApps.mgmt.uninstall(aApp);
|
||||
req.onsuccess = function() {
|
||||
info("App uninstalled");
|
||||
ok(true, "App uninstalled");
|
||||
aApp.ondownloadsuccess = null;
|
||||
aApp.ondownloaderror = null;
|
||||
aApp.onprogress = null;
|
||||
@ -83,11 +83,11 @@ var steps = [
|
||||
// Set up
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.addPermission("webapps-manage", true, document);
|
||||
info("Set up");
|
||||
ok(true, "Set up");
|
||||
PackagedTestHelper.next();
|
||||
},
|
||||
function() {
|
||||
info("autoConfirmAppInstall");
|
||||
ok(true, "autoConfirmAppInstall");
|
||||
SpecialPowers.autoConfirmAppInstall(PackagedTestHelper.next);
|
||||
},
|
||||
function() {
|
||||
@ -96,17 +96,17 @@ var steps = [
|
||||
function() {
|
||||
// Bug 927699 - navigator.mozApps.install(url) lets NS_ERROR_FAILURE onto
|
||||
// the web.
|
||||
info("== TEST == INVALID_URL");
|
||||
ok(true, "== TEST == INVALID_URL");
|
||||
checkAppInstallError("", "INVALID_URL");
|
||||
},
|
||||
function() {
|
||||
// Test network error.
|
||||
info("== TEST == Network error");
|
||||
ok(true, "== TEST == Network error");
|
||||
checkAppInstallError("http://notvalidurl", "NETWORK_ERROR");
|
||||
},
|
||||
function() {
|
||||
// Test wrong mini-manifest content type.
|
||||
info("== TEST == Not valid mini-manifest content type");
|
||||
ok(true, "== TEST == Not valid mini-manifest content type");
|
||||
var miniManifestURL = PackagedTestHelper.gSJS +
|
||||
"?getManifest=true" +
|
||||
"&noManifestContentType=true";
|
||||
@ -114,7 +114,7 @@ var steps = [
|
||||
},
|
||||
function() {
|
||||
// Test mini-manifest 'size' value is not number. Bug 839435.
|
||||
info("== TEST == Size value is not a number");
|
||||
ok(true, "== TEST == Size value is not a number");
|
||||
var miniManifestURL = PackagedTestHelper.gSJS +
|
||||
"?getManifest=true" +
|
||||
"&packageSize=\"NotANumber\"";
|
||||
@ -122,7 +122,7 @@ var steps = [
|
||||
},
|
||||
function() {
|
||||
// Test mini-manifest negative 'size' value. Bug 839435.
|
||||
info("== TEST == Negative size value");
|
||||
ok(true, "== TEST == Negative size value");
|
||||
var miniManifestURL = PackagedTestHelper.gSJS +
|
||||
"?getManifest=true" +
|
||||
"&packageSize=-1";
|
||||
@ -130,7 +130,7 @@ var steps = [
|
||||
},
|
||||
function() {
|
||||
// Test wrong package path
|
||||
info("== TEST == Installing app with wrong package path");
|
||||
ok(true, "== TEST == Installing app with wrong package path");
|
||||
var miniManifestURL = PackagedTestHelper.gSJS +
|
||||
"?getManifest=true" +
|
||||
"&wrongPackagePath=true";
|
||||
@ -138,7 +138,7 @@ var steps = [
|
||||
},
|
||||
function() {
|
||||
// Test no manifest in zip file.
|
||||
info("== TEST == No manifest in the zip file");
|
||||
ok(true, "== TEST == No manifest in the zip file");
|
||||
var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true";
|
||||
PackagedTestHelper.checkAppDownloadError(miniManifestURL,
|
||||
"MISSING_MANIFEST", 0, true, true,
|
||||
@ -150,7 +150,7 @@ var steps = [
|
||||
function() {
|
||||
// Test mini-manifest app name is different from the webapp manifest name.
|
||||
// Bug 844243.
|
||||
info("== TEST == Mini-manifest app name is different from webapp " +
|
||||
ok(true, "== TEST == Mini-manifest app name is different from webapp " +
|
||||
"manifest name");
|
||||
var miniManifestURL = PackagedTestHelper.gSJS +
|
||||
"?getManifest=true" +
|
||||
@ -187,11 +187,11 @@ var steps = [
|
||||
PackagedTestHelper.setAppVersion(2, PackagedTestHelper.next);
|
||||
},
|
||||
function() {
|
||||
info("== TEST == Install packaged app");
|
||||
ok(true, "== TEST == Install packaged app");
|
||||
var miniManifestURL = PackagedTestHelper.gSJS +
|
||||
"?getManifest=true";
|
||||
navigator.mozApps.mgmt.oninstall = function(evt) {
|
||||
info("Got oninstall event");
|
||||
ok(true, "Got oninstall event");
|
||||
PackagedTestHelper.gApp = evt.application;
|
||||
PackagedTestHelper.gApp.ondownloaderror = function() {
|
||||
ok(false, "Download error " +
|
||||
@ -199,7 +199,7 @@ var steps = [
|
||||
PackagedTestHelper.finish();
|
||||
};
|
||||
PackagedTestHelper.gApp.ondownloadsuccess = function() {
|
||||
info("App downloaded");
|
||||
ok(true, "App downloaded");
|
||||
var expected = {
|
||||
name: PackagedTestHelper.gAppName,
|
||||
manifestURL: miniManifestURL,
|
||||
@ -220,85 +220,11 @@ var steps = [
|
||||
var request = navigator.mozApps.installPackage(miniManifestURL);
|
||||
request.onerror = PackagedTestHelper.mozAppsError;
|
||||
request.onsuccess = function() {
|
||||
info("Application installed");
|
||||
ok(true, "Application installed");
|
||||
};
|
||||
},
|
||||
function() {
|
||||
PackagedTestHelper.setAppVersion(3, PackagedTestHelper.next, false, true);
|
||||
},
|
||||
function() {
|
||||
info("== TEST == Install packaged app with a cancel/resume");
|
||||
var miniManifestURL = PackagedTestHelper.gSJS +
|
||||
"?getManifest=true&allowCancel";
|
||||
navigator.mozApps.mgmt.oninstall = function(evt) {
|
||||
info("Got oninstall event");
|
||||
PackagedTestHelper.gApp = evt.application;
|
||||
|
||||
PackagedTestHelper.gApp.onprogress = function() {
|
||||
// Let's try cancelling and resuming the download later on.
|
||||
PackagedTestHelper.gApp.cancelDownload();
|
||||
// And only do this once.
|
||||
PackagedTestHelper.gApp.onprogress = null;
|
||||
};
|
||||
|
||||
var alreadyCancelled = false;
|
||||
PackagedTestHelper.gApp.ondownloaderror = function() {
|
||||
ok(!alreadyCancelled, "The download should be cancelled only once!");
|
||||
is(PackagedTestHelper.gApp.downloadError.name, "DOWNLOAD_CANCELED",
|
||||
"Download error " + PackagedTestHelper.gApp.downloadError.name);
|
||||
if (!alreadyCancelled) {
|
||||
PackagedTestHelper.gApp.download();
|
||||
alreadyCancelled = true;
|
||||
}
|
||||
};
|
||||
|
||||
PackagedTestHelper.gApp.ondownloadsuccess = function() {
|
||||
info("App downloaded");
|
||||
// We could try also applying the download we just made.
|
||||
var expected = {
|
||||
name: PackagedTestHelper.gAppName,
|
||||
manifestURL: miniManifestURL,
|
||||
installOrigin: PackagedTestHelper.gInstallOrigin,
|
||||
progress: 0,
|
||||
installState: "pending",
|
||||
downloadAvailable: false,
|
||||
downloading: false,
|
||||
downloadSize: 0,
|
||||
size: 0,
|
||||
readyToApplyDownload: true
|
||||
};
|
||||
PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 3, expected,
|
||||
true, false, function() {});
|
||||
};
|
||||
|
||||
PackagedTestHelper.gApp.ondownloadapplied = function() {
|
||||
info("App download applied.");
|
||||
var expected = {
|
||||
name: PackagedTestHelper.gAppName,
|
||||
manifestURL: miniManifestURL,
|
||||
installOrigin: PackagedTestHelper.gInstallOrigin,
|
||||
progress: 0,
|
||||
installState: "installed",
|
||||
downloadAvailable: false,
|
||||
downloading: false,
|
||||
downloadSize: 0,
|
||||
size: 0,
|
||||
readyToApplyDownload: false
|
||||
};
|
||||
PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 3, expected,
|
||||
true, false, PackagedTestHelper.next);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var request = navigator.mozApps.installPackage(miniManifestURL);
|
||||
request.onerror = PackagedTestHelper.mozAppsError;
|
||||
request.onsuccess = function() {
|
||||
info("Application installed");
|
||||
};
|
||||
},
|
||||
function() {
|
||||
info("all done!\n");
|
||||
ok(true, "all done!\n");
|
||||
PackagedTestHelper.finish();
|
||||
}
|
||||
];
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "xpcprivate.h"
|
||||
|
||||
#include "mozilla/dom/DOMExceptionBinding.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -553,6 +554,14 @@ Exception::GetData() const
|
||||
return data.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Exception::GetStack(nsAString& aStack, ErrorResult& aRv) const
|
||||
{
|
||||
if (mLocation) {
|
||||
aRv = mLocation->GetFormattedStack(aStack);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Exception::Stringify(nsString& retval)
|
||||
{
|
||||
|
@ -32,6 +32,8 @@ NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, nsACString& aName,
|
||||
uint16_t* aCode = nullptr);
|
||||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
#define MOZILLA_EXCEPTION_IID \
|
||||
@ -81,6 +83,8 @@ public:
|
||||
|
||||
already_AddRefed<nsISupports> GetData() const;
|
||||
|
||||
void GetStack(nsAString& aStack, ErrorResult& aRv) const;
|
||||
|
||||
void Stringify(nsString& retval);
|
||||
|
||||
// XPCOM factory ctor.
|
||||
|
@ -182,188 +182,177 @@ GetCurrentJSStack()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// peel off native frames...
|
||||
uint32_t language;
|
||||
nsCOMPtr<nsIStackFrame> caller;
|
||||
while (stack &&
|
||||
NS_SUCCEEDED(stack->GetLanguage(&language)) &&
|
||||
language != nsIProgrammingLanguage::JAVASCRIPT &&
|
||||
NS_SUCCEEDED(stack->GetCaller(getter_AddRefs(caller))) &&
|
||||
caller) {
|
||||
stack = caller;
|
||||
}
|
||||
// Note that CreateStack only returns JS frames, so we're done here.
|
||||
return stack.forget();
|
||||
}
|
||||
|
||||
namespace exceptions {
|
||||
|
||||
class StackDescriptionOwner {
|
||||
public:
|
||||
StackDescriptionOwner(JS::StackDescription* aDescription)
|
||||
: mDescription(aDescription)
|
||||
{
|
||||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
~StackDescriptionOwner()
|
||||
{
|
||||
// Make sure to set mDescription to null before calling DropJSObjects, since
|
||||
// in debug builds DropJSObjects try to trace us and we don't want to trace
|
||||
// a dead StackDescription.
|
||||
if (mDescription) {
|
||||
JS::FreeStackDescription(nullptr, mDescription);
|
||||
mDescription = nullptr;
|
||||
}
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(StackDescriptionOwner)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(StackDescriptionOwner)
|
||||
|
||||
JS::FrameDescription& FrameAt(size_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(aIndex < mDescription->nframes);
|
||||
return mDescription->frames[aIndex];
|
||||
}
|
||||
|
||||
unsigned NumFrames()
|
||||
{
|
||||
return mDescription->nframes;
|
||||
}
|
||||
|
||||
private:
|
||||
JS::StackDescription* mDescription;
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(StackDescriptionOwner, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(StackDescriptionOwner, Release)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(StackDescriptionOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StackDescriptionOwner)
|
||||
if (tmp->mDescription) {
|
||||
JS::FreeStackDescription(nullptr, tmp->mDescription);
|
||||
tmp->mDescription = nullptr;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StackDescriptionOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(StackDescriptionOwner)
|
||||
JS::StackDescription* desc = tmp->mDescription;
|
||||
if (tmp->mDescription) {
|
||||
for (size_t i = 0; i < desc->nframes; ++i) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDescription->frames[i].markedLocation1());
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDescription->frames[i].markedLocation2());
|
||||
}
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
class JSStackFrame : public nsIStackFrame
|
||||
class StackFrame : public nsIStackFrame
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(JSStackFrame)
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(StackFrame)
|
||||
NS_DECL_NSISTACKFRAME
|
||||
|
||||
// A null aStackDescription or an aIndex that's out of range for the
|
||||
// number of frames aStackDescription has will mean that the
|
||||
// JSStackFrame will never look at the stack description. Instead,
|
||||
// it is expected to be initialized by the caller as needed.
|
||||
JSStackFrame(StackDescriptionOwner* aStackDescription, size_t aIndex);
|
||||
StackFrame(uint32_t aLanguage,
|
||||
const char* aFilename,
|
||||
const char* aFunctionName,
|
||||
int32_t aLineNumber,
|
||||
nsIStackFrame* aCaller);
|
||||
|
||||
StackFrame()
|
||||
: mLineno(0)
|
||||
, mLanguage(nsIProgrammingLanguage::UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIStackFrame>
|
||||
CreateStack(JSContext* aCx, int32_t aMaxDepth = -1);
|
||||
static already_AddRefed<nsIStackFrame>
|
||||
CreateStackFrameLocation(uint32_t aLanguage,
|
||||
const char* aFilename,
|
||||
const char* aFunctionName,
|
||||
int32_t aLineNumber,
|
||||
nsIStackFrame* aCaller);
|
||||
protected:
|
||||
virtual ~StackFrame();
|
||||
|
||||
private:
|
||||
virtual ~JSStackFrame();
|
||||
|
||||
bool IsJSFrame() const {
|
||||
return mLanguage == nsIProgrammingLanguage::JAVASCRIPT;
|
||||
virtual bool IsJSFrame() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t GetLineno();
|
||||
virtual nsresult GetLineno(int32_t* aLineNo)
|
||||
{
|
||||
*aLineNo = mLineno;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<StackDescriptionOwner> mStackDescription;
|
||||
nsCOMPtr<nsIStackFrame> mCaller;
|
||||
|
||||
// Cached values
|
||||
nsString mFilename;
|
||||
nsString mFunname;
|
||||
int32_t mLineno;
|
||||
uint32_t mLanguage;
|
||||
};
|
||||
|
||||
size_t mIndex;
|
||||
StackFrame::StackFrame(uint32_t aLanguage,
|
||||
const char* aFilename,
|
||||
const char* aFunctionName,
|
||||
int32_t aLineNumber,
|
||||
nsIStackFrame* aCaller)
|
||||
: mCaller(aCaller)
|
||||
, mLineno(aLineNumber)
|
||||
, mLanguage(aLanguage)
|
||||
{
|
||||
CopyUTF8toUTF16(aFilename, mFilename);
|
||||
CopyUTF8toUTF16(aFunctionName, mFunname);
|
||||
}
|
||||
|
||||
StackFrame::~StackFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(StackFrame, mCaller)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(StackFrame)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(StackFrame)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StackFrame)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStackFrame)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
class JSStackFrame : public StackFrame
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(JSStackFrame,
|
||||
StackFrame)
|
||||
|
||||
// aStack must not be null.
|
||||
JSStackFrame(JS::Handle<JSObject*> aStack);
|
||||
|
||||
static already_AddRefed<nsIStackFrame>
|
||||
CreateStack(JSContext* aCx, int32_t aMaxDepth = -1);
|
||||
|
||||
NS_IMETHOD GetLanguageName(nsACString& aLanguageName) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetFilename(nsAString& aFilename) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetName(nsAString& aFunction) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetCaller(nsIStackFrame** aCaller) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetFormattedStack(nsAString& aStack) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual bool IsJSFrame() const MOZ_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual nsresult GetLineno(int32_t* aLineNo) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
virtual ~JSStackFrame();
|
||||
|
||||
JS::Heap<JSObject*> mStack;
|
||||
nsString mFormattedStack;
|
||||
|
||||
bool mFilenameInitialized;
|
||||
bool mFunnameInitialized;
|
||||
bool mLinenoInitialized;
|
||||
bool mCallerInitialized;
|
||||
bool mFormattedStackInitialized;
|
||||
};
|
||||
|
||||
JSStackFrame::JSStackFrame(StackDescriptionOwner* aStackDescription,
|
||||
size_t aIndex)
|
||||
: mLineno(0)
|
||||
JSStackFrame::JSStackFrame(JS::Handle<JSObject*> aStack)
|
||||
: mStack(aStack)
|
||||
, mFilenameInitialized(false)
|
||||
, mFunnameInitialized(false)
|
||||
, mLinenoInitialized(false)
|
||||
, mCallerInitialized(false)
|
||||
, mFormattedStackInitialized(false)
|
||||
{
|
||||
if (aStackDescription && aIndex < aStackDescription->NumFrames()) {
|
||||
mStackDescription = aStackDescription;
|
||||
mIndex = aIndex;
|
||||
mFilenameInitialized = false;
|
||||
mFunnameInitialized = false;
|
||||
mLinenoInitialized = false;
|
||||
mCallerInitialized = false;
|
||||
mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
|
||||
} else {
|
||||
MOZ_ASSERT(!mStackDescription);
|
||||
mIndex = 0;
|
||||
mFilenameInitialized = true;
|
||||
mFunnameInitialized = true;
|
||||
mLinenoInitialized = true;
|
||||
mCallerInitialized = true;
|
||||
mLanguage = nsIProgrammingLanguage::UNKNOWN;
|
||||
}
|
||||
MOZ_ASSERT(mStack);
|
||||
|
||||
mozilla::HoldJSObjects(this);
|
||||
mLineno = 0;
|
||||
mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
|
||||
}
|
||||
|
||||
JSStackFrame::~JSStackFrame()
|
||||
{
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(JSStackFrame, mStackDescription, mCaller)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(JSStackFrame)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(JSStackFrame, StackFrame)
|
||||
tmp->mStack = nullptr;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(JSStackFrame, StackFrame)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(JSStackFrame, StackFrame)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStack)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(JSStackFrame)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(JSStackFrame)
|
||||
NS_IMPL_ADDREF_INHERITED(JSStackFrame, StackFrame)
|
||||
NS_IMPL_RELEASE_INHERITED(JSStackFrame, StackFrame)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSStackFrame)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStackFrame)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(JSStackFrame)
|
||||
NS_INTERFACE_MAP_END_INHERITING(StackFrame)
|
||||
|
||||
/* readonly attribute uint32_t language; */
|
||||
NS_IMETHODIMP JSStackFrame::GetLanguage(uint32_t* aLanguage)
|
||||
NS_IMETHODIMP StackFrame::GetLanguage(uint32_t* aLanguage)
|
||||
{
|
||||
*aLanguage = mLanguage;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute string languageName; */
|
||||
NS_IMETHODIMP StackFrame::GetLanguageName(nsACString& aLanguageName)
|
||||
{
|
||||
aLanguageName.AssignLiteral("C++");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JSStackFrame::GetLanguageName(nsACString& aLanguageName)
|
||||
{
|
||||
static const char js[] = "JavaScript";
|
||||
static const char cpp[] = "C++";
|
||||
|
||||
if (IsJSFrame()) {
|
||||
aLanguageName.AssignASCII(js);
|
||||
} else {
|
||||
aLanguageName.AssignASCII(cpp);
|
||||
}
|
||||
|
||||
aLanguageName.AssignLiteral("JavaScript");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -371,13 +360,28 @@ NS_IMETHODIMP JSStackFrame::GetLanguageName(nsACString& aLanguageName)
|
||||
NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename)
|
||||
{
|
||||
if (!mFilenameInitialized) {
|
||||
JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
|
||||
if (const char *filename = desc.filename()) {
|
||||
CopyUTF8toUTF16(filename, mFilename);
|
||||
ThreadsafeAutoJSContext cx;
|
||||
JS::Rooted<JSObject*> stack(cx, mStack);
|
||||
JS::ExposeObjectToActiveJS(mStack);
|
||||
JSAutoCompartment ac(cx, stack);
|
||||
JS::Rooted<JS::Value> filenameVal(cx);
|
||||
if (!JS_GetProperty(cx, stack, "source", &filenameVal) ||
|
||||
!filenameVal.isString()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
nsAutoJSString str;
|
||||
if (!str.init(cx, filenameVal.toString())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mFilename = str;
|
||||
mFilenameInitialized = true;
|
||||
}
|
||||
|
||||
return StackFrame::GetFilename(aFilename);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP StackFrame::GetFilename(nsAString& aFilename)
|
||||
{
|
||||
// The filename must be set to null if empty.
|
||||
if (mFilename.IsEmpty()) {
|
||||
aFilename.SetIsVoid(true);
|
||||
@ -392,13 +396,31 @@ NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename)
|
||||
NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction)
|
||||
{
|
||||
if (!mFunnameInitialized) {
|
||||
JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
|
||||
if (JSFlatString *name = desc.funDisplayName()) {
|
||||
AssignJSFlatString(mFunname, name);
|
||||
ThreadsafeAutoJSContext cx;
|
||||
JS::Rooted<JSObject*> stack(cx, mStack);
|
||||
JS::ExposeObjectToActiveJS(mStack);
|
||||
JSAutoCompartment ac(cx, stack);
|
||||
JS::Rooted<JS::Value> nameVal(cx);
|
||||
// functionDisplayName can be null
|
||||
if (!JS_GetProperty(cx, stack, "functionDisplayName", &nameVal) ||
|
||||
(!nameVal.isString() && !nameVal.isNull())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (nameVal.isString()) {
|
||||
nsAutoJSString str;
|
||||
if (!str.init(cx, nameVal.toString())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mFunname = str;
|
||||
}
|
||||
mFunnameInitialized = true;
|
||||
}
|
||||
|
||||
return StackFrame::GetName(aFunction);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP StackFrame::GetName(nsAString& aFunction)
|
||||
{
|
||||
// The function name must be set to null if empty.
|
||||
if (mFunname.IsEmpty()) {
|
||||
aFunction.SetIsVoid(true);
|
||||
@ -409,27 +431,35 @@ NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
JSStackFrame::GetLineno()
|
||||
// virtual
|
||||
nsresult
|
||||
JSStackFrame::GetLineno(int32_t* aLineNo)
|
||||
{
|
||||
if (!mLinenoInitialized) {
|
||||
JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
|
||||
mLineno = desc.lineno();
|
||||
ThreadsafeAutoJSContext cx;
|
||||
JS::Rooted<JSObject*> stack(cx, mStack);
|
||||
JS::ExposeObjectToActiveJS(mStack);
|
||||
JSAutoCompartment ac(cx, stack);
|
||||
JS::Rooted<JS::Value> lineVal(cx);
|
||||
if (!JS_GetProperty(cx, stack, "line", &lineVal) ||
|
||||
!lineVal.isNumber()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mLineno = lineVal.toNumber();
|
||||
mLinenoInitialized = true;
|
||||
}
|
||||
|
||||
return mLineno;
|
||||
return StackFrame::GetLineno(aLineNo);
|
||||
}
|
||||
|
||||
/* readonly attribute int32_t lineNumber; */
|
||||
NS_IMETHODIMP JSStackFrame::GetLineNumber(int32_t* aLineNumber)
|
||||
NS_IMETHODIMP StackFrame::GetLineNumber(int32_t* aLineNumber)
|
||||
{
|
||||
*aLineNumber = GetLineno();
|
||||
return NS_OK;
|
||||
return GetLineno(aLineNumber);
|
||||
}
|
||||
|
||||
/* readonly attribute AUTF8String sourceLine; */
|
||||
NS_IMETHODIMP JSStackFrame::GetSourceLine(nsACString& aSourceLine)
|
||||
NS_IMETHODIMP StackFrame::GetSourceLine(nsACString& aSourceLine)
|
||||
{
|
||||
aSourceLine.Truncate();
|
||||
return NS_OK;
|
||||
@ -439,15 +469,67 @@ NS_IMETHODIMP JSStackFrame::GetSourceLine(nsACString& aSourceLine)
|
||||
NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller)
|
||||
{
|
||||
if (!mCallerInitialized) {
|
||||
mCaller = new JSStackFrame(mStackDescription, mIndex+1);
|
||||
ThreadsafeAutoJSContext cx;
|
||||
JS::Rooted<JSObject*> stack(cx, mStack);
|
||||
JS::ExposeObjectToActiveJS(mStack);
|
||||
JSAutoCompartment ac(cx, stack);
|
||||
JS::Rooted<JS::Value> callerVal(cx);
|
||||
if (!JS_GetProperty(cx, stack, "parent", &callerVal) ||
|
||||
!callerVal.isObjectOrNull()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (callerVal.isObject()) {
|
||||
JS::Rooted<JSObject*> caller(cx, &callerVal.toObject());
|
||||
mCaller = new JSStackFrame(caller);
|
||||
} else {
|
||||
// Do we really need this dummy frame? If so, we should document why... I
|
||||
// guess for symmetry with the "nothing on the stack" case, which returns
|
||||
// a single dummy frame?
|
||||
mCaller = new StackFrame();
|
||||
}
|
||||
mCallerInitialized = true;
|
||||
}
|
||||
return StackFrame::GetCaller(aCaller);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP StackFrame::GetCaller(nsIStackFrame** aCaller)
|
||||
{
|
||||
NS_IF_ADDREF(*aCaller = mCaller);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JSStackFrame::GetFormattedStack(nsAString& aStack)
|
||||
{
|
||||
if (!mFormattedStackInitialized) {
|
||||
ThreadsafeAutoJSContext cx;
|
||||
JS::Rooted<JS::Value> stack(cx, JS::ObjectValue(*mStack));
|
||||
JS::ExposeObjectToActiveJS(mStack);
|
||||
JSAutoCompartment ac(cx, mStack);
|
||||
JS::Rooted<JSString*> formattedStack(cx, JS::ToString(cx, stack));
|
||||
if (!formattedStack) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
nsAutoJSString str;
|
||||
if (!str.init(cx, formattedStack)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mFormattedStack = str;
|
||||
mFormattedStackInitialized = true;
|
||||
}
|
||||
|
||||
aStack = mFormattedStack;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP StackFrame::GetFormattedStack(nsAString& aStack)
|
||||
{
|
||||
aStack.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* AUTF8String toString (); */
|
||||
NS_IMETHODIMP JSStackFrame::ToString(nsACString& _retval)
|
||||
NS_IMETHODIMP StackFrame::ToString(nsACString& _retval)
|
||||
{
|
||||
_retval.Truncate();
|
||||
|
||||
@ -468,11 +550,16 @@ NS_IMETHODIMP JSStackFrame::ToString(nsACString& _retval)
|
||||
if (funname.IsEmpty()) {
|
||||
funname.AssignLiteral("<TOP_LEVEL>");
|
||||
}
|
||||
|
||||
int32_t lineno;
|
||||
rv = GetLineno(&lineno);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
static const char format[] = "%s frame :: %s :: %s :: line %d";
|
||||
_retval.AppendPrintf(format, frametype,
|
||||
NS_ConvertUTF16toUTF8(filename).get(),
|
||||
NS_ConvertUTF16toUTF8(funname).get(),
|
||||
GetLineno());
|
||||
lineno);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -484,33 +571,29 @@ JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth)
|
||||
aMaxDepth = MAX_FRAMES;
|
||||
}
|
||||
|
||||
JS::StackDescription* desc = JS::DescribeStack(aCx, aMaxDepth);
|
||||
if (!desc) {
|
||||
JS::Rooted<JSObject*> stack(aCx);
|
||||
if (!JS::CaptureCurrentStack(aCx, &stack, aMaxDepth)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<StackDescriptionOwner> descOwner = new StackDescriptionOwner(desc);
|
||||
|
||||
nsRefPtr<JSStackFrame> first = new JSStackFrame(descOwner, 0);
|
||||
nsCOMPtr<nsIStackFrame> first;
|
||||
if (!stack) {
|
||||
first = new StackFrame();
|
||||
} else {
|
||||
first = new JSStackFrame(stack);
|
||||
}
|
||||
return first.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<nsIStackFrame>
|
||||
JSStackFrame::CreateStackFrameLocation(uint32_t aLanguage,
|
||||
const char* aFilename,
|
||||
const char* aFunctionName,
|
||||
int32_t aLineNumber,
|
||||
nsIStackFrame* aCaller)
|
||||
StackFrame::CreateStackFrameLocation(uint32_t aLanguage,
|
||||
const char* aFilename,
|
||||
const char* aFunctionName,
|
||||
int32_t aLineNumber,
|
||||
nsIStackFrame* aCaller)
|
||||
{
|
||||
nsRefPtr<JSStackFrame> self = new JSStackFrame(nullptr, 0);
|
||||
|
||||
self->mLanguage = aLanguage;
|
||||
self->mLineno = aLineNumber;
|
||||
CopyUTF8toUTF16(aFilename, self->mFilename);
|
||||
CopyUTF8toUTF16(aFunctionName, self->mFunname);
|
||||
|
||||
self->mCaller = aCaller;
|
||||
|
||||
nsRefPtr<StackFrame> self =
|
||||
new StackFrame(aLanguage, aFilename, aFunctionName, aLineNumber, aCaller);
|
||||
return self.forget();
|
||||
}
|
||||
|
||||
@ -527,9 +610,9 @@ CreateStackFrameLocation(uint32_t aLanguage,
|
||||
int32_t aLineNumber,
|
||||
nsIStackFrame* aCaller)
|
||||
{
|
||||
return JSStackFrame::CreateStackFrameLocation(aLanguage, aFilename,
|
||||
aFunctionName, aLineNumber,
|
||||
aCaller);
|
||||
return StackFrame::CreateStackFrameLocation(aLanguage, aFilename,
|
||||
aFunctionName, aLineNumber,
|
||||
aCaller);
|
||||
}
|
||||
|
||||
} // namespace exceptions
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
const {classes: Cc,
|
||||
interfaces: Ci,
|
||||
utils: Cu,
|
||||
results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
@ -18,12 +21,14 @@ this.EXPORTED_SYMBOLS = ["DOMIdentity"];
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
|
||||
"resource://gre/modules/identity/IdentityUtils.jsm");
|
||||
|
||||
/* jshint ignore:start */
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
|
||||
#ifdef MOZ_B2G_VERSION
|
||||
"resource://gre/modules/identity/MinimalIdentity.jsm");
|
||||
#else
|
||||
"resource://gre/modules/identity/Identity.jsm");
|
||||
#endif
|
||||
/* jshint ignore:end */
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FirefoxAccounts",
|
||||
"resource://gre/modules/identity/FirefoxAccounts.jsm");
|
||||
@ -51,6 +56,23 @@ function IDDOMMessage(aOptions) {
|
||||
objectCopy(aOptions, this);
|
||||
}
|
||||
|
||||
function _sendAsyncMessage(identifier, message) {
|
||||
if (this._mm) {
|
||||
try {
|
||||
this._mm.sendAsyncMessage(identifier, message);
|
||||
} catch(err) {
|
||||
// We may receive a NS_ERROR_NOT_INITIALIZED if the target window has
|
||||
// been closed. This can legitimately happen if an app has been killed
|
||||
// while we are in the midst of a sign-in flow.
|
||||
if (err.result == Cr.NS_ERROR_NOT_INITIALIZED) {
|
||||
log("Cannot sendAsyncMessage because the recipient frame has closed");
|
||||
return;
|
||||
}
|
||||
log("ERROR: sendAsyncMessage: " + err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function IDPProvisioningContext(aID, aOrigin, aTargetMM) {
|
||||
this._id = aID;
|
||||
this._origin = aOrigin;
|
||||
@ -61,19 +83,21 @@ IDPProvisioningContext.prototype = {
|
||||
get id() this._id,
|
||||
get origin() this._origin,
|
||||
|
||||
sendAsyncMessage: _sendAsyncMessage,
|
||||
|
||||
doBeginProvisioningCallback: function IDPPC_doBeginProvCB(aID, aCertDuration) {
|
||||
let message = new IDDOMMessage({id: this.id});
|
||||
message.identity = aID;
|
||||
message.certDuration = aCertDuration;
|
||||
this._mm.sendAsyncMessage("Identity:IDP:CallBeginProvisioningCallback",
|
||||
message);
|
||||
this.sendAsyncMessage("Identity:IDP:CallBeginProvisioningCallback",
|
||||
message);
|
||||
},
|
||||
|
||||
doGenKeyPairCallback: function IDPPC_doGenKeyPairCallback(aPublicKey) {
|
||||
log("doGenKeyPairCallback");
|
||||
let message = new IDDOMMessage({id: this.id});
|
||||
message.publicKey = aPublicKey;
|
||||
this._mm.sendAsyncMessage("Identity:IDP:CallGenKeyPairCallback", message);
|
||||
this.sendAsyncMessage("Identity:IDP:CallGenKeyPairCallback", message);
|
||||
},
|
||||
|
||||
doError: function(msg) {
|
||||
@ -91,11 +115,13 @@ IDPAuthenticationContext.prototype = {
|
||||
get id() this._id,
|
||||
get origin() this._origin,
|
||||
|
||||
sendAsyncMessage: _sendAsyncMessage,
|
||||
|
||||
doBeginAuthenticationCallback: function IDPAC_doBeginAuthCB(aIdentity) {
|
||||
let message = new IDDOMMessage({id: this.id});
|
||||
message.identity = aIdentity;
|
||||
this._mm.sendAsyncMessage("Identity:IDP:CallBeginAuthenticationCallback",
|
||||
message);
|
||||
this.sendAsyncMessage("Identity:IDP:CallBeginAuthenticationCallback",
|
||||
message);
|
||||
},
|
||||
|
||||
doError: function IDPAC_doError(msg) {
|
||||
@ -123,37 +149,39 @@ function RPWatchContext(aOptions, aTargetMM, aPrincipal) {
|
||||
}
|
||||
|
||||
RPWatchContext.prototype = {
|
||||
sendAsyncMessage: _sendAsyncMessage,
|
||||
|
||||
doLogin: function RPWatchContext_onlogin(aAssertion, aMaybeInternalParams) {
|
||||
log("doLogin: " + this.id);
|
||||
let message = new IDDOMMessage({id: this.id, assertion: aAssertion});
|
||||
if (aMaybeInternalParams) {
|
||||
message._internalParams = aMaybeInternalParams;
|
||||
}
|
||||
this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogin", message);
|
||||
this.sendAsyncMessage("Identity:RP:Watch:OnLogin", message);
|
||||
},
|
||||
|
||||
doLogout: function RPWatchContext_onlogout() {
|
||||
log("doLogout: " + this.id);
|
||||
let message = new IDDOMMessage({id: this.id});
|
||||
this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogout", message);
|
||||
this.sendAsyncMessage("Identity:RP:Watch:OnLogout", message);
|
||||
},
|
||||
|
||||
doReady: function RPWatchContext_onready() {
|
||||
log("doReady: " + this.id);
|
||||
let message = new IDDOMMessage({id: this.id});
|
||||
this._mm.sendAsyncMessage("Identity:RP:Watch:OnReady", message);
|
||||
this.sendAsyncMessage("Identity:RP:Watch:OnReady", message);
|
||||
},
|
||||
|
||||
doCancel: function RPWatchContext_oncancel() {
|
||||
log("doCancel: " + this.id);
|
||||
let message = new IDDOMMessage({id: this.id});
|
||||
this._mm.sendAsyncMessage("Identity:RP:Watch:OnCancel", message);
|
||||
this.sendAsyncMessage("Identity:RP:Watch:OnCancel", message);
|
||||
},
|
||||
|
||||
doError: function RPWatchContext_onerror(aMessage) {
|
||||
log("doError: " + this.id + ": " + JSON.stringify(aMessage));
|
||||
let message = new IDDOMMessage({id: this.id, message: aMessage});
|
||||
this._mm.sendAsyncMessage("Identity:RP:Watch:OnError", message);
|
||||
this.sendAsyncMessage("Identity:RP:Watch:OnError", message);
|
||||
}
|
||||
};
|
||||
|
||||
@ -207,7 +235,8 @@ this.DOMIdentity = {
|
||||
*/
|
||||
getService: function(message) {
|
||||
if (!this._serviceContexts.has(message.id)) {
|
||||
throw new Error("getService called before newContext for " + message.id);
|
||||
log("ERROR: getService called before newContext for " + message.id);
|
||||
return null;
|
||||
}
|
||||
|
||||
let context = this._serviceContexts.get(message.id);
|
||||
@ -348,7 +377,9 @@ this.DOMIdentity = {
|
||||
},
|
||||
|
||||
_subscribeListeners: function DOMIdentity__subscribeListeners() {
|
||||
if (!ppmm) return;
|
||||
if (!ppmm) {
|
||||
return;
|
||||
}
|
||||
for (let message of this.messages) {
|
||||
ppmm.addMessageListener(message, this);
|
||||
}
|
||||
@ -373,20 +404,31 @@ this.DOMIdentity = {
|
||||
// not have the right callbacks, we don't want unwatch to throw, because it
|
||||
// will break the process of releasing the page's resources and leak
|
||||
// memory.
|
||||
try {
|
||||
this.getService(message).RP.unwatch(message.id, targetMM);
|
||||
} catch(ex) {
|
||||
log("ERROR: can't unwatch " + message.id + ": " + ex);
|
||||
let service = this.getService(message);
|
||||
if (service && service.RP) {
|
||||
service.RP.unwatch(message.id, targetMM);
|
||||
this.deleteContextForMM(targetMM);
|
||||
return;
|
||||
}
|
||||
log("Can't find a service to unwatch() for " + message.id);
|
||||
},
|
||||
|
||||
_request: function DOMIdentity__request(message) {
|
||||
this.getService(message).RP.request(message.id, message);
|
||||
let service = this.getService(message);
|
||||
if (service && service.RP) {
|
||||
service.RP.request(message.id, message);
|
||||
return;
|
||||
}
|
||||
log("No context in which to call request(); Did you call watch() first?");
|
||||
},
|
||||
|
||||
_logout: function DOMIdentity__logout(message) {
|
||||
log("logout " + message + "\n");
|
||||
this.getService(message).RP.logout(message.id, message.origin, message);
|
||||
let service = this.getService(message);
|
||||
if (service && service.RP) {
|
||||
service.RP.logout(message.id, message.origin, message);
|
||||
return;
|
||||
}
|
||||
log("No context in which to call logout(); Did you call watch() first?");
|
||||
},
|
||||
|
||||
_childProcessShutdown: function DOMIdentity__childProcessShutdown(targetMM) {
|
||||
@ -394,7 +436,11 @@ this.DOMIdentity = {
|
||||
return;
|
||||
}
|
||||
|
||||
this.getContextForMM(targetMM).RP.childProcessShutdown(targetMM);
|
||||
let service = this.getContextForMM(targetMM);
|
||||
if (service && service.RP) {
|
||||
service.RP.childProcessShutdown(targetMM);
|
||||
}
|
||||
|
||||
this.deleteContextForMM(targetMM);
|
||||
|
||||
let options = makeMessageObject({messageManager: targetMM, id: null, origin: null});
|
||||
|
@ -56,6 +56,10 @@ interface ExceptionMembers
|
||||
|
||||
// Arbitary data for the implementation.
|
||||
readonly attribute nsISupports? data;
|
||||
|
||||
// Formatted exception stack
|
||||
[Throws, Replaceable]
|
||||
readonly attribute DOMString stack;
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
|
@ -43,11 +43,15 @@ public:
|
||||
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize)
|
||||
{
|
||||
if (SharedBufferManagerParent::sManagerMonitor) {
|
||||
SharedBufferManagerParent::sManagerMonitor->Lock();
|
||||
}
|
||||
map<base::ProcessId, SharedBufferManagerParent*>::iterator it;
|
||||
for (it = SharedBufferManagerParent::sManagers.begin(); it != SharedBufferManagerParent::sManagers.end(); it++) {
|
||||
base::ProcessId pid = it->first;
|
||||
SharedBufferManagerParent *mgr = it->second;
|
||||
|
||||
MutexAutoLock lock(mgr->mBuffersMutex);
|
||||
std::map<int64_t, android::sp<android::GraphicBuffer> >::iterator buf_it;
|
||||
for (buf_it = mgr->mBuffers.begin(); buf_it != mgr->mBuffers.end(); buf_it++) {
|
||||
nsresult rv;
|
||||
@ -72,10 +76,16 @@ public:
|
||||
"conditions."),
|
||||
aData);
|
||||
if (rv != NS_OK) {
|
||||
if (SharedBufferManagerParent::sManagerMonitor) {
|
||||
SharedBufferManagerParent::sManagerMonitor->Unlock();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SharedBufferManagerParent::sManagerMonitor) {
|
||||
SharedBufferManagerParent::sManagerMonitor->Unlock();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -548,27 +548,6 @@ TEST_F(AsyncPanZoomControllerTester, Pinch_DefaultGestures_NoTouchAction) {
|
||||
DoPinchTest(false, true);
|
||||
}
|
||||
|
||||
TEST_F(TouchActionEnabledTester, Pinch_DefaultGestures_TouchActionNone) {
|
||||
nsTArray<uint32_t> behaviors;
|
||||
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE);
|
||||
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE);
|
||||
DoPinchTest(false, false, &behaviors);
|
||||
}
|
||||
|
||||
TEST_F(TouchActionEnabledTester, Pinch_DefaultGestures_TouchActionZoom) {
|
||||
nsTArray<uint32_t> behaviors;
|
||||
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
|
||||
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
|
||||
DoPinchTest(false, true, &behaviors);
|
||||
}
|
||||
|
||||
TEST_F(TouchActionEnabledTester, Pinch_DefaultGestures_TouchActionNotAllowZoom) {
|
||||
nsTArray<uint32_t> behaviors;
|
||||
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
|
||||
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
|
||||
DoPinchTest(false, false, &behaviors);
|
||||
}
|
||||
|
||||
TEST_F(AsyncPanZoomControllerTester, Pinch_UseGestureDetector_NoTouchAction) {
|
||||
DoPinchTest(true, true);
|
||||
}
|
||||
|
@ -37,69 +37,6 @@ JS_GetScriptFilename(JSScript *script);
|
||||
|
||||
namespace JS {
|
||||
|
||||
class FrameDescription
|
||||
{
|
||||
public:
|
||||
explicit FrameDescription(const js::FrameIter& iter);
|
||||
FrameDescription(const FrameDescription &rhs);
|
||||
~FrameDescription();
|
||||
|
||||
unsigned lineno() {
|
||||
if (!linenoComputed_) {
|
||||
lineno_ = JS_PCToLineNumber(nullptr, script_, pc_);
|
||||
linenoComputed_ = true;
|
||||
}
|
||||
return lineno_;
|
||||
}
|
||||
|
||||
const char *filename() const {
|
||||
return filename_;
|
||||
}
|
||||
|
||||
JSFlatString *funDisplayName() const {
|
||||
return funDisplayName_ ? JS_ASSERT_STRING_IS_FLAT(funDisplayName_) : nullptr;
|
||||
}
|
||||
|
||||
// Both these locations should be traced during GC but otherwise not used;
|
||||
// they are implementation details.
|
||||
Heap<JSScript*> &markedLocation1() {
|
||||
return script_;
|
||||
}
|
||||
Heap<JSString*> &markedLocation2() {
|
||||
return funDisplayName_;
|
||||
}
|
||||
|
||||
private:
|
||||
void operator=(const FrameDescription &) MOZ_DELETE;
|
||||
|
||||
// These fields are always initialized:
|
||||
Heap<JSString*> funDisplayName_;
|
||||
const char *filename_;
|
||||
|
||||
// One of script_ xor scriptSource_ is non-null.
|
||||
Heap<JSScript*> script_;
|
||||
js::ScriptSource *scriptSource_;
|
||||
|
||||
// For script_-having frames, lineno_ is lazily computed as an optimization.
|
||||
bool linenoComputed_;
|
||||
unsigned lineno_;
|
||||
|
||||
// pc_ is non-null iff script_ is non-null. If !pc_, linenoComputed_ = true.
|
||||
jsbytecode *pc_;
|
||||
};
|
||||
|
||||
struct StackDescription
|
||||
{
|
||||
unsigned nframes;
|
||||
FrameDescription *frames;
|
||||
};
|
||||
|
||||
extern JS_PUBLIC_API(StackDescription *)
|
||||
DescribeStack(JSContext *cx, unsigned maxFrames);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
FreeStackDescription(JSContext *cx, StackDescription *desc);
|
||||
|
||||
extern JS_PUBLIC_API(char *)
|
||||
FormatStackDump(JSContext *cx, char *buf, bool showArgs, bool showLocals, bool showThisProps);
|
||||
|
||||
|
@ -55,9 +55,6 @@ class ChunkPool
|
||||
/* Must be called either during the GC or with the GC lock taken. */
|
||||
inline void put(Chunk *chunk);
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void expireAndFree(JSRuntime *rt, bool releaseAll);
|
||||
|
||||
class Enum {
|
||||
public:
|
||||
Enum(ChunkPool &pool) : pool(pool), chunkp(&pool.emptyChunkListHead) {}
|
||||
@ -358,7 +355,7 @@ class GCRuntime
|
||||
* Return the list of chunks that can be released outside the GC lock.
|
||||
* Must be called either during the GC or with the GC lock taken.
|
||||
*/
|
||||
Chunk *expireChunkPool(bool releaseAll);
|
||||
Chunk *expireChunkPool(bool shrinkBuffers, bool releaseAll);
|
||||
void expireAndFreeChunkPool(bool releaseAll);
|
||||
void freeChunkList(Chunk *chunkListHead);
|
||||
void prepareToFreeChunk(ChunkInfo &info);
|
||||
|
@ -4733,7 +4733,7 @@ JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOption
|
||||
else
|
||||
chars = InflateString(cx, bytes, &length);
|
||||
if (!chars)
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length, fun);
|
||||
}
|
||||
@ -5722,13 +5722,17 @@ JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer,
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandleValue vp)
|
||||
JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, MutableHandleValue vp)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
return ParseJSONWithReviver(cx, mozilla::Range<const jschar>(chars, len), NullHandleValue, vp);
|
||||
}
|
||||
|
||||
RootedValue reviver(cx, NullValue());
|
||||
return ParseJSONWithReviver(cx, mozilla::Range<const jschar>(chars, len), reviver, vp);
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ParseJSON(JSContext *cx, HandleString str, MutableHandleValue vp)
|
||||
{
|
||||
return JS_ParseJSONWithReviver(cx, str, NullHandleValue, vp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
@ -5739,6 +5743,22 @@ JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, Handle
|
||||
return ParseJSONWithReviver(cx, mozilla::Range<const jschar>(chars, len), reviver, vp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ParseJSONWithReviver(JSContext *cx, HandleString str, HandleValue reviver, MutableHandleValue vp)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, str);
|
||||
|
||||
AutoStableStringChars stableChars(cx);
|
||||
if (!stableChars.init(cx, str))
|
||||
return false;
|
||||
|
||||
return stableChars.isLatin1()
|
||||
? ParseJSONWithReviver(cx, stableChars.latin1Range(), reviver, vp)
|
||||
: ParseJSONWithReviver(cx, stableChars.twoByteRange(), reviver, vp);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
@ -4483,10 +4483,17 @@ JS_Stringify(JSContext *cx, JS::MutableHandleValue value, JS::HandleObject repla
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandleValue vp);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ParseJSON(JSContext *cx, JS::HandleString str, JS::MutableHandleValue vp);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, JS::HandleValue reviver,
|
||||
JS::MutableHandleValue vp);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ParseJSONWithReviver(JSContext *cx, JS::HandleString str, JS::HandleValue reviver,
|
||||
JS::MutableHandleValue vp);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -135,6 +135,7 @@ class CompartmentChecker
|
||||
|
||||
void check(InterpreterFrame *fp);
|
||||
void check(AbstractFramePtr frame);
|
||||
void check(SavedStacks *stacks);
|
||||
};
|
||||
#endif /* JS_CRASH_DIAGNOSTICS */
|
||||
|
||||
|
@ -238,10 +238,16 @@ static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
|
||||
/* Increase the IGC marking slice time if we are in highFrequencyGC mode. */
|
||||
static const int IGC_MARK_SLICE_MULTIPLIER = 2;
|
||||
|
||||
#if defined(ANDROID) || defined(MOZ_B2G)
|
||||
static const int MAX_EMPTY_CHUNK_COUNT = 2;
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
static const unsigned MIN_EMPTY_CHUNK_COUNT = 1;
|
||||
#else
|
||||
static const int MAX_EMPTY_CHUNK_COUNT = 30;
|
||||
static const unsigned MIN_EMPTY_CHUNK_COUNT = 0;
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID) || defined(MOZ_B2G)
|
||||
static const unsigned MAX_EMPTY_CHUNK_COUNT = 2;
|
||||
#else
|
||||
static const unsigned MAX_EMPTY_CHUNK_COUNT = 30;
|
||||
#endif
|
||||
|
||||
const AllocKind gc::slotsToThingKind[] = {
|
||||
@ -681,7 +687,7 @@ ChunkPool::Enum::removeAndPopFront()
|
||||
|
||||
/* Must be called either during the GC or with the GC lock taken. */
|
||||
Chunk *
|
||||
GCRuntime::expireChunkPool(bool releaseAll)
|
||||
GCRuntime::expireChunkPool(bool shrinkBuffers, bool releaseAll)
|
||||
{
|
||||
/*
|
||||
* Return old empty chunks to the system while preserving the order of
|
||||
@ -690,14 +696,14 @@ GCRuntime::expireChunkPool(bool releaseAll)
|
||||
* and are more likely to reach the max age.
|
||||
*/
|
||||
Chunk *freeList = nullptr;
|
||||
int freeChunkCount = 0;
|
||||
unsigned freeChunkCount = 0;
|
||||
for (ChunkPool::Enum e(chunkPool); !e.empty(); ) {
|
||||
Chunk *chunk = e.front();
|
||||
JS_ASSERT(chunk->unused());
|
||||
JS_ASSERT(!chunkSet.has(chunk));
|
||||
JS_ASSERT(chunk->info.age <= MAX_EMPTY_CHUNK_AGE);
|
||||
if (releaseAll || chunk->info.age == MAX_EMPTY_CHUNK_AGE ||
|
||||
freeChunkCount++ > MAX_EMPTY_CHUNK_COUNT)
|
||||
if (releaseAll || freeChunkCount >= MAX_EMPTY_CHUNK_COUNT ||
|
||||
(freeChunkCount >= MIN_EMPTY_CHUNK_COUNT &&
|
||||
(shrinkBuffers || chunk->info.age == MAX_EMPTY_CHUNK_AGE)))
|
||||
{
|
||||
e.removeAndPopFront();
|
||||
prepareToFreeChunk(chunk->info);
|
||||
@ -705,10 +711,12 @@ GCRuntime::expireChunkPool(bool releaseAll)
|
||||
freeList = chunk;
|
||||
} else {
|
||||
/* Keep the chunk but increase its age. */
|
||||
++freeChunkCount;
|
||||
++chunk->info.age;
|
||||
e.popFront();
|
||||
}
|
||||
}
|
||||
JS_ASSERT_IF(shrinkBuffers, chunkPool.getEmptyCount() <= MIN_EMPTY_CHUNK_COUNT);
|
||||
JS_ASSERT_IF(releaseAll, chunkPool.getEmptyCount() == 0);
|
||||
return freeList;
|
||||
}
|
||||
@ -726,7 +734,7 @@ GCRuntime::freeChunkList(Chunk *chunkListHead)
|
||||
void
|
||||
GCRuntime::expireAndFreeChunkPool(bool releaseAll)
|
||||
{
|
||||
freeChunkList(expireChunkPool(releaseAll));
|
||||
freeChunkList(expireChunkPool(true, releaseAll));
|
||||
}
|
||||
|
||||
/* static */ Chunk *
|
||||
@ -1024,7 +1032,7 @@ GCRuntime::wantBackgroundAllocation() const
|
||||
* of them.
|
||||
*/
|
||||
return helperState.canBackgroundAllocate() &&
|
||||
chunkPool.getEmptyCount() == 0 &&
|
||||
chunkPool.getEmptyCount() < MIN_EMPTY_CHUNK_COUNT &&
|
||||
chunkSet.count() >= 4;
|
||||
}
|
||||
|
||||
@ -2568,7 +2576,7 @@ GCRuntime::expireChunksAndArenas(bool shouldShrink)
|
||||
rt->threadPool.pruneChunkCache();
|
||||
#endif
|
||||
|
||||
if (Chunk *toFree = expireChunkPool(shouldShrink)) {
|
||||
if (Chunk *toFree = expireChunkPool(shouldShrink, false)) {
|
||||
AutoUnlockGC unlock(rt);
|
||||
freeChunkList(toFree);
|
||||
}
|
||||
|
@ -4183,7 +4183,7 @@ static void
|
||||
UpdateFrameIterPc(FrameIter &iter)
|
||||
{
|
||||
if (iter.abstractFramePtr().isRematerializedFrame()) {
|
||||
#ifdef DEBUG
|
||||
#if defined(DEBUG) && defined(JS_ION)
|
||||
// Rematerialized frames don't need their pc updated. The reason we
|
||||
// need to update pc is because we might get the same Debugger.Frame
|
||||
// object for multiple re-entries into debugger code from debuggee
|
||||
|
@ -895,85 +895,6 @@ js_CallContextDebugHandler(JSContext *cx)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A contructor that crates a FrameDescription from a ScriptFrameIter, to avoid
|
||||
* constructing a FrameDescription on the stack just to append it to a vector.
|
||||
* FrameDescription contains Heap<T> fields that should not live on the stack.
|
||||
*/
|
||||
JS::FrameDescription::FrameDescription(const FrameIter& iter)
|
||||
: scriptSource_(nullptr),
|
||||
linenoComputed_(false),
|
||||
pc_(nullptr)
|
||||
{
|
||||
if (iter.isNonEvalFunctionFrame())
|
||||
funDisplayName_ = iter.functionDisplayAtom();
|
||||
|
||||
if (iter.hasScript()) {
|
||||
script_ = iter.script();
|
||||
pc_ = iter.pc();
|
||||
filename_ = script_->filename();
|
||||
} else {
|
||||
scriptSource_ = iter.scriptSource();
|
||||
scriptSource_->incref();
|
||||
filename_ = scriptSource_->filename();
|
||||
lineno_ = iter.computeLine();
|
||||
linenoComputed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
JS::FrameDescription::FrameDescription(const FrameDescription &rhs)
|
||||
: funDisplayName_(rhs.funDisplayName_),
|
||||
filename_(rhs.filename_),
|
||||
script_(rhs.script_),
|
||||
scriptSource_(rhs.scriptSource_),
|
||||
linenoComputed_(rhs.linenoComputed_),
|
||||
lineno_(rhs.lineno_),
|
||||
pc_(rhs.pc_)
|
||||
{
|
||||
if (scriptSource_)
|
||||
scriptSource_->incref();
|
||||
}
|
||||
|
||||
|
||||
JS::FrameDescription::~FrameDescription()
|
||||
{
|
||||
if (scriptSource_)
|
||||
scriptSource_->decref();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::StackDescription *)
|
||||
JS::DescribeStack(JSContext *cx, unsigned maxFrames)
|
||||
{
|
||||
Vector<FrameDescription> frames(cx);
|
||||
|
||||
NonBuiltinFrameIter i(cx, FrameIter::ALL_CONTEXTS,
|
||||
FrameIter::GO_THROUGH_SAVED,
|
||||
cx->compartment()->principals);
|
||||
for ( ; !i.done(); ++i) {
|
||||
if (!frames.append(i))
|
||||
return nullptr;
|
||||
if (frames.length() == maxFrames)
|
||||
break;
|
||||
}
|
||||
|
||||
JS::StackDescription *desc = js_new<JS::StackDescription>();
|
||||
if (!desc)
|
||||
return nullptr;
|
||||
|
||||
desc->nframes = frames.length();
|
||||
desc->frames = frames.extractRawBuffer();
|
||||
return desc;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::FreeStackDescription(JSContext *cx, JS::StackDescription *desc)
|
||||
{
|
||||
for (size_t i = 0; i < desc->nframes; ++i)
|
||||
desc->frames[i].~FrameDescription();
|
||||
js_free(desc->frames);
|
||||
js_delete(desc);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class AutoPropertyDescArray
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
using mozilla::AddToHash;
|
||||
@ -399,7 +400,7 @@ bool
|
||||
SavedStacks::saveCurrentStack(JSContext *cx, MutableHandleSavedFrame frame, unsigned maxFrameCount)
|
||||
{
|
||||
JS_ASSERT(initialized());
|
||||
JS_ASSERT(&cx->compartment()->savedStacks() == this);
|
||||
assertSameCompartment(cx, this);
|
||||
|
||||
FrameIter iter(cx, FrameIter::ALL_CONTEXTS, FrameIter::GO_THROUGH_SAVED);
|
||||
return insertFrames(cx, iter, frame, maxFrameCount);
|
||||
@ -504,8 +505,11 @@ SavedStacks::insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFram
|
||||
if (iter.hasScript()) {
|
||||
JSScript *script = iter.script();
|
||||
jsbytecode *pc = iter.pc();
|
||||
if (!getLocation(cx, script, pc, &location))
|
||||
return false;
|
||||
{
|
||||
AutoCompartment ac(cx, iter.compartment());
|
||||
if (!cx->compartment()->savedStacks().getLocation(cx, script, pc, &location))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const char *filename = iter.scriptFilename();
|
||||
if (!filename)
|
||||
@ -595,13 +599,13 @@ SavedStacks::createFrameFromLookup(JSContext *cx, const SavedFrame::Lookup &look
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
JS_ASSERT(proto->compartment() == cx->compartment());
|
||||
assertSameCompartment(cx, proto);
|
||||
|
||||
RootedObject global(cx, cx->compartment()->maybeGlobal());
|
||||
if (!global)
|
||||
return nullptr;
|
||||
|
||||
JS_ASSERT(global->compartment() == cx->compartment());
|
||||
assertSameCompartment(cx, global);
|
||||
|
||||
RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto, global));
|
||||
if (!frameObj)
|
||||
@ -635,6 +639,12 @@ bool
|
||||
SavedStacks::getLocation(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
MutableHandleLocationValue locationp)
|
||||
{
|
||||
// We should only ever be caching location values for scripts in this
|
||||
// compartment. Otherwise, we would get dead cross-compartment scripts in
|
||||
// the cache because our compartment's sweep method isn't called when their
|
||||
// compartment gets collected.
|
||||
assertSameCompartment(cx, this, script);
|
||||
|
||||
PCKey key(script, pc);
|
||||
PCLocationMap::AddPtr p = pcLocationMap.lookupForAdd(key);
|
||||
|
||||
@ -666,4 +676,16 @@ SavedStacksMetadataCallback(JSContext *cx, JSObject **pmetadata)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
void
|
||||
CompartmentChecker::check(SavedStacks *stacks)
|
||||
{
|
||||
if (&compartment->savedStacks() != stacks) {
|
||||
printf("*** Compartment SavedStacks mismatch: %p vs. %p\n",
|
||||
(void *) &compartment->savedStacks(), stacks);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
#endif /* JS_CRASH_DIAGNOSTICS */
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -113,8 +113,8 @@ class SavedStacks {
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
private:
|
||||
SavedFrame::Set frames;
|
||||
JSObject *savedFrameProto;
|
||||
SavedFrame::Set frames;
|
||||
JSObject *savedFrameProto;
|
||||
|
||||
bool insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFrame frame,
|
||||
unsigned maxFrameCount = 0);
|
||||
|
@ -229,7 +229,7 @@ CloningFunctionForwarder(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!JS_WrapObject(cx, &argObj))
|
||||
return false;
|
||||
if (!xpc::NewFunctionForwarder(cx, JSID_VOIDHANDLE, argObj, innerOptions, args[i]))
|
||||
return nullptr;
|
||||
return false;
|
||||
} else if (!StackScopedClone(cx, cloneOptions, args[i])) {
|
||||
return false;
|
||||
}
|
||||
|
@ -54,14 +54,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
||||
"we end up with the appropriate constructor: " + c);
|
||||
is(Cu.unwaiveXrays(Cu.waiveXrays(new iwin[c]).constructor), iwin[c],
|
||||
"constructor property is set up right: " + c);
|
||||
is(Object.getPrototypeOf(new iwin[c]), iwin[c].prototype,
|
||||
let expectedProto = /Opaque/.test(new iwin[c]) ? iwin['Object'].prototype
|
||||
: iwin[c].prototype;
|
||||
is(Object.getPrototypeOf(new iwin[c]), expectedProto,
|
||||
"prototype is correct: " + c);
|
||||
is(global(new iwin[c]), iwin, "Got the right global: " + c);
|
||||
}
|
||||
|
||||
// Test Object in more detail.
|
||||
var num = new iwin.Object(4);
|
||||
is(num.valueOf(), 4, "primitive object construction works");
|
||||
is(Cu.waiveXrays(num).valueOf(), 4, "primitive object construction works");
|
||||
is(global(num), iwin, "correct global for num");
|
||||
var obj = new iwin.Object();
|
||||
obj.foo = 2;
|
||||
@ -105,26 +107,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
||||
ok(Object.getOwnPropertyNames(foopyFunction).indexOf('prototype') == -1, "Should not list prototype");
|
||||
ok(Object.getOwnPropertyNames(iwin.Array).indexOf('prototype') >= 0, "Should list prototype for standard constructor");
|
||||
|
||||
// Test interface objects that don't actually construct things.
|
||||
is(iwin.Math.tan(4.5), Math.tan(4.5), "Math.tan works");
|
||||
is(iwin.Math.E, Math.E, "Math.E works");
|
||||
var json = JSON.stringify({a: 2, b: 'hi', c: {d: 'there'}});
|
||||
is(global(iwin.JSON.parse(json)), iwin, "JSON rehydrated into the right context");
|
||||
is(iwin.JSON.stringify(iwin.JSON.parse(json)), json, "JSON composition identity holds");
|
||||
|
||||
// Test proxies.
|
||||
var targetObject = new iwin.Object();
|
||||
targetObject.foo = 9;
|
||||
var forwardingProxy = new iwin.Proxy(targetObject, new iwin.Object());
|
||||
is(global(forwardingProxy), iwin, "proxy global correct");
|
||||
is(forwardingProxy.foo, 9, "forwards correctly");
|
||||
is(Cu.waiveXrays(forwardingProxy).foo, 9, "forwards correctly");
|
||||
// NB: COW-implemented proxy handlers are super dangerous, and we should not
|
||||
// encourage them.
|
||||
var handler = {get: function(target, name) { return name * 2; }, __exposedProps__: {get: 'r'}};
|
||||
var doublingProxy = new iwin.Proxy(targetObject, handler);
|
||||
is(global(doublingProxy), iwin, "doubling proxy global correct");
|
||||
is(doublingProxy[3], 6, "Doubles correctly");
|
||||
is(doublingProxy[20], 40, "Doubles correctly");
|
||||
is(Cu.waiveXrays(doublingProxy)[3], 6, "Doubles correctly");
|
||||
is(Cu.waiveXrays(doublingProxy)[20], 40, "Doubles correctly");
|
||||
|
||||
// Test eval.
|
||||
var toEval = "({a: 2, b: {foo: 'bar'}, f: function() { return window; }})";
|
||||
@ -250,8 +245,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
||||
if (method.length == 0) {
|
||||
is(method.call(xray) + "", local.call(xray) + "",
|
||||
"Xray and local method results stringify identically");
|
||||
is(method.call(xray) + "", lookupCallable(xray.wrappedJSObject).call(xray.wrappedJSObject) + "",
|
||||
"Xray and waived method results stringify identically");
|
||||
|
||||
// If invoking this method returns something non-Xrayable, the
|
||||
// stringification is going to return [object Opaque]. This happens for
|
||||
// xrayedTypedArray.buffer, for instance, since we don't have Xrays
|
||||
// To ArrayBuffers. Just check for that case.
|
||||
if (!/Opaque/.test(method.call(xray))) {
|
||||
is(method.call(xray) + "",
|
||||
lookupCallable(xray.wrappedJSObject).call(xray.wrappedJSObject) + "",
|
||||
"Xray and waived method results stringify identically");
|
||||
}
|
||||
}
|
||||
}
|
||||
is(Object.getOwnPropertyNames(xrayProto).sort().toSource(),
|
||||
|
10
js/xpconnect/tests/unit/test_bug856067.js
Normal file
10
js/xpconnect/tests/unit/test_bug856067.js
Normal file
@ -0,0 +1,10 @@
|
||||
const Cu = Components.utils;
|
||||
|
||||
function run_test() {
|
||||
var sb = new Cu.Sandbox('http://www.example.com');
|
||||
let w = Cu.evalInSandbox('var w = WeakMap(); w.__proto__ = new Set(); w.foopy = 12; w', sb);
|
||||
do_check_eq(Object.getPrototypeOf(w), sb.Object.prototype);
|
||||
do_check_eq(Object.getOwnPropertyNames(w).length, 0);
|
||||
do_check_eq(w.wrappedJSObject.foopy, 12);
|
||||
do_check_eq(w.foopy, undefined);
|
||||
}
|
@ -35,6 +35,7 @@ support-files =
|
||||
[test_bug849730.js]
|
||||
[test_bug851895.js]
|
||||
[test_bug854558.js]
|
||||
[test_bug856067.js]
|
||||
[test_bug868675.js]
|
||||
[test_bug867486.js]
|
||||
[test_bug872772.js]
|
||||
|
@ -370,8 +370,10 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType,
|
||||
return &PermissiveXrayXPCWN::singleton;
|
||||
else if (xrayType == XrayForDOMObject)
|
||||
return &PermissiveXrayDOM::singleton;
|
||||
MOZ_ASSERT(xrayType == XrayForJSObject);
|
||||
return &PermissiveXrayJS::singleton;
|
||||
else if (xrayType == XrayForJSObject)
|
||||
return &PermissiveXrayJS::singleton;
|
||||
MOZ_ASSERT(xrayType == XrayForOpaqueObject);
|
||||
return &PermissiveXrayOpaque::singleton;
|
||||
}
|
||||
|
||||
// This is a security wrapper. Use the security versions and filter.
|
||||
@ -389,7 +391,7 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType,
|
||||
// functions exposed from the XBL scope. We could remove this exception,
|
||||
// if needed, by using ExportFunction to generate the content-side
|
||||
// representations of XBL methods.
|
||||
MOZ_ASSERT(xrayType == XrayForJSObject);
|
||||
MOZ_ASSERT(xrayType == XrayForJSObject || xrayType == XrayForOpaqueObject);
|
||||
if (originIsXBLScope)
|
||||
return &FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>::singleton;
|
||||
return &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
|
||||
@ -443,20 +445,6 @@ WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj,
|
||||
wrapper = &ChromeObjectWrapper::singleton;
|
||||
}
|
||||
|
||||
// Normally, a non-xrayable non-waived content object that finds itself in
|
||||
// a privileged scope is wrapped with a CrossCompartmentWrapper, even though
|
||||
// the lack of a waiver _really_ should give it an opaque wrapper. This is
|
||||
// a bit too entrenched to change for content-chrome, but we can at least fix
|
||||
// it for XBL scopes.
|
||||
//
|
||||
// See bug 843829.
|
||||
else if (targetSubsumesOrigin && !originSubsumesTarget &&
|
||||
!waiveXrayFlag && xrayType == NotXray &&
|
||||
IsContentXBLScope(target))
|
||||
{
|
||||
wrapper = &PermissiveXrayOpaque::singleton;
|
||||
}
|
||||
|
||||
//
|
||||
// Now, handle the regular cases.
|
||||
//
|
||||
|
@ -69,6 +69,8 @@ IsTypedArrayKey(JSProtoKey key)
|
||||
return key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray;
|
||||
}
|
||||
|
||||
bool SilentFailure(JSContext *cx, JS::HandleId id, const char *reason);
|
||||
|
||||
// Whitelist for the standard ES classes we can Xray to.
|
||||
static bool
|
||||
IsJSXraySupported(JSProtoKey key)
|
||||
@ -103,7 +105,14 @@ GetXrayType(JSObject *obj)
|
||||
if (IsJSXraySupported(standardProto))
|
||||
return XrayForJSObject;
|
||||
|
||||
return NotXray;
|
||||
// Modulo a few exceptions, everything else counts as an XrayWrapper to an
|
||||
// opaque object, which means that more-privileged code sees nothing from
|
||||
// the underlying object. This is very important for security. In some cases
|
||||
// though, we need to make an exception for compatibility.
|
||||
if (IsSandbox(obj))
|
||||
return NotXray;
|
||||
|
||||
return XrayForOpaqueObject;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
@ -486,6 +495,17 @@ public:
|
||||
MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
|
||||
}
|
||||
|
||||
virtual bool resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper, HandleObject wrapper,
|
||||
HandleObject holder, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE
|
||||
{
|
||||
bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder, id, desc);
|
||||
if (!ok || desc.object())
|
||||
return ok;
|
||||
|
||||
return SilentFailure(cx, id, "Object is not safely Xrayable");
|
||||
}
|
||||
|
||||
bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
Handle<JSPropertyDescriptor> existingDesc, bool *defined)
|
||||
@ -553,7 +573,7 @@ public:
|
||||
static OpaqueXrayTraits singleton;
|
||||
};
|
||||
|
||||
inline bool
|
||||
bool
|
||||
SilentFailure(JSContext *cx, HandleId id, const char *reason)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -563,7 +583,7 @@ SilentFailure(JSContext *cx, HandleId id, const char *reason)
|
||||
AutoFilename filename;
|
||||
unsigned line = 0;
|
||||
DescribeScriptedCaller(cx, &filename, &line);
|
||||
NS_WARNING(nsPrintfCString("Denied access to property |%s| on Xrayed Object: %s (@%s:%u)",
|
||||
NS_WARNING(nsPrintfCString("Silently denied access to property |%s|: %s (@%s:%u)",
|
||||
NS_LossyConvertUTF16toASCII(name).get(), reason,
|
||||
filename.get(), line).get());
|
||||
#endif
|
||||
|
6
layout/generic/crashtests/1037903.html
Normal file
6
layout/generic/crashtests/1037903.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="-moz-column-width: calc(15px);">
|
||||
<body>
|
||||
<video></video><audio style="box-decoration-break: clone; display: block; direction: rtl;"></audio>
|
||||
</body>
|
||||
</html>
|
@ -535,3 +535,4 @@ asserts(1-2) load 1015563-1.html
|
||||
asserts(1-2) load 1015563-2.html
|
||||
load outline-on-frameset.xhtml
|
||||
pref(font.size.inflation.minTwips,200) load 1032450.html
|
||||
load 1037903.html
|
||||
|
@ -176,7 +176,9 @@ GetBEndMarginClone(nsIFrame* aFrame,
|
||||
if (aFrame->StyleBorder()->mBoxDecorationBreak ==
|
||||
NS_STYLE_BOX_DECORATION_BREAK_CLONE) {
|
||||
nsCSSOffsetState os(aFrame, aRenderingContext, aContentArea.Width(aWritingMode));
|
||||
return os.ComputedLogicalMargin().BEnd(aWritingMode);
|
||||
return os.ComputedLogicalMargin().
|
||||
ConvertTo(aWritingMode,
|
||||
aFrame->GetWritingMode()).BEnd(aWritingMode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ XPIDL_SOURCES += [
|
||||
'nsIExternalProtocolHandler.idl',
|
||||
'nsIFileStreams.idl',
|
||||
'nsIFileURL.idl',
|
||||
'nsIForcePendingChannel.idl',
|
||||
'nsIIncrementalDownload.idl',
|
||||
'nsIInputStreamChannel.idl',
|
||||
'nsIInputStreamPump.idl',
|
||||
|
22
netwerk/base/public/nsIForcePendingChannel.idl
Normal file
22
netwerk/base/public/nsIForcePendingChannel.idl
Normal file
@ -0,0 +1,22 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* nsIForcePending interface exposes a function that enables overwriting of the normal
|
||||
* behavior for the channel's IsPending(), forcing 'true' to be returned.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(225ab092-1554-423a-9492-606f6db3b4fb)]
|
||||
interface nsIForcePendingChannel : nsISupports
|
||||
{
|
||||
|
||||
/**
|
||||
* forcePending(true) overrides the normal behavior for the
|
||||
* channel's IsPending(), forcing 'true' to be returned. A call to
|
||||
* forcePending(false) reverts IsPending() back to normal behavior.
|
||||
*/
|
||||
void forcePending(in boolean aForcePending);
|
||||
};
|
@ -9,6 +9,9 @@
|
||||
#include "nsFTPChannel.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsFtpProtocolHandler.h"
|
||||
#include "nsIEncodedChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIForcePendingChannel.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/unused.h"
|
||||
@ -57,7 +60,8 @@ NS_IMPL_ISUPPORTS(FTPChannelParent,
|
||||
nsIStreamListener,
|
||||
nsIParentChannel,
|
||||
nsIInterfaceRequestor,
|
||||
nsIRequestObserver)
|
||||
nsIRequestObserver,
|
||||
nsIChannelEventSink)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FTPChannelParent::PFTPChannelParent
|
||||
@ -114,13 +118,16 @@ FTPChannelParent::DoAsyncOpen(const URIParams& aURI,
|
||||
if (NS_FAILED(rv))
|
||||
return SendFailedAsyncOpen(rv);
|
||||
|
||||
mChannel = static_cast<nsFtpChannel*>(chan.get());
|
||||
mChannel = chan;
|
||||
|
||||
// later on mChannel may become an HTTP channel (we'll be redirected to one
|
||||
// if we're using a proxy), but for now this is safe
|
||||
nsFtpChannel* ftpChan = static_cast<nsFtpChannel*>(mChannel.get());
|
||||
|
||||
if (mPBOverride != kPBOverride_Unset) {
|
||||
mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
|
||||
ftpChan->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
|
||||
}
|
||||
|
||||
rv = mChannel->SetNotificationCallbacks(this);
|
||||
rv = ftpChan->SetNotificationCallbacks(this);
|
||||
if (NS_FAILED(rv))
|
||||
return SendFailedAsyncOpen(rv);
|
||||
|
||||
@ -128,16 +135,16 @@ FTPChannelParent::DoAsyncOpen(const URIParams& aURI,
|
||||
nsCOMPtr<nsIInputStream> upload = DeserializeInputStream(aUploadStream, fds);
|
||||
if (upload) {
|
||||
// contentType and contentLength are ignored
|
||||
rv = mChannel->SetUploadStream(upload, EmptyCString(), 0);
|
||||
rv = ftpChan->SetUploadStream(upload, EmptyCString(), 0);
|
||||
if (NS_FAILED(rv))
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
rv = mChannel->ResumeAt(aStartPos, aEntityID);
|
||||
rv = ftpChan->ResumeAt(aStartPos, aEntityID);
|
||||
if (NS_FAILED(rv))
|
||||
return SendFailedAsyncOpen(rv);
|
||||
|
||||
rv = mChannel->AsyncOpen(this, nullptr);
|
||||
rv = ftpChan->AsyncOpen(this, nullptr);
|
||||
if (NS_FAILED(rv))
|
||||
return SendFailedAsyncOpen(rv);
|
||||
|
||||
@ -154,7 +161,7 @@ FTPChannelParent::ConnectChannel(const uint32_t& channelId)
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mChannel = static_cast<nsFtpChannel*>(channel.get());
|
||||
mChannel = channel;
|
||||
|
||||
LOG((" found channel %p, rv=%08x", mChannel.get(), rv));
|
||||
|
||||
@ -240,7 +247,10 @@ FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
|
||||
|
||||
// Reset fake pending status in case OnStopRequest has already been called.
|
||||
if (mChannel) {
|
||||
mChannel->ForcePending(false);
|
||||
nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
|
||||
if (forcePendingIChan) {
|
||||
forcePendingIChan->ForcePending(false);
|
||||
}
|
||||
}
|
||||
|
||||
OnStopRequest(mChannel, nullptr, status);
|
||||
@ -297,14 +307,14 @@ FTPChannelParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||
resChan->GetEntityID(entityID);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(aRequest);
|
||||
PRTime lastModified = 0;
|
||||
nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(aRequest);
|
||||
if (ftpChan) {
|
||||
ftpChan->GetLastModifiedTime(&lastModified);
|
||||
} else {
|
||||
// Temporary hack: if we were redirected to use an HTTP channel (ie FTP is
|
||||
// using an HTTP proxy), cancel, as we don't support those redirects yet.
|
||||
aRequest->Cancel(NS_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
nsCOMPtr<nsIHttpChannelInternal> httpChan = do_QueryInterface(aRequest);
|
||||
if (httpChan) {
|
||||
httpChan->GetLastModifiedTime(&lastModified);
|
||||
}
|
||||
|
||||
URIParams uriparam;
|
||||
@ -499,7 +509,10 @@ FTPChannelParent::StartDiversion()
|
||||
|
||||
// Fake pending status in case OnStopRequest has already been called.
|
||||
if (mChannel) {
|
||||
mChannel->ForcePending(true);
|
||||
nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
|
||||
if (forcePendingIChan) {
|
||||
forcePendingIChan->ForcePending(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Call OnStartRequest for the "DivertTo" listener.
|
||||
@ -567,8 +580,10 @@ FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
|
||||
MOZ_RELEASE_ASSERT(mChannel);
|
||||
|
||||
mChannel->Cancel(aErrorCode);
|
||||
|
||||
mChannel->ForcePending(false);
|
||||
nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
|
||||
if (forcePendingIChan) {
|
||||
forcePendingIChan->ForcePending(false);
|
||||
}
|
||||
|
||||
bool isPending = false;
|
||||
nsresult rv = mChannel->IsPending(&isPending);
|
||||
@ -581,9 +596,15 @@ FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
|
||||
// Channel has already sent OnStartRequest to the child, so ensure that we
|
||||
// call it here if it hasn't already been called.
|
||||
if (!mDivertedOnStartRequest) {
|
||||
mChannel->ForcePending(true);
|
||||
nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
|
||||
if (forcePendingIChan) {
|
||||
forcePendingIChan->ForcePending(true);
|
||||
}
|
||||
mDivertToListener->OnStartRequest(mChannel, nullptr);
|
||||
mChannel->ForcePending(false);
|
||||
|
||||
if (forcePendingIChan) {
|
||||
forcePendingIChan->ForcePending(false);
|
||||
}
|
||||
}
|
||||
// If the channel is pending, it will call OnStopRequest itself; otherwise, do
|
||||
// it here.
|
||||
@ -598,6 +619,29 @@ FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FTPChannelParent::nsIChannelEventSink
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
FTPChannelParent::AsyncOnChannelRedirect(
|
||||
nsIChannel *oldChannel,
|
||||
nsIChannel *newChannel,
|
||||
uint32_t redirectFlags,
|
||||
nsIAsyncVerifyRedirectCallback* callback)
|
||||
{
|
||||
nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(newChannel);
|
||||
if (!ftpChan) {
|
||||
// when FTP is set to use HTTP proxying, we wind up getting redirected to an HTTP channel.
|
||||
nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(newChannel);
|
||||
if (!httpChan)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mChannel = newChannel;
|
||||
callback->OnRedirectVerifyCallback(NS_OK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//---------------------
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -24,6 +24,7 @@ class FTPChannelParent : public PFTPChannelParent
|
||||
, public nsIParentChannel
|
||||
, public nsIInterfaceRequestor
|
||||
, public ADivertableParentChannel
|
||||
, public nsIChannelEventSink
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -31,6 +32,7 @@ public:
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIPARENTCHANNEL
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
|
||||
FTPChannelParent(nsILoadContext* aLoadContext, PBOverrideStatus aOverrideStatus);
|
||||
|
||||
@ -77,7 +79,8 @@ protected:
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
|
||||
nsRefPtr<nsFtpChannel> mChannel;
|
||||
// if configured to use HTTP proxy for FTP, this can an an HTTP channel.
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
|
||||
bool mIPCClosed;
|
||||
|
||||
|
@ -29,7 +29,8 @@ NS_IMPL_ISUPPORTS_INHERITED(nsFtpChannel,
|
||||
nsIUploadChannel,
|
||||
nsIResumableChannel,
|
||||
nsIFTPChannel,
|
||||
nsIProxiedChannel)
|
||||
nsIProxiedChannel,
|
||||
nsIForcePendingChannel)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@ -199,7 +200,7 @@ nsFtpChannel::GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult)
|
||||
aResult = mFTPEventSink;
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
nsFtpChannel::ForcePending(bool aForcePending)
|
||||
{
|
||||
// Set true here so IsPending will return true.
|
||||
@ -207,6 +208,8 @@ nsFtpChannel::ForcePending(bool aForcePending)
|
||||
// OnStopRequest can be called in the parent before callbacks are diverted
|
||||
// back from the child to the listener in the parent.
|
||||
mForcePending = aForcePending;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIFTPChannel.h"
|
||||
#include "nsIForcePendingChannel.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsIProxyInfo.h"
|
||||
#include "nsIProxiedChannel.h"
|
||||
@ -23,7 +24,8 @@ class nsFtpChannel : public nsBaseChannel,
|
||||
public nsIFTPChannel,
|
||||
public nsIUploadChannel,
|
||||
public nsIResumableChannel,
|
||||
public nsIProxiedChannel
|
||||
public nsIProxiedChannel,
|
||||
public nsIForcePendingChannel
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
@ -88,8 +90,8 @@ public:
|
||||
// Helper function for getting the nsIFTPEventSink.
|
||||
void GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult);
|
||||
|
||||
public: /* Internal Necko use only. */
|
||||
void ForcePending(bool aForcePending);
|
||||
public:
|
||||
NS_IMETHOD ForcePending(bool aForcePending);
|
||||
|
||||
protected:
|
||||
virtual ~nsFtpChannel() {}
|
||||
|
@ -2858,10 +2858,14 @@ Http2Session::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
|
||||
// this transaction has done its work of setting up a tunnel, let
|
||||
// the connection manager queue it if necessary
|
||||
trans->SetDontRouteViaWildCard(true);
|
||||
trans->EnableKeepAlive();
|
||||
|
||||
if (FindTunnelCount(ci) < gHttpHandler->MaxConnectionsPerOrigin()) {
|
||||
LOG3(("Http2Session::DispatchOnTunnel %p create on new tunnel %s",
|
||||
this, ci->HashKey().get()));
|
||||
// The connect transaction will hold onto the underlying http
|
||||
// transaction so that an auth created by the connect can be mappped
|
||||
// to the correct security callbacks
|
||||
nsRefPtr<SpdyConnectTransaction> connectTrans =
|
||||
new SpdyConnectTransaction(ci, aCallbacks,
|
||||
trans->Caps(), trans, this);
|
||||
@ -2870,13 +2874,14 @@ Http2Session::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
|
||||
Http2Stream *tunnel = mStreamTransactionHash.Get(connectTrans);
|
||||
MOZ_ASSERT(tunnel);
|
||||
RegisterTunnel(tunnel);
|
||||
} else {
|
||||
// requeue it. The connection manager is responsible for actually putting
|
||||
// this on the tunnel connection with the specific ci now that it
|
||||
// has DontRouteViaWildCard set.
|
||||
LOG3(("Http2Session::DispatchOnTunnel %p trans=%p queue in connection manager",
|
||||
this, trans));
|
||||
gHttpHandler->InitiateTransaction(trans, trans->Priority());
|
||||
}
|
||||
|
||||
// requeue it. The connection manager is responsible for actually putting
|
||||
// this on the tunnel connection with the specific ci now that it
|
||||
// has DontRouteViaWildCard set.
|
||||
trans->EnableKeepAlive();
|
||||
gHttpHandler->InitiateTransaction(trans, trans->Priority());
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,6 +69,7 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
|
||||
, mTotalRead(0)
|
||||
, mPushSource(nullptr)
|
||||
, mIsTunnel(false)
|
||||
, mPlainTextTunnel(false)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
@ -219,7 +220,7 @@ Http2Stream::ReadSegments(nsAHttpSegmentReader *reader,
|
||||
}
|
||||
|
||||
// WriteSegments() is used to read data off the socket. Generally this is
|
||||
// just a call through to the associate nsHttpTransaciton for this stream
|
||||
// just a call through to the associated nsHttpTransaction for this stream
|
||||
// for the remaining data bytes indicated by the current DATA frame.
|
||||
|
||||
nsresult
|
||||
@ -862,9 +863,11 @@ Http2Stream::ConvertResponseHeaders(Http2Decompressor *decompressor,
|
||||
|
||||
if (mIsTunnel) {
|
||||
nsresult errcode;
|
||||
if (status.ToInteger(&errcode) != 200) {
|
||||
LOG3(("Http2Stream %p Tunnel not 200", this));
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
int32_t code = status.ToInteger(&errcode);
|
||||
LOG3(("Http2Stream %p Tunnel Response code %d", this, code));
|
||||
if ((code / 100) != 2) {
|
||||
MapStreamToPlainText();
|
||||
}
|
||||
}
|
||||
|
||||
@ -875,12 +878,14 @@ Http2Stream::ConvertResponseHeaders(Http2Decompressor *decompressor,
|
||||
Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_RATIO, ratio);
|
||||
}
|
||||
|
||||
// The decoding went ok. Now we can customize and clean up.
|
||||
|
||||
aHeadersIn.Truncate();
|
||||
aHeadersOut.Append("X-Firefox-Spdy: " NS_HTTP2_DRAFT_TOKEN "\r\n\r\n");
|
||||
LOG (("decoded response headers are:\n%s", aHeadersOut.BeginReading()));
|
||||
if (mIsTunnel) {
|
||||
if (mIsTunnel && !mPlainTextTunnel) {
|
||||
aHeadersOut.Truncate();
|
||||
LOG(("SpdyStream3::ConvertHeaders %p 0x%X headers removed for tunnel\n",
|
||||
LOG(("Http2Stream::ConvertHeaders %p 0x%X headers removed for tunnel\n",
|
||||
this, mStreamID));
|
||||
}
|
||||
return NS_OK;
|
||||
@ -1201,6 +1206,15 @@ Http2Stream::ClearTransactionsBlockedOnTunnel()
|
||||
gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo());
|
||||
}
|
||||
|
||||
void
|
||||
Http2Stream::MapStreamToPlainText()
|
||||
{
|
||||
nsRefPtr<SpdyConnectTransaction> qiTrans(mTransaction->QuerySpdyConnectTransaction());
|
||||
MOZ_ASSERT(qiTrans);
|
||||
mPlainTextTunnel = true;
|
||||
qiTrans->ForcePlainText();
|
||||
}
|
||||
|
||||
void
|
||||
Http2Stream::MapStreamToHttpConnection()
|
||||
{
|
||||
|
@ -281,9 +281,11 @@ public:
|
||||
bool IsTunnel() { return mIsTunnel; }
|
||||
private:
|
||||
void ClearTransactionsBlockedOnTunnel();
|
||||
void MapStreamToPlainText();
|
||||
void MapStreamToHttpConnection();
|
||||
|
||||
bool mIsTunnel;
|
||||
bool mPlainTextTunnel;
|
||||
};
|
||||
|
||||
} // namespace mozilla::net
|
||||
|
@ -164,6 +164,7 @@ NS_INTERFACE_MAP_BEGIN(HttpBaseChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIForcePendingChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRedirectHistory)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
|
||||
@ -1638,6 +1639,18 @@ HttpBaseChannel::ForcePending(bool aForcePending)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::GetLastModifiedTime(PRTime* lastModifiedTime)
|
||||
{
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
uint32_t lastMod;
|
||||
mResponseHead->GetLastModifiedValue(&lastMod);
|
||||
*lastModifiedTime = lastMod;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpBaseChannel::nsISupportsPriority
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsHttpHandler.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIForcePendingChannel.h"
|
||||
#include "nsIRedirectHistory.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsIUploadChannel2.h"
|
||||
@ -63,6 +64,7 @@ class HttpBaseChannel : public nsHashPropertyBag
|
||||
, public nsITraceableChannel
|
||||
, public PrivateBrowsingChannel<HttpBaseChannel>
|
||||
, public nsITimedChannel
|
||||
, public nsIForcePendingChannel
|
||||
{
|
||||
protected:
|
||||
virtual ~HttpBaseChannel();
|
||||
@ -173,6 +175,7 @@ public:
|
||||
NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable);
|
||||
NS_IMETHOD AddRedirect(nsIPrincipal *aRedirect);
|
||||
NS_IMETHOD ForcePending(bool aForcePending);
|
||||
NS_IMETHOD GetLastModifiedTime(PRTime* lastModifiedTime);
|
||||
|
||||
inline void CleanRedirectCacheChainIfNecessary()
|
||||
{
|
||||
|
@ -2527,10 +2527,14 @@ SpdySession3::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
|
||||
// this transaction has done its work of setting up a tunnel, let
|
||||
// the connection manager queue it if necessary
|
||||
trans->SetDontRouteViaWildCard(true);
|
||||
trans->EnableKeepAlive();
|
||||
|
||||
if (FindTunnelCount(ci) < gHttpHandler->MaxConnectionsPerOrigin()) {
|
||||
LOG3(("SpdySession3::DispatchOnTunnel %p create on new tunnel %s",
|
||||
this, ci->HashKey().get()));
|
||||
// The connect transaction will hold onto the underlying http
|
||||
// transaction so that an auth created by the connect can be mappped
|
||||
// to the correct security callbacks
|
||||
nsRefPtr<SpdyConnectTransaction> connectTrans =
|
||||
new SpdyConnectTransaction(ci, aCallbacks,
|
||||
trans->Caps(), trans, this);
|
||||
@ -2539,13 +2543,14 @@ SpdySession3::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
|
||||
SpdyStream3 *tunnel = mStreamTransactionHash.Get(connectTrans);
|
||||
MOZ_ASSERT(tunnel);
|
||||
RegisterTunnel(tunnel);
|
||||
} else {
|
||||
// requeue it. The connection manager is responsible for actually putting
|
||||
// this on the tunnel connection with the specific ci now that it
|
||||
// has DontRouteViaWildCard set.
|
||||
LOG3(("SpdySession3::DispatchOnTunnel %p trans=%p queue in connection manager",
|
||||
this, trans));
|
||||
gHttpHandler->InitiateTransaction(trans, trans->Priority());
|
||||
}
|
||||
|
||||
// requeue it. The connection manager is responsible for actually putting
|
||||
// this on the tunnel connection with the specific ci now that it
|
||||
// has DontRouteViaWildCard set.
|
||||
trans->EnableKeepAlive();
|
||||
gHttpHandler->InitiateTransaction(trans, trans->Priority());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -2659,10 +2659,14 @@ SpdySession31::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
|
||||
// this transaction has done its work of setting up a tunnel, let
|
||||
// the connection manager queue it if necessary
|
||||
trans->SetDontRouteViaWildCard(true);
|
||||
trans->EnableKeepAlive();
|
||||
|
||||
if (FindTunnelCount(ci) < gHttpHandler->MaxConnectionsPerOrigin()) {
|
||||
LOG3(("SpdySession31::DispatchOnTunnel %p create on new tunnel %s",
|
||||
this, ci->HashKey().get()));
|
||||
// The connect transaction will hold onto the underlying http
|
||||
// transaction so that an auth created by the connect can be mappped
|
||||
// to the correct security callbacks
|
||||
nsRefPtr<SpdyConnectTransaction> connectTrans =
|
||||
new SpdyConnectTransaction(ci, aCallbacks,
|
||||
trans->Caps(), trans, this);
|
||||
@ -2671,13 +2675,14 @@ SpdySession31::DispatchOnTunnel(nsAHttpTransaction *aHttpTransaction,
|
||||
SpdyStream31 *tunnel = mStreamTransactionHash.Get(connectTrans);
|
||||
MOZ_ASSERT(tunnel);
|
||||
RegisterTunnel(tunnel);
|
||||
} else {
|
||||
// requeue it. The connection manager is responsible for actually putting
|
||||
// this on the tunnel connection with the specific ci now that it
|
||||
// has DontRouteViaWildCard set.
|
||||
LOG3(("SpdySession31::DispatchOnTunnel %p trans=%p queue in connection manager",
|
||||
this, trans));
|
||||
gHttpHandler->InitiateTransaction(trans, trans->Priority());
|
||||
}
|
||||
|
||||
// requeue it. The connection manager is responsible for actually putting
|
||||
// this on the tunnel connection with the specific ci now that it
|
||||
// has DontRouteViaWildCard set.
|
||||
trans->EnableKeepAlive();
|
||||
gHttpHandler->InitiateTransaction(trans, trans->Priority());
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -72,6 +72,7 @@ SpdyStream3::SpdyStream3(nsAHttpTransaction *httpTransaction,
|
||||
, mTotalRead(0)
|
||||
, mPushSource(nullptr)
|
||||
, mIsTunnel(false)
|
||||
, mPlainTextTunnel(false)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
@ -194,7 +195,7 @@ SpdyStream3::ReadSegments(nsAHttpSegmentReader *reader,
|
||||
}
|
||||
|
||||
// WriteSegments() is used to read data off the socket. Generally this is
|
||||
// just a call through to the associate nsHttpTransaciton for this stream
|
||||
// just a call through to the associated nsHttpTransaction for this stream
|
||||
// for the remaining data bytes indicated by the current DATA frame.
|
||||
|
||||
nsresult
|
||||
@ -1277,6 +1278,8 @@ SpdyStream3::ConvertHeaders(nsACString &aHeadersOut)
|
||||
nvpair += 4;
|
||||
} while (lastHeaderByte >= nvpair);
|
||||
|
||||
// The decoding went ok. Now we can customize and clean up.
|
||||
|
||||
aHeadersOut.AppendLiteral("X-Firefox-Spdy: 3\r\n\r\n");
|
||||
LOG (("decoded response headers are:\n%s",
|
||||
aHeadersOut.BeginReading()));
|
||||
@ -1286,7 +1289,7 @@ SpdyStream3::ConvertHeaders(nsACString &aHeadersOut)
|
||||
mDecompressBufferSize = 0;
|
||||
mDecompressBufferUsed = 0;
|
||||
|
||||
if (mIsTunnel) {
|
||||
if (mIsTunnel && !mPlainTextTunnel) {
|
||||
aHeadersOut.Truncate();
|
||||
LOG(("SpdyStream3::ConvertHeaders %p 0x%X headers removed for tunnel\n",
|
||||
this, mStreamID));
|
||||
@ -1371,18 +1374,18 @@ SpdyStream3::SetFullyOpen()
|
||||
MOZ_ASSERT(!mFullyOpen);
|
||||
mFullyOpen = 1;
|
||||
if (mIsTunnel) {
|
||||
int32_t code = 0;
|
||||
nsDependentCSubstring statusSubstring;
|
||||
nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"),
|
||||
statusSubstring);
|
||||
nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"), statusSubstring);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCString status(statusSubstring);
|
||||
nsresult errcode;
|
||||
code = status.ToInteger(&errcode);
|
||||
}
|
||||
|
||||
if (status.ToInteger(&errcode) != 200) {
|
||||
LOG3(("SpdyStream3::SetFullyOpen %p Tunnel not 200", this));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOG3(("SpdyStream3::SetFullyOpen %p Tunnel 200 OK", this));
|
||||
LOG3(("SpdyStream3::SetFullyOpen %p Tunnel Response code %d", this, code));
|
||||
if ((code / 100) != 2) {
|
||||
MapStreamToPlainText();
|
||||
}
|
||||
|
||||
MapStreamToHttpConnection();
|
||||
@ -1561,6 +1564,15 @@ SpdyStream3::ClearTransactionsBlockedOnTunnel()
|
||||
gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo());
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream3::MapStreamToPlainText()
|
||||
{
|
||||
nsRefPtr<SpdyConnectTransaction> qiTrans(mTransaction->QuerySpdyConnectTransaction());
|
||||
MOZ_ASSERT(qiTrans);
|
||||
mPlainTextTunnel = true;
|
||||
qiTrans->ForcePlainText();
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream3::MapStreamToHttpConnection()
|
||||
{
|
||||
|
@ -257,9 +257,11 @@ public:
|
||||
bool IsTunnel() { return mIsTunnel; }
|
||||
private:
|
||||
void ClearTransactionsBlockedOnTunnel();
|
||||
void MapStreamToPlainText();
|
||||
void MapStreamToHttpConnection();
|
||||
|
||||
bool mIsTunnel;
|
||||
bool mPlainTextTunnel;
|
||||
};
|
||||
|
||||
}} // namespace mozilla::net
|
||||
|
@ -70,6 +70,7 @@ SpdyStream31::SpdyStream31(nsAHttpTransaction *httpTransaction,
|
||||
, mTotalRead(0)
|
||||
, mPushSource(nullptr)
|
||||
, mIsTunnel(false)
|
||||
, mPlainTextTunnel(false)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
@ -199,7 +200,7 @@ SpdyStream31::ReadSegments(nsAHttpSegmentReader *reader,
|
||||
}
|
||||
|
||||
// WriteSegments() is used to read data off the socket. Generally this is
|
||||
// just a call through to the associate nsHttpTransaciton for this stream
|
||||
// just a call through to the associated nsHttpTransaction for this stream
|
||||
// for the remaining data bytes indicated by the current DATA frame.
|
||||
|
||||
nsresult
|
||||
@ -1293,6 +1294,8 @@ SpdyStream31::ConvertHeaders(nsACString &aHeadersOut)
|
||||
nvpair += 4;
|
||||
} while (lastHeaderByte >= nvpair);
|
||||
|
||||
// The decoding went ok. Now we can customize and clean up.
|
||||
|
||||
aHeadersOut.AppendLiteral("X-Firefox-Spdy: 3.1\r\n\r\n");
|
||||
LOG (("decoded response headers are:\n%s",
|
||||
aHeadersOut.BeginReading()));
|
||||
@ -1302,7 +1305,7 @@ SpdyStream31::ConvertHeaders(nsACString &aHeadersOut)
|
||||
mDecompressBufferSize = 0;
|
||||
mDecompressBufferUsed = 0;
|
||||
|
||||
if (mIsTunnel) {
|
||||
if (mIsTunnel && !mPlainTextTunnel) {
|
||||
aHeadersOut.Truncate();
|
||||
LOG(("SpdyStream31::ConvertHeaders %p 0x%X headers removed for tunnel\n",
|
||||
this, mStreamID));
|
||||
@ -1385,18 +1388,18 @@ SpdyStream31::SetFullyOpen()
|
||||
MOZ_ASSERT(!mFullyOpen);
|
||||
mFullyOpen = 1;
|
||||
if (mIsTunnel) {
|
||||
int32_t code = 0;
|
||||
nsDependentCSubstring statusSubstring;
|
||||
nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"),
|
||||
statusSubstring);
|
||||
nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"), statusSubstring);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCString status(statusSubstring);
|
||||
nsresult errcode;
|
||||
code = status.ToInteger(&errcode);
|
||||
}
|
||||
|
||||
if (status.ToInteger(&errcode) != 200) {
|
||||
LOG3(("SpdyStream31::SetFullyOpen %p Tunnel not 200", this));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOG3(("SpdyStream31::SetFullyOpen %p Tunnel 200 OK", this));
|
||||
LOG3(("SpdyStream31::SetFullyOpen %p Tunnel Response code %d", this, code));
|
||||
if ((code / 100) != 2) {
|
||||
MapStreamToPlainText();
|
||||
}
|
||||
|
||||
MapStreamToHttpConnection();
|
||||
@ -1585,6 +1588,15 @@ SpdyStream31::ClearTransactionsBlockedOnTunnel()
|
||||
gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo());
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream31::MapStreamToPlainText()
|
||||
{
|
||||
nsRefPtr<SpdyConnectTransaction> qiTrans(mTransaction->QuerySpdyConnectTransaction());
|
||||
MOZ_ASSERT(qiTrans);
|
||||
mPlainTextTunnel = true;
|
||||
qiTrans->ForcePlainText();
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream31::MapStreamToHttpConnection()
|
||||
{
|
||||
|
@ -252,9 +252,11 @@ public:
|
||||
bool IsTunnel() { return mIsTunnel; }
|
||||
private:
|
||||
void ClearTransactionsBlockedOnTunnel();
|
||||
void MapStreamToPlainText();
|
||||
void MapStreamToHttpConnection();
|
||||
|
||||
bool mIsTunnel;
|
||||
bool mPlainTextTunnel;
|
||||
};
|
||||
|
||||
}} // namespace mozilla::net
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "nsISocketProviderService.h"
|
||||
#include "nsISSLSocketControl.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "nsNetAddr.h"
|
||||
#include "prerror.h"
|
||||
#include "prio.h"
|
||||
@ -825,7 +826,7 @@ private:
|
||||
SpdyConnectTransaction::SpdyConnectTransaction(nsHttpConnectionInfo *ci,
|
||||
nsIInterfaceRequestor *callbacks,
|
||||
uint32_t caps,
|
||||
nsAHttpTransaction *trans,
|
||||
nsHttpTransaction *trans,
|
||||
nsAHttpConnection *session)
|
||||
: NullHttpTransaction(ci, callbacks, caps | NS_HTTP_ALLOW_KEEPALIVE)
|
||||
, mConnectStringOffset(0)
|
||||
@ -837,12 +838,14 @@ SpdyConnectTransaction::SpdyConnectTransaction(nsHttpConnectionInfo *ci,
|
||||
, mOutputDataSize(0)
|
||||
, mOutputDataUsed(0)
|
||||
, mOutputDataOffset(0)
|
||||
, mForcePlainText(false)
|
||||
{
|
||||
LOG(("SpdyConnectTransaction ctor %p\n", this));
|
||||
|
||||
mTimestampSyn = TimeStamp::Now();
|
||||
mRequestHead = new nsHttpRequestHead();
|
||||
nsHttpConnection::MakeConnectString(trans, mRequestHead, mConnectString);
|
||||
mDrivingTransaction = trans;
|
||||
}
|
||||
|
||||
SpdyConnectTransaction::~SpdyConnectTransaction()
|
||||
@ -851,6 +854,24 @@ SpdyConnectTransaction::~SpdyConnectTransaction()
|
||||
if (mRequestHead) {
|
||||
delete mRequestHead;
|
||||
}
|
||||
|
||||
if (mDrivingTransaction) {
|
||||
// requeue it I guess. This should be gone.
|
||||
gHttpHandler->InitiateTransaction(mDrivingTransaction,
|
||||
mDrivingTransaction->Priority());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpdyConnectTransaction::ForcePlainText()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
MOZ_ASSERT(!mInputDataUsed && !mInputDataSize && !mInputDataOffset);
|
||||
MOZ_ASSERT(!mForcePlainText);
|
||||
MOZ_ASSERT(!mTunnelTransport, "call before mapstreamtohttpconnection");
|
||||
|
||||
mForcePlainText = true;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
@ -880,10 +901,23 @@ SpdyConnectTransaction::MapStreamToHttpConnection(nsISocketTransport *aTransport
|
||||
true, callbacks,
|
||||
PR_MillisecondsToInterval(
|
||||
static_cast<uint32_t>(rtt.ToMilliseconds())));
|
||||
mTunneledConn->SetupSecondaryTLS();
|
||||
mTunneledConn->SetInSpdyTunnel(true);
|
||||
if (mForcePlainText) {
|
||||
mTunneledConn->ForcePlainText();
|
||||
} else {
|
||||
mTunneledConn->SetupSecondaryTLS();
|
||||
mTunneledConn->SetInSpdyTunnel(true);
|
||||
}
|
||||
|
||||
gHttpHandler->ConnMgr()->ReclaimConnection(mTunneledConn);
|
||||
// make the originating transaction stick to the tunneled conn
|
||||
nsRefPtr<nsAHttpConnection> wrappedConn =
|
||||
gHttpHandler->ConnMgr()->MakeConnectionHandle(mTunneledConn);
|
||||
mDrivingTransaction->SetConnection(wrappedConn);
|
||||
mDrivingTransaction->MakeSticky();
|
||||
|
||||
// jump the priority and start the dispatcher
|
||||
gHttpHandler->InitiateTransaction(
|
||||
mDrivingTransaction, nsISupportsPriority::PRIORITY_HIGHEST - 60);
|
||||
mDrivingTransaction = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -933,7 +967,8 @@ SpdyConnectTransaction::ReadSegments(nsAHttpSegmentReader *reader,
|
||||
uint32_t *countRead)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
LOG(("SpdyConnectTransaction::ReadSegments %p count %d\n", this, count));
|
||||
LOG(("SpdyConnectTransaction::ReadSegments %p count %d conn %p\n",
|
||||
this, count, mTunneledConn.get()));
|
||||
|
||||
mSegmentReader = reader;
|
||||
|
||||
@ -962,6 +997,17 @@ SpdyConnectTransaction::ReadSegments(nsAHttpSegmentReader *reader,
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
if (mForcePlainText) {
|
||||
// this path just ignores sending the request so that we can
|
||||
// send a synthetic reply in writesegments()
|
||||
LOG(("SpdyConnectTransaciton::ReadSegments %p dropping %d output bytes "
|
||||
"due to synthetic reply\n", this, mOutputDataUsed - mOutputDataOffset));
|
||||
*countRead = mOutputDataUsed - mOutputDataOffset;
|
||||
mOutputDataOffset = mOutputDataUsed = 0;
|
||||
mTunneledConn->DontReuse();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*countRead = 0;
|
||||
Flush(count, countRead);
|
||||
if (!mTunnelStreamOut->mCallback) {
|
||||
@ -1020,7 +1066,7 @@ SpdyConnectTransaction::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||
count, countWritten);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
LOG(("SpdyConnectTransaction::Flush %p Error %x\n", this, rv));
|
||||
LOG(("SpdyConnectTransaction::WriteSegments wrapped writer %p Error %x\n", this, rv));
|
||||
CreateShimError(rv);
|
||||
}
|
||||
return rv;
|
||||
|
@ -175,12 +175,15 @@ public:
|
||||
SpdyConnectTransaction(nsHttpConnectionInfo *ci,
|
||||
nsIInterfaceRequestor *callbacks,
|
||||
uint32_t caps,
|
||||
nsAHttpTransaction *trans,
|
||||
nsHttpTransaction *trans,
|
||||
nsAHttpConnection *session);
|
||||
~SpdyConnectTransaction();
|
||||
|
||||
SpdyConnectTransaction *QuerySpdyConnectTransaction() { return this; }
|
||||
|
||||
// A transaction is forced into plaintext when it is intended to be used as a CONNECT
|
||||
// tunnel but the setup fails. The plaintext only carries the CONNECT error.
|
||||
void ForcePlainText();
|
||||
void MapStreamToHttpConnection(nsISocketTransport *aTransport,
|
||||
nsHttpConnectionInfo *aConnInfo);
|
||||
|
||||
@ -215,6 +218,7 @@ private:
|
||||
uint32_t mOutputDataUsed;
|
||||
uint32_t mOutputDataOffset;
|
||||
|
||||
bool mForcePlainText;
|
||||
TimeStamp mTimestampSyn;
|
||||
nsRefPtr<nsHttpConnectionInfo> mConnInfo;
|
||||
|
||||
@ -226,6 +230,7 @@ private:
|
||||
nsRefPtr<SocketTransportShim> mTunnelTransport;
|
||||
nsRefPtr<InputStreamShim> mTunnelStreamIn;
|
||||
nsRefPtr<OutputStreamShim> mTunnelStreamOut;
|
||||
nsRefPtr<nsHttpTransaction> mDrivingTransaction;
|
||||
};
|
||||
|
||||
}} // namespace mozilla::net
|
||||
|
@ -48,7 +48,7 @@ private:
|
||||
bool UsingSSL() const { return mUsingSSL; }
|
||||
|
||||
bool UsingHttpProxy() const
|
||||
{ return !!(mProxyInfo && !nsCRT::strcmp(mProxyInfo->Type(), "http")); }
|
||||
{ return mProxyInfo && (mProxyInfo->IsHTTP() || mProxyInfo->IsHTTPS()); }
|
||||
|
||||
nsresult PrepareForAuthentication(bool proxyAuth);
|
||||
nsresult GenCredsAndSetEntry(nsIHttpAuthenticator *, bool proxyAuth,
|
||||
|
@ -68,6 +68,7 @@ nsHttpConnection::nsHttpConnection()
|
||||
, mProxyConnectInProgress(false)
|
||||
, mExperienced(false)
|
||||
, mInSpdyTunnel(false)
|
||||
, mForcePlainText(false)
|
||||
, mHttp1xTransactionCount(0)
|
||||
, mRemainingConnectionUses(0xffffffff)
|
||||
, mClassification(nsAHttpTransaction::CLASS_GENERAL)
|
||||
@ -460,7 +461,7 @@ nsHttpConnection::SetupSSL()
|
||||
// of this function
|
||||
mNPNComplete = true;
|
||||
|
||||
if (!mConnInfo->FirstHopSSL()) {
|
||||
if (!mConnInfo->FirstHopSSL() || mForcePlainText) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -111,6 +111,13 @@ public:
|
||||
return mConnInfo->UsingHttpsProxy() && !mTLSFilter && mConnInfo->UsingConnect();
|
||||
}
|
||||
|
||||
// A connection is forced into plaintext when it is intended to be used as a CONNECT
|
||||
// tunnel but the setup fails. The plaintext only carries the CONNECT error.
|
||||
void ForcePlainText()
|
||||
{
|
||||
mForcePlainText = true;
|
||||
}
|
||||
|
||||
nsISocketTransport *Transport() { return mSocketTransport; }
|
||||
nsAHttpTransaction *Transaction() { return mTransaction; }
|
||||
nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; }
|
||||
@ -123,7 +130,7 @@ public:
|
||||
nsIAsyncInputStream **,
|
||||
nsIAsyncOutputStream **);
|
||||
void GetSecurityInfo(nsISupports **);
|
||||
bool IsPersistent() { return IsKeepAlive(); }
|
||||
bool IsPersistent() { return IsKeepAlive() && !mDontReuse; }
|
||||
bool IsReused();
|
||||
void SetIsReusedAfter(uint32_t afterMilliseconds);
|
||||
nsresult PushBack(const char *data, uint32_t length);
|
||||
@ -283,6 +290,7 @@ private:
|
||||
bool mProxyConnectInProgress;
|
||||
bool mExperienced;
|
||||
bool mInSpdyTunnel;
|
||||
bool mForcePlainText;
|
||||
|
||||
// The number of <= HTTP/1.1 transactions performed on this connection. This
|
||||
// excludes spdy transactions.
|
||||
|
@ -1984,10 +1984,21 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
||||
|
||||
if (conn) {
|
||||
MOZ_ASSERT(trans->Caps() & NS_HTTP_STICKY_CONNECTION);
|
||||
MOZ_ASSERT(((int32_t)ent->mActiveConns.IndexOf(conn)) != -1,
|
||||
"Sticky Connection Not In Active List");
|
||||
LOG(("nsHttpConnectionMgr::ProcessNewTransaction trans=%p "
|
||||
"sticky connection=%p\n", trans, conn.get()));
|
||||
|
||||
if (static_cast<int32_t>(ent->mActiveConns.IndexOf(conn)) == -1) {
|
||||
LOG(("nsHttpConnectionMgr::ProcessNewTransaction trans=%p "
|
||||
"sticky connection=%p needs to go on the active list\n", trans, conn.get()));
|
||||
|
||||
// make sure it isn't on the idle list - we expect this to be an
|
||||
// unknown fresh connection
|
||||
MOZ_ASSERT(static_cast<int32_t>(ent->mIdleConns.IndexOf(conn)) == -1);
|
||||
MOZ_ASSERT(!conn->IsExperienced());
|
||||
|
||||
AddActiveConn(conn, ent); // make it active
|
||||
}
|
||||
|
||||
trans->SetConnection(nullptr);
|
||||
rv = DispatchTransaction(ent, trans, conn);
|
||||
} else {
|
||||
|
@ -405,6 +405,12 @@ private:
|
||||
|
||||
nsHttpConnection *mConn;
|
||||
};
|
||||
public:
|
||||
static nsAHttpConnection *MakeConnectionHandle(nsHttpConnection *aWrapped)
|
||||
{
|
||||
return new nsConnectionHandle(aWrapped);
|
||||
}
|
||||
private:
|
||||
|
||||
// nsHalfOpenSocket is used to hold the state of an opening TCP socket
|
||||
// while we wait for it to establish and bind it to a connection
|
||||
|
@ -109,6 +109,7 @@ public:
|
||||
void SetDontRouteViaWildCard(bool var) { mDontRouteViaWildCard = var; }
|
||||
bool DontRouteViaWildCard() { return mDontRouteViaWildCard; }
|
||||
void EnableKeepAlive() { mCaps |= NS_HTTP_ALLOW_KEEPALIVE; }
|
||||
void MakeSticky() { mCaps |= NS_HTTP_STICKY_CONNECTION; }
|
||||
|
||||
// SetPriority() may only be used by the connection manager.
|
||||
void SetPriority(int32_t priority) { mPriority = priority; }
|
||||
|
@ -200,10 +200,5 @@ interface nsIHttpChannelInternal : nsISupports
|
||||
*/
|
||||
void addRedirect(in nsIPrincipal aPrincipal);
|
||||
|
||||
/**
|
||||
* ForcePending(true) overrides the normal behavior for the
|
||||
* channel's IsPending(), forcing 'true' to be returned. A call to
|
||||
* ForcePending(false) reverts IsPending() back to normal behavior.
|
||||
*/
|
||||
void ForcePending(in boolean aForcePending);
|
||||
readonly attribute PRTime lastModifiedTime;
|
||||
};
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "nsIViewSourceChannel.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIForcePendingChannel.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
@ -204,9 +204,9 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt,
|
||||
// Make sure channel listeners see channel as pending while we call
|
||||
// OnStartRequest/OnDataAvailable, even though the underlying channel
|
||||
// has already hit OnStopRequest.
|
||||
nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(request);
|
||||
if (httpChannel) {
|
||||
httpChannel->ForcePending(true);
|
||||
nsCOMPtr<nsIForcePendingChannel> forcePendingChannel = do_QueryInterface(request);
|
||||
if (forcePendingChannel) {
|
||||
forcePendingChannel->ForcePending(true);
|
||||
}
|
||||
|
||||
rv = FireListenerNotifications(request, aCtxt);
|
||||
@ -216,8 +216,8 @@ nsUnknownDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt,
|
||||
}
|
||||
|
||||
// now we need to set pending state to false before calling OnStopRequest
|
||||
if (httpChannel) {
|
||||
httpChannel->ForcePending(false);
|
||||
if (forcePendingChannel) {
|
||||
forcePendingChannel->ForcePending(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,9 +98,16 @@ function isObjectOrArray(obj) {
|
||||
// security in general, but tends to break tests that try to pass object
|
||||
// literals into SpecialPowers. So we waive [[Object]] and [[Array]]
|
||||
// instances before inspecting properties.
|
||||
//
|
||||
// * When we don't have meaningful Xray semantics, we create an Opaque
|
||||
// XrayWrapper for security reasons. For test code, we generally want to see
|
||||
// through that sort of thing.
|
||||
function waiveXraysIfAppropriate(obj, propName) {
|
||||
if (propName == 'toString' || isObjectOrArray(obj))
|
||||
if (propName == 'toString' || isObjectOrArray(obj) ||
|
||||
/Opaque/.test(Object.prototype.toString.call(obj)))
|
||||
{
|
||||
return XPCNativeWrapper.unwrap(obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -3699,18 +3699,21 @@ DebuggerServer.ObjectActorPreviewers = {
|
||||
|
||||
let raw = obj.unsafeDereference();
|
||||
let entries = aGrip.preview.entries = [];
|
||||
// We don't have Xrays to Iterators, so .entries returns [key, value]
|
||||
// Arrays that live in content. But since we have Array Xrays,
|
||||
// we'll deny access depending on the nature of those values. So we need
|
||||
// to waive Xrays on those tuples (and re-apply them on the underlying
|
||||
// values) until we fix bug 1023984.
|
||||
// Iterating over a Map via .entries goes through various intermediate
|
||||
// objects - an Iterator object, then a 2-element Array object, then the
|
||||
// actual values we care about. We don't have Xrays to Iterator objects,
|
||||
// so we get Opaque wrappers for them. And even though we have Xrays to
|
||||
// Arrays, the semantics often deny access to the entires based on the
|
||||
// nature of the values. So we need waive Xrays for the iterator object
|
||||
// and the tupes, and then re-apply them on the underlying values until
|
||||
// we fix bug 1023984.
|
||||
//
|
||||
// Even then though, we might want to continue waiving Xrays here for the
|
||||
// same reason we do so for Arrays above - this filtering behavior is likely
|
||||
// to be more confusing than beneficial in the case of Object previews.
|
||||
for (let keyValuePair of Map.prototype.entries.call(raw)) {
|
||||
let key = Cu.unwaiveXrays(Cu.waiveXrays(keyValuePair)[0]);
|
||||
let value = Cu.unwaiveXrays(Cu.waiveXrays(keyValuePair)[1]);
|
||||
for (let keyValuePair of Cu.waiveXrays(Map.prototype.entries.call(raw))) {
|
||||
let key = Cu.unwaiveXrays(keyValuePair[0]);
|
||||
let value = Cu.unwaiveXrays(keyValuePair[1]);
|
||||
key = makeDebuggeeValueIfNeeded(obj, key);
|
||||
value = makeDebuggeeValueIfNeeded(obj, value);
|
||||
entries.push([threadActor.createValueGrip(key),
|
||||
|
@ -1588,14 +1588,8 @@ NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(JS::HandleValue val,
|
||||
}
|
||||
JS::RootedString jsonStr(cx, val.toString());
|
||||
|
||||
size_t strLen = 0;
|
||||
const jschar* strChar = JS_GetStringCharsAndLength(cx, jsonStr, &strLen);
|
||||
if (!strChar) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
JS::RootedValue jsonVal(cx);
|
||||
if (!JS_ParseJSON(cx, strChar, strLen, &jsonVal) || !jsonVal.isObject()) {
|
||||
if (!JS_ParseJSON(cx, jsonStr, &jsonVal) || !jsonVal.isObject()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(3bc4793f-e6be-44d6-b839-d6b9e85e5346)]
|
||||
[scriptable, uuid(13b75be1-f950-497b-81e4-a0214a14e5ae)]
|
||||
interface nsIStackFrame : nsISupports
|
||||
{
|
||||
// see nsIProgrammingLanguage for list of language consts
|
||||
@ -23,6 +23,11 @@ interface nsIStackFrame : nsISupports
|
||||
readonly attribute AUTF8String sourceLine;
|
||||
readonly attribute nsIStackFrame caller;
|
||||
|
||||
// Returns a formatted stack string that looks like the sort of
|
||||
// string that would be returned by .stack on JS Error objects.
|
||||
// Only works on JS-language stack frames.
|
||||
readonly attribute AString formattedStack;
|
||||
|
||||
AUTF8String toString();
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user