mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 815523 - Remote the app: and jar: protocols. r=fabrice,mwu,jdm
This commit is contained in:
parent
fccec36a4b
commit
e7f09d1290
@ -58,6 +58,16 @@ AppsService.prototype = {
|
||||
return DOMApplicationRegistry.getAppFromObserverMessage(aMessage);
|
||||
},
|
||||
|
||||
getCoreAppsBasePath: function getCoreAppsBasePath() {
|
||||
debug("getCoreAppsBasePath()");
|
||||
return DOMApplicationRegistry.getCoreAppsBasePath();
|
||||
},
|
||||
|
||||
getWebAppsBasePath: function getWebAppsBasePath() {
|
||||
debug("getWebAppsBasePath()");
|
||||
return DOMApplicationRegistry.getWebAppsBasePath();
|
||||
},
|
||||
|
||||
classID : APPS_SERVICE_CID,
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService])
|
||||
}
|
||||
|
@ -86,6 +86,15 @@ this.DOMApplicationRegistry = {
|
||||
getAppFromObserverMessage: function getAppFromObserverMessage(aMessage) {
|
||||
debug("getAppFromObserverMessage " + aMessage);
|
||||
return AppsUtils.getAppFromObserverMessage(this.webapps. aMessage);
|
||||
},
|
||||
getCoreAppsBasePath: function getCoreAppsBasePath() {
|
||||
debug("getCoreAppsBasePath() not yet supported on child!");
|
||||
return null;
|
||||
},
|
||||
|
||||
getWebAppsBasePath: function getWebAppsBasePath() {
|
||||
debug("getWebAppsBasePath() not yet supported on child!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,9 @@ this.AppsUtils = {
|
||||
manifestURL: aApp.manifestURL,
|
||||
appStatus: aApp.appStatus,
|
||||
removable: aApp.removable,
|
||||
id: aApp.id,
|
||||
localId: aApp.localId,
|
||||
basePath: aApp.basePath,
|
||||
progress: aApp.progress || 0.0,
|
||||
installState: aApp.installState || "installed",
|
||||
downloadAvailable: aApp.downloadAvailable,
|
||||
|
@ -75,7 +75,7 @@ this.DOMApplicationRegistry = {
|
||||
"Webapps:GetSelf", "Webapps:CheckInstalled",
|
||||
"Webapps:GetInstalled", "Webapps:GetNotInstalled",
|
||||
"Webapps:Launch", "Webapps:GetAll",
|
||||
"Webapps:InstallPackage", "Webapps:GetBasePath",
|
||||
"Webapps:InstallPackage", "Webapps:GetAppInfo",
|
||||
"Webapps:GetList", "Webapps:RegisterForMessages",
|
||||
"Webapps:UnregisterForMessages",
|
||||
"Webapps:CancelDownload", "Webapps:CheckForUpdate",
|
||||
@ -110,6 +110,9 @@ this.DOMApplicationRegistry = {
|
||||
this.webapps = aData;
|
||||
let appDir = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], false);
|
||||
for (let id in this.webapps) {
|
||||
|
||||
this.webapps[id].id = id;
|
||||
|
||||
// Make sure we have a localId
|
||||
if (this.webapps[id].localId === undefined) {
|
||||
this.webapps[id].localId = this._nextLocalId();
|
||||
@ -215,7 +218,7 @@ this.DOMApplicationRegistry = {
|
||||
let app = this.webapps[aId];
|
||||
let baseDir;
|
||||
try {
|
||||
baseDir = FileUtils.getDir("coreAppsDir", ["webapps", aId], true, true);
|
||||
baseDir = FileUtils.getDir("coreAppsDir", ["webapps", aId], false);
|
||||
} catch(e) {
|
||||
// In ENG builds, we don't have apps in coreAppsDir.
|
||||
return;
|
||||
@ -320,6 +323,8 @@ this.DOMApplicationRegistry = {
|
||||
this.webapps[id] = aData[id];
|
||||
this.webapps[id].basePath = appDir.path;
|
||||
|
||||
this.webapps[id].id = id;
|
||||
|
||||
// Create a new localId.
|
||||
this.webapps[id].localId = this._nextLocalId();
|
||||
|
||||
@ -779,12 +784,13 @@ this.DOMApplicationRegistry = {
|
||||
case "Webapps:InstallPackage":
|
||||
this.doInstallPackage(msg, mm);
|
||||
break;
|
||||
case "Webapps:GetBasePath":
|
||||
case "Webapps:GetAppInfo":
|
||||
if (!this.webapps[msg.id]) {
|
||||
debug("No webapp for " + msg.id);
|
||||
return null;
|
||||
}
|
||||
return this.webapps[msg.id].basePath;
|
||||
return { "basePath": this.webapps[msg.id].basePath + "/",
|
||||
"isCoreApp": !this.webapps[msg.id].removable };
|
||||
break;
|
||||
case "Webapps:RegisterForMessages":
|
||||
this.addMessageListener(msg, mm);
|
||||
@ -1479,9 +1485,9 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
} else {
|
||||
id = this.makeAppId();
|
||||
app.id = id;
|
||||
localId = this._nextLocalId();
|
||||
}
|
||||
app.id = id;
|
||||
|
||||
let manifestName = "manifest.webapp";
|
||||
if (aData.isPackage) {
|
||||
@ -1506,6 +1512,7 @@ this.DOMApplicationRegistry = {
|
||||
let appNote = JSON.stringify(appObject);
|
||||
appNote.id = id;
|
||||
|
||||
appObject.id = id;
|
||||
appObject.localId = localId;
|
||||
appObject.basePath = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], true, true).path;
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
|
||||
@ -2189,6 +2196,14 @@ this.DOMApplicationRegistry = {
|
||||
return AppsUtils.getAppFromObserverMessage(this.webapps, aMessage);
|
||||
},
|
||||
|
||||
getCoreAppsBasePath: function() {
|
||||
return FileUtils.getDir("coreAppsDir", ["webapps"], false).path;
|
||||
},
|
||||
|
||||
getWebAppsBasePath: function getWebAppsBasePath() {
|
||||
return FileUtils.getDir(DIRECTORY_NAME, ["webapps"], false).path;
|
||||
},
|
||||
|
||||
getAllWithoutManifests: function(aCallback) {
|
||||
let result = {};
|
||||
for (let id in this.webapps) {
|
||||
|
@ -11,7 +11,7 @@
|
||||
* We expose Gecko-internal helpers related to "web apps" through this
|
||||
* sub-interface.
|
||||
*/
|
||||
[scriptable, uuid(8ac7827f-f982-40fb-be11-ba16dd665635)]
|
||||
[scriptable, uuid(cfa75628-4d31-481f-b51e-fe0ce18fa98f)]
|
||||
interface mozIApplication: mozIDOMApplication
|
||||
{
|
||||
/* Return true if this app has |permission|. */
|
||||
@ -20,9 +20,15 @@ interface mozIApplication: mozIDOMApplication
|
||||
/* Application status as defined in nsIPrincipal. */
|
||||
readonly attribute unsigned short appStatus;
|
||||
|
||||
/* Returns the local id of the app (not the uuid used for sync). */
|
||||
/* Returns the uuid of the app. */
|
||||
readonly attribute DOMString id;
|
||||
|
||||
/* Returns the local id of the app. */
|
||||
readonly attribute unsigned long localId;
|
||||
|
||||
/* Returns the base directory for the app */
|
||||
readonly attribute DOMString basePath;
|
||||
|
||||
/* Name copied from the manifest */
|
||||
readonly attribute DOMString name;
|
||||
|
||||
|
@ -16,7 +16,7 @@ interface mozIApplication;
|
||||
* This service allows accessing some DOMApplicationRegistry methods from
|
||||
* non-javascript code.
|
||||
*/
|
||||
[scriptable, uuid(4a182c18-dbdf-4f9c-93a0-0f0cffb88ed0)]
|
||||
[scriptable, uuid(e65f9397-e191-4273-aa5f-f13c185ce63b)]
|
||||
interface nsIAppsService : nsISupports
|
||||
{
|
||||
mozIDOMApplication getAppByManifestURL(in DOMString manifestURL);
|
||||
@ -50,4 +50,14 @@ interface nsIAppsService : nsISupports
|
||||
* Returns the CSP associated to this localId.
|
||||
*/
|
||||
DOMString getCSPByLocalId(in unsigned long localId);
|
||||
|
||||
/**
|
||||
* Returns the basepath for core apps
|
||||
*/
|
||||
DOMString getCoreAppsBasePath();
|
||||
|
||||
/**
|
||||
* Returns the basepath for regular packaged apps
|
||||
*/
|
||||
DOMString getWebAppsBasePath();
|
||||
};
|
||||
|
@ -185,7 +185,7 @@ interface nsIZipReader : nsISupports
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIZipReaderCache
|
||||
|
||||
[scriptable, uuid(72fc56e5-3e6e-4d11-8967-26ab96071032)]
|
||||
[scriptable, uuid(748050ac-3ab6-4472-bc2a-cb1564ac6a81)]
|
||||
interface nsIZipReaderCache : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -210,6 +210,11 @@ interface nsIZipReaderCache : nsISupports
|
||||
*/
|
||||
nsIZipReader getZip(in nsIFile zipFile);
|
||||
|
||||
/**
|
||||
* returns true if this zipreader already has this file cached
|
||||
*/
|
||||
bool isCached(in nsIFile zipFile);
|
||||
|
||||
/**
|
||||
* Returns a (possibly shared) nsIZipReader for a zip inside another zip
|
||||
*
|
||||
|
@ -1062,6 +1062,27 @@ nsZipReaderCache::~nsZipReaderCache()
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsZipReaderCache::IsCached(nsIFile* zipFile, bool* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(zipFile);
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIZipReader> antiLockZipGrip;
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
nsAutoCString uri;
|
||||
rv = zipFile->GetNativePath(uri);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
uri.Insert(NS_LITERAL_CSTRING("file:"), 0);
|
||||
|
||||
nsCStringKey key(uri);
|
||||
|
||||
*aResult = mZips.Exists(&key);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
@ -18,10 +18,14 @@
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/net/RemoteOpenFileChild.h"
|
||||
#include "nsITabChild.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::net;
|
||||
|
||||
static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
|
||||
|
||||
@ -188,6 +192,7 @@ nsJARChannel::nsJARChannel()
|
||||
, mStatus(NS_OK)
|
||||
, mIsPending(false)
|
||||
, mIsUnsafe(true)
|
||||
, mOpeningRemote(false)
|
||||
{
|
||||
#if defined(PR_LOGGING)
|
||||
if (!gJarProtocolLog)
|
||||
@ -205,13 +210,14 @@ nsJARChannel::~nsJARChannel()
|
||||
NS_RELEASE(handler); // NULL parameter
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED6(nsJARChannel,
|
||||
NS_IMPL_ISUPPORTS_INHERITED7(nsJARChannel,
|
||||
nsHashPropertyBag,
|
||||
nsIRequest,
|
||||
nsIChannel,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver,
|
||||
nsIDownloadObserver,
|
||||
nsIRemoteOpenFileListener,
|
||||
nsIJARChannel)
|
||||
|
||||
nsresult
|
||||
@ -263,9 +269,9 @@ nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache, nsJARInputThunk **resu
|
||||
nsCOMPtr<nsIZipReader> reader;
|
||||
if (jarCache) {
|
||||
if (mInnerJarEntry.IsEmpty())
|
||||
rv = jarCache->GetZip(mJarFile, getter_AddRefs(reader));
|
||||
rv = jarCache->GetZip(clonedFile, getter_AddRefs(reader));
|
||||
else
|
||||
rv = jarCache->GetInnerZip(mJarFile, mInnerJarEntry,
|
||||
rv = jarCache->GetInnerZip(clonedFile, mInnerJarEntry,
|
||||
getter_AddRefs(reader));
|
||||
} else {
|
||||
// create an uncached jar reader
|
||||
@ -273,7 +279,7 @@ nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache, nsJARInputThunk **resu
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = outerReader->Open(mJarFile);
|
||||
rv = outerReader->Open(clonedFile);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
@ -334,6 +340,37 @@ nsJARChannel::LookupFile()
|
||||
if (fileURL)
|
||||
fileURL->GetFile(getter_AddRefs(mJarFile));
|
||||
}
|
||||
// if we're in child process and have special "remoteopenfile:://" scheme,
|
||||
// create special nsIFile that gets file handle from parent when opened.
|
||||
if (!mJarFile && XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = mJarBaseURI->GetScheme(scheme);
|
||||
if (NS_SUCCEEDED(rv) && scheme.EqualsLiteral("remoteopenfile")) {
|
||||
nsRefPtr<RemoteOpenFileChild> remoteFile = new RemoteOpenFileChild();
|
||||
rv = remoteFile->Init(mJarBaseURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mJarFile = remoteFile;
|
||||
|
||||
nsIZipReaderCache *jarCache = gJarHandler->JarCache();
|
||||
if (jarCache) {
|
||||
bool cached = false;
|
||||
rv = jarCache->IsCached(mJarFile, &cached);
|
||||
if (NS_SUCCEEDED(rv) && cached) {
|
||||
// zipcache already has file mmapped: don't open on parent,
|
||||
// just return and proceed to cache hit in CreateJarInput()
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Open file on parent: OnRemoteFileOpenComplete called when done
|
||||
nsCOMPtr<nsITabChild> tabChild;
|
||||
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, tabChild);
|
||||
rv = remoteFile->AsyncRemoteFileOpen(PR_RDONLY, this, tabChild.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mOpeningRemote = true;
|
||||
}
|
||||
}
|
||||
// try to handle a nested jar
|
||||
if (!mJarFile) {
|
||||
nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(mJarBaseURI);
|
||||
@ -655,7 +692,7 @@ nsJARChannel::Open(nsIInputStream **stream)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsJARInputThunk> input;
|
||||
nsRefPtr<nsJARInputThunk> input;
|
||||
rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
@ -702,12 +739,13 @@ nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
|
||||
rv = NS_OpenURI(mDownloader, nullptr, mJarBaseURI, nullptr,
|
||||
mLoadGroup, mCallbacks,
|
||||
mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS));
|
||||
}
|
||||
else {
|
||||
} else if (mOpeningRemote) {
|
||||
// nothing to do: already asked parent to open file.
|
||||
} else {
|
||||
// local files are always considered safe
|
||||
mIsUnsafe = false;
|
||||
|
||||
nsCOMPtr<nsJARInputThunk> input;
|
||||
nsRefPtr<nsJARInputThunk> input;
|
||||
rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// create input stream pump and call AsyncRead as a block
|
||||
@ -845,7 +883,7 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
mJarFile = file;
|
||||
|
||||
nsCOMPtr<nsJARInputThunk> input;
|
||||
nsRefPtr<nsJARInputThunk> input;
|
||||
rv = CreateJarInput(nullptr, getter_AddRefs(input));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// create input stream pump
|
||||
@ -865,6 +903,38 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIRemoteOpenFileListener
|
||||
//-----------------------------------------------------------------------------
|
||||
nsresult
|
||||
nsJARChannel::OnRemoteFileOpenComplete(nsresult aOpenStatus)
|
||||
{
|
||||
nsresult rv = aOpenStatus;
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// files on parent are always considered safe
|
||||
mIsUnsafe = false;
|
||||
|
||||
nsRefPtr<nsJARInputThunk> input;
|
||||
rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// create input stream pump and call AsyncRead as a block
|
||||
rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mPump->AsyncRead(this, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mStatus = rv;
|
||||
OnStartRequest(nullptr, nullptr);
|
||||
OnStopRequest(nullptr, nullptr, mStatus);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIStreamListener
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIRemoteOpenFileListener.h"
|
||||
#include "nsIZipReader.h"
|
||||
#include "nsIDownloader.h"
|
||||
#include "nsILoadGroup.h"
|
||||
@ -29,6 +30,7 @@ class nsJARInputThunk;
|
||||
class nsJARChannel : public nsIJARChannel
|
||||
, public nsIDownloadObserver
|
||||
, public nsIStreamListener
|
||||
, public nsIRemoteOpenFileListener
|
||||
, public nsHashPropertyBag
|
||||
{
|
||||
public:
|
||||
@ -39,6 +41,7 @@ public:
|
||||
NS_DECL_NSIDOWNLOADOBSERVER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREMOTEOPENFILELISTENER
|
||||
|
||||
nsJARChannel();
|
||||
virtual ~nsJARChannel();
|
||||
@ -76,6 +79,7 @@ private:
|
||||
nsresult mStatus;
|
||||
bool mIsPending;
|
||||
bool mIsUnsafe;
|
||||
bool mOpeningRemote;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> mDownloader;
|
||||
nsCOMPtr<nsIInputStreamPump> mPump;
|
||||
|
17
modules/libjar/test/unit/head_ipc.js
Normal file
17
modules/libjar/test/unit/head_ipc.js
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* If we're running in e10s, determines whether we're in child directory or
|
||||
* not.
|
||||
*/
|
||||
|
||||
var inChild = false;
|
||||
var filePrefix = "";
|
||||
try {
|
||||
inChild = Components.classes["@mozilla.org/xre/runtime;1"].
|
||||
getService(Components.interfaces.nsIXULRuntime).processType
|
||||
!= Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
if (inChild) {
|
||||
// use "jar:remoteopenfile://" in child instead of "jar:file://"
|
||||
filePrefix = "remoteopen";
|
||||
}
|
||||
}
|
||||
catch (e) { }
|
@ -27,7 +27,8 @@ const nsIBinaryInputStream = ctor("@mozilla.org/binaryinputstream;1",
|
||||
|
||||
const fileBase = "test_bug637286.zip";
|
||||
const file = do_get_file("data/" + fileBase);
|
||||
const jarBase = "jar:" + ios.newFileURI(file).spec + "!";
|
||||
// on child we'll test with jar:remoteopenfile:// instead of jar:file://
|
||||
const jarBase = "jar:" + filePrefix + ios.newFileURI(file).spec + "!";
|
||||
const tmpDir = dirSvc.get("TmpD", Ci.nsIFile);
|
||||
|
||||
function Listener(callback) {
|
||||
@ -65,6 +66,34 @@ Listener.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic reading test for asynchronously opened jar channel
|
||||
*/
|
||||
function testAsync() {
|
||||
var uri = jarBase + "/inner40.zip";
|
||||
var chan = ios.newChannel(uri, null, null);
|
||||
do_check_true(chan.contentLength < 0);
|
||||
chan.asyncOpen(new Listener(function(l) {
|
||||
do_check_true(chan.contentLength > 0);
|
||||
do_check_true(l.gotStartRequest);
|
||||
do_check_true(l.gotStopRequest);
|
||||
do_check_eq(l.available, chan.contentLength);
|
||||
|
||||
run_next_test();
|
||||
}), null);
|
||||
}
|
||||
|
||||
add_test(testAsync);
|
||||
// Run same test again so we test the codepath for a zipcache hit
|
||||
add_test(testAsync);
|
||||
|
||||
|
||||
// In e10s child processes we don't currently support
|
||||
// 1) synchronously opening jar files on parent
|
||||
// 2) nested jar channels in e10s: (app:// doesn't use them).
|
||||
// 3) we can't do file lock checks on android, so skip those tests too.
|
||||
if (!inChild) {
|
||||
|
||||
/**
|
||||
* Basic reading test for synchronously opened jar channels
|
||||
*/
|
||||
@ -80,22 +109,6 @@ add_test(function testSync() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Basic reading test for asynchronously opened jar channel
|
||||
*/
|
||||
add_test(function testAsync() {
|
||||
var uri = jarBase + "/inner40.zip";
|
||||
var chan = ios.newChannel(uri, null, null);
|
||||
do_check_true(chan.contentLength < 0);
|
||||
chan.asyncOpen(new Listener(function(l) {
|
||||
do_check_true(chan.contentLength > 0);
|
||||
do_check_true(l.gotStartRequest);
|
||||
do_check_true(l.gotStopRequest);
|
||||
do_check_eq(l.available, chan.contentLength);
|
||||
|
||||
run_next_test();
|
||||
}), null);
|
||||
});
|
||||
|
||||
/**
|
||||
* Basic reading test for synchronously opened, nested jar channels
|
||||
@ -184,4 +197,6 @@ add_test(function testAsyncCloseUnlocks() {
|
||||
}), null);
|
||||
});
|
||||
|
||||
} // if !inChild
|
||||
|
||||
function run_test() run_next_test();
|
||||
|
7
modules/libjar/test/unit/test_jarchannel_e10s.js
Normal file
7
modules/libjar/test/unit/test_jarchannel_e10s.js
Normal file
@ -0,0 +1,7 @@
|
||||
//
|
||||
// Run test script in content process instead of chrome (xpcshell's default)
|
||||
//
|
||||
|
||||
function run_test() {
|
||||
run_test_in_child("../unit/test_jarchannel.js");
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
[DEFAULT]
|
||||
head =
|
||||
head = head_ipc.js
|
||||
tail =
|
||||
|
||||
[test_jarchannel.js]
|
||||
[test_jarchannel_e10s.js]
|
||||
skip-if = os == "mac" || os == "windows"
|
||||
[test_bug278262.js]
|
||||
[test_bug333423.js]
|
||||
[test_bug336691.js]
|
||||
|
@ -16,6 +16,11 @@ LIBRARY_NAME = neckoipc_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
EXPORT_LIBRARY = 1
|
||||
XPIDL_MODULE = necko_ipc
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIRemoteOpenFileListener.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_NAMESPACES = mozilla/net
|
||||
|
||||
@ -25,12 +30,16 @@ EXPORTS_mozilla/net = \
|
||||
NeckoCommon.h \
|
||||
NeckoMessageUtils.h \
|
||||
ChannelEventQueue.h \
|
||||
RemoteOpenFileParent.h \
|
||||
RemoteOpenFileChild.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
NeckoChild.cpp \
|
||||
NeckoParent.cpp \
|
||||
ChannelEventQueue.cpp \
|
||||
RemoteOpenFileParent.cpp \
|
||||
RemoteOpenFileChild.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES += \
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/net/WyciwygChannelChild.h"
|
||||
#include "mozilla/net/FTPChannelChild.h"
|
||||
#include "mozilla/net/WebSocketChannelChild.h"
|
||||
#include "mozilla/net/RemoteOpenFileChild.h"
|
||||
#include "mozilla/dom/network/TCPSocketChild.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
@ -172,5 +173,22 @@ NeckoChild::DeallocPTCPSocket(PTCPSocketChild* child)
|
||||
return true;
|
||||
}
|
||||
|
||||
PRemoteOpenFileChild*
|
||||
NeckoChild::AllocPRemoteOpenFile(const URIParams&, PBrowserChild*)
|
||||
{
|
||||
// We don't allocate here: instead we always use IPDL constructor that takes
|
||||
// an existing RemoteOpenFileChild
|
||||
NS_NOTREACHED("AllocPRemoteOpenFile should not be called on child");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
NeckoChild::DeallocPRemoteOpenFile(PRemoteOpenFileChild* aChild)
|
||||
{
|
||||
RemoteOpenFileChild *p = static_cast<RemoteOpenFileChild*>(aChild);
|
||||
p->ReleaseIPDLReference();
|
||||
return true;
|
||||
}
|
||||
|
||||
}} // mozilla::net
|
||||
|
||||
|
@ -43,6 +43,9 @@ protected:
|
||||
const nsString& aBinaryType,
|
||||
PBrowserChild* aBrowser);
|
||||
virtual bool DeallocPTCPSocket(PTCPSocketChild*);
|
||||
virtual PRemoteOpenFileChild* AllocPRemoteOpenFile(const URIParams&,
|
||||
PBrowserChild*);
|
||||
virtual bool DeallocPRemoteOpenFile(PRemoteOpenFileChild*);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -12,11 +12,15 @@
|
||||
#include "mozilla/net/WyciwygChannelParent.h"
|
||||
#include "mozilla/net/FTPChannelParent.h"
|
||||
#include "mozilla/net/WebSocketChannelParent.h"
|
||||
#include "mozilla/net/RemoteOpenFileParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/dom/network/TCPSocketParent.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "nsHTMLDNSPrefetch.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsEscape.h"
|
||||
|
||||
using mozilla::dom::TabParent;
|
||||
using mozilla::net::PTCPSocketParent;
|
||||
@ -32,6 +36,21 @@ static const char kPrefDisableIPCSecurity[] = "network.disable.ipc.security";
|
||||
NeckoParent::NeckoParent()
|
||||
{
|
||||
Preferences::AddBoolVarCache(&gDisableIPCSecurity, kPrefDisableIPCSecurity);
|
||||
|
||||
if (!gDisableIPCSecurity) {
|
||||
// cache values for core/packaged apps basepaths
|
||||
nsAutoString corePath, webPath;
|
||||
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
|
||||
if (appsService) {
|
||||
appsService->GetCoreAppsBasePath(corePath);
|
||||
appsService->GetWebAppsBasePath(webPath);
|
||||
}
|
||||
// corePath may be empty: we don't use it for all build types
|
||||
MOZ_ASSERT(!webPath.IsEmpty());
|
||||
|
||||
LossyCopyUTF16toASCII(corePath, mCoreAppsBasePath);
|
||||
LossyCopyUTF16toASCII(webPath, mWebAppsBasePath);
|
||||
}
|
||||
}
|
||||
|
||||
NeckoParent::~NeckoParent()
|
||||
@ -149,6 +168,116 @@ NeckoParent::DeallocPTCPSocket(PTCPSocketParent* actor)
|
||||
return true;
|
||||
}
|
||||
|
||||
PRemoteOpenFileParent*
|
||||
NeckoParent::AllocPRemoteOpenFile(const URIParams& aURI,
|
||||
PBrowserParent* aBrowser)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
|
||||
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(uri);
|
||||
if (!fileURL) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// security checks
|
||||
if (!gDisableIPCSecurity) {
|
||||
if (!aBrowser) {
|
||||
NS_WARNING("NeckoParent::AllocPRemoteOpenFile: "
|
||||
"FATAL error: missing TabParent: KILLING CHILD PROCESS\n");
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<TabParent> tabParent = static_cast<TabParent*>(aBrowser);
|
||||
uint32_t appId = tabParent->OwnOrContainingAppId();
|
||||
nsCOMPtr<nsIAppsService> appsService =
|
||||
do_GetService(APPS_SERVICE_CONTRACTID);
|
||||
if (!appsService) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<mozIDOMApplication> domApp;
|
||||
nsresult rv = appsService->GetAppByLocalId(appId, getter_AddRefs(domApp));
|
||||
if (!domApp) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<mozIApplication> mozApp = do_QueryInterface(domApp);
|
||||
if (!mozApp) {
|
||||
return nullptr;
|
||||
}
|
||||
bool hasManage = false;
|
||||
rv = mozApp->HasPermission("webapps-manage", &hasManage);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString requestedPath;
|
||||
fileURL->GetPath(requestedPath);
|
||||
NS_UnescapeURL(requestedPath);
|
||||
|
||||
if (hasManage) {
|
||||
// webapps-manage permission means allow reading any application.zip file
|
||||
// in either the regular webapps directory, or the core apps directory (if
|
||||
// we're using one).
|
||||
NS_NAMED_LITERAL_CSTRING(appzip, "/application.zip");
|
||||
nsAutoCString pathEnd;
|
||||
requestedPath.Right(pathEnd, appzip.Length());
|
||||
if (!pathEnd.Equals(appzip)) {
|
||||
return nullptr;
|
||||
}
|
||||
nsAutoCString pathStart;
|
||||
requestedPath.Left(pathStart, mWebAppsBasePath.Length());
|
||||
if (!pathStart.Equals(mWebAppsBasePath)) {
|
||||
if (mCoreAppsBasePath.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
requestedPath.Left(pathStart, mCoreAppsBasePath.Length());
|
||||
if (!pathStart.Equals(mCoreAppsBasePath)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Finally: make sure there are no "../" in URI.
|
||||
// Note: not checking for symlinks (would cause I/O for each path
|
||||
// component). So it's up to us to avoid creating symlinks that could
|
||||
// provide attack vectors.
|
||||
if (PL_strnstr(requestedPath.BeginReading(), "/../",
|
||||
requestedPath.Length())) {
|
||||
NS_WARNING("NeckoParent::AllocPRemoteOpenFile: "
|
||||
"FATAL error: requested file URI contains '/../' "
|
||||
"KILLING CHILD PROCESS\n");
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// regular packaged apps can only access their own application.zip file
|
||||
nsAutoString basePath;
|
||||
rv = mozApp->GetBasePath(basePath);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
nsAutoString uuid;
|
||||
rv = mozApp->GetId(uuid);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
nsPrintfCString mustMatch("%s/%s/application.zip",
|
||||
NS_LossyConvertUTF16toASCII(basePath).get(),
|
||||
NS_LossyConvertUTF16toASCII(uuid).get());
|
||||
if (!requestedPath.Equals(mustMatch)) {
|
||||
NS_WARNING("NeckoParent::AllocPRemoteOpenFile: "
|
||||
"FATAL error: requesting file other than application.zip: "
|
||||
"KILLING CHILD PROCESS\n");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RemoteOpenFileParent* parent = new RemoteOpenFileParent(fileURL);
|
||||
return parent;
|
||||
}
|
||||
|
||||
bool
|
||||
NeckoParent::DeallocPRemoteOpenFile(PRemoteOpenFileParent* actor)
|
||||
{
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
NeckoParent::RecvHTMLDNSPrefetch(const nsString& hostname,
|
||||
const uint16_t& flags)
|
||||
|
@ -39,6 +39,11 @@ protected:
|
||||
const bool& useSSL,
|
||||
const nsString& aBinaryType,
|
||||
PBrowserParent* aBrowser);
|
||||
virtual PRemoteOpenFileParent* AllocPRemoteOpenFile(
|
||||
const URIParams& fileuri,
|
||||
PBrowserParent* browser);
|
||||
virtual bool DeallocPRemoteOpenFile(PRemoteOpenFileParent* actor);
|
||||
|
||||
virtual bool RecvPTCPSocketConstructor(PTCPSocketParent*,
|
||||
const nsString& aHost,
|
||||
const uint16_t& aPort,
|
||||
@ -52,6 +57,9 @@ protected:
|
||||
const uint16_t& flags,
|
||||
const nsresult& reason);
|
||||
|
||||
private:
|
||||
nsCString mCoreAppsBasePath;
|
||||
nsCString mWebAppsBasePath;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
@ -13,6 +13,8 @@ include protocol PWyciwygChannel;
|
||||
include protocol PFTPChannel;
|
||||
include protocol PWebSocket;
|
||||
include protocol PTCPSocket;
|
||||
include protocol PRemoteOpenFile;
|
||||
include URIParams;
|
||||
|
||||
include "SerializedLoadContext.h";
|
||||
|
||||
@ -32,6 +34,7 @@ sync protocol PNecko
|
||||
manages PFTPChannel;
|
||||
manages PWebSocket;
|
||||
manages PTCPSocket;
|
||||
manages PRemoteOpenFile;
|
||||
|
||||
parent:
|
||||
__delete__();
|
||||
@ -44,6 +47,7 @@ parent:
|
||||
PWebSocket(PBrowser browser);
|
||||
PTCPSocket(nsString host, uint16_t port, bool useSSL, nsString binaryType,
|
||||
nullable PBrowser browser);
|
||||
PRemoteOpenFile(URIParams fileuri, nullable PBrowser browser);
|
||||
|
||||
HTMLDNSPrefetch(nsString hostname, uint16_t flags);
|
||||
CancelHTMLDNSPrefetch(nsString hostname, uint16_t flags, nsresult reason);
|
||||
|
35
netwerk/ipc/PRemoteOpenFile.ipdl
Normal file
35
netwerk/ipc/PRemoteOpenFile.ipdl
Normal file
@ -0,0 +1,35 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
|
||||
|
||||
/* 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 protocol PNecko;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
/**
|
||||
* Protocol to support RemoteOpenFile, an nsIFile that opens it's file handle on
|
||||
* the parent instead of the child (since child lacks permission to do so).
|
||||
*/
|
||||
protocol PRemoteOpenFile
|
||||
{
|
||||
manager PNecko;
|
||||
|
||||
parent:
|
||||
// Tell parent to open file. URI to open was passed and vetted for security in
|
||||
// IPDL constructor: see NeckoParent::AllocPRemoteOpenFile()
|
||||
AsyncOpenFile();
|
||||
|
||||
__delete__();
|
||||
|
||||
child:
|
||||
// success/failure code, and if NS_SUCCEEDED(rv), an open file descriptor
|
||||
FileOpened(FileDescriptor fd, nsresult rv);
|
||||
};
|
||||
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
644
netwerk/ipc/RemoteOpenFileChild.cpp
Normal file
644
netwerk/ipc/RemoteOpenFileChild.cpp
Normal file
@ -0,0 +1,644 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/net/RemoteOpenFileChild.h"
|
||||
#include "nsIRemoteOpenFileListener.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
|
||||
// needed to alloc/free NSPR file descriptors
|
||||
#include "private/pprio.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(RemoteOpenFileChild,
|
||||
nsIFile,
|
||||
nsIHashable)
|
||||
|
||||
|
||||
RemoteOpenFileChild::RemoteOpenFileChild(const RemoteOpenFileChild& other)
|
||||
: mNSPRFileDesc(other.mNSPRFileDesc)
|
||||
, mAsyncOpenCalled(other.mAsyncOpenCalled)
|
||||
, mNSPROpenCalled(other.mNSPROpenCalled)
|
||||
{
|
||||
// Note: don't clone mListener or we'll have a refcount leak.
|
||||
other.mURI->Clone(getter_AddRefs(mURI));
|
||||
other.mFile->Clone(getter_AddRefs(mFile));
|
||||
}
|
||||
|
||||
RemoteOpenFileChild::~RemoteOpenFileChild()
|
||||
{
|
||||
if (mNSPRFileDesc) {
|
||||
// If we handed out fd we shouldn't have pointer to it any more.
|
||||
MOZ_ASSERT(!mNSPROpenCalled);
|
||||
// PR_Close both closes the file and deallocates the PRFileDesc
|
||||
PR_Close(mNSPRFileDesc);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::Init(nsIURI* aRemoteOpenUri)
|
||||
{
|
||||
if (!aRemoteOpenUri) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = aRemoteOpenUri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!scheme.EqualsLiteral("remoteopenfile")) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// scheme of URI is not file:// so this is not a nsIFileURL. Convert to one.
|
||||
nsCOMPtr<nsIURI> clonedURI;
|
||||
rv = aRemoteOpenUri->Clone(getter_AddRefs(clonedURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
clonedURI->SetScheme(NS_LITERAL_CSTRING("file"));
|
||||
nsAutoCString spec;
|
||||
clonedURI->GetSpec(spec);
|
||||
|
||||
rv = NS_NewURI(getter_AddRefs(mURI), spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get nsIFile
|
||||
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mURI);
|
||||
if (!fileURL) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
rv = fileURL->GetFile(getter_AddRefs(mFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::AsyncRemoteFileOpen(int32_t aFlags,
|
||||
nsIRemoteOpenFileListener* aListener,
|
||||
nsITabChild* aTabChild)
|
||||
{
|
||||
if (!mFile) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (!aListener) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (mAsyncOpenCalled) {
|
||||
return NS_ERROR_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
if (aFlags != PR_RDONLY) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mozilla::dom::TabChild* tabChild = nullptr;
|
||||
if (aTabChild) {
|
||||
tabChild = static_cast<mozilla::dom::TabChild*>(aTabChild);
|
||||
}
|
||||
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
|
||||
// we do nothing on these platforms: we'll just open file locally when asked
|
||||
// for NSPR handle
|
||||
mListener->OnRemoteFileOpenComplete(NS_OK);
|
||||
mListener = nullptr;
|
||||
mAsyncOpenCalled = true;
|
||||
return NS_OK;
|
||||
|
||||
#else
|
||||
URIParams uri;
|
||||
SerializeURI(mURI, uri);
|
||||
|
||||
gNeckoChild->SendPRemoteOpenFileConstructor(this, uri, tabChild);
|
||||
|
||||
// Can't seem to reply from within IPDL Parent constructor, so send open as
|
||||
// separate message
|
||||
SendAsyncOpenFile();
|
||||
|
||||
// The chrome process now has a logical ref to us until we call Send__delete
|
||||
AddIPDLReference();
|
||||
|
||||
mListener = aListener;
|
||||
mAsyncOpenCalled = true;
|
||||
return NS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RemoteOpenFileChild::PRemoteOpenFileChild
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
RemoteOpenFileChild::RecvFileOpened(const FileDescriptor& aFD,
|
||||
const nsresult& aRV)
|
||||
{
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
|
||||
NS_NOTREACHED("osX and Windows shouldn't be doing IPDL here");
|
||||
#else
|
||||
if (NS_SUCCEEDED(aRV)) {
|
||||
mNSPRFileDesc = PR_AllocFileDesc(aFD.PlatformHandle(), PR_GetFileMethods());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mListener);
|
||||
|
||||
mListener->OnRemoteFileOpenComplete(aRV);
|
||||
|
||||
mListener = nullptr; // release ref to listener
|
||||
|
||||
// This calls NeckoChild::DeallocPRemoteOpenFile(), which deletes |this| if
|
||||
// IPDL holds the last reference. Don't rely on |this| existing after here!
|
||||
Send__delete__(this);
|
||||
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
RemoteOpenFileChild::AddIPDLReference()
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
void
|
||||
RemoteOpenFileChild::ReleaseIPDLReference()
|
||||
{
|
||||
// if we haven't gotten fd from parent yet, we're not going to.
|
||||
if (mListener) {
|
||||
mListener->OnRemoteFileOpenComplete(NS_ERROR_UNEXPECTED);
|
||||
mListener = nullptr;
|
||||
}
|
||||
|
||||
Release();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RemoteOpenFileChild::nsIFile functions that we override logic for
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Clone(nsIFile **file)
|
||||
{
|
||||
*file = new RemoteOpenFileChild(*this);
|
||||
NS_ADDREF(*file);
|
||||
|
||||
// if we transferred ownership of file to clone, forget our pointer.
|
||||
if (mNSPRFileDesc) {
|
||||
mNSPRFileDesc = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* The main event: get file descriptor from parent process
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::OpenNSPRFileDesc(int32_t aFlags, int32_t aMode,
|
||||
PRFileDesc **aRetval)
|
||||
{
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
|
||||
// Windows and OSX builds: just open nsIFile locally.
|
||||
return mFile->OpenNSPRFileDesc(aFlags, aMode, aRetval);
|
||||
|
||||
#else
|
||||
if (aFlags != PR_RDONLY) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Unlike regular nsIFile we can't (easily) support multiple open()s.
|
||||
if (mNSPROpenCalled) {
|
||||
return NS_ERROR_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
if (!mNSPRFileDesc) {
|
||||
// client skipped AsyncRemoteFileOpen() or didn't wait for result, or this
|
||||
// object has been cloned
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// hand off ownership (i.e responsibility to PR_Close() file handle) to caller
|
||||
*aRetval = mNSPRFileDesc;
|
||||
mNSPRFileDesc = nullptr;
|
||||
mNSPROpenCalled = true;
|
||||
|
||||
return NS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RemoteOpenFileChild::nsIFile functions that we delegate to underlying nsIFile
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::GetLeafName(nsAString &aLeafName)
|
||||
{
|
||||
return mFile->GetLeafName(aLeafName);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetNativeLeafName(nsACString &aLeafName)
|
||||
{
|
||||
return mFile->GetNativeLeafName(aLeafName);
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::GetTarget(nsAString &_retval)
|
||||
{
|
||||
return mFile->GetTarget(_retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetNativeTarget(nsACString &_retval)
|
||||
{
|
||||
return mFile->GetNativeTarget(_retval);
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::GetPath(nsAString &_retval)
|
||||
{
|
||||
return mFile->GetPath(_retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetNativePath(nsACString &_retval)
|
||||
{
|
||||
return mFile->GetNativePath(_retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Equals(nsIFile *inFile, bool *_retval)
|
||||
{
|
||||
return mFile->Equals(inFile, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Contains(nsIFile *inFile, bool recur, bool *_retval)
|
||||
{
|
||||
return mFile->Contains(inFile, recur, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetParent(nsIFile **aParent)
|
||||
{
|
||||
return mFile->GetParent(aParent);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetFollowLinks(bool *aFollowLinks)
|
||||
{
|
||||
return mFile->GetFollowLinks(aFollowLinks);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RemoteOpenFileChild::nsIFile functions that are not currently supported
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::Append(const nsAString &node)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::AppendNative(const nsACString &fragment)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Normalize()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Create(uint32_t type, uint32_t permissions)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::SetLeafName(const nsAString &aLeafName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::SetNativeLeafName(const nsACString &aLeafName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::InitWithPath(const nsAString &filePath)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::InitWithNativePath(const nsACString &filePath)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::InitWithFile(nsIFile *aFile)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::SetFollowLinks(bool aFollowLinks)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::AppendRelativePath(const nsAString &node)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::AppendRelativeNativePath(const nsACString &fragment)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetPersistentDescriptor(nsACString &aPersistentDescriptor)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::SetPersistentDescriptor(const nsACString &aPersistentDescriptor)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetRelativeDescriptor(nsIFile *fromFile, nsACString& _retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::SetRelativeDescriptor(nsIFile *fromFile,
|
||||
const nsACString& relativeDesc)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::CopyTo(nsIFile *newParentDir, const nsAString &newName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::CopyToNative(nsIFile *newParent, const nsACString &newName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::CopyToFollowingLinks(nsIFile *newParentDir,
|
||||
const nsAString &newName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::CopyToFollowingLinksNative(nsIFile *newParent,
|
||||
const nsACString &newName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::MoveTo(nsIFile *newParentDir, const nsAString &newName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::MoveToNative(nsIFile *newParent, const nsACString &newName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Remove(bool recursive)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetPermissions(uint32_t *aPermissions)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::SetPermissions(uint32_t aPermissions)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetPermissionsOfLink(uint32_t *aPermissionsOfLink)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::SetPermissionsOfLink(uint32_t aPermissions)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetLastModifiedTime(PRTime *aLastModTime)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::SetLastModifiedTime(PRTime aLastModTime)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetLastModifiedTimeOfLink(PRTime *aLastModTimeOfLink)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::SetLastModifiedTimeOfLink(PRTime aLastModTimeOfLink)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetFileSize(int64_t *aFileSize)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::SetFileSize(int64_t aFileSize)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetFileSizeOfLink(int64_t *aFileSize)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Exists(bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::IsWritable(bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::IsReadable(bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::IsExecutable(bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::IsHidden(bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::IsDirectory(bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::IsFile(bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::IsSymlink(bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::IsSpecial(bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::CreateUnique(uint32_t type, uint32_t attributes)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetDirectoryEntries(nsISimpleEnumerator **entries)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::OpenANSIFileDesc(const char *mode, FILE **_retval)
|
||||
{
|
||||
// TODO: can implement using fdopen()?
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Load(PRLibrary **_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetDiskSpaceAvailable(int64_t *aDiskSpaceAvailable)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Reveal()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Launch()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RemoteOpenFileChild::nsIHashable functions that we delegate to underlying nsIFile
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::Equals(nsIHashable* aOther, bool *aResult)
|
||||
{
|
||||
nsCOMPtr<nsIHashable> hashable = do_QueryInterface(mFile);
|
||||
|
||||
MOZ_ASSERT(hashable);
|
||||
|
||||
if (hashable) {
|
||||
return hashable->Equals(aOther, aResult);
|
||||
}
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemoteOpenFileChild::GetHashCode(uint32_t *aResult)
|
||||
{
|
||||
nsCOMPtr<nsIHashable> hashable = do_QueryInterface(mFile);
|
||||
|
||||
MOZ_ASSERT(hashable);
|
||||
|
||||
if (hashable) {
|
||||
return hashable->GetHashCode(aResult);
|
||||
}
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
86
netwerk/ipc/RemoteOpenFileChild.h
Normal file
86
netwerk/ipc/RemoteOpenFileChild.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef _RemoteOpenFileChild_h
|
||||
#define _RemoteOpenFileChild_h
|
||||
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/net/PRemoteOpenFileChild.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsIRemoteOpenFileListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
/**
|
||||
* RemoteOpenFileChild: a thin wrapper around regular nsIFile classes that does
|
||||
* IPC to open a file handle on parent instead of child. Used when we can't
|
||||
* open file handle on child (don't have permission), but we don't want the
|
||||
* overhead of shipping all I/O traffic across IPDL. Example: JAR files.
|
||||
*
|
||||
* To open a file handle with this class, AsyncRemoteFileOpen() must be called
|
||||
* first. After the listener's OnRemoteFileOpenComplete() is called, if the
|
||||
* result is NS_OK, nsIFile.OpenNSPRFileDesc() may be called--once--to get the
|
||||
* file handle.
|
||||
*
|
||||
* Note that calling Clone() on this class results in the filehandle ownership
|
||||
* being passed on to the new RemoteOpenFileChild. I.e. if
|
||||
* OnRemoteFileOpenComplete is called and then Clone(), OpenNSPRFileDesc() will
|
||||
* work in the cloned object, but not in the original.
|
||||
*
|
||||
* This class should only be instantiated in a child process.
|
||||
*
|
||||
*/
|
||||
class RemoteOpenFileChild MOZ_FINAL
|
||||
: public PRemoteOpenFileChild
|
||||
, public nsIFile
|
||||
, public nsIHashable
|
||||
{
|
||||
public:
|
||||
RemoteOpenFileChild()
|
||||
: mNSPRFileDesc(nullptr)
|
||||
, mAsyncOpenCalled(false)
|
||||
, mNSPROpenCalled(false)
|
||||
{}
|
||||
|
||||
virtual ~RemoteOpenFileChild();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFILE
|
||||
NS_DECL_NSIHASHABLE
|
||||
|
||||
// URI must be scheme 'remoteopenfile://': otherwise looks like a file:// uri.
|
||||
nsresult Init(nsIURI* aRemoteOpenUri);
|
||||
|
||||
void AddIPDLReference();
|
||||
void ReleaseIPDLReference();
|
||||
|
||||
// Send message to parent to tell it to open file handle for file.
|
||||
// TabChild is required, for IPC security.
|
||||
// Note: currently only PR_RDONLY is supported for 'flags'
|
||||
nsresult AsyncRemoteFileOpen(int32_t aFlags,
|
||||
nsIRemoteOpenFileListener* aListener,
|
||||
nsITabChild* aTabChild);
|
||||
private:
|
||||
RemoteOpenFileChild(const RemoteOpenFileChild& other);
|
||||
|
||||
protected:
|
||||
virtual bool RecvFileOpened(const FileDescriptor&, const nsresult&);
|
||||
|
||||
// regular nsIFile object, that we forward most calls to.
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIRemoteOpenFileListener> mListener;
|
||||
PRFileDesc* mNSPRFileDesc;
|
||||
bool mAsyncOpenCalled;
|
||||
bool mNSPROpenCalled;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // _RemoteOpenFileChild_h
|
||||
|
69
netwerk/ipc/RemoteOpenFileParent.cpp
Normal file
69
netwerk/ipc/RemoteOpenFileParent.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/net/RemoteOpenFileParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsEscape.h"
|
||||
|
||||
#if !defined(XP_WIN) && !defined(MOZ_WIDGET_COCOA)
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
RemoteOpenFileParent::RemoteOpenFileParent(nsIFileURL *aURI)
|
||||
: mURI(aURI)
|
||||
#if !defined(XP_WIN) && !defined(MOZ_WIDGET_COCOA)
|
||||
, mFd(-1)
|
||||
#endif
|
||||
{}
|
||||
|
||||
RemoteOpenFileParent::~RemoteOpenFileParent()
|
||||
{
|
||||
#if !defined(XP_WIN) && !defined(MOZ_WIDGET_COCOA)
|
||||
if (mFd != -1) {
|
||||
// close file handle now that other process has it open, else we'll leak
|
||||
// file handles in parent process
|
||||
close(mFd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
RemoteOpenFileParent::RecvAsyncOpenFile()
|
||||
{
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
|
||||
NS_NOTREACHED("osX and Windows shouldn't be doing IPDL here");
|
||||
#else
|
||||
|
||||
// TODO: make this async!
|
||||
|
||||
nsAutoCString path;
|
||||
nsresult rv = mURI->GetFilePath(path);
|
||||
NS_UnescapeURL(path);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
int fd = open(path.get(), O_RDONLY);
|
||||
if (fd != -1) {
|
||||
unused << SendFileOpened(FileDescriptor(fd), NS_OK);
|
||||
// file handle needs to stay open until it's shared with child (and IPDL
|
||||
// is async, so hasn't happened yet). Close in destructor.
|
||||
mFd = fd;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: sending an invalid file descriptor currently kills the child process:
|
||||
// but that's ok for our use case (failing to open application.jar).
|
||||
unused << SendFileOpened(FileDescriptor(mFd), NS_ERROR_NOT_AVAILABLE);
|
||||
#endif // OS_TYPE
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
38
netwerk/ipc/RemoteOpenFileParent.h
Normal file
38
netwerk/ipc/RemoteOpenFileParent.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_RemoteOpenFileParent_h
|
||||
#define mozilla_net_RemoteOpenFileParent_h
|
||||
|
||||
#include "mozilla/net/PRemoteOpenFileParent.h"
|
||||
#include "mozilla/net/NeckoCommon.h"
|
||||
#include "nsIFileURL.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class RemoteOpenFileParent : public PRemoteOpenFileParent
|
||||
{
|
||||
public:
|
||||
RemoteOpenFileParent(nsIFileURL* aURI);
|
||||
|
||||
~RemoteOpenFileParent();
|
||||
|
||||
virtual bool RecvAsyncOpenFile();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIFileURL> mURI;
|
||||
|
||||
#if !defined(XP_WIN) && !defined(MOZ_WIDGET_COCOA)
|
||||
int mFd;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_RemoteOpenFileParent_h
|
@ -4,5 +4,6 @@
|
||||
|
||||
IPDLSRCS = \
|
||||
PNecko.ipdl \
|
||||
PRemoteOpenFile.ipdl \
|
||||
$(NULL)
|
||||
|
||||
|
30
netwerk/ipc/nsIRemoteOpenFileListener.idl
Normal file
30
netwerk/ipc/nsIRemoteOpenFileListener.idl
Normal file
@ -0,0 +1,30 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=4 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* nsIRemoteOpenFileListener: passed to RemoteOpenFileChild::AsyncRemoteFileOpen.
|
||||
*
|
||||
* Interface for notifying when the file has been opened and is available in
|
||||
* child.
|
||||
*/
|
||||
[uuid(5c89208c-fe2b-4e04-9783-93bcf5c3b783)]
|
||||
interface nsIRemoteOpenFileListener : nsISupports
|
||||
{
|
||||
/**
|
||||
* Called when result of opening RemoteOpenFileChild:AsyncRemoteFileOpen()
|
||||
* is available in child.
|
||||
*
|
||||
* @param aOpenStatus: nsresult from opening file in parent. If NS_OK,
|
||||
* then a following call to RemoteOpenFileChild::OpenNSPRFileDesc that
|
||||
* passes the same flags as were passed to
|
||||
* RemoteOpenFileChild::AsyncRemoteFileOpen is guaranteed to succeed. If
|
||||
* !NS_OK or if different flags were passed, the call will fail.
|
||||
*/
|
||||
void onRemoteFileOpenComplete(in nsresult aOpenStatus);
|
||||
};
|
||||
|
@ -16,7 +16,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"nsISyncMessageSender");
|
||||
|
||||
function AppProtocolHandler() {
|
||||
this._basePath = [];
|
||||
this._appInfo = [];
|
||||
this._runningInParent = Cc["@mozilla.org/xre/runtime;1"]
|
||||
.getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
}
|
||||
|
||||
AppProtocolHandler.prototype = {
|
||||
@ -30,14 +33,13 @@ AppProtocolHandler.prototype = {
|
||||
Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD |
|
||||
Ci.nsIProtocolHandler.URI_CROSS_ORIGIN_NEEDS_WEBAPPS_PERM,
|
||||
|
||||
getBasePath: function app_phGetBasePath(aId) {
|
||||
getAppInfo: function app_phGetAppInfo(aId) {
|
||||
|
||||
if (!this._basePath[aId]) {
|
||||
this._basePath[aId] = cpmm.sendSyncMessage("Webapps:GetBasePath",
|
||||
{ id: aId })[0] + "/";
|
||||
if (!this._appInfo[aId]) {
|
||||
let reply = cpmm.sendSyncMessage("Webapps:GetAppInfo", { id: aId });
|
||||
this._appInfo[aId] = reply[0];
|
||||
}
|
||||
|
||||
return this._basePath[aId];
|
||||
return this._appInfo[aId];
|
||||
},
|
||||
|
||||
newURI: function app_phNewURI(aSpec, aOriginCharset, aBaseURI) {
|
||||
@ -62,7 +64,15 @@ AppProtocolHandler.prototype = {
|
||||
}
|
||||
|
||||
// Build a jar channel and masquerade as an app:// URI.
|
||||
let uri = "jar:file://" + this.getBasePath(appId) + appId + "/application.zip!" + fileSpec;
|
||||
let appInfo = this.getAppInfo(appId);
|
||||
let uri;
|
||||
if (this._runningInParent || appInfo.isCoreApp) {
|
||||
// In-parent and CoreApps can directly access files, so use jar:file://
|
||||
uri = "jar:file://" + appInfo.basePath + appId + "/application.zip!" + fileSpec;
|
||||
} else {
|
||||
// non-CoreApps in child need to ask parent for file handle, use jar:ipcfile://
|
||||
uri = "jar:remoteopenfile://" + appInfo.basePath + appId + "/application.zip!" + fileSpec;
|
||||
}
|
||||
let channel = Services.io.newChannel(uri, null, null);
|
||||
channel.QueryInterface(Ci.nsIJARChannel).setAppURI(aURI);
|
||||
channel.QueryInterface(Ci.nsIChannel).originalURI = aURI;
|
||||
|
Loading…
Reference in New Issue
Block a user