Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-07-14 15:47:36 -04:00
commit 99886e5bda
64 changed files with 870 additions and 651 deletions

View File

@ -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"
}];

View File

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

View File

@ -73,7 +73,7 @@ FFmpegRuntimeLinker::Link()
Unlink();
sLinkStatus = LinkStatus_FAILED;
return nullptr;
return false;
}
/* static */ bool

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
/************************************************************************/
/*

View File

@ -135,6 +135,7 @@ class CompartmentChecker
void check(InterpreterFrame *fp);
void check(AbstractFramePtr frame);
void check(SavedStacks *stacks);
};
#endif /* JS_CRASH_DIAGNOSTICS */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(),

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@ -43,6 +43,7 @@ XPIDL_SOURCES += [
'nsIExternalProtocolHandler.idl',
'nsIFileStreams.idl',
'nsIFileURL.idl',
'nsIForcePendingChannel.idl',
'nsIIncrementalDownload.idl',
'nsIInputStreamChannel.idl',
'nsIInputStreamPump.idl',

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()
{

View File

@ -281,9 +281,11 @@ public:
bool IsTunnel() { return mIsTunnel; }
private:
void ClearTransactionsBlockedOnTunnel();
void MapStreamToPlainText();
void MapStreamToHttpConnection();
bool mIsTunnel;
bool mPlainTextTunnel;
};
} // namespace mozilla::net

View File

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

View File

@ -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()
{

View File

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

View File

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

View File

@ -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()
{

View File

@ -257,9 +257,11 @@ public:
bool IsTunnel() { return mIsTunnel; }
private:
void ClearTransactionsBlockedOnTunnel();
void MapStreamToPlainText();
void MapStreamToHttpConnection();
bool mIsTunnel;
bool mPlainTextTunnel;
};
}} // namespace mozilla::net

View File

@ -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()
{

View File

@ -252,9 +252,11 @@ public:
bool IsTunnel() { return mIsTunnel; }
private:
void ClearTransactionsBlockedOnTunnel();
void MapStreamToPlainText();
void MapStreamToHttpConnection();
bool mIsTunnel;
bool mPlainTextTunnel;
};
}} // namespace mozilla::net

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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