mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
b564bd67d3
- Use CompositorWidgetProxy for dispatching vsync to the compositor. (bug 1269037 part 1, r=mchang) (c8b7a4240c) - Remove unused null widget checks. (bug 1269037 part 2, r=mchang) (4f4cc9952b) - Bug 1269422: Wrap Gonk widget in |CompositorWidgetProxyWrapper|. r=dvander (4513035cbf) - Remove nsBaseWidget::NewCompositorBridgeParent. (bug 1272472 part 1, r=kats) (ca813c1f2b) - Use IPDL to schedule composites on GTK. (bug 1272472 part 2, r=nical) (7402cf834e) - Use IPC to schedule composites on Windows. (bug 1272472 part 3, r=jimm) (e5d7281dd7) - Don't use nsIWidget to check APZ in LayerManagerComposite. (bug 1269653 part 1, r=kats) (79a1644111) - Restrict SetDispAcquireFence's nsIWidget access to Gonk. (bug 1269653 part 2, r=kats) (72110b7bc7) - Bug 1264764 - Move PTexture under PCompositorBridge r=nical,dvander (17e6ec7fc1) - Move CompositorThreadHolder into its own file. (bug 1273017 part 1, r=mattwoodrow) (464ede8be1) - Move CompositorBridgeParent::CompositorLoop to CompositorThreadHolder. (bug 1273017 part 2, r=mattwoodrow) (85708f3cde) - Bug 1268313: Part 1 - Be explicit about which NewRunnableMethod callers want to be able to cancel. r=froydnj (faa07aa139) - Bug 1268313: Part 2 - Replace some NewRunnableMethods with NS_NewNonOwningRunnableMethod. r=froydnj (010c43d000) - Bug 1268313: Part 3 - Replace some NewCancelableRunnableMethod with NS_NewNonOwningCancelableRunnableMethod. r=froydnj (55018ef234) - Bug 1268313: Part 4 - Replace NewCancelableRunnableMethod with NS_NewCancelableRunnableMethod. r=froydnj (c22711b35d) - Bug 1268313: Part 5 - Make NS_NewRunnableMethod able to call const functions. r=froydnj (b0f60963a3) - Bug 1268313: Part 6 - Replace NewRunnableMethod with NS_NewRunnableMethod. r=froydnj (18d40def2c) - Bug 1260950 - Set mInitialSizeFound to true when the initial size id found. r=jesup, r=pehrsons a=kwierso (5d6abe57e0) - Bug 1237176 - Notify synth start if we get a finished event without a blocking-changed event. r=roc (c1aebe903a) - Bug 911546, use a runnable so that popups don't rollup during a grab, r=karlt (a06bd44e6c) - Bug 1237617 - Call nsWindow::ForcePresent during going active r=bas.schouten (066cad8f89) - Bug 1268313: Part 7 - Move NS_NewRunnableMethod and friends to mozilla::NewRunnableMethod. r=froydnj (8b4bf34961) - Bug 1266595: Followup to fix IPDL tests. r=billm (216f2dcff5) - Bug 1268313: Fix up IPDL tests. r=billm (228348d642) - Add WinCompositorWidgetProxy. (bug 1265975 part 1, r=jimm) (bfafe7a8e2) - Implement WinCompositorWidgetProxy::GetClientSize. (bug 1265975 part 2, r=jimm) (a8710a3259) - Move the WM_SETTEXT present lock to CompositorWidgetProxy. (bug 1265975 part 3, r=jimm) (297ce28c8a) - Move transparency handling to WinCompositorWigetProxy. (bug 1265975 part 4, r=jimm) (46ba0c6d01) - Remove Windows-specific compositor calls to nsIWidget. (bug 1265975 part 5, r=jimm) (3ef157c160) - Remove plugin-related CompositorBridgeParent use of nsIWidget. (bug 1265975 part 6, r=jimm) (6d80cdd6fd) - Hide top-level CompositorBridgeParents behind a new API. (bug 1272472 part 4, r=mattwoodrow,kats,gwagner) (228c0efdb7) - Bug 1253424 - part 1 - add a already_AddRefed nsTransactionStack::Push overload; r=erahm (7059e20914) - Bug 1253424 - part 2 - add nsTransactionStack::IsEmpty; r=erahm (7e9764a146) - Bug 1254618 - modify nsTransactionStack to use nsDeque rather than std::deque; r=ehsan (5e47ea431e) - Bug 1136857 - Make DOMStorageCache::mLoaded flag atomic to prevent potential races, r=nfroyd (39aaea1de3) - Bug 1265408 - Add webidl for IIRFilterNode; r=smaug (040ce9aa43) - Bug 1265408 - Implement IIRFilterNode; r=padenot (6bf569a412) - Bug 1265408 - Import IIRFilter from blink; r=padenot (71b28c0ad2) - Bug 1265408 - Use IIRFilter from blink; r=padenot (5d058d8568) - Bug 1265408 - Add buffersAreZero to IIRFilter; r=karlt (45edba3e13) - Bug 1265408 - Avoid subnormals in IIRFilter; r=karlt (0e1ae93f0b) - Bug 1265408 - Add LogToDeveloperConsole to WebAudioUtils; r=padenot (88d5f0222a) - Bug 1268984 - Store GMPStorage on GMPServiceParent so that it persists inside the same PB session. r=gerald (17d4d0abaf) - Bug 1267905 - Replace uses of ScopedCERTCertList with UniqueCERTCertList. r=keeler (783bf11b2a) - Bug 1270005 - Replace uses of ScopedPK11SlotInfo with UniquePK11SlotInfo in PSM. r=keeler (ea9a4011aa) - Bug 1271501 - Remove unnecessary uses of reinterpret_cast in PSM. r=keeler (6be40f0a85) - Bug 1271501 - Downgrade unnecessarily strong reinterpret_casts in PSM. r=keeler (95245f00ce) - Bug 1082346 - 01. Convert PKCS12 password endian using copyAndSwapToBigEndian. r=keeler (9cc58fc550) - Bug 1082346 - 02. Test case. r=keeler r=Cykesiopka (7fb0e8abc4) - Bug 160122 - Stop using PR_smprintf in PSM. r=keeler (1e5b68819c) - Bug 1271501 - Use mozilla::BitwiseCast instead of reinterpret_cast in PSM. r=keeler (894966a2ef) - Bug 1273855: TraceLogger - Include PID in the log names in order to support browser with e10s, r=bbouvier (8cf2233db3) - Bug 1274189. Part 1 - rename some functions to be consistent with other MediaDataDecoder sub-classes. r=jya. (4511b3d3f7) - Bug 1274189. Part 2 - remove use of FlushableTaskQueue::Flush(). r=jya. (77e745fdd1) - Bug 1274189. Part 3 - remove use of FlushableTaskQueue. r=jya (aac61dcd02) - Bug 1269963. Part 1 - Add a SyncRunnable::DispatchToThread() overload for AbstractThread. r=bobbyholley. (839752aff4) - Bug 1269672 - part1 : revert sampling rate changing of the bug1235612. (9015782e13) - Bug 1270698 - check if we need to enter buffering periodically to ensure we start buffering when running out of decoded audio/video data. r=cpearce. (16734549b7) - Bug 1271581 - use newCurrentTime, instead of GetMediaTime() to decide the nextState; r=jwwang (9c5075eada) - Bug 1224973 - Part 1: Remove MediaDecoderOwner->IsHidden(). r=cpearce,jwwang (4fde3ede5a) - Bug 1224973 - Part 2: Set MediaDecoder visibility via NotifyOwnerActivityChanged. r=cpearce,jwwang (be917202eb) - Bug 1224973 - Part 3: Plumb element visibility into MDSM. r=jya,jwwang (9ec83fa243) - Bug 1224973 - Part 4: Pref media.suspend-bkgnd-video.enabled. r=cpearce,jwwang (43413a025f) - Bug 1269408: P1. Retry InternalSeek if previous attempt failed once more data is available. r=gerald (05db58dc7c) - crude fix (0097068989) - Bug 1269408: P2. Update mochitest. r=gerald (464b4c0724) - Bug 1269408: P3. Ensure a new seek request will cancel the previous internal seek. r=gerald (6ed4b8dc95) - Bug 1269408: P4. Ensure the decoders are flushed prior performing an internal seek. r=gerald (074234067b) - Bug 1269408: P5. Only drop the seek target if it's exactly the seek target. r=gerald (88701eb05a) - Bug 1269408: P6. Add debugging information, useful when a mochitest timeout. r=gerald (ef0270ab0d) - Bug 1269408: P7. Start skip to next keyframe logic when resume point is behind current time. r=gerald (bd40ebf3bc) - Bug 1269408: P8. Add debugging log. r=gerald (e6dbd1f0a6) - Bug 1269408: P9. Move handling logic of skip to next keyframe to its own function. r=gerald (3c8039e417) - Bug 1269408: P10. Reject promise early if in error state. r=me (8af54c574e) - Bug 1224973 - Part 5: Implement suspend decoding for background video. r=cpearce,jwwang,jya (22081521e3) - Bug 1242874 - part1 : create suspened types. r=baku (d3ac9548e5) - Bug 1242874 - part2 : window's suspend attribute. r=baku, r=ehsan (1fd9dc2647) - remove allowscirpted (39ab523036) - Bug 1242874 - part3 : implement different suspended methods. r=baku, r=jwwang (25d1f27a03) - Bug 1242874 - part4 : wrap the volume/mute/suspend for notifyStartedPlaying. r=baku (b8ba3238c2) - bug 1242874 - part5 : add test. r=baku, r=ehsan (f840139b5a) - Bug 1235612 - Part 1: Implement notify media-playback. r=baku (b5ec29da20) - Bug 1235612 - Part 2: Notify audible state in NotifyStartedPlaying. r=baku (dc38583a62) - Bug 1235612 - Part 3: Implement the logic of audible state notification for agent owners. r=baku (f65b3952fa) - Bug 1235612 - Part 4: Modify check audible method. r=jwwang (73457e39eb) - Bug 1269672 - part2 : move audible data checking from MDSM to DecodedAudioDataSink. (d2c3b6874c) - Bug 1269936 - Introduce and call a runtime-wide servo initialization hook. r=heycam (d4d505d4c2) - Bug 1263778 - Rename a bunch of low-level [[Prototype]] access methods to make their interactions with statically-known and dynamically-computed [[Prototype]]s clearer. r=efaust (66bbe8e7db) - Bug 888969 - Permit a cyclic [[Prototype]] chain to be created through a Location object. r=bz, r=efaust (3e3b9cbb16) - re-apply Bug 1054906 - Implement ES6 Symbol.hasInstance 2/2; r=jandem (8d5c7573ff) - Bug 1054906 - Implement ES6 Symbol.hasInstance 1/2; r=evilpie,bz (a836904e5d) - fix misspatch (54a5f2d708) - Bug 1270349 part 1. Add IDL parser support for [LegacyUnenumerableNamedProperties]. r=peterv (8c836bc74a) - Bug 1270349 part 2. Add [LegacyUnenumerableNamedProperties] to the interfaces that specify it in DOM and HTML. r=peterv (25d3cc1377) - Bug 1270349 part 3. Add a way to ask an interface descriptor for a proxy whether its named props should be enumerable. r=peterv (0a9f804867) - Bug 1270349 part 4. Use LegacyUnenumerableNamedProperties instead of NameIsEnumerable() calls to determine whether named props on DOM proxies should be enumerable. r=peterv (82f5158963) - Bug 1270349 part 5. Use LegacyUnenumerableNamedProperties instead of passing flags to GetSupportedNames to determine whether named props on DOM proxies should be reflected in ownPropertyKeys. r=peterv (3984176834) - Bug 1270349 followup to address a review comment. r=peterv (b49f4c5335)
1262 lines
35 KiB
C++
1262 lines
35 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "nsJAR.h"
|
|
#include "nsJARChannel.h"
|
|
#include "nsJARProtocolHandler.h"
|
|
#include "nsMimeTypes.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsEscape.h"
|
|
#include "nsIPrefService.h"
|
|
#include "nsIPrefBranch.h"
|
|
#include "nsIViewSourceChannel.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsProxyRelease.h"
|
|
#include "nsContentSecurityManager.h"
|
|
|
|
#include "nsIScriptSecurityManager.h"
|
|
#include "nsIPrincipal.h"
|
|
#include "nsIFileURL.h"
|
|
|
|
#include "mozilla/Preferences.h"
|
|
#include "mozilla/Telemetry.h"
|
|
#include "mozilla/net/RemoteOpenFileChild.h"
|
|
#include "nsITabChild.h"
|
|
#include "private/pprio.h"
|
|
#include "nsInputStreamPump.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::net;
|
|
|
|
static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
|
|
|
|
// the entry for a directory will either be empty (in the case of the
|
|
// top-level directory) or will end with a slash
|
|
#define ENTRY_IS_DIRECTORY(_entry) \
|
|
((_entry).IsEmpty() || '/' == (_entry).Last())
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Ignore any LOG macro that we inherit from arbitrary headers. (We define our
|
|
// own LOG macro below.)
|
|
#ifdef LOG
|
|
#undef LOG
|
|
#endif
|
|
|
|
//
|
|
// set NSPR_LOG_MODULES=nsJarProtocol:5
|
|
//
|
|
static LazyLogModule gJarProtocolLog("nsJarProtocol");
|
|
|
|
#define LOG(args) MOZ_LOG(gJarProtocolLog, mozilla::LogLevel::Debug, args)
|
|
#define LOG_ENABLED() MOZ_LOG_TEST(gJarProtocolLog, mozilla::LogLevel::Debug)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// nsJARInputThunk
|
|
//
|
|
// this class allows us to do some extra work on the stream transport thread.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class nsJARInputThunk : public nsIInputStream
|
|
{
|
|
public:
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
NS_DECL_NSIINPUTSTREAM
|
|
|
|
nsJARInputThunk(nsIZipReader *zipReader,
|
|
nsIURI* fullJarURI,
|
|
const nsACString &jarEntry,
|
|
bool usingJarCache)
|
|
: mUsingJarCache(usingJarCache)
|
|
, mJarReader(zipReader)
|
|
, mJarEntry(jarEntry)
|
|
, mContentLength(-1)
|
|
{
|
|
if (fullJarURI) {
|
|
#ifdef DEBUG
|
|
nsresult rv =
|
|
#endif
|
|
fullJarURI->GetAsciiSpec(mJarDirSpec);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "this shouldn't fail");
|
|
}
|
|
}
|
|
|
|
int64_t GetContentLength()
|
|
{
|
|
return mContentLength;
|
|
}
|
|
|
|
nsresult Init();
|
|
|
|
private:
|
|
|
|
virtual ~nsJARInputThunk()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
bool mUsingJarCache;
|
|
nsCOMPtr<nsIZipReader> mJarReader;
|
|
nsCString mJarDirSpec;
|
|
nsCOMPtr<nsIInputStream> mJarStream;
|
|
nsCString mJarEntry;
|
|
int64_t mContentLength;
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS(nsJARInputThunk, nsIInputStream)
|
|
|
|
nsresult
|
|
nsJARInputThunk::Init()
|
|
{
|
|
nsresult rv;
|
|
if (ENTRY_IS_DIRECTORY(mJarEntry)) {
|
|
// A directory stream also needs the Spec of the FullJarURI
|
|
// because is included in the stream data itself.
|
|
|
|
NS_ENSURE_STATE(!mJarDirSpec.IsEmpty());
|
|
|
|
rv = mJarReader->GetInputStreamWithSpec(mJarDirSpec,
|
|
mJarEntry,
|
|
getter_AddRefs(mJarStream));
|
|
}
|
|
else {
|
|
rv = mJarReader->GetInputStream(mJarEntry,
|
|
getter_AddRefs(mJarStream));
|
|
}
|
|
if (NS_FAILED(rv)) {
|
|
// convert to the proper result if the entry wasn't found
|
|
// so that error pages work
|
|
if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
|
|
rv = NS_ERROR_FILE_NOT_FOUND;
|
|
return rv;
|
|
}
|
|
|
|
// ask the JarStream for the content length
|
|
uint64_t avail;
|
|
rv = mJarStream->Available((uint64_t *) &avail);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
mContentLength = avail < INT64_MAX ? (int64_t) avail : -1;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARInputThunk::Close()
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mJarStream)
|
|
rv = mJarStream->Close();
|
|
|
|
if (!mUsingJarCache && mJarReader)
|
|
mJarReader->Close();
|
|
|
|
mJarReader = nullptr;
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARInputThunk::Available(uint64_t *avail)
|
|
{
|
|
return mJarStream->Available(avail);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARInputThunk::Read(char *buf, uint32_t count, uint32_t *countRead)
|
|
{
|
|
return mJarStream->Read(buf, count, countRead);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARInputThunk::ReadSegments(nsWriteSegmentFun writer, void *closure,
|
|
uint32_t count, uint32_t *countRead)
|
|
{
|
|
// stream transport does only calls Read()
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARInputThunk::IsNonBlocking(bool *nonBlocking)
|
|
{
|
|
*nonBlocking = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// nsJARChannel
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
nsJARChannel::nsJARChannel()
|
|
: mOpened(false)
|
|
, mAppURI(nullptr)
|
|
, mContentDisposition(0)
|
|
, mContentLength(-1)
|
|
, mLoadFlags(LOAD_NORMAL)
|
|
, mStatus(NS_OK)
|
|
, mIsPending(false)
|
|
, mIsUnsafe(true)
|
|
, mOpeningRemote(false)
|
|
, mBlockRemoteFiles(false)
|
|
{
|
|
mBlockRemoteFiles = Preferences::GetBool("network.jar.block-remote-files", false);
|
|
|
|
// hold an owning reference to the jar handler
|
|
NS_ADDREF(gJarHandler);
|
|
}
|
|
|
|
nsJARChannel::~nsJARChannel()
|
|
{
|
|
NS_ReleaseOnMainThread(mLoadInfo.forget());
|
|
|
|
// release owning reference to the jar handler
|
|
nsJARProtocolHandler *handler = gJarHandler;
|
|
NS_RELEASE(handler); // nullptr parameter
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED(nsJARChannel,
|
|
nsHashPropertyBag,
|
|
nsIRequest,
|
|
nsIChannel,
|
|
nsIStreamListener,
|
|
nsIRequestObserver,
|
|
nsIRemoteOpenFileListener,
|
|
nsIThreadRetargetableRequest,
|
|
nsIThreadRetargetableStreamListener,
|
|
nsIJARChannel)
|
|
|
|
nsresult
|
|
nsJARChannel::Init(nsIURI *uri)
|
|
{
|
|
nsresult rv;
|
|
mJarURI = do_QueryInterface(uri, &rv);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
mOriginalURI = mJarURI;
|
|
|
|
// Prevent loading jar:javascript URIs (see bug 290982).
|
|
nsCOMPtr<nsIURI> innerURI;
|
|
rv = mJarURI->GetJARFile(getter_AddRefs(innerURI));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
bool isJS;
|
|
rv = innerURI->SchemeIs("javascript", &isJS);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
if (isJS) {
|
|
NS_WARNING("blocking jar:javascript:");
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
mJarURI->GetSpec(mSpec);
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache, nsJARInputThunk **resultInput)
|
|
{
|
|
MOZ_ASSERT(resultInput);
|
|
MOZ_ASSERT(mJarFile || mTempMem);
|
|
|
|
// important to pass a clone of the file since the nsIFile impl is not
|
|
// necessarily MT-safe
|
|
nsCOMPtr<nsIFile> clonedFile;
|
|
nsresult rv = NS_OK;
|
|
if (mJarFile) {
|
|
rv = mJarFile->Clone(getter_AddRefs(clonedFile));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIZipReader> reader;
|
|
if (jarCache) {
|
|
MOZ_ASSERT(mJarFile);
|
|
if (mInnerJarEntry.IsEmpty())
|
|
rv = jarCache->GetZip(clonedFile, getter_AddRefs(reader));
|
|
else
|
|
rv = jarCache->GetInnerZip(clonedFile, mInnerJarEntry,
|
|
getter_AddRefs(reader));
|
|
} else {
|
|
// create an uncached jar reader
|
|
nsCOMPtr<nsIZipReader> outerReader = do_CreateInstance(kZipReaderCID, &rv);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (mJarFile) {
|
|
rv = outerReader->Open(clonedFile);
|
|
} else {
|
|
rv = outerReader->OpenMemory(mTempMem->Elements(),
|
|
mTempMem->Length());
|
|
}
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (mInnerJarEntry.IsEmpty())
|
|
reader = outerReader;
|
|
else {
|
|
reader = do_CreateInstance(kZipReaderCID, &rv);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
rv = reader->OpenInner(outerReader, mInnerJarEntry);
|
|
}
|
|
}
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
RefPtr<nsJARInputThunk> input = new nsJARInputThunk(reader,
|
|
mJarURI,
|
|
mJarEntry,
|
|
jarCache != nullptr
|
|
);
|
|
rv = input->Init();
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
// Make GetContentLength meaningful
|
|
mContentLength = input->GetContentLength();
|
|
|
|
input.forget(resultInput);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsJARChannel::LookupFile(bool aAllowAsync)
|
|
{
|
|
LOG(("nsJARChannel::LookupFile [this=%x %s]\n", this, mSpec.get()));
|
|
|
|
if (mJarFile)
|
|
return NS_OK;
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
rv = mJarURI->GetJARFile(getter_AddRefs(mJarBaseURI));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
rv = mJarURI->GetJAREntry(mJarEntry);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
// The name of the JAR entry must not contain URL-escaped characters:
|
|
// we're moving from URL domain to a filename domain here. nsStandardURL
|
|
// does basic escaping by default, which breaks reading zipped files which
|
|
// have e.g. spaces in their filenames.
|
|
NS_UnescapeURL(mJarEntry);
|
|
|
|
// try to get a nsIFile directly from the url, which will often succeed.
|
|
{
|
|
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mJarBaseURI);
|
|
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 && !gJarHandler->IsMainProcess()) {
|
|
nsAutoCString scheme;
|
|
rv = mJarBaseURI->GetScheme(scheme);
|
|
if (NS_SUCCEEDED(rv) && scheme.EqualsLiteral("remoteopenfile")) {
|
|
RefPtr<RemoteOpenFileChild> remoteFile = new RemoteOpenFileChild();
|
|
rv = remoteFile->Init(mJarBaseURI, mAppURI);
|
|
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().
|
|
// When the file descriptor is needed, get it from JAR cache
|
|
// if available, otherwise do the remote open to get a new
|
|
// one.
|
|
#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
|
|
// Windows/OSX desktop builds skip remoting, we don't need
|
|
// file descriptor here.
|
|
return NS_OK;
|
|
#else
|
|
PRFileDesc *fd = nullptr;
|
|
jarCache->GetFd(mJarFile, &fd);
|
|
if (fd) {
|
|
return SetRemoteNSPRFileDesc(fd);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (!aAllowAsync) {
|
|
mJarFile = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
mOpeningRemote = true;
|
|
|
|
if (gJarHandler->RemoteOpenFileInProgress(remoteFile, this)) {
|
|
// JarHandler will trigger OnRemoteFileOpen() after the first
|
|
// request for this file completes and we'll get a JAR cache
|
|
// hit.
|
|
return NS_OK;
|
|
}
|
|
|
|
// Open file on parent: OnRemoteFileOpenComplete called when done
|
|
nsCOMPtr<nsITabChild> tabChild;
|
|
NS_QueryNotificationCallbacks(this, tabChild);
|
|
nsCOMPtr<nsILoadContext> loadContext;
|
|
NS_QueryNotificationCallbacks(this, loadContext);
|
|
rv = remoteFile->AsyncRemoteFileOpen(PR_RDONLY, this, tabChild,
|
|
loadContext);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
}
|
|
// try to handle a nested jar
|
|
if (!mJarFile) {
|
|
nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(mJarBaseURI);
|
|
if (jarURI) {
|
|
nsCOMPtr<nsIFileURL> fileURL;
|
|
nsCOMPtr<nsIURI> innerJarURI;
|
|
rv = jarURI->GetJARFile(getter_AddRefs(innerJarURI));
|
|
if (NS_SUCCEEDED(rv))
|
|
fileURL = do_QueryInterface(innerJarURI);
|
|
if (fileURL) {
|
|
fileURL->GetFile(getter_AddRefs(mJarFile));
|
|
jarURI->GetJAREntry(mInnerJarEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsJARChannel::OpenLocalFile()
|
|
{
|
|
MOZ_ASSERT(mIsPending);
|
|
|
|
// Local files are always considered safe.
|
|
mIsUnsafe = false;
|
|
|
|
RefPtr<nsJARInputThunk> input;
|
|
nsresult 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);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
nsJARChannel::NotifyError(nsresult aError)
|
|
{
|
|
MOZ_ASSERT(NS_FAILED(aError));
|
|
|
|
mStatus = aError;
|
|
|
|
OnStartRequest(nullptr, nullptr);
|
|
OnStopRequest(nullptr, nullptr, aError);
|
|
}
|
|
|
|
void
|
|
nsJARChannel::FireOnProgress(uint64_t aProgress)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(mProgressSink);
|
|
|
|
mProgressSink->OnProgress(this, nullptr, aProgress, mContentLength);
|
|
}
|
|
|
|
nsresult
|
|
nsJARChannel::SetRemoteNSPRFileDesc(PRFileDesc *fd)
|
|
{
|
|
PROsfd osfd = dup(PR_FileDesc2NativeHandle(fd));
|
|
if (osfd == -1) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
RemoteOpenFileChild* remoteFile =
|
|
static_cast<RemoteOpenFileChild*>(mJarFile.get());
|
|
nsresult rv = remoteFile->SetNSPRFileDesc(PR_ImportFile(osfd));
|
|
if (NS_FAILED(rv)) {
|
|
close(osfd);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// nsIRequest
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetName(nsACString &result)
|
|
{
|
|
return mJarURI->GetSpec(result);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::IsPending(bool *result)
|
|
{
|
|
*result = mIsPending;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetStatus(nsresult *status)
|
|
{
|
|
if (mPump && NS_SUCCEEDED(mStatus))
|
|
mPump->GetStatus(status);
|
|
else
|
|
*status = mStatus;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::Cancel(nsresult status)
|
|
{
|
|
mStatus = status;
|
|
if (mPump)
|
|
return mPump->Cancel(status);
|
|
|
|
NS_ASSERTION(!mIsPending, "need to implement cancel when downloading");
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::Suspend()
|
|
{
|
|
if (mPump)
|
|
return mPump->Suspend();
|
|
|
|
NS_ASSERTION(!mIsPending, "need to implement suspend when downloading");
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::Resume()
|
|
{
|
|
if (mPump)
|
|
return mPump->Resume();
|
|
|
|
NS_ASSERTION(!mIsPending, "need to implement resume when downloading");
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
|
{
|
|
*aLoadFlags = mLoadFlags;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
|
|
{
|
|
mLoadFlags = aLoadFlags;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
|
|
{
|
|
NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
|
|
{
|
|
mLoadGroup = aLoadGroup;
|
|
return NS_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// nsIChannel
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetOriginalURI(nsIURI **aURI)
|
|
{
|
|
*aURI = mOriginalURI;
|
|
NS_ADDREF(*aURI);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetOriginalURI(nsIURI *aURI)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aURI);
|
|
mOriginalURI = aURI;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetURI(nsIURI **aURI)
|
|
{
|
|
if (mAppURI) {
|
|
NS_IF_ADDREF(*aURI = mAppURI);
|
|
} else {
|
|
NS_IF_ADDREF(*aURI = mJarURI);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetOwner(nsISupports **aOwner)
|
|
{
|
|
// JAR signatures are not processed to avoid main-thread network I/O (bug 726125)
|
|
*aOwner = mOwner;
|
|
NS_IF_ADDREF(*aOwner);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetOwner(nsISupports *aOwner)
|
|
{
|
|
mOwner = aOwner;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetLoadInfo(nsILoadInfo **aLoadInfo)
|
|
{
|
|
NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
|
|
{
|
|
mLoadInfo = aLoadInfo;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
|
|
{
|
|
NS_IF_ADDREF(*aCallbacks = mCallbacks);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
|
|
{
|
|
mCallbacks = aCallbacks;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsJARChannel::OverrideSecurityInfo(nsISupports* aSecurityInfo)
|
|
{
|
|
MOZ_RELEASE_ASSERT(!mSecurityInfo,
|
|
"This can only be called when we don't have a security info object already");
|
|
MOZ_RELEASE_ASSERT(aSecurityInfo,
|
|
"This can only be called with a valid security info object");
|
|
mSecurityInfo = aSecurityInfo;
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsJARChannel::OverrideURI(nsIURI* aRedirectedURI)
|
|
{
|
|
MOZ_RELEASE_ASSERT(mLoadFlags & LOAD_REPLACE,
|
|
"This can only happen if the LOAD_REPLACE flag is set");
|
|
mAppURI = aRedirectedURI;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
|
|
{
|
|
NS_PRECONDITION(aSecurityInfo, "Null out param");
|
|
NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetContentType(nsACString &result)
|
|
{
|
|
// If the Jar file has not been open yet,
|
|
// We return application/x-unknown-content-type
|
|
if (!mOpened) {
|
|
result.Assign(UNKNOWN_CONTENT_TYPE);
|
|
return NS_OK;
|
|
}
|
|
|
|
if (mContentType.IsEmpty()) {
|
|
|
|
//
|
|
// generate content type and set it
|
|
//
|
|
const char *ext = nullptr, *fileName = mJarEntry.get();
|
|
int32_t len = mJarEntry.Length();
|
|
|
|
// check if we're displaying a directory
|
|
// mJarEntry will be empty if we're trying to display
|
|
// the topmost directory in a zip, e.g. jar:foo.zip!/
|
|
if (ENTRY_IS_DIRECTORY(mJarEntry)) {
|
|
mContentType.AssignLiteral(APPLICATION_HTTP_INDEX_FORMAT);
|
|
}
|
|
else {
|
|
// not a directory, take a guess by its extension
|
|
for (int32_t i = len-1; i >= 0; i--) {
|
|
if (fileName[i] == '.') {
|
|
ext = &fileName[i + 1];
|
|
break;
|
|
}
|
|
}
|
|
if (ext) {
|
|
nsIMIMEService *mimeServ = gJarHandler->MimeService();
|
|
if (mimeServ)
|
|
mimeServ->GetTypeFromExtension(nsDependentCString(ext), mContentType);
|
|
}
|
|
if (mContentType.IsEmpty())
|
|
mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
|
|
}
|
|
}
|
|
result = mContentType;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetContentType(const nsACString &aContentType)
|
|
{
|
|
// If someone gives us a type hint we should just use that type instead of
|
|
// doing our guessing. So we don't care when this is being called.
|
|
|
|
// mContentCharset is unchanged if not parsed
|
|
NS_ParseResponseContentType(aContentType, mContentType, mContentCharset);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetContentCharset(nsACString &aContentCharset)
|
|
{
|
|
// If someone gives us a charset hint we should just use that charset.
|
|
// So we don't care when this is being called.
|
|
aContentCharset = mContentCharset;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetContentCharset(const nsACString &aContentCharset)
|
|
{
|
|
mContentCharset = aContentCharset;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetContentDisposition(uint32_t *aContentDisposition)
|
|
{
|
|
if (mContentDispositionHeader.IsEmpty())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
*aContentDisposition = mContentDisposition;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetContentDisposition(uint32_t aContentDisposition)
|
|
{
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
|
|
{
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
|
|
{
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
|
|
{
|
|
if (mContentDispositionHeader.IsEmpty())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aContentDispositionHeader = mContentDispositionHeader;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetContentLength(int64_t *result)
|
|
{
|
|
*result = mContentLength;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetContentLength(int64_t aContentLength)
|
|
{
|
|
// XXX does this really make any sense at all?
|
|
mContentLength = aContentLength;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::Open(nsIInputStream **stream)
|
|
{
|
|
LOG(("nsJARChannel::Open [this=%x]\n", this));
|
|
|
|
NS_ENSURE_TRUE(!mOpened, NS_ERROR_IN_PROGRESS);
|
|
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
|
|
|
mJarFile = nullptr;
|
|
mIsUnsafe = true;
|
|
|
|
nsresult rv = LookupFile(false);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
// If mJarInput was not set by LookupFile, the JAR is a remote jar.
|
|
if (!mJarFile) {
|
|
NS_NOTREACHED("need sync downloader");
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
RefPtr<nsJARInputThunk> input;
|
|
rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
input.forget(stream);
|
|
mOpened = true;
|
|
// local files are always considered safe
|
|
mIsUnsafe = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::Open2(nsIInputStream** aStream)
|
|
{
|
|
nsCOMPtr<nsIStreamListener> listener;
|
|
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
return Open(aStream);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
|
|
{
|
|
MOZ_ASSERT(!mLoadInfo ||
|
|
mLoadInfo->GetSecurityMode() == 0 ||
|
|
mLoadInfo->GetInitialSecurityCheckDone() ||
|
|
(mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
|
|
nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
|
|
"security flags in loadInfo but asyncOpen2() not called");
|
|
|
|
LOG(("nsJARChannel::AsyncOpen [this=%x]\n", this));
|
|
|
|
NS_ENSURE_ARG_POINTER(listener);
|
|
NS_ENSURE_TRUE(!mOpened, NS_ERROR_IN_PROGRESS);
|
|
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
|
|
|
mJarFile = nullptr;
|
|
mIsUnsafe = true;
|
|
|
|
// Initialize mProgressSink
|
|
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, mProgressSink);
|
|
|
|
mListener = listener;
|
|
mListenerContext = ctx;
|
|
mIsPending = true;
|
|
|
|
nsresult rv = LookupFile(true);
|
|
if (NS_FAILED(rv)) {
|
|
mIsPending = false;
|
|
mListenerContext = nullptr;
|
|
mListener = nullptr;
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIChannel> channel;
|
|
|
|
if (!mJarFile) {
|
|
// Not a local file...
|
|
|
|
// Check preferences to see if all remote jar support should be disabled
|
|
if (mBlockRemoteFiles) {
|
|
mIsUnsafe = true;
|
|
return NS_ERROR_UNSAFE_CONTENT_TYPE;
|
|
}
|
|
|
|
static bool reportedRemoteJAR = false;
|
|
if (!reportedRemoteJAR) {
|
|
reportedRemoteJAR = true;
|
|
Telemetry::Accumulate(Telemetry::REMOTE_JAR_PROTOCOL_USED, 1);
|
|
}
|
|
|
|
// kick off an async download of the base URI...
|
|
nsCOMPtr<nsIStreamListener> downloader = new MemoryDownloader(this);
|
|
uint32_t loadFlags =
|
|
mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS);
|
|
rv = NS_NewChannelInternal(getter_AddRefs(channel),
|
|
mJarBaseURI,
|
|
mLoadInfo,
|
|
mLoadGroup,
|
|
mCallbacks,
|
|
loadFlags);
|
|
if (NS_FAILED(rv)) {
|
|
mIsPending = false;
|
|
mListenerContext = nullptr;
|
|
mListener = nullptr;
|
|
return rv;
|
|
}
|
|
if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) {
|
|
rv = channel->AsyncOpen2(downloader);
|
|
}
|
|
else {
|
|
rv = channel->AsyncOpen(downloader, nullptr);
|
|
}
|
|
} else if (mOpeningRemote) {
|
|
// nothing to do: already asked parent to open file.
|
|
} else {
|
|
rv = OpenLocalFile();
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
mIsPending = false;
|
|
mListenerContext = nullptr;
|
|
mListener = nullptr;
|
|
return rv;
|
|
}
|
|
|
|
if (mLoadGroup)
|
|
mLoadGroup->AddRequest(this, nullptr);
|
|
|
|
mOpened = true;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::AsyncOpen2(nsIStreamListener *aListener)
|
|
{
|
|
nsCOMPtr<nsIStreamListener> listener = aListener;
|
|
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
return AsyncOpen(listener, nullptr);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// nsIJARChannel
|
|
//-----------------------------------------------------------------------------
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetIsUnsafe(bool *isUnsafe)
|
|
{
|
|
*isUnsafe = mIsUnsafe;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::SetAppURI(nsIURI *aURI) {
|
|
NS_ENSURE_ARG_POINTER(aURI);
|
|
|
|
nsAutoCString scheme;
|
|
aURI->GetScheme(scheme);
|
|
if (!scheme.EqualsLiteral("app")) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
mAppURI = aURI;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetJarFile(nsIFile **aFile)
|
|
{
|
|
NS_IF_ADDREF(*aFile = mJarFile);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::GetZipEntry(nsIZipEntry **aZipEntry)
|
|
{
|
|
nsresult rv = LookupFile(false);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (!mJarFile)
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
nsCOMPtr<nsIZipReader> reader;
|
|
rv = gJarHandler->JarCache()->GetZip(mJarFile, getter_AddRefs(reader));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
return reader->GetEntry(mJarEntry, aZipEntry);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// mozilla::net::MemoryDownloader::IObserver
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void
|
|
nsJARChannel::OnDownloadComplete(MemoryDownloader* aDownloader,
|
|
nsIRequest *request,
|
|
nsISupports *context,
|
|
nsresult status,
|
|
MemoryDownloader::Data aData)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
|
|
if (channel) {
|
|
uint32_t loadFlags;
|
|
channel->GetLoadFlags(&loadFlags);
|
|
if (loadFlags & LOAD_REPLACE) {
|
|
mLoadFlags |= LOAD_REPLACE;
|
|
|
|
if (!mOriginalURI) {
|
|
SetOriginalURI(mJarURI);
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> innerURI;
|
|
rv = channel->GetURI(getter_AddRefs(innerURI));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
nsCOMPtr<nsIJARURI> newURI;
|
|
rv = mJarURI->CloneWithJARFile(innerURI,
|
|
getter_AddRefs(newURI));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
mJarURI = newURI;
|
|
}
|
|
}
|
|
if (NS_SUCCEEDED(status)) {
|
|
status = rv;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NS_SUCCEEDED(status) && channel) {
|
|
// Grab the security info from our base channel
|
|
channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
|
|
if (httpChannel) {
|
|
// We only want to run scripts if the server really intended to
|
|
// send us a JAR file. Check the server-supplied content type for
|
|
// a JAR type.
|
|
nsAutoCString header;
|
|
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
|
|
header);
|
|
nsAutoCString contentType;
|
|
nsAutoCString charset;
|
|
NS_ParseResponseContentType(header, contentType, charset);
|
|
nsAutoCString channelContentType;
|
|
channel->GetContentType(channelContentType);
|
|
mIsUnsafe = !(contentType.Equals(channelContentType) &&
|
|
(contentType.EqualsLiteral("application/java-archive") ||
|
|
contentType.EqualsLiteral("application/x-jar")));
|
|
} else {
|
|
nsCOMPtr<nsIJARChannel> innerJARChannel(do_QueryInterface(channel));
|
|
if (innerJARChannel) {
|
|
bool unsafe;
|
|
innerJARChannel->GetIsUnsafe(&unsafe);
|
|
mIsUnsafe = unsafe;
|
|
}
|
|
}
|
|
|
|
channel->GetContentDispositionHeader(mContentDispositionHeader);
|
|
mContentDisposition = NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
|
|
}
|
|
|
|
// This is a defense-in-depth check for the preferences to see if all remote jar
|
|
// support should be disabled. This check may not be needed.
|
|
MOZ_RELEASE_ASSERT(!mBlockRemoteFiles);
|
|
|
|
if (NS_SUCCEEDED(status) && mIsUnsafe &&
|
|
!Preferences::GetBool("network.jar.open-unsafe-types", false)) {
|
|
status = NS_ERROR_UNSAFE_CONTENT_TYPE;
|
|
}
|
|
|
|
if (NS_SUCCEEDED(status)) {
|
|
// Refuse to unpack view-source: jars even if open-unsafe-types is set.
|
|
nsCOMPtr<nsIViewSourceChannel> viewSource = do_QueryInterface(channel);
|
|
if (viewSource) {
|
|
status = NS_ERROR_UNSAFE_CONTENT_TYPE;
|
|
}
|
|
}
|
|
|
|
if (NS_SUCCEEDED(status)) {
|
|
mTempMem = Move(aData);
|
|
|
|
RefPtr<nsJARInputThunk> input;
|
|
rv = CreateJarInput(nullptr, getter_AddRefs(input));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
// create input stream pump
|
|
rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input);
|
|
if (NS_SUCCEEDED(rv))
|
|
rv = mPump->AsyncRead(this, nullptr);
|
|
}
|
|
status = rv;
|
|
}
|
|
|
|
if (NS_FAILED(status)) {
|
|
NotifyError(status);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// nsIRemoteOpenFileListener
|
|
//-----------------------------------------------------------------------------
|
|
nsresult
|
|
nsJARChannel::OnRemoteFileOpenComplete(nsresult aOpenStatus)
|
|
{
|
|
nsresult rv = aOpenStatus;
|
|
|
|
// NS_ERROR_ALREADY_OPENED here means we'll hit JAR cache in
|
|
// OpenLocalFile().
|
|
if (NS_SUCCEEDED(rv) || rv == NS_ERROR_ALREADY_OPENED) {
|
|
#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
|
|
// Windows/OSX desktop builds skip remoting, we don't need file
|
|
// descriptor here.
|
|
#else
|
|
// Set file descriptor from Jar cache into remote Jar file, if it
|
|
// has not been set previously.
|
|
mozilla::AutoFDClose fd;
|
|
mJarFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd.rwget());
|
|
if (!fd) {
|
|
nsIZipReaderCache *jarCache = gJarHandler->JarCache();
|
|
if (!jarCache) {
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
PRFileDesc *jar_fd = nullptr;
|
|
jarCache->GetFd(mJarFile, &jar_fd);
|
|
// If we failed to get fd here, an error rv would be returned
|
|
// by SetRemoteNSPRFileDesc(), which would then stop the
|
|
// channel by NotifyError().
|
|
rv = SetRemoteNSPRFileDesc(jar_fd);
|
|
}
|
|
#endif
|
|
if (NS_SUCCEEDED(rv) || rv == NS_ERROR_ALREADY_OPENED) {
|
|
rv = OpenLocalFile();
|
|
}
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
NotifyError(rv);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// nsIStreamListener
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx)
|
|
{
|
|
LOG(("nsJARChannel::OnStartRequest [this=%x %s]\n", this, mSpec.get()));
|
|
|
|
mRequest = req;
|
|
nsresult rv = mListener->OnStartRequest(this, mListenerContext);
|
|
mRequest = nullptr;
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
|
|
{
|
|
LOG(("nsJARChannel::OnStopRequest [this=%x %s status=%x]\n",
|
|
this, mSpec.get(), status));
|
|
|
|
if (NS_SUCCEEDED(mStatus))
|
|
mStatus = status;
|
|
|
|
if (mListener) {
|
|
mListener->OnStopRequest(this, mListenerContext, status);
|
|
mListener = 0;
|
|
mListenerContext = 0;
|
|
}
|
|
|
|
if (mLoadGroup)
|
|
mLoadGroup->RemoveRequest(this, nullptr, status);
|
|
|
|
mPump = 0;
|
|
mIsPending = false;
|
|
|
|
// Drop notification callbacks to prevent cycles.
|
|
mCallbacks = 0;
|
|
mProgressSink = 0;
|
|
|
|
#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
|
|
#else
|
|
// To deallocate file descriptor by RemoteOpenFileChild destructor.
|
|
mJarFile = nullptr;
|
|
#endif
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx,
|
|
nsIInputStream *stream,
|
|
uint64_t offset, uint32_t count)
|
|
{
|
|
LOG(("nsJARChannel::OnDataAvailable [this=%x %s]\n", this, mSpec.get()));
|
|
|
|
nsresult rv;
|
|
|
|
rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count);
|
|
|
|
// simply report progress here instead of hooking ourselves up as a
|
|
// nsITransportEventSink implementation.
|
|
// XXX do the 64-bit stuff for real
|
|
if (mProgressSink && NS_SUCCEEDED(rv)) {
|
|
if (NS_IsMainThread()) {
|
|
FireOnProgress(offset + count);
|
|
} else {
|
|
NS_DispatchToMainThread(NewRunnableMethod
|
|
<uint64_t>(this,
|
|
&nsJARChannel::FireOnProgress,
|
|
offset + count));
|
|
}
|
|
}
|
|
|
|
return rv; // let the pump cancel on failure
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::RetargetDeliveryTo(nsIEventTarget* aEventTarget)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
nsCOMPtr<nsIThreadRetargetableRequest> request = do_QueryInterface(mRequest);
|
|
if (!request) {
|
|
return NS_ERROR_NO_INTERFACE;
|
|
}
|
|
|
|
return request->RetargetDeliveryTo(aEventTarget);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsJARChannel::CheckListenerChain()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
nsCOMPtr<nsIThreadRetargetableStreamListener> listener =
|
|
do_QueryInterface(mListener);
|
|
if (!listener) {
|
|
return NS_ERROR_NO_INTERFACE;
|
|
}
|
|
|
|
return listener->CheckListenerChain();
|
|
}
|