From a968b880dfdbc7be67e944d5be2b3a482ece2318 Mon Sep 17 00:00:00 2001 From: Shian-Yow Wu Date: Fri, 18 Jul 2014 10:46:22 +0800 Subject: [PATCH] Bug 988816 - Support multiple OpenNSPRFileOpen() on RemoteOpenFile. r=aklotz, jduell --- content/base/src/nsXMLHttpRequest.cpp | 8 +++++ modules/libjar/nsIJARChannel.idl | 9 +++++- modules/libjar/nsJARChannel.cpp | 18 +++++++++-- modules/libjar/nsJARChannel.h | 1 + netwerk/ipc/RemoteOpenFileChild.cpp | 35 +++++++++------------ netwerk/protocol/app/AppProtocolHandler.cpp | 5 +++ 6 files changed, 53 insertions(+), 23 deletions(-) diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index a7b268a9557..16827a349be 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -2991,6 +2991,14 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable& aBody) if (scheme.LowerCaseEqualsLiteral("app") || scheme.LowerCaseEqualsLiteral("jar")) { mIsMappedArrayBuffer = true; + if (XRE_GetProcessType() != GeckoProcessType_Default) { + nsCOMPtr jarChannel = do_QueryInterface(mChannel); + // For memory mapping from child process, we need to get file + // descriptor of the JAR file opened remotely on the parent proess. + // Set this to make sure that file descriptor can be obtained by + // child process. + jarChannel->EnsureChildFd(); + } } } } diff --git a/modules/libjar/nsIJARChannel.idl b/modules/libjar/nsIJARChannel.idl index e0fcc833d3e..8d68066761f 100644 --- a/modules/libjar/nsIJARChannel.idl +++ b/modules/libjar/nsIJARChannel.idl @@ -7,7 +7,7 @@ interface nsIFile; -[scriptable, builtinclass, uuid(063e9698-ec67-4fe2-aa19-d21505beaa61)] +[scriptable, builtinclass, uuid(5a4f8df0-3bd9-45c2-9db9-67e74c3dd47d)] interface nsIJARChannel : nsIChannel { /** @@ -27,4 +27,11 @@ interface nsIJARChannel : nsIChannel * Returns the JAR file. */ readonly attribute nsIFile jarFile; + + /** + * For child process, set this to make sure that a valid file descriptor of + * JAR file is always provided when calling NSPRFileDesc(). + * Must be set before Open() or AsyncOpen() to be effective. + */ + void ensureChildFd(); }; diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 64373f81005..e7c283c8e04 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -199,6 +199,7 @@ nsJARChannel::nsJARChannel() , mIsPending(false) , mIsUnsafe(true) , mOpeningRemote(false) + , mEnsureChildFd(false) { #if defined(PR_LOGGING) if (!gJarProtocolLog) @@ -356,7 +357,7 @@ nsJARChannel::LookupFile() mJarFile = remoteFile; nsIZipReaderCache *jarCache = gJarHandler->JarCache(); - if (jarCache) { + if (jarCache && !mEnsureChildFd) { bool cached = false; rv = jarCache->IsCached(mJarFile, &cached); if (NS_SUCCEEDED(rv) && cached) { @@ -368,7 +369,8 @@ nsJARChannel::LookupFile() mOpeningRemote = true; - if (gJarHandler->RemoteOpenFileInProgress(remoteFile, this)) { + if (gJarHandler->RemoteOpenFileInProgress(remoteFile, this) && + !mEnsureChildFd) { // JarHandler will trigger OnRemoteFileOpen() after the first // request for this file completes and we'll get a JAR cache // hit. @@ -865,6 +867,13 @@ nsJARChannel::GetJarFile(nsIFile **aFile) return NS_OK; } +NS_IMETHODIMP +nsJARChannel::EnsureChildFd() +{ + mEnsureChildFd = true; + return NS_OK; +} + //----------------------------------------------------------------------------- // nsIDownloadObserver //----------------------------------------------------------------------------- @@ -1035,6 +1044,11 @@ nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) mCallbacks = 0; mProgressSink = 0; + if (mOpeningRemote) { + // To deallocate file descriptor by RemoteOpenFileChild destructor. + mJarFile = nullptr; + } + return NS_OK; } diff --git a/modules/libjar/nsJARChannel.h b/modules/libjar/nsJARChannel.h index bfaf294de55..796494353f0 100644 --- a/modules/libjar/nsJARChannel.h +++ b/modules/libjar/nsJARChannel.h @@ -93,6 +93,7 @@ private: bool mIsPending; bool mIsUnsafe; bool mOpeningRemote; + bool mEnsureChildFd; nsCOMPtr mDownloader; nsCOMPtr mPump; diff --git a/netwerk/ipc/RemoteOpenFileChild.cpp b/netwerk/ipc/RemoteOpenFileChild.cpp index 707ad23613c..ec445a12d67 100644 --- a/netwerk/ipc/RemoteOpenFileChild.cpp +++ b/netwerk/ipc/RemoteOpenFileChild.cpp @@ -72,10 +72,20 @@ NS_IMPL_ISUPPORTS(RemoteOpenFileChild, RemoteOpenFileChild::RemoteOpenFileChild(const RemoteOpenFileChild& other) : mTabChild(other.mTabChild) - , mNSPRFileDesc(other.mNSPRFileDesc) + , mNSPRFileDesc(nullptr) , mAsyncOpenCalled(other.mAsyncOpenCalled) - , mNSPROpenCalled(other.mNSPROpenCalled) { +#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA) + // Windows/OSX desktop builds skip remoting, so the file descriptor should + // be nullptr here. + MOZ_ASSERT(!other.mNSPRFileDesc); +#else + if (other.mNSPRFileDesc) { + PROsfd osfd = dup(PR_FileDesc2NativeHandle(other.mNSPRFileDesc)); + mNSPRFileDesc = PR_ImportFile(osfd); + } +#endif + // Note: don't clone mListener or we'll have a refcount leak. other.mURI->Clone(getter_AddRefs(mURI)); if (other.mAppURI) { @@ -123,8 +133,6 @@ 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); } @@ -347,11 +355,6 @@ 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; } @@ -370,21 +373,13 @@ RemoteOpenFileChild::OpenNSPRFileDesc(int32_t aFlags, int32_t aMode, 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 + // Client skipped AsyncRemoteFileOpen() or didn't wait for result. return NS_ERROR_NOT_AVAILABLE; } - // hand off ownership (i.e responsibility to PR_Close() file handle) to caller - *aRetval = mNSPRFileDesc; - mNSPRFileDesc = nullptr; - mNSPROpenCalled = true; + PROsfd osfd = dup(PR_FileDesc2NativeHandle(mNSPRFileDesc)); + *aRetval = PR_ImportFile(osfd); return NS_OK; #endif diff --git a/netwerk/protocol/app/AppProtocolHandler.cpp b/netwerk/protocol/app/AppProtocolHandler.cpp index 94a5f32a1e8..7a1443b0bcb 100644 --- a/netwerk/protocol/app/AppProtocolHandler.cpp +++ b/netwerk/protocol/app/AppProtocolHandler.cpp @@ -127,6 +127,11 @@ NS_IMETHODIMP DummyChannel::GetJarFile(nsIFile* *aFile) return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP DummyChannel::EnsureChildFd() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP DummyChannel::Run() { nsresult rv = mListener->OnStartRequest(this, mListenerContext);