mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-03 22:07:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
33
uriloader/base/moz.build
Normal file
33
uriloader/base/moz.build
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsCURILoader.idl',
|
||||
'nsIContentHandler.idl',
|
||||
'nsIDocumentLoader.idl',
|
||||
'nsITransfer.idl',
|
||||
'nsIURIContentListener.idl',
|
||||
'nsIURILoader.idl',
|
||||
'nsIWebProgress.idl',
|
||||
'nsIWebProgressListener.idl',
|
||||
'nsIWebProgressListener2.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'uriloader'
|
||||
|
||||
EXPORTS += [
|
||||
'nsDocLoader.h',
|
||||
'nsURILoader.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsDocLoader.cpp',
|
||||
'nsURILoader.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
49
uriloader/base/nsCURILoader.idl
Normal file
49
uriloader/base/nsCURILoader.idl
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- Mode: IDL; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 "nsIURILoader.idl"
|
||||
|
||||
/*
|
||||
nsCURILoader implements:
|
||||
-------------------------
|
||||
nsIURILoader
|
||||
*/
|
||||
|
||||
%{ C++
|
||||
// {9F6D5D40-90E7-11d3-AF93-00A024FFC08C} -
|
||||
#define NS_URI_LOADER_CID \
|
||||
{ 0x9f6d5d40, 0x90e7, 0x11d3, { 0xaf, 0x80, 0x00, 0xa0, 0x24, 0xff, 0xc0, 0x8c } }
|
||||
#define NS_URI_LOADER_CONTRACTID \
|
||||
"@mozilla.org/uriloader;1"
|
||||
|
||||
/* 057b04d0-0ccf-11d2-beba-00805f8a66dc */
|
||||
#define NS_DOCUMENTLOADER_SERVICE_CID \
|
||||
{ 0x057b04d0, 0x0ccf, 0x11d2,{0xbe, 0xba, 0x00, 0x80, 0x5f, 0x8a, 0x66, 0xdc}}
|
||||
|
||||
#define NS_DOCUMENTLOADER_SERVICE_CONTRACTID \
|
||||
"@mozilla.org/docloaderservice;1"
|
||||
|
||||
#define NS_CONTENT_HANDLER_CONTRACTID "@mozilla.org/uriloader/content-handler;1"
|
||||
#define NS_CONTENT_HANDLER_CONTRACTID_PREFIX NS_CONTENT_HANDLER_CONTRACTID "?type="
|
||||
|
||||
/**
|
||||
* A category where content listeners can register. The name of the entry must
|
||||
* be the content that this listener wants to handle, the value must be a
|
||||
* contract ID for the listener. It will be created using createInstance (not
|
||||
* getService).
|
||||
*
|
||||
* Listeners added this way are tried after the initial target of the load and
|
||||
* after explicitly registered listeners (nsIURILoader::registerContentListener).
|
||||
*
|
||||
* These listeners must implement at least nsIURIContentListener (and
|
||||
* nsISupports).
|
||||
*
|
||||
* @see nsICategoryManager
|
||||
* @see nsIURIContentListener
|
||||
*/
|
||||
#define NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY "external-uricontentlisteners"
|
||||
|
||||
%}
|
||||
1516
uriloader/base/nsDocLoader.cpp
Normal file
1516
uriloader/base/nsDocLoader.cpp
Normal file
File diff suppressed because it is too large
Load diff
335
uriloader/base/nsDocLoader.h
Normal file
335
uriloader/base/nsDocLoader.h
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 nsDocLoader_h__
|
||||
#define nsDocLoader_h__
|
||||
|
||||
#include "nsIDocumentLoader.h"
|
||||
#include "nsIWebProgress.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsIRequestObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsISecurityEventSink.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "PLDHashTable.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#include "mozilla/LinkedList.h"
|
||||
|
||||
/****************************************************************************
|
||||
* nsDocLoader implementation...
|
||||
****************************************************************************/
|
||||
|
||||
#define NS_THIS_DOCLOADER_IMPL_CID \
|
||||
{ /* b4ec8387-98aa-4c08-93b6-6d23069c06f2 */ \
|
||||
0xb4ec8387, \
|
||||
0x98aa, \
|
||||
0x4c08, \
|
||||
{0x93, 0xb6, 0x6d, 0x23, 0x06, 0x9c, 0x06, 0xf2} \
|
||||
}
|
||||
|
||||
class nsDocLoader : public nsIDocumentLoader,
|
||||
public nsIRequestObserver,
|
||||
public nsSupportsWeakReference,
|
||||
public nsIProgressEventSink,
|
||||
public nsIWebProgress,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIChannelEventSink,
|
||||
public nsISecurityEventSink,
|
||||
public nsISupportsPriority
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_THIS_DOCLOADER_IMPL_CID)
|
||||
|
||||
nsDocLoader();
|
||||
|
||||
virtual MOZ_MUST_USE nsresult Init();
|
||||
|
||||
static already_AddRefed<nsDocLoader> GetAsDocLoader(nsISupports* aSupports);
|
||||
// Needed to deal with ambiguous inheritance from nsISupports...
|
||||
static nsISupports* GetAsSupports(nsDocLoader* aDocLoader) {
|
||||
return static_cast<nsIDocumentLoader*>(aDocLoader);
|
||||
}
|
||||
|
||||
// Add aDocLoader as a child to the docloader service.
|
||||
static MOZ_MUST_USE nsresult AddDocLoaderAsChildOfRoot(nsDocLoader* aDocLoader);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOCUMENTLOADER
|
||||
|
||||
// nsIProgressEventSink
|
||||
NS_DECL_NSIPROGRESSEVENTSINK
|
||||
|
||||
NS_DECL_NSISECURITYEVENTSINK
|
||||
|
||||
// nsIRequestObserver methods: (for observing the load group)
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSIWEBPROGRESS
|
||||
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
NS_DECL_NSISUPPORTSPRIORITY
|
||||
|
||||
// Implementation specific methods...
|
||||
|
||||
// Remove aChild from our childlist. This nulls out the child's mParent
|
||||
// pointer.
|
||||
MOZ_MUST_USE nsresult RemoveChildLoader(nsDocLoader *aChild);
|
||||
// Add aChild to our child list. This will set aChild's mParent pointer to
|
||||
// |this|.
|
||||
MOZ_MUST_USE nsresult AddChildLoader(nsDocLoader* aChild);
|
||||
nsDocLoader* GetParent() const { return mParent; }
|
||||
|
||||
struct nsListenerInfo {
|
||||
nsListenerInfo(nsIWeakReference *aListener, unsigned long aNotifyMask)
|
||||
: mWeakListener(aListener),
|
||||
mNotifyMask(aNotifyMask)
|
||||
{
|
||||
}
|
||||
|
||||
// Weak pointer for the nsIWebProgressListener...
|
||||
nsWeakPtr mWeakListener;
|
||||
|
||||
// Mask indicating which notifications the listener wants to receive.
|
||||
unsigned long mNotifyMask;
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual ~nsDocLoader();
|
||||
|
||||
virtual MOZ_MUST_USE nsresult SetDocLoaderParent(nsDocLoader * aLoader);
|
||||
|
||||
bool IsBusy();
|
||||
|
||||
void Destroy();
|
||||
virtual void DestroyChildren();
|
||||
|
||||
nsIDocumentLoader* ChildAt(int32_t i) {
|
||||
return mChildList.SafeElementAt(i, nullptr);
|
||||
}
|
||||
|
||||
void FireOnProgressChange(nsDocLoader* aLoadInitiator,
|
||||
nsIRequest *request,
|
||||
int64_t aProgress,
|
||||
int64_t aProgressMax,
|
||||
int64_t aProgressDelta,
|
||||
int64_t aTotalProgress,
|
||||
int64_t aMaxTotalProgress);
|
||||
|
||||
// This should be at least 2 long since we'll generally always
|
||||
// have the current page and the global docloader on the ancestor
|
||||
// list. But to deal with frames it's better to make it a bit
|
||||
// longer, and it's always a stack temporary so there's no real
|
||||
// reason not to.
|
||||
typedef AutoTArray<RefPtr<nsDocLoader>, 8> WebProgressList;
|
||||
void GatherAncestorWebProgresses(WebProgressList& aList);
|
||||
|
||||
void FireOnStateChange(nsIWebProgress *aProgress,
|
||||
nsIRequest* request,
|
||||
int32_t aStateFlags,
|
||||
nsresult aStatus);
|
||||
|
||||
// The guts of FireOnStateChange, but does not call itself on our ancestors.
|
||||
// The arguments that are const are const so that we can detect cases when
|
||||
// DoFireOnStateChange wants to propagate changes to the next web progress
|
||||
// at compile time. The ones that are not, are references so that such
|
||||
// changes can be propagated.
|
||||
void DoFireOnStateChange(nsIWebProgress * const aProgress,
|
||||
nsIRequest* const request,
|
||||
int32_t &aStateFlags,
|
||||
const nsresult aStatus);
|
||||
|
||||
void FireOnStatusChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest,
|
||||
nsresult aStatus,
|
||||
const char16_t* aMessage);
|
||||
|
||||
void FireOnLocationChange(nsIWebProgress* aWebProgress,
|
||||
nsIRequest* aRequest,
|
||||
nsIURI *aUri,
|
||||
uint32_t aFlags);
|
||||
|
||||
MOZ_MUST_USE bool RefreshAttempted(nsIWebProgress* aWebProgress,
|
||||
nsIURI *aURI,
|
||||
int32_t aDelay,
|
||||
bool aSameURI);
|
||||
|
||||
// this function is overridden by the docshell, it is provided so that we
|
||||
// can pass more information about redirect state (the normal OnStateChange
|
||||
// doesn't get the new channel).
|
||||
// @param aRedirectFlags The flags being sent to OnStateChange that
|
||||
// indicate the type of redirect.
|
||||
// @param aStateFlags The channel flags normally sent to OnStateChange.
|
||||
virtual void OnRedirectStateChange(nsIChannel* aOldChannel,
|
||||
nsIChannel* aNewChannel,
|
||||
uint32_t aRedirectFlags,
|
||||
uint32_t aStateFlags) {}
|
||||
|
||||
void doStartDocumentLoad();
|
||||
void doStartURLLoad(nsIRequest *request);
|
||||
void doStopURLLoad(nsIRequest *request, nsresult aStatus);
|
||||
void doStopDocumentLoad(nsIRequest *request, nsresult aStatus);
|
||||
|
||||
// Inform a parent docloader that aChild is about to call its onload
|
||||
// handler.
|
||||
MOZ_MUST_USE bool ChildEnteringOnload(nsIDocumentLoader* aChild) {
|
||||
// It's ok if we're already in the list -- we'll just be in there twice
|
||||
// and then the RemoveObject calls from ChildDoneWithOnload will remove
|
||||
// us.
|
||||
return mChildrenInOnload.AppendObject(aChild);
|
||||
}
|
||||
|
||||
// Inform a parent docloader that aChild is done calling its onload
|
||||
// handler.
|
||||
void ChildDoneWithOnload(nsIDocumentLoader* aChild) {
|
||||
mChildrenInOnload.RemoveObject(aChild);
|
||||
DocLoaderIsEmpty(true);
|
||||
}
|
||||
|
||||
protected:
|
||||
struct nsStatusInfo : public mozilla::LinkedListElement<nsStatusInfo>
|
||||
{
|
||||
nsString mStatusMessage;
|
||||
nsresult mStatusCode;
|
||||
// Weak mRequest is ok; we'll be told if it decides to go away.
|
||||
nsIRequest * const mRequest;
|
||||
|
||||
explicit nsStatusInfo(nsIRequest* aRequest) :
|
||||
mRequest(aRequest)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsStatusInfo);
|
||||
}
|
||||
~nsStatusInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsStatusInfo);
|
||||
}
|
||||
};
|
||||
|
||||
struct nsRequestInfo : public PLDHashEntryHdr
|
||||
{
|
||||
explicit nsRequestInfo(const void* key)
|
||||
: mKey(key), mCurrentProgress(0), mMaxProgress(0), mUploading(false)
|
||||
, mLastStatus(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsRequestInfo);
|
||||
}
|
||||
|
||||
~nsRequestInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsRequestInfo);
|
||||
}
|
||||
|
||||
nsIRequest* Request() {
|
||||
return static_cast<nsIRequest*>(const_cast<void*>(mKey));
|
||||
}
|
||||
|
||||
const void* mKey; // Must be first for the PLDHashTable stubs to work
|
||||
int64_t mCurrentProgress;
|
||||
int64_t mMaxProgress;
|
||||
bool mUploading;
|
||||
|
||||
nsAutoPtr<nsStatusInfo> mLastStatus;
|
||||
};
|
||||
|
||||
static void RequestInfoHashInitEntry(PLDHashEntryHdr* entry, const void* key);
|
||||
static void RequestInfoHashClearEntry(PLDHashTable* table, PLDHashEntryHdr* entry);
|
||||
|
||||
// IMPORTANT: The ownership implicit in the following member
|
||||
// variables has been explicitly checked and set using nsCOMPtr
|
||||
// for owning pointers and raw COM interface pointers for weak
|
||||
// (ie, non owning) references. If you add any members to this
|
||||
// class, please make the ownership explicit (pinkerton, scc).
|
||||
|
||||
nsCOMPtr<nsIRequest> mDocumentRequest; // [OWNER] ???compare with document
|
||||
|
||||
nsDocLoader* mParent; // [WEAK]
|
||||
|
||||
typedef nsAutoTObserverArray<nsListenerInfo, 8> ListenerArray;
|
||||
ListenerArray mListenerInfoList;
|
||||
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
// We hold weak refs to all our kids
|
||||
nsTObserverArray<nsDocLoader*> mChildList;
|
||||
|
||||
// The following member variables are related to the new nsIWebProgress
|
||||
// feedback interfaces that travis cooked up.
|
||||
int32_t mProgressStateFlags;
|
||||
|
||||
int64_t mCurrentSelfProgress;
|
||||
int64_t mMaxSelfProgress;
|
||||
|
||||
int64_t mCurrentTotalProgress;
|
||||
int64_t mMaxTotalProgress;
|
||||
|
||||
PLDHashTable mRequestInfoHash;
|
||||
int64_t mCompletedTotalProgress;
|
||||
|
||||
mozilla::LinkedList<nsStatusInfo> mStatusInfoList;
|
||||
|
||||
/*
|
||||
* This flag indicates that the loader is loading a document. It is set
|
||||
* from the call to LoadDocument(...) until the OnConnectionsComplete(...)
|
||||
* notification is fired...
|
||||
*/
|
||||
bool mIsLoadingDocument;
|
||||
|
||||
/* Flag to indicate that we're in the process of restoring a document. */
|
||||
bool mIsRestoringDocument;
|
||||
|
||||
/* Flag to indicate that we're in the process of flushing layout
|
||||
under DocLoaderIsEmpty() and should not do another flush. */
|
||||
bool mDontFlushLayout;
|
||||
|
||||
/* Flag to indicate whether we should consider ourselves as currently
|
||||
flushing layout for the purposes of IsBusy. For example, if Stop has
|
||||
been called then IsBusy should return false even if we are still
|
||||
flushing. */
|
||||
bool mIsFlushingLayout;
|
||||
|
||||
private:
|
||||
static const PLDHashTableOps sRequestInfoHashOps;
|
||||
|
||||
// A list of kids that are in the middle of their onload calls and will let
|
||||
// us know once they're done. We don't want to fire onload for "normal"
|
||||
// DocLoaderIsEmpty calls (those coming from requests finishing in our
|
||||
// loadgroup) unless this is empty.
|
||||
nsCOMArray<nsIDocumentLoader> mChildrenInOnload;
|
||||
|
||||
// DocLoaderIsEmpty should be called whenever the docloader may be empty.
|
||||
// This method is idempotent and does nothing if the docloader is not in
|
||||
// fact empty. This method _does_ make sure that layout is flushed if our
|
||||
// loadgroup has no active requests before checking for "real" emptiness if
|
||||
// aFlushLayout is true.
|
||||
void DocLoaderIsEmpty(bool aFlushLayout);
|
||||
|
||||
int64_t GetMaxTotalProgress();
|
||||
|
||||
nsresult AddRequestInfo(nsIRequest* aRequest);
|
||||
void RemoveRequestInfo(nsIRequest* aRequest);
|
||||
nsRequestInfo *GetRequestInfo(nsIRequest* aRequest);
|
||||
void ClearRequestInfoHash();
|
||||
int64_t CalculateMaxProgress();
|
||||
/// void DumpChannelInfo(void);
|
||||
|
||||
// used to clear our internal progress state between loads...
|
||||
void ClearInternalProgress();
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsDocLoader, NS_THIS_DOCLOADER_IMPL_CID)
|
||||
|
||||
#endif /* nsDocLoader_h__ */
|
||||
35
uriloader/base/nsIContentHandler.idl
Normal file
35
uriloader/base/nsIContentHandler.idl
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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"
|
||||
interface nsIRequest;
|
||||
interface nsIInterfaceRequestor;
|
||||
|
||||
[scriptable, uuid(49439df2-b3d2-441c-bf62-866bdaf56fd2)]
|
||||
interface nsIContentHandler : nsISupports
|
||||
{
|
||||
/**
|
||||
* Tells the content handler to take over handling the content. If this
|
||||
* function succeeds, the URI Loader will leave this request alone, ignoring
|
||||
* progress notifications. Failure of this method will cause the request to be
|
||||
* cancelled, unless the error code is NS_ERROR_WONT_HANDLE_CONTENT (see
|
||||
* below).
|
||||
*
|
||||
* @param aWindowContext
|
||||
* Window context, used to get things like the current nsIDOMWindow
|
||||
* for this request. May be null.
|
||||
* @param aContentType
|
||||
* The content type of aRequest
|
||||
* @param aRequest
|
||||
* A request whose content type is already known.
|
||||
*
|
||||
* @throw NS_ERROR_WONT_HANDLE_CONTENT Indicates that this handler does not
|
||||
* want to handle this content. A different way for handling this
|
||||
* content should be tried.
|
||||
*/
|
||||
void handleContent(in string aContentType,
|
||||
in nsIInterfaceRequestor aWindowContext,
|
||||
in nsIRequest aRequest);
|
||||
};
|
||||
36
uriloader/base/nsIDocumentLoader.idl
Normal file
36
uriloader/base/nsIDocumentLoader.idl
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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"
|
||||
interface nsILoadGroup;
|
||||
interface nsIChannel;
|
||||
interface nsIURI;
|
||||
interface nsIWebProgress;
|
||||
interface nsIRequest;
|
||||
|
||||
/**
|
||||
* An nsIDocumentLoader is an interface responsible for tracking groups of
|
||||
* loads that belong together (images, external scripts, etc) and subdocuments
|
||||
* (<iframe>, <frame>, etc). It is also responsible for sending
|
||||
* nsIWebProgressListener notifications.
|
||||
* XXXbz this interface should go away, we think...
|
||||
*/
|
||||
[scriptable, uuid(bbe961ee-59e9-42bb-be50-0331979bb79f)]
|
||||
interface nsIDocumentLoader : nsISupports
|
||||
{
|
||||
// Stop all loads in the loadgroup of this docloader
|
||||
void stop();
|
||||
|
||||
// XXXbz is this needed? For embedding? What this does is does is not
|
||||
// defined by this interface!
|
||||
readonly attribute nsISupports container;
|
||||
|
||||
// The loadgroup associated with this docloader
|
||||
readonly attribute nsILoadGroup loadGroup;
|
||||
|
||||
// The defaultLoadRequest of the loadgroup associated with this docloader
|
||||
readonly attribute nsIChannel documentChannel;
|
||||
};
|
||||
|
||||
106
uriloader/base/nsITransfer.idl
Normal file
106
uriloader/base/nsITransfer.idl
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/* -*- 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
|
||||
* 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 "nsIWebProgressListener2.idl"
|
||||
|
||||
interface nsIArray;
|
||||
interface nsIURI;
|
||||
interface nsICancelable;
|
||||
interface nsIMIMEInfo;
|
||||
interface nsIFile;
|
||||
|
||||
[scriptable, uuid(37ec75d3-97ad-4da8-afaa-eabe5b4afd73)]
|
||||
interface nsITransfer : nsIWebProgressListener2 {
|
||||
|
||||
/**
|
||||
* Initializes the transfer with certain properties. This function must
|
||||
* be called prior to accessing any properties on this interface.
|
||||
*
|
||||
* @param aSource The source URI of the transfer. Must not be null.
|
||||
*
|
||||
* @param aTarget The target URI of the transfer. Must not be null.
|
||||
*
|
||||
* @param aDisplayName The user-readable description of the transfer.
|
||||
* Can be empty.
|
||||
*
|
||||
* @param aMIMEInfo The MIME info associated with the target,
|
||||
* including MIME type and helper app when appropriate.
|
||||
* This parameter is optional.
|
||||
*
|
||||
* @param startTime Time when the download started (ie, when the first
|
||||
* response from the server was received)
|
||||
* XXX presumably wbp and exthandler do this differently
|
||||
*
|
||||
* @param aTempFile The location of a temporary file; i.e. a file in which
|
||||
* the received data will be stored, but which is not
|
||||
* equal to the target file. (will be moved to the real
|
||||
* target by the caller, when the download is finished)
|
||||
* May be null.
|
||||
*
|
||||
* @param aCancelable An object that can be used to abort the download.
|
||||
* Must not be null.
|
||||
* Implementations are expected to hold a strong
|
||||
* reference to this object until the download is
|
||||
* finished, at which point they should release the
|
||||
* reference.
|
||||
*
|
||||
* @param aIsPrivate Used to determine the privacy status of the new transfer.
|
||||
* If true, indicates that the transfer was initiated from
|
||||
* a source that desires privacy.
|
||||
*/
|
||||
void init(in nsIURI aSource,
|
||||
in nsIURI aTarget,
|
||||
in AString aDisplayName,
|
||||
in nsIMIMEInfo aMIMEInfo,
|
||||
in PRTime startTime,
|
||||
in nsIFile aTempFile,
|
||||
in nsICancelable aCancelable,
|
||||
in boolean aIsPrivate);
|
||||
|
||||
/*
|
||||
* Used to notify the transfer object of the hash of the downloaded file.
|
||||
* Must be called on the main thread, only after the download has finished
|
||||
* successfully.
|
||||
* @param aHash The SHA-256 hash in raw bytes of the downloaded file.
|
||||
*/
|
||||
void setSha256Hash(in ACString aHash);
|
||||
|
||||
/*
|
||||
* Used to notify the transfer object of the signature of the downloaded
|
||||
* file. Must be called on the main thread, only after the download has
|
||||
* finished successfully.
|
||||
* @param aSignatureInfo The nsIArray of nsIX509CertList of nsIX509Cert
|
||||
* certificates of the downloaded file.
|
||||
*/
|
||||
void setSignatureInfo(in nsIArray aSignatureInfo);
|
||||
|
||||
/*
|
||||
* Used to notify the transfer object of the redirects associated with the
|
||||
* channel that terminated in the downloaded file. Must be called on the
|
||||
* main thread, only after the download has finished successfully.
|
||||
* @param aRedirects The nsIArray of nsIPrincipal of redirected URIs
|
||||
* associated with the downloaded file.
|
||||
*/
|
||||
void setRedirects(in nsIArray aRedirects);
|
||||
};
|
||||
|
||||
%{C++
|
||||
/**
|
||||
* A component with this contract ID will be created each time a download is
|
||||
* started, and nsITransfer::Init will be called on it and an observer will be set.
|
||||
*
|
||||
* Notifications of the download progress will happen via
|
||||
* nsIWebProgressListener/nsIWebProgressListener2.
|
||||
*
|
||||
* INTERFACES THAT MUST BE IMPLEMENTED:
|
||||
* nsITransfer
|
||||
* nsIWebProgressListener
|
||||
* nsIWebProgressListener2
|
||||
*
|
||||
* XXX move this to nsEmbedCID.h once the interfaces (and the contract ID) are
|
||||
* frozen.
|
||||
*/
|
||||
#define NS_TRANSFER_CONTRACTID "@mozilla.org/transfer;1"
|
||||
%}
|
||||
135
uriloader/base/nsIURIContentListener.idl
Normal file
135
uriloader/base/nsIURIContentListener.idl
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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"
|
||||
|
||||
interface nsIRequest;
|
||||
interface nsIStreamListener;
|
||||
interface nsIURI;
|
||||
|
||||
/**
|
||||
* nsIURIContentListener is an interface used by components which
|
||||
* want to know (and have a chance to handle) a particular content type.
|
||||
* Typical usage scenarios will include running applications which register
|
||||
* a nsIURIContentListener for each of its content windows with the uri
|
||||
* dispatcher service.
|
||||
*/
|
||||
[scriptable, uuid(10a28f38-32e8-4c63-8aa1-12eaaebc369a)]
|
||||
interface nsIURIContentListener : nsISupports
|
||||
{
|
||||
/**
|
||||
* Gives the original content listener first crack at stopping a load before
|
||||
* it happens.
|
||||
*
|
||||
* @param aURI URI that is being opened.
|
||||
*
|
||||
* @return <code>false</code> if the load can continue;
|
||||
* <code>true</code> if the open should be aborted.
|
||||
*/
|
||||
boolean onStartURIOpen(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Notifies the content listener to hook up an nsIStreamListener capable of
|
||||
* consuming the data stream.
|
||||
*
|
||||
* @param aContentType Content type of the data.
|
||||
* @param aIsContentPreferred Indicates whether the content should be
|
||||
* preferred by this listener.
|
||||
* @param aRequest Request that is providing the data.
|
||||
* @param aContentHandler nsIStreamListener that will consume the data.
|
||||
* This should be set to <code>nullptr</code> if
|
||||
* this content listener can't handle the content
|
||||
* type; in this case, doContent should also fail
|
||||
* (i.e., return failure nsresult).
|
||||
*
|
||||
* @return <code>true</code> if the load should
|
||||
* be aborted and consumer wants to
|
||||
* handle the load completely by itself. This
|
||||
* causes the URI Loader do nothing else...
|
||||
* <code>false</code> if the URI Loader should
|
||||
* continue handling the load and call the
|
||||
* returned streamlistener's methods.
|
||||
*/
|
||||
boolean doContent(in ACString aContentType,
|
||||
in boolean aIsContentPreferred,
|
||||
in nsIRequest aRequest,
|
||||
out nsIStreamListener aContentHandler);
|
||||
|
||||
/**
|
||||
* When given a uri to dispatch, if the URI is specified as 'preferred
|
||||
* content' then the uri loader tries to find a preferred content handler
|
||||
* for the content type. The thought is that many content listeners may
|
||||
* be able to handle the same content type if they have to. i.e. the mail
|
||||
* content window can handle text/html just like a browser window content
|
||||
* listener. However, if the user clicks on a link with text/html content,
|
||||
* then the browser window should handle that content and not the mail
|
||||
* window where the user may have clicked the link. This is the difference
|
||||
* between isPreferred and canHandleContent.
|
||||
*
|
||||
* @param aContentType Content type of the data.
|
||||
* @param aDesiredContentType Indicates that aContentType must be converted
|
||||
* to aDesiredContentType before processing the
|
||||
* data. This causes a stream converted to be
|
||||
* inserted into the nsIStreamListener chain.
|
||||
* This argument can be <code>nullptr</code> if
|
||||
* the content should be consumed directly as
|
||||
* aContentType.
|
||||
*
|
||||
* @return <code>true</code> if this is a preferred
|
||||
* content handler for aContentType;
|
||||
* <code>false<code> otherwise.
|
||||
*/
|
||||
boolean isPreferred(in string aContentType, out string aDesiredContentType);
|
||||
|
||||
/**
|
||||
* When given a uri to dispatch, if the URI is not specified as 'preferred
|
||||
* content' then the uri loader calls canHandleContent to see if the content
|
||||
* listener is capable of handling the content.
|
||||
*
|
||||
* @param aContentType Content type of the data.
|
||||
* @param aIsContentPreferred Indicates whether the content should be
|
||||
* preferred by this listener.
|
||||
* @param aDesiredContentType Indicates that aContentType must be converted
|
||||
* to aDesiredContentType before processing the
|
||||
* data. This causes a stream converted to be
|
||||
* inserted into the nsIStreamListener chain.
|
||||
* This argument can be <code>nullptr</code> if
|
||||
* the content should be consumed directly as
|
||||
* aContentType.
|
||||
*
|
||||
* @return <code>true</code> if the data can be consumed.
|
||||
* <code>false</code> otherwise.
|
||||
*
|
||||
* Note: I really envision canHandleContent as a method implemented
|
||||
* by the docshell as the implementation is generic to all doc
|
||||
* shells. The isPreferred decision is a decision made by a top level
|
||||
* application content listener that sits at the top of the docshell
|
||||
* hierarchy.
|
||||
*/
|
||||
boolean canHandleContent(in string aContentType,
|
||||
in boolean aIsContentPreferred,
|
||||
out string aDesiredContentType);
|
||||
|
||||
/**
|
||||
* The load context associated with a particular content listener.
|
||||
* The URI Loader stores and accesses this value as needed.
|
||||
*/
|
||||
attribute nsISupports loadCookie;
|
||||
|
||||
/**
|
||||
* The parent content listener if this particular listener is part of a chain
|
||||
* of content listeners (i.e. a docshell!)
|
||||
*
|
||||
* @note If this attribute is set to an object that implements
|
||||
* nsISupportsWeakReference, the implementation should get the
|
||||
* nsIWeakReference and hold that. Otherwise, the implementation
|
||||
* should not refcount this interface; it should assume that a non
|
||||
* null value is always valid. In that case, the caller is
|
||||
* responsible for explicitly setting this value back to null if the
|
||||
* parent content listener is destroyed.
|
||||
*/
|
||||
attribute nsIURIContentListener parentContentListener;
|
||||
};
|
||||
|
||||
140
uriloader/base/nsIURILoader.idl
Normal file
140
uriloader/base/nsIURILoader.idl
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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"
|
||||
|
||||
interface nsIURIContentListener;
|
||||
interface nsIURI;
|
||||
interface nsILoadGroup;
|
||||
interface nsIProgressEventSink;
|
||||
interface nsIChannel;
|
||||
interface nsIRequest;
|
||||
interface nsIStreamListener;
|
||||
interface nsIInputStream;
|
||||
interface nsIInterfaceRequestor;
|
||||
|
||||
/**
|
||||
* The uri dispatcher is responsible for taking uri's, determining
|
||||
* the content and routing the opened url to the correct content
|
||||
* handler.
|
||||
*
|
||||
* When you encounter a url you want to open, you typically call
|
||||
* openURI, passing it the content listener for the window the uri is
|
||||
* originating from. The uri dispatcher opens the url to discover the
|
||||
* content type. It then gives the content listener first crack at
|
||||
* handling the content. If it doesn't want it, the dispatcher tries
|
||||
* to hand it off one of the registered content listeners. This allows
|
||||
* running applications the chance to jump in and handle the content.
|
||||
*
|
||||
* If that also fails, then the uri dispatcher goes to the registry
|
||||
* looking for the preferred content handler for the content type
|
||||
* of the uri. The content handler may create an app instance
|
||||
* or it may hand the contents off to a platform specific plugin
|
||||
* or helper app. Or it may hand the url off to an OS registered
|
||||
* application.
|
||||
*/
|
||||
[scriptable, uuid(8762c4e7-be35-4958-9b81-a05685bb516d)]
|
||||
interface nsIURILoader : nsISupports
|
||||
{
|
||||
/**
|
||||
* @name Flags for opening URIs.
|
||||
*/
|
||||
/* @{ */
|
||||
/**
|
||||
* Should the content be displayed in a container that prefers the
|
||||
* content-type, or will any container do.
|
||||
*/
|
||||
const unsigned long IS_CONTENT_PREFERRED = 1 << 0;
|
||||
/**
|
||||
* If this flag is set, only the listener of the specified window context will
|
||||
* be considered for content handling; if it refuses the load, an error will
|
||||
* be indicated.
|
||||
*/
|
||||
const unsigned long DONT_RETARGET = 1 << 1;
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* As applications such as messenger and the browser are instantiated,
|
||||
* they register content listener's with the uri dispatcher corresponding
|
||||
* to content windows within that application.
|
||||
*
|
||||
* Note to self: we may want to optimize things a bit more by requiring
|
||||
* the content types the registered content listener cares about.
|
||||
*
|
||||
* @param aContentListener
|
||||
* The listener to register. This listener must implement
|
||||
* nsISupportsWeakReference.
|
||||
*
|
||||
* @see the nsIURILoader class description
|
||||
*/
|
||||
void registerContentListener (in nsIURIContentListener aContentListener);
|
||||
void unRegisterContentListener (in nsIURIContentListener aContentListener);
|
||||
|
||||
/**
|
||||
* OpenURI requires the following parameters.....
|
||||
* @param aChannel
|
||||
* The channel that should be opened. This must not be asyncOpen'd yet!
|
||||
* If a loadgroup is set on the channel, it will get replaced with a
|
||||
* different one.
|
||||
* @param aFlags
|
||||
* Combination (bitwise OR) of the flags specified above. 0 indicates
|
||||
* default handling.
|
||||
* @param aWindowContext
|
||||
* If you are running the url from a doc shell or a web shell, this is
|
||||
* your window context. If you have a content listener you want to
|
||||
* give first crack to, the uri loader needs to be able to get it
|
||||
* from the window context. We will also be using the window context
|
||||
* to get at the progress event sink interface.
|
||||
* <b>Must not be null!</b>
|
||||
*/
|
||||
void openURI(in nsIChannel aChannel,
|
||||
in unsigned long aFlags,
|
||||
in nsIInterfaceRequestor aWindowContext);
|
||||
|
||||
/**
|
||||
* Loads data from a channel. This differs from openURI in that the channel
|
||||
* may already be opened, and that it returns a stream listener into which the
|
||||
* caller should pump data. The caller is responsible for opening the channel
|
||||
* and pumping the channel's data into the returned stream listener.
|
||||
*
|
||||
* Note: If the channel already has a loadgroup, it will be replaced with the
|
||||
* window context's load group, or null if the context doesn't have one.
|
||||
*
|
||||
* If the window context's nsIURIContentListener refuses the load immediately
|
||||
* (e.g. in nsIURIContentListener::onStartURIOpen), this method will return
|
||||
* NS_ERROR_WONT_HANDLE_CONTENT. At that point, the caller should probably
|
||||
* cancel the channel if it's already open (this method will not cancel the
|
||||
* channel).
|
||||
*
|
||||
* If flags include DONT_RETARGET, and the content listener refuses the load
|
||||
* during onStartRequest (e.g. in canHandleContent/isPreferred), then the
|
||||
* returned stream listener's onStartRequest method will return
|
||||
* NS_ERROR_WONT_HANDLE_CONTENT.
|
||||
*
|
||||
* @param aChannel
|
||||
* The channel that should be loaded. The channel may already be
|
||||
* opened. It must not be closed (i.e. this must be called before the
|
||||
* channel calls onStopRequest on its stream listener).
|
||||
* @param aFlags
|
||||
* Combination (bitwise OR) of the flags specified above. 0 indicates
|
||||
* default handling.
|
||||
* @param aWindowContext
|
||||
* If you are running the url from a doc shell or a web shell, this is
|
||||
* your window context. If you have a content listener you want to
|
||||
* give first crack to, the uri loader needs to be able to get it
|
||||
* from the window context. We will also be using the window context
|
||||
* to get at the progress event sink interface.
|
||||
* <b>Must not be null!</b>
|
||||
*/
|
||||
nsIStreamListener openChannel(in nsIChannel aChannel,
|
||||
in unsigned long aFlags,
|
||||
in nsIInterfaceRequestor aWindowContext);
|
||||
|
||||
/**
|
||||
* Stops an in progress load
|
||||
*/
|
||||
void stop(in nsISupports aLoadCookie);
|
||||
};
|
||||
|
||||
153
uriloader/base/nsIWebProgress.idl
Normal file
153
uriloader/base/nsIWebProgress.idl
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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"
|
||||
|
||||
interface mozIDOMWindowProxy;
|
||||
interface nsIWebProgressListener;
|
||||
|
||||
/**
|
||||
* The nsIWebProgress interface is used to add or remove nsIWebProgressListener
|
||||
* instances to observe the loading of asynchronous requests (usually in the
|
||||
* context of a DOM window).
|
||||
*
|
||||
* nsIWebProgress instances may be arranged in a parent-child configuration,
|
||||
* corresponding to the parent-child configuration of their respective DOM
|
||||
* windows. However, in some cases a nsIWebProgress instance may not have an
|
||||
* associated DOM window. The parent-child relationship of nsIWebProgress
|
||||
* instances is not made explicit by this interface, but the relationship may
|
||||
* exist in some implementations.
|
||||
*
|
||||
* A nsIWebProgressListener instance receives notifications for the
|
||||
* nsIWebProgress instance to which it added itself, and it may also receive
|
||||
* notifications from any nsIWebProgress instances that are children of that
|
||||
* nsIWebProgress instance.
|
||||
*/
|
||||
[scriptable, uuid(c4d64640-b332-4db6-a2a5-e08566000dc9)]
|
||||
interface nsIWebProgress : nsISupports
|
||||
{
|
||||
/**
|
||||
* The following flags may be combined to form the aNotifyMask parameter for
|
||||
* the addProgressListener method. They limit the set of events that are
|
||||
* delivered to an nsIWebProgressListener instance.
|
||||
*/
|
||||
|
||||
/**
|
||||
* These flags indicate the state transistions to observe, corresponding to
|
||||
* nsIWebProgressListener::onStateChange.
|
||||
*
|
||||
* NOTIFY_STATE_REQUEST
|
||||
* Only receive the onStateChange event if the aStateFlags parameter
|
||||
* includes nsIWebProgressListener::STATE_IS_REQUEST.
|
||||
*
|
||||
* NOTIFY_STATE_DOCUMENT
|
||||
* Only receive the onStateChange event if the aStateFlags parameter
|
||||
* includes nsIWebProgressListener::STATE_IS_DOCUMENT.
|
||||
*
|
||||
* NOTIFY_STATE_NETWORK
|
||||
* Only receive the onStateChange event if the aStateFlags parameter
|
||||
* includes nsIWebProgressListener::STATE_IS_NETWORK.
|
||||
*
|
||||
* NOTIFY_STATE_WINDOW
|
||||
* Only receive the onStateChange event if the aStateFlags parameter
|
||||
* includes nsIWebProgressListener::STATE_IS_WINDOW.
|
||||
*
|
||||
* NOTIFY_STATE_ALL
|
||||
* Receive all onStateChange events.
|
||||
*/
|
||||
const unsigned long NOTIFY_STATE_REQUEST = 0x00000001;
|
||||
const unsigned long NOTIFY_STATE_DOCUMENT = 0x00000002;
|
||||
const unsigned long NOTIFY_STATE_NETWORK = 0x00000004;
|
||||
const unsigned long NOTIFY_STATE_WINDOW = 0x00000008;
|
||||
const unsigned long NOTIFY_STATE_ALL = 0x0000000f;
|
||||
|
||||
/**
|
||||
* These flags indicate the other events to observe, corresponding to the
|
||||
* other four methods defined on nsIWebProgressListener.
|
||||
*
|
||||
* NOTIFY_PROGRESS
|
||||
* Receive onProgressChange events.
|
||||
*
|
||||
* NOTIFY_STATUS
|
||||
* Receive onStatusChange events.
|
||||
*
|
||||
* NOTIFY_SECURITY
|
||||
* Receive onSecurityChange events.
|
||||
*
|
||||
* NOTIFY_LOCATION
|
||||
* Receive onLocationChange events.
|
||||
*
|
||||
* NOTIFY_REFRESH
|
||||
* Receive onRefreshAttempted events.
|
||||
* This is defined on nsIWebProgressListener2.
|
||||
*/
|
||||
const unsigned long NOTIFY_PROGRESS = 0x00000010;
|
||||
const unsigned long NOTIFY_STATUS = 0x00000020;
|
||||
const unsigned long NOTIFY_SECURITY = 0x00000040;
|
||||
const unsigned long NOTIFY_LOCATION = 0x00000080;
|
||||
const unsigned long NOTIFY_REFRESH = 0x00000100;
|
||||
|
||||
/**
|
||||
* This flag enables all notifications.
|
||||
*/
|
||||
const unsigned long NOTIFY_ALL = 0x000001ff;
|
||||
|
||||
/**
|
||||
* Registers a listener to receive web progress events.
|
||||
*
|
||||
* @param aListener
|
||||
* The listener interface to be called when a progress event occurs.
|
||||
* This object must also implement nsISupportsWeakReference.
|
||||
* @param aNotifyMask
|
||||
* The types of notifications to receive.
|
||||
*
|
||||
* @throw NS_ERROR_INVALID_ARG
|
||||
* Indicates that aListener was either null or that it does not
|
||||
* support weak references.
|
||||
* @throw NS_ERROR_FAILURE
|
||||
* Indicates that aListener was already registered.
|
||||
*/
|
||||
void addProgressListener(in nsIWebProgressListener aListener,
|
||||
in unsigned long aNotifyMask);
|
||||
|
||||
/**
|
||||
* Removes a previously registered listener of progress events.
|
||||
*
|
||||
* @param aListener
|
||||
* The listener interface previously registered with a call to
|
||||
* addProgressListener.
|
||||
*
|
||||
* @throw NS_ERROR_FAILURE
|
||||
* Indicates that aListener was not registered.
|
||||
*/
|
||||
void removeProgressListener(in nsIWebProgressListener aListener);
|
||||
|
||||
/**
|
||||
* The DOM window associated with this nsIWebProgress instance.
|
||||
*
|
||||
* @throw NS_ERROR_FAILURE
|
||||
* Indicates that there is no associated DOM window.
|
||||
*/
|
||||
readonly attribute mozIDOMWindowProxy DOMWindow;
|
||||
readonly attribute uint64_t DOMWindowID;
|
||||
|
||||
/**
|
||||
* Indicates whether DOMWindow.top == DOMWindow.
|
||||
*/
|
||||
readonly attribute boolean isTopLevel;
|
||||
|
||||
/**
|
||||
* Indicates whether or not a document is currently being loaded
|
||||
* in the context of this nsIWebProgress instance.
|
||||
*/
|
||||
readonly attribute boolean isLoadingDocument;
|
||||
|
||||
/**
|
||||
* Contains a load type as specified by the load* constants in
|
||||
* nsIDocShellLoadInfo.idl.
|
||||
*/
|
||||
readonly attribute unsigned long loadType;
|
||||
};
|
||||
425
uriloader/base/nsIWebProgressListener.idl
Normal file
425
uriloader/base/nsIWebProgressListener.idl
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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"
|
||||
|
||||
interface nsIWebProgress;
|
||||
interface nsIRequest;
|
||||
interface nsIURI;
|
||||
|
||||
/**
|
||||
* The nsIWebProgressListener interface is implemented by clients wishing to
|
||||
* listen in on the progress associated with the loading of asynchronous
|
||||
* requests in the context of a nsIWebProgress instance as well as any child
|
||||
* nsIWebProgress instances. nsIWebProgress.idl describes the parent-child
|
||||
* relationship of nsIWebProgress instances.
|
||||
*/
|
||||
[scriptable, uuid(a9df523b-efe2-421e-9d8e-3d7f807dda4c)]
|
||||
interface nsIWebProgressListener : nsISupports
|
||||
{
|
||||
/**
|
||||
* State Transition Flags
|
||||
*
|
||||
* These flags indicate the various states that requests may transition
|
||||
* through as they are being loaded. These flags are mutually exclusive.
|
||||
*
|
||||
* For any given request, onStateChange is called once with the STATE_START
|
||||
* flag, zero or more times with the STATE_TRANSFERRING flag or once with the
|
||||
* STATE_REDIRECTING flag, and then finally once with the STATE_STOP flag.
|
||||
* NOTE: For document requests, a second STATE_STOP is generated (see the
|
||||
* description of STATE_IS_WINDOW for more details).
|
||||
*
|
||||
* STATE_START
|
||||
* This flag indicates the start of a request. This flag is set when a
|
||||
* request is initiated. The request is complete when onStateChange is
|
||||
* called for the same request with the STATE_STOP flag set.
|
||||
*
|
||||
* STATE_REDIRECTING
|
||||
* This flag indicates that a request is being redirected. The request
|
||||
* passed to onStateChange is the request that is being redirected. When a
|
||||
* redirect occurs, a new request is generated automatically to process the
|
||||
* new request. Expect a corresponding STATE_START event for the new
|
||||
* request, and a STATE_STOP for the redirected request.
|
||||
*
|
||||
* STATE_TRANSFERRING
|
||||
* This flag indicates that data for a request is being transferred to an
|
||||
* end consumer. This flag indicates that the request has been targeted,
|
||||
* and that the user may start seeing content corresponding to the request.
|
||||
*
|
||||
* STATE_NEGOTIATING
|
||||
* This flag is not used.
|
||||
*
|
||||
* STATE_STOP
|
||||
* This flag indicates the completion of a request. The aStatus parameter
|
||||
* to onStateChange indicates the final status of the request.
|
||||
*/
|
||||
const unsigned long STATE_START = 0x00000001;
|
||||
const unsigned long STATE_REDIRECTING = 0x00000002;
|
||||
const unsigned long STATE_TRANSFERRING = 0x00000004;
|
||||
const unsigned long STATE_NEGOTIATING = 0x00000008;
|
||||
const unsigned long STATE_STOP = 0x00000010;
|
||||
|
||||
|
||||
/**
|
||||
* State Type Flags
|
||||
*
|
||||
* These flags further describe the entity for which the state transition is
|
||||
* occuring. These flags are NOT mutually exclusive (i.e., an onStateChange
|
||||
* event may indicate some combination of these flags).
|
||||
*
|
||||
* STATE_IS_REQUEST
|
||||
* This flag indicates that the state transition is for a request, which
|
||||
* includes but is not limited to document requests. (See below for a
|
||||
* description of document requests.) Other types of requests, such as
|
||||
* requests for inline content (e.g., images and stylesheets) are
|
||||
* considered normal requests.
|
||||
*
|
||||
* STATE_IS_DOCUMENT
|
||||
* This flag indicates that the state transition is for a document request.
|
||||
* This flag is set in addition to STATE_IS_REQUEST. A document request
|
||||
* supports the nsIChannel interface and its loadFlags attribute includes
|
||||
* the nsIChannel::LOAD_DOCUMENT_URI flag.
|
||||
*
|
||||
* A document request does not complete until all requests associated with
|
||||
* the loading of its corresponding document have completed. This includes
|
||||
* other document requests (e.g., corresponding to HTML <iframe> elements).
|
||||
* The document corresponding to a document request is available via the
|
||||
* DOMWindow attribute of onStateChange's aWebProgress parameter.
|
||||
*
|
||||
* STATE_IS_NETWORK
|
||||
* This flag indicates that the state transition corresponds to the start
|
||||
* or stop of activity in the indicated nsIWebProgress instance. This flag
|
||||
* is accompanied by either STATE_START or STATE_STOP, and it may be
|
||||
* combined with other State Type Flags.
|
||||
*
|
||||
* Unlike STATE_IS_WINDOW, this flag is only set when activity within the
|
||||
* nsIWebProgress instance being observed starts or stops. If activity
|
||||
* only occurs in a child nsIWebProgress instance, then this flag will be
|
||||
* set to indicate the start and stop of that activity.
|
||||
*
|
||||
* For example, in the case of navigation within a single frame of a HTML
|
||||
* frameset, a nsIWebProgressListener instance attached to the
|
||||
* nsIWebProgress of the frameset window will receive onStateChange calls
|
||||
* with the STATE_IS_NETWORK flag set to indicate the start and stop of
|
||||
* said navigation. In other words, an observer of an outer window can
|
||||
* determine when activity, that may be constrained to a child window or
|
||||
* set of child windows, starts and stops.
|
||||
*
|
||||
* STATE_IS_WINDOW
|
||||
* This flag indicates that the state transition corresponds to the start
|
||||
* or stop of activity in the indicated nsIWebProgress instance. This flag
|
||||
* is accompanied by either STATE_START or STATE_STOP, and it may be
|
||||
* combined with other State Type Flags.
|
||||
*
|
||||
* This flag is similar to STATE_IS_DOCUMENT. However, when a document
|
||||
* request completes, two onStateChange calls with STATE_STOP are
|
||||
* generated. The document request is passed as aRequest to both calls.
|
||||
* The first has STATE_IS_REQUEST and STATE_IS_DOCUMENT set, and the second
|
||||
* has the STATE_IS_WINDOW flag set (and possibly the STATE_IS_NETWORK flag
|
||||
* set as well -- see above for a description of when the STATE_IS_NETWORK
|
||||
* flag may be set). This second STATE_STOP event may be useful as a way
|
||||
* to partition the work that occurs when a document request completes.
|
||||
*/
|
||||
const unsigned long STATE_IS_REQUEST = 0x00010000;
|
||||
const unsigned long STATE_IS_DOCUMENT = 0x00020000;
|
||||
const unsigned long STATE_IS_NETWORK = 0x00040000;
|
||||
const unsigned long STATE_IS_WINDOW = 0x00080000;
|
||||
|
||||
|
||||
/**
|
||||
* State Modifier Flags
|
||||
*
|
||||
* These flags further describe the transition which is occuring. These
|
||||
* flags are NOT mutually exclusive (i.e., an onStateChange event may
|
||||
* indicate some combination of these flags).
|
||||
*
|
||||
* STATE_RESTORING
|
||||
* This flag indicates that the state transition corresponds to the start
|
||||
* or stop of activity for restoring a previously-rendered presentation.
|
||||
* As such, there is no actual network activity associated with this
|
||||
* request, and any modifications made to the document or presentation
|
||||
* when it was originally loaded will still be present.
|
||||
*/
|
||||
const unsigned long STATE_RESTORING = 0x01000000;
|
||||
|
||||
/**
|
||||
* State Security Flags
|
||||
*
|
||||
* These flags describe the security state reported by a call to the
|
||||
* onSecurityChange method. These flags are mutually exclusive.
|
||||
*
|
||||
* STATE_IS_INSECURE
|
||||
* This flag indicates that the data corresponding to the request
|
||||
* was received over an insecure channel.
|
||||
*
|
||||
* STATE_IS_BROKEN
|
||||
* This flag indicates an unknown security state. This may mean that the
|
||||
* request is being loaded as part of a page in which some content was
|
||||
* received over an insecure channel.
|
||||
*
|
||||
* STATE_IS_SECURE
|
||||
* This flag indicates that the data corresponding to the request was
|
||||
* received over a secure channel. The degree of security is expressed by
|
||||
* STATE_SECURE_HIGH, STATE_SECURE_MED, or STATE_SECURE_LOW.
|
||||
*/
|
||||
const unsigned long STATE_IS_INSECURE = 0x00000004;
|
||||
const unsigned long STATE_IS_BROKEN = 0x00000001;
|
||||
const unsigned long STATE_IS_SECURE = 0x00000002;
|
||||
|
||||
/**
|
||||
* Mixed active content flags
|
||||
*
|
||||
* May be set in addition to the State Security Flags, to indicate that
|
||||
* mixed active content has been encountered.
|
||||
*
|
||||
* STATE_BLOCKED_MIXED_ACTIVE_CONTENT
|
||||
* Mixed active content has been blocked from loading.
|
||||
*
|
||||
* STATE_LOADED_MIXED_ACTIVE_CONTENT
|
||||
* Mixed active content has been loaded. State should be STATE_IS_BROKEN.
|
||||
*/
|
||||
const unsigned long STATE_BLOCKED_MIXED_ACTIVE_CONTENT = 0x00000010;
|
||||
const unsigned long STATE_LOADED_MIXED_ACTIVE_CONTENT = 0x00000020;
|
||||
|
||||
/**
|
||||
* Mixed display content flags
|
||||
*
|
||||
* May be set in addition to the State Security Flags, to indicate that
|
||||
* mixed display content has been encountered.
|
||||
*
|
||||
* STATE_BLOCKED_MIXED_DISPLAY_CONTENT
|
||||
* Mixed display content has been blocked from loading.
|
||||
*
|
||||
* STATE_LOADED_MIXED_DISPLAY_CONTENT
|
||||
* Mixed display content has been loaded. State should be STATE_IS_BROKEN.
|
||||
*/
|
||||
const unsigned long STATE_BLOCKED_MIXED_DISPLAY_CONTENT = 0x00000100;
|
||||
const unsigned long STATE_LOADED_MIXED_DISPLAY_CONTENT = 0x00000200;
|
||||
|
||||
/**
|
||||
* Tracking content flags
|
||||
*
|
||||
* May be set in addition to the State security Flags, to indicate that
|
||||
* tracking content has been encountered.
|
||||
*
|
||||
* STATE_BLOCKED_TRACKING_CONTENT
|
||||
* Tracking content has been blocked from loading.
|
||||
*
|
||||
* STATE_LOADED_TRACKING_CONTENT
|
||||
* Tracking content has been loaded.
|
||||
*/
|
||||
const unsigned long STATE_BLOCKED_TRACKING_CONTENT = 0x00001000;
|
||||
const unsigned long STATE_LOADED_TRACKING_CONTENT = 0x00002000;
|
||||
|
||||
/**
|
||||
* Security Strength Flags
|
||||
*
|
||||
* These flags describe the security strength and accompany STATE_IS_SECURE
|
||||
* in a call to the onSecurityChange method. These flags are mutually
|
||||
* exclusive.
|
||||
*
|
||||
* These flags are not meant to provide a precise description of data
|
||||
* transfer security. These are instead intended as a rough indicator that
|
||||
* may be used to, for example, color code a security indicator or otherwise
|
||||
* provide basic data transfer security feedback to the user.
|
||||
*
|
||||
* STATE_SECURE_HIGH
|
||||
* This flag indicates a high degree of security.
|
||||
*
|
||||
* STATE_SECURE_MED
|
||||
* This flag indicates a medium degree of security.
|
||||
*
|
||||
* STATE_SECURE_LOW
|
||||
* This flag indicates a low degree of security.
|
||||
*/
|
||||
const unsigned long STATE_SECURE_HIGH = 0x00040000;
|
||||
const unsigned long STATE_SECURE_MED = 0x00010000;
|
||||
const unsigned long STATE_SECURE_LOW = 0x00020000;
|
||||
|
||||
/**
|
||||
* State bits for EV == Extended Validation == High Assurance
|
||||
*
|
||||
* These flags describe the level of identity verification
|
||||
* in a call to the onSecurityChange method.
|
||||
*
|
||||
* STATE_IDENTITY_EV_TOPLEVEL
|
||||
* The topmost document uses an EV cert.
|
||||
* NOTE: Available since Gecko 1.9
|
||||
*/
|
||||
|
||||
const unsigned long STATE_IDENTITY_EV_TOPLEVEL = 0x00100000;
|
||||
|
||||
/**
|
||||
* Broken state flags
|
||||
*
|
||||
* These flags describe the reason of the broken state.
|
||||
*
|
||||
* STATE_USES_SSL_3
|
||||
* The topmost document uses SSL 3.0.
|
||||
*
|
||||
* STATE_USES_WEAK_CRYPTO
|
||||
* The topmost document uses a weak cipher suite such as RC4.
|
||||
*
|
||||
* STATE_CERT_USER_OVERRIDDEN
|
||||
* The user has added a security exception for the site.
|
||||
*/
|
||||
const unsigned long STATE_USES_SSL_3 = 0x01000000;
|
||||
const unsigned long STATE_USES_WEAK_CRYPTO = 0x02000000;
|
||||
const unsigned long STATE_CERT_USER_OVERRIDDEN = 0x04000000;
|
||||
|
||||
/**
|
||||
* Notification indicating the state has changed for one of the requests
|
||||
* associated with aWebProgress.
|
||||
*
|
||||
* @param aWebProgress
|
||||
* The nsIWebProgress instance that fired the notification
|
||||
* @param aRequest
|
||||
* The nsIRequest that has changed state.
|
||||
* @param aStateFlags
|
||||
* Flags indicating the new state. This value is a combination of one
|
||||
* of the State Transition Flags and one or more of the State Type
|
||||
* Flags defined above. Any undefined bits are reserved for future
|
||||
* use.
|
||||
* @param aStatus
|
||||
* Error status code associated with the state change. This parameter
|
||||
* should be ignored unless aStateFlags includes the STATE_STOP bit.
|
||||
* The status code indicates success or failure of the request
|
||||
* associated with the state change. NOTE: aStatus may be a success
|
||||
* code even for server generated errors, such as the HTTP 404 error.
|
||||
* In such cases, the request itself should be queried for extended
|
||||
* error information (e.g., for HTTP requests see nsIHttpChannel).
|
||||
*/
|
||||
void onStateChange(in nsIWebProgress aWebProgress,
|
||||
in nsIRequest aRequest,
|
||||
in unsigned long aStateFlags,
|
||||
in nsresult aStatus);
|
||||
|
||||
/**
|
||||
* Notification that the progress has changed for one of the requests
|
||||
* associated with aWebProgress. Progress totals are reset to zero when all
|
||||
* requests in aWebProgress complete (corresponding to onStateChange being
|
||||
* called with aStateFlags including the STATE_STOP and STATE_IS_WINDOW
|
||||
* flags).
|
||||
*
|
||||
* @param aWebProgress
|
||||
* The nsIWebProgress instance that fired the notification.
|
||||
* @param aRequest
|
||||
* The nsIRequest that has new progress.
|
||||
* @param aCurSelfProgress
|
||||
* The current progress for aRequest.
|
||||
* @param aMaxSelfProgress
|
||||
* The maximum progress for aRequest.
|
||||
* @param aCurTotalProgress
|
||||
* The current progress for all requests associated with aWebProgress.
|
||||
* @param aMaxTotalProgress
|
||||
* The total progress for all requests associated with aWebProgress.
|
||||
*
|
||||
* NOTE: If any progress value is unknown, or if its value would exceed the
|
||||
* maximum value of type long, then its value is replaced with -1.
|
||||
*
|
||||
* NOTE: If the object also implements nsIWebProgressListener2 and the caller
|
||||
* knows about that interface, this function will not be called. Instead,
|
||||
* nsIWebProgressListener2::onProgressChange64 will be called.
|
||||
*/
|
||||
void onProgressChange(in nsIWebProgress aWebProgress,
|
||||
in nsIRequest aRequest,
|
||||
in long aCurSelfProgress,
|
||||
in long aMaxSelfProgress,
|
||||
in long aCurTotalProgress,
|
||||
in long aMaxTotalProgress);
|
||||
|
||||
/**
|
||||
* Flags for onLocationChange
|
||||
*
|
||||
* LOCATION_CHANGE_SAME_DOCUMENT
|
||||
* This flag is on when |aWebProgress| did not load a new document.
|
||||
* For example, the location change is due to an anchor scroll or a
|
||||
* pushState/popState/replaceState.
|
||||
*
|
||||
* LOCATION_CHANGE_ERROR_PAGE
|
||||
* This flag is on when |aWebProgress| redirected from the requested
|
||||
* contents to an internal page to show error status, such as
|
||||
* <about:neterror>, <about:certerror> and so on.
|
||||
*
|
||||
* Generally speaking, |aURI| and |aRequest| are the original data. DOM
|
||||
* |window.location.href| is also the original location, while
|
||||
* |document.documentURI| is the redirected location. Sometimes |aURI| is
|
||||
* <about:blank> and |aRequest| is null when the original data does not
|
||||
+ remain.
|
||||
*
|
||||
* |aWebProgress| does NOT set this flag when it did not try to load a new
|
||||
* document. In this case, it should set LOCATION_CHANGE_SAME_DOCUMENT.
|
||||
*/
|
||||
const unsigned long LOCATION_CHANGE_SAME_DOCUMENT = 0x00000001;
|
||||
const unsigned long LOCATION_CHANGE_ERROR_PAGE = 0x00000002;
|
||||
|
||||
/**
|
||||
* Called when the location of the window being watched changes. This is not
|
||||
* when a load is requested, but rather once it is verified that the load is
|
||||
* going to occur in the given window. For instance, a load that starts in a
|
||||
* window might send progress and status messages for the new site, but it
|
||||
* will not send the onLocationChange until we are sure that we are loading
|
||||
* this new page here.
|
||||
*
|
||||
* @param aWebProgress
|
||||
* The nsIWebProgress instance that fired the notification.
|
||||
* @param aRequest
|
||||
* The associated nsIRequest. This may be null in some cases.
|
||||
* @param aLocation
|
||||
* The URI of the location that is being loaded.
|
||||
* @param aFlags
|
||||
* This is a value which explains the situation or the reason why
|
||||
* the location has changed.
|
||||
*/
|
||||
void onLocationChange(in nsIWebProgress aWebProgress,
|
||||
in nsIRequest aRequest,
|
||||
in nsIURI aLocation,
|
||||
[optional] in unsigned long aFlags);
|
||||
|
||||
/**
|
||||
* Notification that the status of a request has changed. The status message
|
||||
* is intended to be displayed to the user (e.g., in the status bar of the
|
||||
* browser).
|
||||
*
|
||||
* @param aWebProgress
|
||||
* The nsIWebProgress instance that fired the notification.
|
||||
* @param aRequest
|
||||
* The nsIRequest that has new status.
|
||||
* @param aStatus
|
||||
* This value is not an error code. Instead, it is a numeric value
|
||||
* that indicates the current status of the request. This interface
|
||||
* does not define the set of possible status codes. NOTE: Some
|
||||
* status values are defined by nsITransport and nsISocketTransport.
|
||||
* @param aMessage
|
||||
* Localized text corresponding to aStatus.
|
||||
*/
|
||||
void onStatusChange(in nsIWebProgress aWebProgress,
|
||||
in nsIRequest aRequest,
|
||||
in nsresult aStatus,
|
||||
in wstring aMessage);
|
||||
|
||||
/**
|
||||
* Notification called for security progress. This method will be called on
|
||||
* security transitions (eg HTTP -> HTTPS, HTTPS -> HTTP, FOO -> HTTPS) and
|
||||
* after document load completion. It might also be called if an error
|
||||
* occurs during network loading.
|
||||
*
|
||||
* @param aWebProgress
|
||||
* The nsIWebProgress instance that fired the notification.
|
||||
* @param aRequest
|
||||
* The nsIRequest that has new security state.
|
||||
* @param aState
|
||||
* A value composed of the Security State Flags and the Security
|
||||
* Strength Flags listed above. Any undefined bits are reserved for
|
||||
* future use.
|
||||
*
|
||||
* NOTE: These notifications will only occur if a security package is
|
||||
* installed.
|
||||
*/
|
||||
void onSecurityChange(in nsIWebProgress aWebProgress,
|
||||
in nsIRequest aRequest,
|
||||
in unsigned long aState);
|
||||
};
|
||||
69
uriloader/base/nsIWebProgressListener2.idl
Normal file
69
uriloader/base/nsIWebProgressListener2.idl
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/* 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 "nsIWebProgressListener.idl"
|
||||
|
||||
/**
|
||||
* An extended version of nsIWebProgressListener.
|
||||
*/
|
||||
[scriptable, uuid(dde39de0-e4e0-11da-8ad9-0800200c9a66)]
|
||||
interface nsIWebProgressListener2 : nsIWebProgressListener {
|
||||
/**
|
||||
* Notification that the progress has changed for one of the requests
|
||||
* associated with aWebProgress. Progress totals are reset to zero when all
|
||||
* requests in aWebProgress complete (corresponding to onStateChange being
|
||||
* called with aStateFlags including the STATE_STOP and STATE_IS_WINDOW
|
||||
* flags).
|
||||
*
|
||||
* This function is identical to nsIWebProgressListener::onProgressChange,
|
||||
* except that this function supports 64-bit values.
|
||||
*
|
||||
* @param aWebProgress
|
||||
* The nsIWebProgress instance that fired the notification.
|
||||
* @param aRequest
|
||||
* The nsIRequest that has new progress.
|
||||
* @param aCurSelfProgress
|
||||
* The current progress for aRequest.
|
||||
* @param aMaxSelfProgress
|
||||
* The maximum progress for aRequest.
|
||||
* @param aCurTotalProgress
|
||||
* The current progress for all requests associated with aWebProgress.
|
||||
* @param aMaxTotalProgress
|
||||
* The total progress for all requests associated with aWebProgress.
|
||||
*
|
||||
* NOTE: If any progress value is unknown, then its value is replaced with -1.
|
||||
*
|
||||
* @see nsIWebProgressListener2::onProgressChange64
|
||||
*/
|
||||
void onProgressChange64(in nsIWebProgress aWebProgress,
|
||||
in nsIRequest aRequest,
|
||||
in long long aCurSelfProgress,
|
||||
in long long aMaxSelfProgress,
|
||||
in long long aCurTotalProgress,
|
||||
in long long aMaxTotalProgress);
|
||||
|
||||
/**
|
||||
* Notification that a refresh or redirect has been requested in aWebProgress
|
||||
* For example, via a <meta http-equiv="refresh"> or an HTTP Refresh: header
|
||||
*
|
||||
* @param aWebProgress
|
||||
* The nsIWebProgress instance that fired the notification.
|
||||
* @param aRefreshURI
|
||||
* The new URI that aWebProgress has requested redirecting to.
|
||||
* @param aMillis
|
||||
* The delay (in milliseconds) before refresh.
|
||||
* @param aSameURI
|
||||
* True if aWebProgress is requesting a refresh of the
|
||||
* current URI.
|
||||
* False if aWebProgress is requesting a redirection to
|
||||
* a different URI.
|
||||
*
|
||||
* @return True if the refresh may proceed.
|
||||
* False if the refresh should be aborted.
|
||||
*/
|
||||
boolean onRefreshAttempted(in nsIWebProgress aWebProgress,
|
||||
in nsIURI aRefreshURI,
|
||||
in long aMillis,
|
||||
in boolean aSameURI);
|
||||
};
|
||||
966
uriloader/base/nsURILoader.cpp
Normal file
966
uriloader/base/nsURILoader.cpp
Normal file
|
|
@ -0,0 +1,966 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sts=2 sw=2 et cin: */
|
||||
/* 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 "nsURILoader.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIURIContentListener.h"
|
||||
#include "nsIContentHandler.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsIDocumentLoader.h"
|
||||
#include "nsIWebProgress.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIMultiPartChannel.h"
|
||||
#include "netCore.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#include "nsIThreadRetargetableStreamListener.h"
|
||||
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsError.h"
|
||||
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsCExternalHandlerService.h" // contains contractids for the helper app service
|
||||
|
||||
#include "nsIMIMEHeaderParam.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
#include "nsMimeTypes.h"
|
||||
|
||||
#include "nsDocLoader.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
mozilla::LazyLogModule nsURILoader::mLog("URILoader");
|
||||
|
||||
#define LOG(args) MOZ_LOG(nsURILoader::mLog, mozilla::LogLevel::Debug, args)
|
||||
#define LOG_ERROR(args) MOZ_LOG(nsURILoader::mLog, mozilla::LogLevel::Error, args)
|
||||
#define LOG_ENABLED() MOZ_LOG_TEST(nsURILoader::mLog, mozilla::LogLevel::Debug)
|
||||
|
||||
#define NS_PREF_DISABLE_BACKGROUND_HANDLING \
|
||||
"security.exthelperapp.disable_background_handling"
|
||||
|
||||
/**
|
||||
* The nsDocumentOpenInfo contains the state required when a single
|
||||
* document is being opened in order to discover the content type...
|
||||
* Each instance remains alive until its target URL has been loaded
|
||||
* (or aborted).
|
||||
*/
|
||||
class nsDocumentOpenInfo final : public nsIStreamListener
|
||||
, public nsIThreadRetargetableStreamListener
|
||||
{
|
||||
public:
|
||||
// Needed for nsCOMPtr to work right... Don't call this!
|
||||
nsDocumentOpenInfo();
|
||||
|
||||
// Real constructor
|
||||
// aFlags is a combination of the flags on nsIURILoader
|
||||
nsDocumentOpenInfo(nsIInterfaceRequestor* aWindowContext,
|
||||
uint32_t aFlags,
|
||||
nsURILoader* aURILoader);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
/**
|
||||
* Prepares this object for receiving data. The stream
|
||||
* listener methods of this class must not be called before calling this
|
||||
* method.
|
||||
*/
|
||||
nsresult Prepare();
|
||||
|
||||
// Call this (from OnStartRequest) to attempt to find an nsIStreamListener to
|
||||
// take the data off our hands.
|
||||
nsresult DispatchContent(nsIRequest *request, nsISupports * aCtxt);
|
||||
|
||||
// Call this if we need to insert a stream converter from aSrcContentType to
|
||||
// aOutContentType into the StreamListener chain. DO NOT call it if the two
|
||||
// types are the same, since no conversion is needed in that case.
|
||||
nsresult ConvertData(nsIRequest *request,
|
||||
nsIURIContentListener *aListener,
|
||||
const nsACString & aSrcContentType,
|
||||
const nsACString & aOutContentType);
|
||||
|
||||
/**
|
||||
* Function to attempt to use aListener to handle the load. If
|
||||
* true is returned, nothing else needs to be done; if false
|
||||
* is returned, then a different way of handling the load should be
|
||||
* tried.
|
||||
*/
|
||||
bool TryContentListener(nsIURIContentListener* aListener,
|
||||
nsIChannel* aChannel);
|
||||
|
||||
// nsIRequestObserver methods:
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
// nsIStreamListener methods:
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
// nsIThreadRetargetableStreamListener
|
||||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
protected:
|
||||
~nsDocumentOpenInfo();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The first content listener to try dispatching data to. Typically
|
||||
* the listener associated with the entity that originated the load.
|
||||
*/
|
||||
nsCOMPtr<nsIURIContentListener> m_contentListener;
|
||||
|
||||
/**
|
||||
* The stream listener to forward nsIStreamListener notifications
|
||||
* to. This is set once the load is dispatched.
|
||||
*/
|
||||
nsCOMPtr<nsIStreamListener> m_targetStreamListener;
|
||||
|
||||
/**
|
||||
* A pointer to the entity that originated the load. We depend on getting
|
||||
* things like nsIURIContentListeners, nsIDOMWindows, etc off of it.
|
||||
*/
|
||||
nsCOMPtr<nsIInterfaceRequestor> m_originalContext;
|
||||
|
||||
/**
|
||||
* IS_CONTENT_PREFERRED is used for the boolean to pass to CanHandleContent
|
||||
* (also determines whether we use CanHandleContent or IsPreferred).
|
||||
* DONT_RETARGET means that we will only try m_originalContext, no other
|
||||
* listeners.
|
||||
*/
|
||||
uint32_t mFlags;
|
||||
|
||||
/**
|
||||
* The type of the data we will be trying to dispatch.
|
||||
*/
|
||||
nsCString mContentType;
|
||||
|
||||
/**
|
||||
* Reference to the URILoader service so we can access its list of
|
||||
* nsIURIContentListeners.
|
||||
*/
|
||||
RefPtr<nsURILoader> mURILoader;
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF(nsDocumentOpenInfo)
|
||||
NS_IMPL_RELEASE(nsDocumentOpenInfo)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDocumentOpenInfo)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener)
|
||||
NS_INTERFACE_MAP_END_THREADSAFE
|
||||
|
||||
nsDocumentOpenInfo::nsDocumentOpenInfo()
|
||||
{
|
||||
NS_NOTREACHED("This should never be called\n");
|
||||
}
|
||||
|
||||
nsDocumentOpenInfo::nsDocumentOpenInfo(nsIInterfaceRequestor* aWindowContext,
|
||||
uint32_t aFlags,
|
||||
nsURILoader* aURILoader)
|
||||
: m_originalContext(aWindowContext),
|
||||
mFlags(aFlags),
|
||||
mURILoader(aURILoader)
|
||||
{
|
||||
}
|
||||
|
||||
nsDocumentOpenInfo::~nsDocumentOpenInfo()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult nsDocumentOpenInfo::Prepare()
|
||||
{
|
||||
LOG(("[0x%p] nsDocumentOpenInfo::Prepare", this));
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// ask our window context if it has a uri content listener...
|
||||
m_contentListener = do_GetInterface(m_originalContext, &rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocumentOpenInfo::OnStartRequest(nsIRequest *request, nsISupports * aCtxt)
|
||||
{
|
||||
LOG(("[0x%p] nsDocumentOpenInfo::OnStartRequest", this));
|
||||
MOZ_ASSERT(request);
|
||||
if (!request) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
//
|
||||
// Deal with "special" HTTP responses:
|
||||
//
|
||||
// - In the case of a 204 (No Content) or 205 (Reset Content) response, do
|
||||
// not try to find a content handler. Return NS_BINDING_ABORTED to cancel
|
||||
// the request. This has the effect of ensuring that the DocLoader does
|
||||
// not try to interpret this as a real request.
|
||||
//
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request, &rv));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
uint32_t responseCode = 0;
|
||||
|
||||
rv = httpChannel->GetResponseStatus(&responseCode);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG_ERROR((" Failed to get HTTP response status"));
|
||||
|
||||
// behave as in the canceled case
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
LOG((" HTTP response status: %d", responseCode));
|
||||
|
||||
if (204 == responseCode || 205 == responseCode) {
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
|
||||
static bool sLargeAllocationHeaderEnabled = false;
|
||||
static bool sCachedLargeAllocationPref = false;
|
||||
if (!sCachedLargeAllocationPref) {
|
||||
sCachedLargeAllocationPref = true;
|
||||
mozilla::Preferences::AddBoolVarCache(&sLargeAllocationHeaderEnabled,
|
||||
"dom.largeAllocationHeader.enabled");
|
||||
}
|
||||
|
||||
if (sLargeAllocationHeaderEnabled) {
|
||||
// If we have a Large-Allocation header, let's check if we should perform a process switch.
|
||||
nsAutoCString largeAllocationHeader;
|
||||
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Large-Allocation"), largeAllocationHeader);
|
||||
if (NS_SUCCEEDED(rv) && nsContentUtils::AttemptLargeAllocationLoad(httpChannel)) {
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure that the transaction has succeeded, so far...
|
||||
//
|
||||
nsresult status;
|
||||
|
||||
rv = request->GetStatus(&status);
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to get request status!");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (NS_FAILED(status)) {
|
||||
LOG_ERROR((" Request failed, status: 0x%08X", rv));
|
||||
|
||||
//
|
||||
// The transaction has already reported an error - so it will be torn
|
||||
// down. Therefore, it is not necessary to return an error code...
|
||||
//
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = DispatchContent(request, aCtxt);
|
||||
|
||||
LOG((" After dispatch, m_targetStreamListener: 0x%p, rv: 0x%08X", m_targetStreamListener.get(), rv));
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) || !m_targetStreamListener,
|
||||
"Must not have an m_targetStreamListener with a failure return!");
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (m_targetStreamListener)
|
||||
rv = m_targetStreamListener->OnStartRequest(request, aCtxt);
|
||||
|
||||
LOG((" OnStartRequest returning: 0x%08X", rv));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocumentOpenInfo::CheckListenerChain()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread!");
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
|
||||
do_QueryInterface(m_targetStreamListener, &rv);
|
||||
if (retargetableListener) {
|
||||
rv = retargetableListener->CheckListenerChain();
|
||||
}
|
||||
LOG(("[0x%p] nsDocumentOpenInfo::CheckListenerChain %s listener %p rv %x",
|
||||
this, (NS_SUCCEEDED(rv) ? "success" : "failure"),
|
||||
(nsIStreamListener*)m_targetStreamListener, rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocumentOpenInfo::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
|
||||
nsIInputStream * inStr,
|
||||
uint64_t sourceOffset, uint32_t count)
|
||||
{
|
||||
// if we have retarged to the end stream listener, then forward the call....
|
||||
// otherwise, don't do anything
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (m_targetStreamListener)
|
||||
rv = m_targetStreamListener->OnDataAvailable(request, aCtxt, inStr, sourceOffset, count);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocumentOpenInfo::OnStopRequest(nsIRequest *request, nsISupports *aCtxt,
|
||||
nsresult aStatus)
|
||||
{
|
||||
LOG(("[0x%p] nsDocumentOpenInfo::OnStopRequest", this));
|
||||
|
||||
if ( m_targetStreamListener)
|
||||
{
|
||||
nsCOMPtr<nsIStreamListener> listener(m_targetStreamListener);
|
||||
|
||||
// If this is a multipart stream, we could get another
|
||||
// OnStartRequest after this... reset state.
|
||||
m_targetStreamListener = nullptr;
|
||||
mContentType.Truncate();
|
||||
listener->OnStopRequest(request, aCtxt, aStatus);
|
||||
}
|
||||
|
||||
// Remember...
|
||||
// In the case of multiplexed streams (such as multipart/x-mixed-replace)
|
||||
// these stream listener methods could be called again :-)
|
||||
//
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports * aCtxt)
|
||||
{
|
||||
LOG(("[0x%p] nsDocumentOpenInfo::DispatchContent for type '%s'", this, mContentType.get()));
|
||||
|
||||
NS_PRECONDITION(!m_targetStreamListener,
|
||||
"Why do we already have a target stream listener?");
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request);
|
||||
if (!aChannel) {
|
||||
LOG_ERROR((" Request is not a channel. Bailing."));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(anyType, "*/*");
|
||||
if (mContentType.IsEmpty() || mContentType == anyType) {
|
||||
rv = aChannel->GetContentType(mContentType);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
LOG((" Got type from channel: '%s'", mContentType.get()));
|
||||
}
|
||||
|
||||
bool isGuessFromExt =
|
||||
mContentType.LowerCaseEqualsASCII(APPLICATION_GUESS_FROM_EXT);
|
||||
if (isGuessFromExt) {
|
||||
// Reset to application/octet-stream for now; no one other than the
|
||||
// external helper app service should see APPLICATION_GUESS_FROM_EXT.
|
||||
mContentType = APPLICATION_OCTET_STREAM;
|
||||
aChannel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_OCTET_STREAM));
|
||||
}
|
||||
|
||||
// Check whether the data should be forced to be handled externally. This
|
||||
// could happen because the Content-Disposition header is set so, or, in the
|
||||
// future, because the user has specified external handling for the MIME
|
||||
// type.
|
||||
bool forceExternalHandling = false;
|
||||
uint32_t disposition;
|
||||
rv = aChannel->GetContentDisposition(&disposition);
|
||||
|
||||
bool allowContentDispositionToForceExternalHandling = true;
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
|
||||
// On B2G, OMA content files should never be handled by an external handler
|
||||
// (even if the server specifies Content-Disposition: attachment) because the
|
||||
// data should never be stored on an unencrypted form.
|
||||
allowContentDispositionToForceExternalHandling =
|
||||
!mContentType.LowerCaseEqualsASCII("application/vnd.oma.drm.message");
|
||||
|
||||
#endif
|
||||
|
||||
if (NS_SUCCEEDED(rv) && (disposition == nsIChannel::DISPOSITION_ATTACHMENT) &&
|
||||
allowContentDispositionToForceExternalHandling) {
|
||||
forceExternalHandling = true;
|
||||
}
|
||||
|
||||
LOG((" forceExternalHandling: %s", forceExternalHandling ? "yes" : "no"));
|
||||
|
||||
// The type or data the contentListener wants.
|
||||
nsXPIDLCString desiredContentType;
|
||||
|
||||
if (!forceExternalHandling)
|
||||
{
|
||||
//
|
||||
// First step: See whether m_contentListener wants to handle this
|
||||
// content type.
|
||||
//
|
||||
if (m_contentListener && TryContentListener(m_contentListener, aChannel)) {
|
||||
LOG((" Success! Our default listener likes this type"));
|
||||
// All done here
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we aren't allowed to try other listeners, just skip through to
|
||||
// trying to convert the data.
|
||||
if (!(mFlags & nsIURILoader::DONT_RETARGET)) {
|
||||
|
||||
//
|
||||
// Second step: See whether some other registered listener wants
|
||||
// to handle this content type.
|
||||
//
|
||||
int32_t count = mURILoader->m_listeners.Count();
|
||||
nsCOMPtr<nsIURIContentListener> listener;
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
listener = do_QueryReferent(mURILoader->m_listeners[i]);
|
||||
if (listener) {
|
||||
if (TryContentListener(listener, aChannel)) {
|
||||
LOG((" Found listener registered on the URILoader"));
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
// remove from the listener list, reset i and update count
|
||||
mURILoader->m_listeners.RemoveObjectAt(i--);
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Third step: Try to find a content listener that has not yet had
|
||||
// the chance to register, as it is contained in a not-yet-loaded
|
||||
// module, but which has registered a contract ID.
|
||||
//
|
||||
nsCOMPtr<nsICategoryManager> catman =
|
||||
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
||||
if (catman) {
|
||||
nsXPIDLCString contractidString;
|
||||
rv = catman->GetCategoryEntry(NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY,
|
||||
mContentType.get(),
|
||||
getter_Copies(contractidString));
|
||||
if (NS_SUCCEEDED(rv) && !contractidString.IsEmpty()) {
|
||||
LOG((" Listener contractid for '%s' is '%s'",
|
||||
mContentType.get(), contractidString.get()));
|
||||
|
||||
listener = do_CreateInstance(contractidString);
|
||||
LOG((" Listener from category manager: 0x%p", listener.get()));
|
||||
|
||||
if (listener && TryContentListener(listener, aChannel)) {
|
||||
LOG((" Listener from category manager likes this type"));
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Fourth step: try to find an nsIContentHandler for our type.
|
||||
//
|
||||
nsAutoCString handlerContractID (NS_CONTENT_HANDLER_CONTRACTID_PREFIX);
|
||||
handlerContractID += mContentType;
|
||||
|
||||
nsCOMPtr<nsIContentHandler> contentHandler =
|
||||
do_CreateInstance(handlerContractID.get());
|
||||
if (contentHandler) {
|
||||
LOG((" Content handler found"));
|
||||
rv = contentHandler->HandleContent(mContentType.get(),
|
||||
m_originalContext, request);
|
||||
// XXXbz returning an error code to represent handling the
|
||||
// content is just bizarre!
|
||||
if (rv != NS_ERROR_WONT_HANDLE_CONTENT) {
|
||||
if (NS_FAILED(rv)) {
|
||||
// The content handler has unexpectedly failed. Cancel the request
|
||||
// just in case the handler didn't...
|
||||
LOG((" Content handler failed. Aborting load"));
|
||||
request->Cancel(rv);
|
||||
}
|
||||
else {
|
||||
LOG((" Content handler taking over load"));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG((" DONT_RETARGET flag set, so skipped over random other content "
|
||||
"listeners and content handlers"));
|
||||
}
|
||||
|
||||
//
|
||||
// Fifth step: If no listener prefers this type, see if any stream
|
||||
// converters exist to transform this content type into
|
||||
// some other.
|
||||
//
|
||||
// Don't do this if the server sent us a MIME type of "*/*" because they saw
|
||||
// it in our Accept header and got confused.
|
||||
// XXXbz have to be careful here; may end up in some sort of bizarre infinite
|
||||
// decoding loop.
|
||||
if (mContentType != anyType) {
|
||||
rv = ConvertData(request, m_contentListener, mContentType, anyType);
|
||||
if (NS_FAILED(rv)) {
|
||||
m_targetStreamListener = nullptr;
|
||||
} else if (m_targetStreamListener) {
|
||||
// We found a converter for this MIME type. We'll just pump data into it
|
||||
// and let the downstream nsDocumentOpenInfo handle things.
|
||||
LOG((" Converter taking over now"));
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(!m_targetStreamListener,
|
||||
"If we found a listener, why are we not using it?");
|
||||
|
||||
if (mFlags & nsIURILoader::DONT_RETARGET) {
|
||||
LOG((" External handling forced or (listener not interested and no "
|
||||
"stream converter exists), and retargeting disallowed -> aborting"));
|
||||
return NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
}
|
||||
|
||||
// Before dispatching to the external helper app service, check for an HTTP
|
||||
// error page. If we got one, we don't want to handle it with a helper app,
|
||||
// really.
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
|
||||
if (httpChannel) {
|
||||
bool requestSucceeded;
|
||||
httpChannel->GetRequestSucceeded(&requestSucceeded);
|
||||
if (!requestSucceeded) {
|
||||
// returning error from OnStartRequest will cancel the channel
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
// Sixth step:
|
||||
//
|
||||
// All attempts to dispatch this content have failed. Just pass it off to
|
||||
// the helper app service.
|
||||
//
|
||||
|
||||
//
|
||||
// Optionally, we may want to disable background handling by the external
|
||||
// helper application service.
|
||||
//
|
||||
if (mozilla::Preferences::GetBool(NS_PREF_DISABLE_BACKGROUND_HANDLING,
|
||||
false)) {
|
||||
// First, we will ensure that the parent docshell is in an active
|
||||
// state as we will disallow all external application handling unless it is
|
||||
// in the foreground.
|
||||
nsCOMPtr<nsIDocShell> docShell(do_GetInterface(m_originalContext));
|
||||
if (!docShell) {
|
||||
// If we can't perform our security check we definitely don't want to go
|
||||
// any further!
|
||||
LOG(("Failed to get DocShell to ensure it is active before anding off to "
|
||||
"helper app service. Aborting."));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Ensure the DocShell is active before continuing.
|
||||
bool isActive = false;
|
||||
docShell->GetIsActive(&isActive);
|
||||
if (!isActive) {
|
||||
LOG((" Check for active DocShell returned false. Aborting hand off to "
|
||||
"helper app service."));
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIExternalHelperAppService> helperAppService =
|
||||
do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &rv);
|
||||
if (helperAppService) {
|
||||
LOG((" Passing load off to helper app service"));
|
||||
|
||||
// Set these flags to indicate that the channel has been targeted and that
|
||||
// we are not using the original consumer.
|
||||
nsLoadFlags loadFlags = 0;
|
||||
request->GetLoadFlags(&loadFlags);
|
||||
request->SetLoadFlags(loadFlags | nsIChannel::LOAD_RETARGETED_DOCUMENT_URI
|
||||
| nsIChannel::LOAD_TARGETED);
|
||||
|
||||
if (isGuessFromExt) {
|
||||
mContentType = APPLICATION_GUESS_FROM_EXT;
|
||||
aChannel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_GUESS_FROM_EXT));
|
||||
}
|
||||
|
||||
rv = helperAppService->DoContent(mContentType,
|
||||
request,
|
||||
m_originalContext,
|
||||
false,
|
||||
nullptr,
|
||||
getter_AddRefs(m_targetStreamListener));
|
||||
if (NS_FAILED(rv)) {
|
||||
request->SetLoadFlags(loadFlags);
|
||||
m_targetStreamListener = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(m_targetStreamListener || NS_FAILED(rv),
|
||||
"There is no way we should be successful at this point without a m_targetStreamListener");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocumentOpenInfo::ConvertData(nsIRequest *request,
|
||||
nsIURIContentListener* aListener,
|
||||
const nsACString& aSrcContentType,
|
||||
const nsACString& aOutContentType)
|
||||
{
|
||||
LOG(("[0x%p] nsDocumentOpenInfo::ConvertData from '%s' to '%s'", this,
|
||||
PromiseFlatCString(aSrcContentType).get(),
|
||||
PromiseFlatCString(aOutContentType).get()));
|
||||
|
||||
NS_PRECONDITION(aSrcContentType != aOutContentType,
|
||||
"ConvertData called when the two types are the same!");
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIStreamConverterService> StreamConvService =
|
||||
do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
LOG((" Got converter service"));
|
||||
|
||||
// When applying stream decoders, it is necessary to "insert" an
|
||||
// intermediate nsDocumentOpenInfo instance to handle the targeting of
|
||||
// the "final" stream or streams.
|
||||
//
|
||||
// For certain content types (ie. multi-part/x-mixed-replace) the input
|
||||
// stream is split up into multiple destination streams. This
|
||||
// intermediate instance is used to target these "decoded" streams...
|
||||
//
|
||||
RefPtr<nsDocumentOpenInfo> nextLink =
|
||||
new nsDocumentOpenInfo(m_originalContext, mFlags, mURILoader);
|
||||
|
||||
LOG((" Downstream DocumentOpenInfo would be: 0x%p", nextLink.get()));
|
||||
|
||||
// Make sure nextLink starts with the contentListener that said it wanted the
|
||||
// results of this decode.
|
||||
nextLink->m_contentListener = aListener;
|
||||
// Also make sure it has to look for a stream listener to pump data into.
|
||||
nextLink->m_targetStreamListener = nullptr;
|
||||
|
||||
// Make sure that nextLink treats the data as aOutContentType when
|
||||
// dispatching; that way even if the stream converters don't change the type
|
||||
// on the channel we will still do the right thing. If aOutContentType is
|
||||
// */*, that's OK -- that will just indicate to nextLink that it should get
|
||||
// the type off the channel.
|
||||
nextLink->mContentType = aOutContentType;
|
||||
|
||||
// The following call sets m_targetStreamListener to the input end of the
|
||||
// stream converter and sets the output end of the stream converter to
|
||||
// nextLink. As we pump data into m_targetStreamListener the stream
|
||||
// converter will convert it and pass the converted data to nextLink.
|
||||
return StreamConvService->AsyncConvertData(PromiseFlatCString(aSrcContentType).get(),
|
||||
PromiseFlatCString(aOutContentType).get(),
|
||||
nextLink,
|
||||
request,
|
||||
getter_AddRefs(m_targetStreamListener));
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocumentOpenInfo::TryContentListener(nsIURIContentListener* aListener,
|
||||
nsIChannel* aChannel)
|
||||
{
|
||||
LOG(("[0x%p] nsDocumentOpenInfo::TryContentListener; mFlags = 0x%x",
|
||||
this, mFlags));
|
||||
|
||||
NS_PRECONDITION(aListener, "Must have a non-null listener");
|
||||
NS_PRECONDITION(aChannel, "Must have a channel");
|
||||
|
||||
bool listenerWantsContent = false;
|
||||
nsXPIDLCString typeToUse;
|
||||
|
||||
if (mFlags & nsIURILoader::IS_CONTENT_PREFERRED) {
|
||||
aListener->IsPreferred(mContentType.get(),
|
||||
getter_Copies(typeToUse),
|
||||
&listenerWantsContent);
|
||||
} else {
|
||||
aListener->CanHandleContent(mContentType.get(), false,
|
||||
getter_Copies(typeToUse),
|
||||
&listenerWantsContent);
|
||||
}
|
||||
if (!listenerWantsContent) {
|
||||
LOG((" Listener is not interested"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!typeToUse.IsEmpty() && typeToUse != mContentType) {
|
||||
// Need to do a conversion here.
|
||||
|
||||
nsresult rv = ConvertData(aChannel, aListener, mContentType, typeToUse);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// No conversion path -- we don't want this listener, if we got one
|
||||
m_targetStreamListener = nullptr;
|
||||
}
|
||||
|
||||
LOG((" Found conversion: %s", m_targetStreamListener ? "yes" : "no"));
|
||||
|
||||
// m_targetStreamListener is now the input end of the converter, and we can
|
||||
// just pump the data in there, if it exists. If it does not, we need to
|
||||
// try other nsIURIContentListeners.
|
||||
return m_targetStreamListener != nullptr;
|
||||
}
|
||||
|
||||
// At this point, aListener wants data of type mContentType. Let 'em have
|
||||
// it. But first, if we are retargeting, set an appropriate flag on the
|
||||
// channel
|
||||
nsLoadFlags loadFlags = 0;
|
||||
aChannel->GetLoadFlags(&loadFlags);
|
||||
|
||||
// Set this flag to indicate that the channel has been targeted at a final
|
||||
// consumer. This load flag is tested in nsDocLoader::OnProgress.
|
||||
nsLoadFlags newLoadFlags = nsIChannel::LOAD_TARGETED;
|
||||
|
||||
nsCOMPtr<nsIURIContentListener> originalListener =
|
||||
do_GetInterface(m_originalContext);
|
||||
if (originalListener != aListener) {
|
||||
newLoadFlags |= nsIChannel::LOAD_RETARGETED_DOCUMENT_URI;
|
||||
}
|
||||
aChannel->SetLoadFlags(loadFlags | newLoadFlags);
|
||||
|
||||
bool abort = false;
|
||||
bool isPreferred = (mFlags & nsIURILoader::IS_CONTENT_PREFERRED) != 0;
|
||||
nsresult rv = aListener->DoContent(mContentType,
|
||||
isPreferred,
|
||||
aChannel,
|
||||
getter_AddRefs(m_targetStreamListener),
|
||||
&abort);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG_ERROR((" DoContent failed"));
|
||||
|
||||
// Unset the RETARGETED_DOCUMENT_URI flag if we set it...
|
||||
aChannel->SetLoadFlags(loadFlags);
|
||||
m_targetStreamListener = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (abort) {
|
||||
// Nothing else to do here -- aListener is handling it all. Make
|
||||
// sure m_targetStreamListener is null so we don't do anything
|
||||
// after this point.
|
||||
LOG((" Listener has aborted the load"));
|
||||
m_targetStreamListener = nullptr;
|
||||
}
|
||||
|
||||
NS_ASSERTION(abort || m_targetStreamListener, "DoContent returned no listener?");
|
||||
|
||||
// aListener is handling the load from this point on.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of nsURILoader
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsURILoader::nsURILoader()
|
||||
{
|
||||
}
|
||||
|
||||
nsURILoader::~nsURILoader()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsURILoader)
|
||||
NS_IMPL_RELEASE(nsURILoader)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsURILoader)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURILoader)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURILoader)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP nsURILoader::RegisterContentListener(nsIURIContentListener * aContentListener)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsWeakPtr weakListener = do_GetWeakReference(aContentListener);
|
||||
NS_ASSERTION(weakListener, "your URIContentListener must support weak refs!\n");
|
||||
|
||||
if (weakListener)
|
||||
m_listeners.AppendObject(weakListener);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsURILoader::UnRegisterContentListener(nsIURIContentListener * aContentListener)
|
||||
{
|
||||
nsWeakPtr weakListener = do_GetWeakReference(aContentListener);
|
||||
if (weakListener)
|
||||
m_listeners.RemoveObject(weakListener);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsURILoader::OpenURI(nsIChannel *channel,
|
||||
uint32_t aFlags,
|
||||
nsIInterfaceRequestor *aWindowContext)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(channel);
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
channel->GetURI(getter_AddRefs(uri));
|
||||
nsAutoCString spec;
|
||||
uri->GetAsciiSpec(spec);
|
||||
LOG(("nsURILoader::OpenURI for %s", spec.get()));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStreamListener> loader;
|
||||
nsresult rv = OpenChannel(channel,
|
||||
aFlags,
|
||||
aWindowContext,
|
||||
false,
|
||||
getter_AddRefs(loader));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// this method is not complete!!! Eventually, we should first go
|
||||
// to the content listener and ask them for a protocol handler...
|
||||
// if they don't give us one, we need to go to the registry and get
|
||||
// the preferred protocol handler.
|
||||
|
||||
// But for now, I'm going to let necko do the work for us....
|
||||
rv = channel->AsyncOpen(loader, nullptr);
|
||||
|
||||
// no content from this load - that's OK.
|
||||
if (rv == NS_ERROR_NO_CONTENT) {
|
||||
LOG((" rv is NS_ERROR_NO_CONTENT -- doing nothing"));
|
||||
rv = NS_OK;
|
||||
}
|
||||
} else if (rv == NS_ERROR_WONT_HANDLE_CONTENT) {
|
||||
// Not really an error, from this method's point of view
|
||||
rv = NS_OK;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsURILoader::OpenChannel(nsIChannel* channel,
|
||||
uint32_t aFlags,
|
||||
nsIInterfaceRequestor* aWindowContext,
|
||||
bool aChannelIsOpen,
|
||||
nsIStreamListener** aListener)
|
||||
{
|
||||
NS_ASSERTION(channel, "Trying to open a null channel!");
|
||||
NS_ASSERTION(aWindowContext, "Window context must not be null");
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
channel->GetURI(getter_AddRefs(uri));
|
||||
nsAutoCString spec;
|
||||
uri->GetAsciiSpec(spec);
|
||||
LOG(("nsURILoader::OpenChannel for %s", spec.get()));
|
||||
}
|
||||
|
||||
// Let the window context's uriListener know that the open is starting. This
|
||||
// gives that window a chance to abort the load process.
|
||||
nsCOMPtr<nsIURIContentListener> winContextListener(do_GetInterface(aWindowContext));
|
||||
if (winContextListener) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
channel->GetURI(getter_AddRefs(uri));
|
||||
if (uri) {
|
||||
bool doAbort = false;
|
||||
winContextListener->OnStartURIOpen(uri, &doAbort);
|
||||
|
||||
if (doAbort) {
|
||||
LOG((" OnStartURIOpen aborted load"));
|
||||
return NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we need to create a DocumentOpenInfo object which will go ahead and open
|
||||
// the url and discover the content type....
|
||||
RefPtr<nsDocumentOpenInfo> loader =
|
||||
new nsDocumentOpenInfo(aWindowContext, aFlags, this);
|
||||
|
||||
// Set the correct loadgroup on the channel
|
||||
nsCOMPtr<nsILoadGroup> loadGroup(do_GetInterface(aWindowContext));
|
||||
|
||||
if (!loadGroup) {
|
||||
// XXXbz This context is violating what we'd like to be the new uriloader
|
||||
// api.... Set up a nsDocLoader to handle the loadgroup for this context.
|
||||
// This really needs to go away!
|
||||
nsCOMPtr<nsIURIContentListener> listener(do_GetInterface(aWindowContext));
|
||||
if (listener) {
|
||||
nsCOMPtr<nsISupports> cookie;
|
||||
listener->GetLoadCookie(getter_AddRefs(cookie));
|
||||
if (!cookie) {
|
||||
RefPtr<nsDocLoader> newDocLoader = new nsDocLoader();
|
||||
nsresult rv = newDocLoader->Init();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
rv = nsDocLoader::AddDocLoaderAsChildOfRoot(newDocLoader);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
cookie = nsDocLoader::GetAsSupports(newDocLoader);
|
||||
listener->SetLoadCookie(cookie);
|
||||
}
|
||||
loadGroup = do_GetInterface(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
// If the channel is pending, then we need to remove it from its current
|
||||
// loadgroup
|
||||
nsCOMPtr<nsILoadGroup> oldGroup;
|
||||
channel->GetLoadGroup(getter_AddRefs(oldGroup));
|
||||
if (aChannelIsOpen && !SameCOMIdentity(oldGroup, loadGroup)) {
|
||||
// It is important to add the channel to the new group before
|
||||
// removing it from the old one, so that the load isn't considered
|
||||
// done as soon as the request is removed.
|
||||
loadGroup->AddRequest(channel, nullptr);
|
||||
|
||||
if (oldGroup) {
|
||||
oldGroup->RemoveRequest(channel, nullptr, NS_BINDING_RETARGETED);
|
||||
}
|
||||
}
|
||||
|
||||
channel->SetLoadGroup(loadGroup);
|
||||
|
||||
// prepare the loader for receiving data
|
||||
nsresult rv = loader->Prepare();
|
||||
if (NS_SUCCEEDED(rv))
|
||||
NS_ADDREF(*aListener = loader);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsURILoader::OpenChannel(nsIChannel* channel,
|
||||
uint32_t aFlags,
|
||||
nsIInterfaceRequestor* aWindowContext,
|
||||
nsIStreamListener** aListener)
|
||||
{
|
||||
bool pending;
|
||||
if (NS_FAILED(channel->IsPending(&pending))) {
|
||||
pending = false;
|
||||
}
|
||||
|
||||
return OpenChannel(channel, aFlags, aWindowContext, pending, aListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsURILoader::Stop(nsISupports* aLoadCookie)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDocumentLoader> docLoader;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aLoadCookie);
|
||||
|
||||
docLoader = do_GetInterface(aLoadCookie, &rv);
|
||||
if (docLoader) {
|
||||
rv = docLoader->Stop();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
59
uriloader/base/nsURILoader.h
Normal file
59
uriloader/base/nsURILoader.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 nsURILoader_h__
|
||||
#define nsURILoader_h__
|
||||
|
||||
#include "nsCURILoader.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
class nsDocumentOpenInfo;
|
||||
|
||||
class nsURILoader final : public nsIURILoader
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIURILOADER
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsURILoader();
|
||||
|
||||
protected:
|
||||
~nsURILoader();
|
||||
|
||||
/**
|
||||
* Equivalent to nsIURILoader::openChannel, but allows specifying whether the
|
||||
* channel is opened already.
|
||||
*/
|
||||
MOZ_MUST_USE nsresult OpenChannel(nsIChannel* channel,
|
||||
uint32_t aFlags,
|
||||
nsIInterfaceRequestor* aWindowContext,
|
||||
bool aChannelOpen,
|
||||
nsIStreamListener** aListener);
|
||||
|
||||
/**
|
||||
* we shouldn't need to have an owning ref count on registered
|
||||
* content listeners because they are supposed to unregister themselves
|
||||
* when they go away. This array stores weak references
|
||||
*/
|
||||
nsCOMArray<nsIWeakReference> m_listeners;
|
||||
|
||||
/**
|
||||
* Logging. The module is called "URILoader"
|
||||
*/
|
||||
static mozilla::LazyLogModule mLog;
|
||||
|
||||
friend class nsDocumentOpenInfo;
|
||||
};
|
||||
|
||||
#endif /* nsURILoader_h__ */
|
||||
169
uriloader/exthandler/ContentHandlerService.cpp
Normal file
169
uriloader/exthandler/ContentHandlerService.cpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
#include "ContentHandlerService.h"
|
||||
#include "HandlerServiceChild.h"
|
||||
#include "ContentChild.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
|
||||
using mozilla::dom::ContentChild;
|
||||
using mozilla::dom::PHandlerServiceChild;
|
||||
using mozilla::dom::HandlerInfo;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(ContentHandlerService, nsIHandlerService)
|
||||
|
||||
ContentHandlerService::ContentHandlerService()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
ContentHandlerService::Init()
|
||||
{
|
||||
if (!XRE_IsContentProcess()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
ContentChild* cpc = ContentChild::GetSingleton();
|
||||
|
||||
mHandlerServiceChild = static_cast<HandlerServiceChild*>(cpc->SendPHandlerServiceConstructor());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ContentHandlerService::nsIHandlerInfoToHandlerInfo(nsIHandlerInfo* aInfo,
|
||||
HandlerInfo* aHandlerInfo)
|
||||
{
|
||||
nsCString type;
|
||||
aInfo->GetType(type);
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo = do_QueryInterface(aInfo);
|
||||
bool isMIMEInfo = !!mimeInfo;
|
||||
nsString description;
|
||||
aInfo->GetDescription(description);
|
||||
bool alwaysAskBeforeHandling;
|
||||
aInfo->GetAlwaysAskBeforeHandling(&alwaysAskBeforeHandling);
|
||||
nsCOMPtr<nsIHandlerApp> app;
|
||||
aInfo->GetPreferredApplicationHandler(getter_AddRefs(app));
|
||||
nsString name;
|
||||
nsString detailedDescription;
|
||||
if (app) {
|
||||
app->GetName(name);
|
||||
app->GetDetailedDescription(detailedDescription);
|
||||
}
|
||||
HandlerApp happ(name, detailedDescription);
|
||||
nsTArray<HandlerApp> happs;
|
||||
nsCOMPtr<nsIMutableArray> apps;
|
||||
aInfo->GetPossibleApplicationHandlers(getter_AddRefs(apps));
|
||||
if (apps) {
|
||||
unsigned int length;
|
||||
apps->GetLength(&length);
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
apps->QueryElementAt(i, NS_GET_IID(nsIHandlerApp), getter_AddRefs(app));
|
||||
app->GetName(name);
|
||||
app->GetDetailedDescription(detailedDescription);
|
||||
happs.AppendElement(HandlerApp(name, detailedDescription));
|
||||
}
|
||||
}
|
||||
nsHandlerInfoAction action;
|
||||
aInfo->GetPreferredAction(&action);
|
||||
HandlerInfo info(type, isMIMEInfo, description, alwaysAskBeforeHandling, happ, happs, action);
|
||||
*aHandlerInfo = info;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP RemoteHandlerApp::GetName(nsAString & aName)
|
||||
{
|
||||
aName.Assign(mAppChild.name());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP RemoteHandlerApp::SetName(const nsAString & aName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP RemoteHandlerApp::GetDetailedDescription(nsAString & aDetailedDescription)
|
||||
{
|
||||
aDetailedDescription.Assign(mAppChild.detailedDescription());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP RemoteHandlerApp::SetDetailedDescription(const nsAString & aDetailedDescription)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP RemoteHandlerApp::Equals(nsIHandlerApp *aHandlerApp, bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP RemoteHandlerApp::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(RemoteHandlerApp, nsIHandlerApp)
|
||||
|
||||
static inline void CopyHanderInfoTonsIHandlerInfo(HandlerInfo info, nsIHandlerInfo* aHandlerInfo)
|
||||
{
|
||||
HandlerApp preferredApplicationHandler = info.preferredApplicationHandler();
|
||||
nsCOMPtr<nsIHandlerApp> preferredApp(new RemoteHandlerApp(preferredApplicationHandler));
|
||||
aHandlerInfo->SetPreferredApplicationHandler(preferredApp);
|
||||
nsCOMPtr<nsIMutableArray> possibleHandlers;
|
||||
aHandlerInfo->GetPossibleApplicationHandlers(getter_AddRefs(possibleHandlers));
|
||||
possibleHandlers->AppendElement(preferredApp, false);
|
||||
}
|
||||
ContentHandlerService::~ContentHandlerService()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ContentHandlerService::Enumerate(nsISimpleEnumerator * *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ContentHandlerService::FillHandlerInfo(nsIHandlerInfo *aHandlerInfo, const nsACString & aOverrideType)
|
||||
{
|
||||
HandlerInfo info;
|
||||
nsIHandlerInfoToHandlerInfo(aHandlerInfo, &info);
|
||||
mHandlerServiceChild->SendFillHandlerInfo(info, nsCString(aOverrideType), &info);
|
||||
CopyHanderInfoTonsIHandlerInfo(info, aHandlerInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ContentHandlerService::Store(nsIHandlerInfo *aHandlerInfo)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ContentHandlerService::Exists(nsIHandlerInfo *aHandlerInfo, bool *_retval)
|
||||
{
|
||||
HandlerInfo info;
|
||||
nsIHandlerInfoToHandlerInfo(aHandlerInfo, &info);
|
||||
mHandlerServiceChild->SendExists(info, _retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ContentHandlerService::Remove(nsIHandlerInfo *aHandlerInfo)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP ContentHandlerService::GetTypeFromExtension(const nsACString & aFileExtension, nsACString & _retval)
|
||||
{
|
||||
nsCString* cachedType = nullptr;
|
||||
if (!!mExtToTypeMap.Get(aFileExtension, &cachedType) && !!cachedType) {
|
||||
_retval.Assign(*cachedType);
|
||||
return NS_OK;
|
||||
}
|
||||
nsCString type;
|
||||
mHandlerServiceChild->SendGetTypeFromExtension(nsCString(aFileExtension), &type);
|
||||
_retval.Assign(type);
|
||||
mExtToTypeMap.Put(nsCString(aFileExtension), new nsCString(type));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
52
uriloader/exthandler/ContentHandlerService.h
Normal file
52
uriloader/exthandler/ContentHandlerService.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef ContentHandlerService_h
|
||||
#define ContentHandlerService_h
|
||||
|
||||
#include "nsIHandlerService.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "HandlerServiceChild.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
|
||||
#define NS_CONTENTHANDLERSERVICE_CID \
|
||||
{0xc4b6fb7c, 0xbfb1, 0x49dc, {0xa6, 0x5f, 0x03, 0x57, 0x96, 0x52, 0x4b, 0x53}}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class PHandlerServiceChild;
|
||||
|
||||
class ContentHandlerService : public nsIHandlerService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHANDLERSERVICE
|
||||
|
||||
ContentHandlerService();
|
||||
MOZ_MUST_USE nsresult Init();
|
||||
static void nsIHandlerInfoToHandlerInfo(nsIHandlerInfo* aInfo, HandlerInfo* aHandlerInfo);
|
||||
|
||||
private:
|
||||
virtual ~ContentHandlerService();
|
||||
RefPtr<HandlerServiceChild> mHandlerServiceChild;
|
||||
nsClassHashtable<nsCStringHashKey, nsCString> mExtToTypeMap;
|
||||
};
|
||||
|
||||
class RemoteHandlerApp : public nsIHandlerApp
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHANDLERAPP
|
||||
|
||||
explicit RemoteHandlerApp(HandlerApp aAppChild) : mAppChild(aAppChild)
|
||||
{
|
||||
}
|
||||
private:
|
||||
virtual ~RemoteHandlerApp()
|
||||
{
|
||||
}
|
||||
HandlerApp mAppChild;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
127
uriloader/exthandler/ExternalHelperAppChild.cpp
Normal file
127
uriloader/exthandler/ExternalHelperAppChild.cpp
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 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 "ExternalHelperAppChild.h"
|
||||
#include "mozilla/net/ChannelDiverterChild.h"
|
||||
#include "nsIDivertableChannel.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIFTPChannel.h"
|
||||
#include "nsIRequest.h"
|
||||
#include "nsIResumableChannel.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(ExternalHelperAppChild,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver)
|
||||
|
||||
ExternalHelperAppChild::ExternalHelperAppChild()
|
||||
: mStatus(NS_OK)
|
||||
{
|
||||
}
|
||||
|
||||
ExternalHelperAppChild::~ExternalHelperAppChild()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIStreamListener
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppChild::OnDataAvailable(nsIRequest *request,
|
||||
nsISupports *ctx,
|
||||
nsIInputStream *input,
|
||||
uint64_t offset,
|
||||
uint32_t count)
|
||||
{
|
||||
if (NS_FAILED(mStatus))
|
||||
return mStatus;
|
||||
|
||||
nsCString data;
|
||||
nsresult rv = NS_ReadInputStreamToString(input, data, count);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (!SendOnDataAvailable(data, offset, count))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// nsIRequestObserver
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppChild::OnStartRequest(nsIRequest *request, nsISupports *ctx)
|
||||
{
|
||||
nsCOMPtr<nsIDivertableChannel> divertable = do_QueryInterface(request);
|
||||
if (divertable) {
|
||||
return DivertToParent(divertable, request);
|
||||
}
|
||||
|
||||
nsresult rv = mHandler->OnStartRequest(request, ctx);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsCString entityID;
|
||||
nsCOMPtr<nsIResumableChannel> resumable(do_QueryInterface(request));
|
||||
if (resumable) {
|
||||
resumable->GetEntityID(entityID);
|
||||
}
|
||||
SendOnStartRequest(entityID);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppChild::OnStopRequest(nsIRequest *request,
|
||||
nsISupports *ctx,
|
||||
nsresult status)
|
||||
{
|
||||
// mHandler can be null if we diverted the request to the parent
|
||||
if (mHandler) {
|
||||
nsresult rv = mHandler->OnStopRequest(request, ctx, status);
|
||||
SendOnStopRequest(status);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExternalHelperAppChild::DivertToParent(nsIDivertableChannel *divertable,
|
||||
nsIRequest *request)
|
||||
{
|
||||
// nsIDivertable must know about content conversions before being diverted.
|
||||
MOZ_ASSERT(mHandler);
|
||||
mHandler->MaybeApplyDecodingForExtension(request);
|
||||
|
||||
mozilla::net::ChannelDiverterChild *diverter = nullptr;
|
||||
nsresult rv = divertable->DivertToParent(&diverter);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
MOZ_ASSERT(diverter);
|
||||
|
||||
if (SendDivertToParentUsing(diverter)) {
|
||||
mHandler->DidDivertRequest(request);
|
||||
mHandler = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool
|
||||
ExternalHelperAppChild::RecvCancel(const nsresult& aStatus)
|
||||
{
|
||||
mStatus = aStatus;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
45
uriloader/exthandler/ExternalHelperAppChild.h
Normal file
45
uriloader/exthandler/ExternalHelperAppChild.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 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_dom_ExternalHelperAppChild_h
|
||||
#define mozilla_dom_ExternalHelperAppChild_h
|
||||
|
||||
#include "mozilla/dom/PExternalHelperAppChild.h"
|
||||
#include "nsExternalHelperAppService.h"
|
||||
#include "nsIStreamListener.h"
|
||||
|
||||
class nsIDivertableChannel;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ExternalHelperAppChild : public PExternalHelperAppChild
|
||||
, public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
ExternalHelperAppChild();
|
||||
|
||||
// Give the listener a real nsExternalAppHandler to complete processing on
|
||||
// the child.
|
||||
void SetHandler(nsExternalAppHandler *handler) { mHandler = handler; }
|
||||
|
||||
virtual bool RecvCancel(const nsresult& aStatus) override;
|
||||
private:
|
||||
virtual ~ExternalHelperAppChild();
|
||||
MOZ_MUST_USE nsresult DivertToParent(nsIDivertableChannel *divertable, nsIRequest *request);
|
||||
|
||||
RefPtr<nsExternalAppHandler> mHandler;
|
||||
nsresult mStatus;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ExternalHelperAppChild_h
|
||||
512
uriloader/exthandler/ExternalHelperAppParent.cpp
Normal file
512
uriloader/exthandler/ExternalHelperAppParent.cpp
Normal file
|
|
@ -0,0 +1,512 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 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/DebugOnly.h"
|
||||
|
||||
#include "ExternalHelperAppParent.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsIExternalHelperAppService.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "nsIBrowserDOMWindow.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "mozilla/net/ChannelDiverterParent.h"
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(ExternalHelperAppParent,
|
||||
nsHashPropertyBag,
|
||||
nsIRequest,
|
||||
nsIChannel,
|
||||
nsIMultiPartChannel,
|
||||
nsIPrivateBrowsingChannel,
|
||||
nsIResumableChannel,
|
||||
nsIStreamListener,
|
||||
nsIExternalHelperAppParent)
|
||||
|
||||
ExternalHelperAppParent::ExternalHelperAppParent(
|
||||
const OptionalURIParams& uri,
|
||||
const int64_t& aContentLength,
|
||||
const bool& aWasFileChannel)
|
||||
: mURI(DeserializeURI(uri))
|
||||
, mPending(false)
|
||||
#ifdef DEBUG
|
||||
, mDiverted(false)
|
||||
#endif
|
||||
, mIPCClosed(false)
|
||||
, mLoadFlags(0)
|
||||
, mStatus(NS_OK)
|
||||
, mContentLength(aContentLength)
|
||||
, mWasFileChannel(aWasFileChannel)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ExternalHelperAppParent::Init(ContentParent *parent,
|
||||
const nsCString& aMimeContentType,
|
||||
const nsCString& aContentDispositionHeader,
|
||||
const uint32_t& aContentDispositionHint,
|
||||
const nsString& aContentDispositionFilename,
|
||||
const bool& aForceSave,
|
||||
const OptionalURIParams& aReferrer,
|
||||
PBrowserParent* aBrowser)
|
||||
{
|
||||
nsCOMPtr<nsIExternalHelperAppService> helperAppService =
|
||||
do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID);
|
||||
NS_ASSERTION(helperAppService, "No Helper App Service!");
|
||||
|
||||
nsCOMPtr<nsIURI> referrer = DeserializeURI(aReferrer);
|
||||
if (referrer)
|
||||
SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"), referrer);
|
||||
|
||||
mContentDispositionHeader = aContentDispositionHeader;
|
||||
if (!mContentDispositionHeader.IsEmpty()) {
|
||||
NS_GetFilenameFromDisposition(mContentDispositionFilename,
|
||||
mContentDispositionHeader,
|
||||
mURI);
|
||||
mContentDisposition =
|
||||
NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
|
||||
}
|
||||
else {
|
||||
mContentDisposition = aContentDispositionHint;
|
||||
mContentDispositionFilename = aContentDispositionFilename;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> window;
|
||||
if (aBrowser) {
|
||||
TabParent* tabParent = TabParent::GetFrom(aBrowser);
|
||||
if (tabParent->GetOwnerElement())
|
||||
window = do_QueryInterface(tabParent->GetOwnerElement()->OwnerDoc()->GetWindow());
|
||||
|
||||
bool isPrivate = false;
|
||||
nsCOMPtr<nsILoadContext> loadContext = tabParent->GetLoadContext();
|
||||
loadContext->GetUsePrivateBrowsing(&isPrivate);
|
||||
SetPrivate(isPrivate);
|
||||
}
|
||||
|
||||
helperAppService->DoContent(aMimeContentType, this, window,
|
||||
aForceSave, nullptr,
|
||||
getter_AddRefs(mListener));
|
||||
}
|
||||
|
||||
void
|
||||
ExternalHelperAppParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
mIPCClosed = true;
|
||||
}
|
||||
|
||||
void
|
||||
ExternalHelperAppParent::Delete()
|
||||
{
|
||||
if (!mIPCClosed) {
|
||||
Unused << Send__delete__(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ExternalHelperAppParent::RecvOnStartRequest(const nsCString& entityID)
|
||||
{
|
||||
MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted");
|
||||
|
||||
mEntityID = entityID;
|
||||
mPending = true;
|
||||
mStatus = mListener->OnStartRequest(this, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ExternalHelperAppParent::RecvOnDataAvailable(const nsCString& data,
|
||||
const uint64_t& offset,
|
||||
const uint32_t& count)
|
||||
{
|
||||
if (NS_FAILED(mStatus))
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted");
|
||||
MOZ_ASSERT(mPending, "must be pending!");
|
||||
|
||||
nsCOMPtr<nsIInputStream> stringStream;
|
||||
DebugOnly<nsresult> rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(), count, NS_ASSIGNMENT_DEPEND);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create dependent string!");
|
||||
mStatus = mListener->OnDataAvailable(this, nullptr, stringStream, offset, count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ExternalHelperAppParent::RecvOnStopRequest(const nsresult& code)
|
||||
{
|
||||
MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted");
|
||||
|
||||
mPending = false;
|
||||
mListener->OnStopRequest(this, nullptr,
|
||||
(NS_SUCCEEDED(code) && NS_FAILED(mStatus)) ? mStatus : code);
|
||||
Delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ExternalHelperAppParent::RecvDivertToParentUsing(PChannelDiverterParent* diverter)
|
||||
{
|
||||
MOZ_ASSERT(diverter);
|
||||
auto p = static_cast<mozilla::net::ChannelDiverterParent*>(diverter);
|
||||
p->DivertTo(this);
|
||||
#ifdef DEBUG
|
||||
mDiverted = true;
|
||||
#endif
|
||||
Unused << p->Send__delete__(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIStreamListener
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::OnDataAvailable(nsIRequest *request,
|
||||
nsISupports *ctx,
|
||||
nsIInputStream *input,
|
||||
uint64_t offset,
|
||||
uint32_t count)
|
||||
{
|
||||
MOZ_ASSERT(mDiverted);
|
||||
return mListener->OnDataAvailable(request, ctx, input, offset, count);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::OnStartRequest(nsIRequest *request, nsISupports *ctx)
|
||||
{
|
||||
MOZ_ASSERT(mDiverted);
|
||||
return mListener->OnStartRequest(request, ctx);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::OnStopRequest(nsIRequest *request,
|
||||
nsISupports *ctx,
|
||||
nsresult status)
|
||||
{
|
||||
MOZ_ASSERT(mDiverted);
|
||||
nsresult rv = mListener->OnStopRequest(request, ctx, status);
|
||||
Delete();
|
||||
return rv;
|
||||
}
|
||||
|
||||
ExternalHelperAppParent::~ExternalHelperAppParent()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// nsIRequest implementation...
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetName(nsACString& aResult)
|
||||
{
|
||||
if (!mURI) {
|
||||
aResult.Truncate();
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mURI->GetAsciiSpec(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::IsPending(bool *aResult)
|
||||
{
|
||||
*aResult = mPending;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetStatus(nsresult *aResult)
|
||||
{
|
||||
*aResult = mStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::Cancel(nsresult aStatus)
|
||||
{
|
||||
mStatus = aStatus;
|
||||
Unused << SendCancel(aStatus);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::Suspend()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::Resume()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIChannel implementation
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetOriginalURI(nsIURI * *aURI)
|
||||
{
|
||||
NS_IF_ADDREF(*aURI = mURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetOriginalURI(nsIURI *aURI)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetURI(nsIURI **aURI)
|
||||
{
|
||||
NS_IF_ADDREF(*aURI = mURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::Open(nsIInputStream **aResult)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::Open2(nsIInputStream** aStream)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::AsyncOpen(nsIStreamListener *aListener,
|
||||
nsISupports *aContext)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::AsyncOpen2(nsIStreamListener *aListener)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
||||
{
|
||||
*aLoadFlags = mLoadFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetLoadFlags(nsLoadFlags aLoadFlags)
|
||||
{
|
||||
mLoadFlags = aLoadFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetLoadGroup(nsILoadGroup* *aLoadGroup)
|
||||
{
|
||||
*aLoadGroup = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetLoadGroup(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetOwner(nsISupports* *aOwner)
|
||||
{
|
||||
*aOwner = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetOwner(nsISupports* aOwner)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetLoadInfo(nsILoadInfo* *aLoadInfo)
|
||||
{
|
||||
*aLoadInfo = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetLoadInfo(nsILoadInfo* aLoadInfo)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
|
||||
{
|
||||
*aCallbacks = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetSecurityInfo(nsISupports * *aSecurityInfo)
|
||||
{
|
||||
*aSecurityInfo = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetContentType(nsACString& aContentType)
|
||||
{
|
||||
aContentType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetContentType(const nsACString& aContentType)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetContentCharset(nsACString& aContentCharset)
|
||||
{
|
||||
aContentCharset.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetContentCharset(const nsACString& aContentCharset)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetContentDisposition(uint32_t *aContentDisposition)
|
||||
{
|
||||
// NB: mContentDisposition may or may not be set to a non UINT32_MAX value in
|
||||
// nsExternalHelperAppService::DoContentContentProcessHelper
|
||||
if (mContentDispositionHeader.IsEmpty() && mContentDisposition == UINT32_MAX)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
*aContentDisposition = mContentDisposition;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetContentDisposition(uint32_t aContentDisposition)
|
||||
{
|
||||
mContentDisposition = aContentDisposition;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetContentDispositionFilename(nsAString& aContentDispositionFilename)
|
||||
{
|
||||
if (mContentDispositionFilename.IsEmpty())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
aContentDispositionFilename = mContentDispositionFilename;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetContentDispositionFilename(const nsAString& aContentDispositionFilename)
|
||||
{
|
||||
mContentDispositionFilename = aContentDispositionFilename;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetContentDispositionHeader(nsACString& aContentDispositionHeader)
|
||||
{
|
||||
if (mContentDispositionHeader.IsEmpty())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
aContentDispositionHeader = mContentDispositionHeader;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetContentLength(int64_t *aContentLength)
|
||||
{
|
||||
if (mContentLength < 0)
|
||||
*aContentLength = -1;
|
||||
else
|
||||
*aContentLength = mContentLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::SetContentLength(int64_t aContentLength)
|
||||
{
|
||||
mContentLength = aContentLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIResumableChannel implementation
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::ResumeAt(uint64_t startPos, const nsACString& entityID)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetEntityID(nsACString& aEntityID)
|
||||
{
|
||||
aEntityID = mEntityID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIMultiPartChannel implementation
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetBaseChannel(nsIChannel* *aChannel)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetPartID(uint32_t* aPartID)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ExternalHelperAppParent::GetIsLastPart(bool* aIsLastPart)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
119
uriloader/exthandler/ExternalHelperAppParent.h
Normal file
119
uriloader/exthandler/ExternalHelperAppParent.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 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/dom/PExternalHelperAppParent.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIMultiPartChannel.h"
|
||||
#include "nsIResumableChannel.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "PrivateBrowsingChannel.h"
|
||||
|
||||
namespace IPC {
|
||||
class URI;
|
||||
} // namespace IPC
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
class OptionalURIParams;
|
||||
} // namespace ipc
|
||||
|
||||
namespace net {
|
||||
class PChannelDiverterParent;
|
||||
} // namespace net
|
||||
|
||||
namespace dom {
|
||||
|
||||
#define NS_IEXTERNALHELPERAPPPARENT_IID \
|
||||
{ 0x127a01bc, 0x2a49, 0x46a8, \
|
||||
{ 0x8c, 0x63, 0x4b, 0x5d, 0x3c, 0xa4, 0x07, 0x9c } }
|
||||
|
||||
class nsIExternalHelperAppParent : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IEXTERNALHELPERAPPPARENT_IID)
|
||||
|
||||
/**
|
||||
* Returns true if this fake channel represented a file channel in the child.
|
||||
*/
|
||||
virtual bool WasFileChannel() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIExternalHelperAppParent, NS_IEXTERNALHELPERAPPPARENT_IID)
|
||||
|
||||
class ContentParent;
|
||||
class PBrowserParent;
|
||||
|
||||
class ExternalHelperAppParent : public PExternalHelperAppParent
|
||||
, public nsHashPropertyBag
|
||||
, public nsIChannel
|
||||
, public nsIMultiPartChannel
|
||||
, public nsIResumableChannel
|
||||
, public nsIStreamListener
|
||||
, public net::PrivateBrowsingChannel<ExternalHelperAppParent>
|
||||
, public nsIExternalHelperAppParent
|
||||
{
|
||||
typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSICHANNEL
|
||||
NS_DECL_NSIMULTIPARTCHANNEL
|
||||
NS_DECL_NSIRESUMABLECHANNEL
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
bool RecvOnStartRequest(const nsCString& entityID) override;
|
||||
bool RecvOnDataAvailable(const nsCString& data,
|
||||
const uint64_t& offset,
|
||||
const uint32_t& count) override;
|
||||
bool RecvOnStopRequest(const nsresult& code) override;
|
||||
|
||||
bool RecvDivertToParentUsing(PChannelDiverterParent* diverter) override;
|
||||
|
||||
bool WasFileChannel() override {
|
||||
return mWasFileChannel;
|
||||
}
|
||||
|
||||
ExternalHelperAppParent(const OptionalURIParams& uri, const int64_t& contentLength,
|
||||
const bool& wasFileChannel);
|
||||
void Init(ContentParent *parent,
|
||||
const nsCString& aMimeContentType,
|
||||
const nsCString& aContentDisposition,
|
||||
const uint32_t& aContentDispositionHint,
|
||||
const nsString& aContentDispositionFilename,
|
||||
const bool& aForceSave,
|
||||
const OptionalURIParams& aReferrer,
|
||||
PBrowserParent* aBrowser);
|
||||
|
||||
protected:
|
||||
virtual ~ExternalHelperAppParent();
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
void Delete();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
bool mPending;
|
||||
#ifdef DEBUG
|
||||
bool mDiverted;
|
||||
#endif
|
||||
bool mIPCClosed;
|
||||
nsLoadFlags mLoadFlags;
|
||||
nsresult mStatus;
|
||||
int64_t mContentLength;
|
||||
bool mWasFileChannel;
|
||||
uint32_t mContentDisposition;
|
||||
nsString mContentDispositionFilename;
|
||||
nsCString mContentDispositionHeader;
|
||||
nsCString mEntityID;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
15
uriloader/exthandler/HandlerServiceChild.h
Normal file
15
uriloader/exthandler/HandlerServiceChild.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef handler_service_child_h
|
||||
#define handler_service_child_h
|
||||
|
||||
#include "mozilla/dom/PHandlerServiceChild.h"
|
||||
|
||||
class HandlerServiceChild final : public mozilla::dom::PHandlerServiceChild
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(HandlerServiceChild)
|
||||
HandlerServiceChild() {}
|
||||
private:
|
||||
virtual ~HandlerServiceChild() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
270
uriloader/exthandler/HandlerServiceParent.cpp
Normal file
270
uriloader/exthandler/HandlerServiceParent.cpp
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
#include "HandlerServiceParent.h"
|
||||
#include "nsIHandlerService.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "ContentHandlerService.h"
|
||||
|
||||
using mozilla::dom::HandlerInfo;
|
||||
using mozilla::dom::HandlerApp;
|
||||
using mozilla::dom::ContentHandlerService;
|
||||
using mozilla::dom::RemoteHandlerApp;
|
||||
|
||||
namespace {
|
||||
|
||||
class ProxyHandlerInfo final : public nsIHandlerInfo {
|
||||
public:
|
||||
explicit ProxyHandlerInfo(const HandlerInfo& aHandlerInfo);
|
||||
NS_DECL_ISUPPORTS;
|
||||
NS_DECL_NSIHANDLERINFO;
|
||||
protected:
|
||||
~ProxyHandlerInfo() {}
|
||||
HandlerInfo mHandlerInfo;
|
||||
nsHandlerInfoAction mPrefAction;
|
||||
nsCOMPtr<nsIMutableArray> mPossibleApps;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ProxyHandlerInfo, nsIHandlerInfo)
|
||||
|
||||
ProxyHandlerInfo::ProxyHandlerInfo(const HandlerInfo& aHandlerInfo) : mHandlerInfo(aHandlerInfo), mPossibleApps(do_CreateInstance(NS_ARRAY_CONTRACTID))
|
||||
{
|
||||
for (auto& happ : aHandlerInfo.possibleApplicationHandlers()) {
|
||||
mPossibleApps->AppendElement(new RemoteHandlerApp(happ), false);
|
||||
}
|
||||
}
|
||||
|
||||
/* readonly attribute ACString type; */
|
||||
NS_IMETHODIMP ProxyHandlerInfo::GetType(nsACString & aType)
|
||||
{
|
||||
aType.Assign(mHandlerInfo.type());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute AString description; */
|
||||
NS_IMETHODIMP ProxyHandlerInfo::GetDescription(nsAString & aDescription)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHODIMP ProxyHandlerInfo::SetDescription(const nsAString & aDescription)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* attribute nsIHandlerApp preferredApplicationHandler; */
|
||||
NS_IMETHODIMP ProxyHandlerInfo::GetPreferredApplicationHandler(nsIHandlerApp * *aPreferredApplicationHandler)
|
||||
{
|
||||
*aPreferredApplicationHandler = new RemoteHandlerApp(mHandlerInfo.preferredApplicationHandler());
|
||||
NS_IF_ADDREF(*aPreferredApplicationHandler);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ProxyHandlerInfo::SetPreferredApplicationHandler(nsIHandlerApp *aApp)
|
||||
{
|
||||
nsString name;
|
||||
nsString detailedDescription;
|
||||
if (aApp) {
|
||||
aApp->GetName(name);
|
||||
aApp->GetDetailedDescription(detailedDescription);
|
||||
}
|
||||
HandlerApp happ(name, detailedDescription);
|
||||
mHandlerInfo = HandlerInfo(mHandlerInfo.type(),
|
||||
mHandlerInfo.isMIMEInfo(),
|
||||
mHandlerInfo.description(),
|
||||
mHandlerInfo.alwaysAskBeforeHandling(),
|
||||
happ,
|
||||
mHandlerInfo.possibleApplicationHandlers(),
|
||||
mHandlerInfo.preferredAction());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute nsIMutableArray possibleApplicationHandlers; */
|
||||
NS_IMETHODIMP ProxyHandlerInfo::GetPossibleApplicationHandlers(nsIMutableArray * *aPossibleApplicationHandlers)
|
||||
{
|
||||
*aPossibleApplicationHandlers = mPossibleApps;
|
||||
NS_IF_ADDREF(*aPossibleApplicationHandlers);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute boolean hasDefaultHandler; */
|
||||
NS_IMETHODIMP ProxyHandlerInfo::GetHasDefaultHandler(bool *aHasDefaultHandler)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* readonly attribute AString defaultDescription; */
|
||||
NS_IMETHODIMP ProxyHandlerInfo::GetDefaultDescription(nsAString & aDefaultDescription)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* void launchWithURI (in nsIURI aURI, [optional] in nsIInterfaceRequestor aWindowContext); */
|
||||
NS_IMETHODIMP ProxyHandlerInfo::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* attribute ProxyHandlerInfoAction preferredAction; */
|
||||
NS_IMETHODIMP ProxyHandlerInfo::GetPreferredAction(nsHandlerInfoAction *aPreferredAction)
|
||||
{
|
||||
*aPreferredAction = mPrefAction;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP ProxyHandlerInfo::SetPreferredAction(nsHandlerInfoAction aPreferredAction)
|
||||
{
|
||||
mHandlerInfo = HandlerInfo(mHandlerInfo.type(),
|
||||
mHandlerInfo.isMIMEInfo(),
|
||||
mHandlerInfo.description(),
|
||||
mHandlerInfo.alwaysAskBeforeHandling(),
|
||||
mHandlerInfo.preferredApplicationHandler(),
|
||||
mHandlerInfo.possibleApplicationHandlers(),
|
||||
aPreferredAction);
|
||||
mPrefAction = aPreferredAction;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute boolean alwaysAskBeforeHandling; */
|
||||
NS_IMETHODIMP ProxyHandlerInfo::GetAlwaysAskBeforeHandling(bool *aAlwaysAskBeforeHandling)
|
||||
{
|
||||
*aAlwaysAskBeforeHandling = mHandlerInfo.alwaysAskBeforeHandling();
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP ProxyHandlerInfo::SetAlwaysAskBeforeHandling(bool aAlwaysAskBeforeHandling)
|
||||
{
|
||||
mHandlerInfo = HandlerInfo(mHandlerInfo.type(),
|
||||
mHandlerInfo.isMIMEInfo(),
|
||||
mHandlerInfo.description(),
|
||||
aAlwaysAskBeforeHandling,
|
||||
mHandlerInfo.preferredApplicationHandler(),
|
||||
mHandlerInfo.possibleApplicationHandlers(),
|
||||
mHandlerInfo.preferredAction());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
class ProxyMIMEInfo : public nsIMIMEInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMIMEINFO
|
||||
NS_FORWARD_NSIHANDLERINFO(mProxyHandlerInfo->);
|
||||
|
||||
explicit ProxyMIMEInfo(HandlerInfo aHandlerInfo) : mProxyHandlerInfo(new ProxyHandlerInfo(aHandlerInfo)) {}
|
||||
|
||||
private:
|
||||
virtual ~ProxyMIMEInfo() {}
|
||||
nsCOMPtr<nsIHandlerInfo> mProxyHandlerInfo;
|
||||
|
||||
protected:
|
||||
/* additional members */
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ProxyMIMEInfo, nsIMIMEInfo, nsIHandlerInfo)
|
||||
|
||||
/* nsIUTF8StringEnumerator getFileExtensions (); */
|
||||
NS_IMETHODIMP ProxyMIMEInfo::GetFileExtensions(nsIUTF8StringEnumerator * *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* void setFileExtensions (in AUTF8String aExtensions); */
|
||||
NS_IMETHODIMP ProxyMIMEInfo::SetFileExtensions(const nsACString & aExtensions)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* boolean extensionExists (in AUTF8String aExtension); */
|
||||
NS_IMETHODIMP ProxyMIMEInfo::ExtensionExists(const nsACString & aExtension, bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* void appendExtension (in AUTF8String aExtension); */
|
||||
NS_IMETHODIMP ProxyMIMEInfo::AppendExtension(const nsACString & aExtension)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* attribute AUTF8String primaryExtension; */
|
||||
NS_IMETHODIMP ProxyMIMEInfo::GetPrimaryExtension(nsACString & aPrimaryExtension)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ProxyMIMEInfo::SetPrimaryExtension(const nsACString & aPrimaryExtension)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* readonly attribute ACString MIMEType; */
|
||||
NS_IMETHODIMP ProxyMIMEInfo::GetMIMEType(nsACString & aMIMEType)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* boolean equals (in nsIMIMEInfo aMIMEInfo); */
|
||||
NS_IMETHODIMP ProxyMIMEInfo::Equals(nsIMIMEInfo *aMIMEInfo, bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* readonly attribute nsIArray possibleLocalHandlers; */
|
||||
NS_IMETHODIMP ProxyMIMEInfo::GetPossibleLocalHandlers(nsIArray * *aPossibleLocalHandlers)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* void launchWithFile (in nsIFile aFile); */
|
||||
NS_IMETHODIMP ProxyMIMEInfo::LaunchWithFile(nsIFile *aFile)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIHandlerInfo> WrapHandlerInfo(const HandlerInfo& aHandlerInfo) {
|
||||
nsCOMPtr<nsIHandlerInfo> info;
|
||||
if (aHandlerInfo.isMIMEInfo()) {
|
||||
info = new ProxyMIMEInfo(aHandlerInfo);
|
||||
} else {
|
||||
info = new ProxyHandlerInfo(aHandlerInfo);
|
||||
}
|
||||
return info.forget();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
HandlerServiceParent::HandlerServiceParent()
|
||||
{
|
||||
}
|
||||
|
||||
HandlerServiceParent::~HandlerServiceParent()
|
||||
{
|
||||
}
|
||||
|
||||
bool HandlerServiceParent::RecvFillHandlerInfo(const HandlerInfo& aHandlerInfoData,
|
||||
const nsCString& aOverrideType,
|
||||
HandlerInfo* handlerInfoData)
|
||||
{
|
||||
nsCOMPtr<nsIHandlerInfo> info(WrapHandlerInfo(aHandlerInfoData));
|
||||
nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID);
|
||||
handlerSvc->FillHandlerInfo(info, aOverrideType);
|
||||
ContentHandlerService::nsIHandlerInfoToHandlerInfo(info, handlerInfoData);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandlerServiceParent::RecvExists(const HandlerInfo& aHandlerInfo,
|
||||
bool* exists)
|
||||
{
|
||||
nsCOMPtr<nsIHandlerInfo> info(WrapHandlerInfo(aHandlerInfo));
|
||||
nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID);
|
||||
handlerSvc->Exists(info, exists);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandlerServiceParent::RecvGetTypeFromExtension(const nsCString& aFileExtension,
|
||||
nsCString* type)
|
||||
{
|
||||
nsCOMPtr<nsIHandlerService> handlerSvc = do_GetService(NS_HANDLERSERVICE_CONTRACTID);
|
||||
handlerSvc->GetTypeFromExtension(aFileExtension, *type);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandlerServiceParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
}
|
||||
31
uriloader/exthandler/HandlerServiceParent.h
Normal file
31
uriloader/exthandler/HandlerServiceParent.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef handler_service_parent_h
|
||||
#define handler_service_parent_h
|
||||
|
||||
#include "mozilla/dom/PHandlerServiceParent.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
|
||||
class nsIHandlerApp;
|
||||
|
||||
class HandlerServiceParent final : public mozilla::dom::PHandlerServiceParent
|
||||
{
|
||||
public:
|
||||
HandlerServiceParent();
|
||||
NS_INLINE_DECL_REFCOUNTING(HandlerServiceParent)
|
||||
|
||||
private:
|
||||
virtual ~HandlerServiceParent();
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
|
||||
virtual bool RecvFillHandlerInfo(const HandlerInfo& aHandlerInfoData,
|
||||
const nsCString& aOverrideType,
|
||||
HandlerInfo* handlerInfoData) override;
|
||||
virtual bool RecvExists(const HandlerInfo& aHandlerInfo,
|
||||
bool* exits) override;
|
||||
|
||||
virtual bool RecvGetTypeFromExtension(const nsCString& aFileExtension,
|
||||
nsCString* type) override;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
29
uriloader/exthandler/PExternalHelperApp.ipdl
Normal file
29
uriloader/exthandler/PExternalHelperApp.ipdl
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* 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 PContent;
|
||||
include protocol PChannelDiverter;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
protocol PExternalHelperApp
|
||||
{
|
||||
manager PContent;
|
||||
|
||||
parent:
|
||||
async OnStartRequest(nsCString entityID);
|
||||
async OnDataAvailable(nsCString data, uint64_t offset, uint32_t count);
|
||||
async OnStopRequest(nsresult code);
|
||||
|
||||
async DivertToParentUsing(PChannelDiverter diverter);
|
||||
|
||||
child:
|
||||
async Cancel(nsresult aStatus);
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
42
uriloader/exthandler/PHandlerService.ipdl
Normal file
42
uriloader/exthandler/PHandlerService.ipdl
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* 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 PContent;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct HandlerApp {
|
||||
nsString name;
|
||||
nsString detailedDescription;
|
||||
};
|
||||
|
||||
struct HandlerInfo {
|
||||
nsCString type;
|
||||
bool isMIMEInfo;
|
||||
nsString description;
|
||||
bool alwaysAskBeforeHandling;
|
||||
HandlerApp preferredApplicationHandler;
|
||||
HandlerApp[] possibleApplicationHandlers;
|
||||
long preferredAction;
|
||||
};
|
||||
|
||||
sync protocol PHandlerService
|
||||
{
|
||||
manager PContent;
|
||||
|
||||
parent:
|
||||
sync FillHandlerInfo(HandlerInfo aHandlerInfoData,
|
||||
nsCString aOverrideType)
|
||||
returns (HandlerInfo handlerInfoData);
|
||||
sync Exists(HandlerInfo aHandlerInfo)
|
||||
returns (bool exists);
|
||||
sync GetTypeFromExtension(nsCString aFileExtension)
|
||||
returns (nsCString type);
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
91
uriloader/exthandler/android/nsAndroidHandlerApp.cpp
Normal file
91
uriloader/exthandler/android/nsAndroidHandlerApp.cpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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 "nsAndroidHandlerApp.h"
|
||||
#include "GeneratedJNIWrappers.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAndroidHandlerApp, nsIHandlerApp, nsISharingHandlerApp)
|
||||
|
||||
nsAndroidHandlerApp::nsAndroidHandlerApp(const nsAString& aName,
|
||||
const nsAString& aDescription,
|
||||
const nsAString& aPackageName,
|
||||
const nsAString& aClassName,
|
||||
const nsACString& aMimeType,
|
||||
const nsAString& aAction) :
|
||||
mName(aName), mDescription(aDescription), mPackageName(aPackageName),
|
||||
mClassName(aClassName), mMimeType(aMimeType), mAction(aAction)
|
||||
{
|
||||
}
|
||||
|
||||
nsAndroidHandlerApp::~nsAndroidHandlerApp()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAndroidHandlerApp::GetName(nsAString & aName)
|
||||
{
|
||||
aName.Assign(mName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAndroidHandlerApp::SetName(const nsAString & aName)
|
||||
{
|
||||
mName.Assign(aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAndroidHandlerApp::GetDetailedDescription(nsAString & aDescription)
|
||||
{
|
||||
aDescription.Assign(mDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAndroidHandlerApp::SetDetailedDescription(const nsAString & aDescription)
|
||||
{
|
||||
mDescription.Assign(aDescription);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXX Workaround for bug 986975 to maintain the existing broken semantics
|
||||
template<>
|
||||
struct nsISharingHandlerApp::COMTypeInfo<nsAndroidHandlerApp, void> {
|
||||
static const nsIID kIID;
|
||||
};
|
||||
const nsIID nsISharingHandlerApp::COMTypeInfo<nsAndroidHandlerApp, void>::kIID = NS_IHANDLERAPP_IID;
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAndroidHandlerApp::Equals(nsIHandlerApp *aHandlerApp, bool *aRetval)
|
||||
{
|
||||
nsCOMPtr<nsAndroidHandlerApp> aApp = do_QueryInterface(aHandlerApp);
|
||||
*aRetval = aApp && aApp->mName.Equals(mName) &&
|
||||
aApp->mDescription.Equals(mDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAndroidHandlerApp::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext)
|
||||
{
|
||||
nsCString uriSpec;
|
||||
aURI->GetSpec(uriSpec);
|
||||
return java::GeckoAppShell::OpenUriExternal(
|
||||
uriSpec, mMimeType, mPackageName, mClassName,
|
||||
mAction, EmptyString()) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAndroidHandlerApp::Share(const nsAString & data, const nsAString & title)
|
||||
{
|
||||
return java::GeckoAppShell::OpenUriExternal(
|
||||
data, mMimeType, mPackageName, mClassName,
|
||||
mAction, EmptyString()) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
33
uriloader/exthandler/android/nsAndroidHandlerApp.h
Normal file
33
uriloader/exthandler/android/nsAndroidHandlerApp.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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 nsAndroidHandlerApp_h
|
||||
#define nsAndroidHandlerApp_h
|
||||
|
||||
#include "nsMIMEInfoImpl.h"
|
||||
#include "nsIExternalSharingAppService.h"
|
||||
|
||||
class nsAndroidHandlerApp : public nsISharingHandlerApp {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHANDLERAPP
|
||||
NS_DECL_NSISHARINGHANDLERAPP
|
||||
|
||||
nsAndroidHandlerApp(const nsAString& aName, const nsAString& aDescription,
|
||||
const nsAString& aPackageName,
|
||||
const nsAString& aClassName,
|
||||
const nsACString& aMimeType, const nsAString& aAction);
|
||||
|
||||
private:
|
||||
virtual ~nsAndroidHandlerApp();
|
||||
|
||||
nsString mName;
|
||||
nsString mDescription;
|
||||
nsString mPackageName;
|
||||
nsString mClassName;
|
||||
nsCString mMimeType;
|
||||
nsString mAction;
|
||||
};
|
||||
#endif
|
||||
61
uriloader/exthandler/android/nsExternalSharingAppService.cpp
Normal file
61
uriloader/exthandler/android/nsExternalSharingAppService.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* 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 "nsExternalSharingAppService.h"
|
||||
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
|
||||
#include "AndroidBridge.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsExternalSharingAppService, nsIExternalSharingAppService)
|
||||
|
||||
nsExternalSharingAppService::nsExternalSharingAppService()
|
||||
{
|
||||
}
|
||||
|
||||
nsExternalSharingAppService::~nsExternalSharingAppService()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExternalSharingAppService::ShareWithDefault(const nsAString & data,
|
||||
const nsAString & mime,
|
||||
const nsAString & title)
|
||||
{
|
||||
NS_NAMED_LITERAL_STRING(sendAction, "android.intent.action.SEND");
|
||||
const nsString emptyString = EmptyString();
|
||||
return java::GeckoAppShell::OpenUriExternal(data,
|
||||
mime, emptyString, emptyString, sendAction, title) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExternalSharingAppService::GetSharingApps(const nsAString & aMIMEType,
|
||||
uint32_t *aLen,
|
||||
nsISharingHandlerApp ***aHandlers)
|
||||
{
|
||||
nsresult rv;
|
||||
NS_NAMED_LITERAL_STRING(sendAction, "android.intent.action.SEND");
|
||||
nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!AndroidBridge::Bridge())
|
||||
return NS_OK;
|
||||
AndroidBridge::Bridge()->GetHandlersForMimeType(aMIMEType, array,
|
||||
nullptr, sendAction);
|
||||
array->GetLength(aLen);
|
||||
*aHandlers =
|
||||
static_cast<nsISharingHandlerApp**>(moz_xmalloc(sizeof(nsISharingHandlerApp*)
|
||||
* *aLen));
|
||||
for (uint32_t i = 0; i < *aLen; i++) {
|
||||
rv = array->QueryElementAt(i, NS_GET_IID(nsISharingHandlerApp),
|
||||
(void**)(*aHandlers + i));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
28
uriloader/exthandler/android/nsExternalSharingAppService.h
Normal file
28
uriloader/exthandler/android/nsExternalSharingAppService.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* 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 NS_EXTERNAL_SHARING_APP_SERVICE_H
|
||||
#define NS_EXTERNAL_SHARING_APP_SERVICE_H
|
||||
#include "nsIExternalSharingAppService.h"
|
||||
|
||||
|
||||
#define NS_EXTERNALSHARINGAPPSERVICE_CID \
|
||||
{0x93e2c46e, 0x0011, 0x434b, \
|
||||
{0x81, 0x2e, 0xb6, 0xf3, 0xa8, 0x1e, 0x2a, 0x58}}
|
||||
|
||||
class nsExternalSharingAppService final
|
||||
: public nsIExternalSharingAppService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIEXTERNALSHARINGAPPSERVICE
|
||||
|
||||
nsExternalSharingAppService();
|
||||
|
||||
private:
|
||||
~nsExternalSharingAppService();
|
||||
|
||||
};
|
||||
|
||||
#endif /*NS_EXTERNAL_SHARING_APP_SERVICE_H */
|
||||
27
uriloader/exthandler/android/nsExternalURLHandlerService.cpp
Normal file
27
uriloader/exthandler/android/nsExternalURLHandlerService.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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 "nsExternalURLHandlerService.h"
|
||||
#include "nsMIMEInfoAndroid.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsExternalURLHandlerService, nsIExternalURLHandlerService)
|
||||
|
||||
nsExternalURLHandlerService::nsExternalURLHandlerService()
|
||||
{
|
||||
}
|
||||
|
||||
nsExternalURLHandlerService::~nsExternalURLHandlerService()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExternalURLHandlerService::GetURLHandlerInfoFromOS(nsIURI *aURL,
|
||||
bool *found,
|
||||
nsIHandlerInfo **info)
|
||||
{
|
||||
nsCString uriSpec;
|
||||
aURL->GetSpec(uriSpec);
|
||||
return nsMIMEInfoAndroid::GetMimeInfoForURL(uriSpec, found, info);
|
||||
}
|
||||
27
uriloader/exthandler/android/nsExternalURLHandlerService.h
Normal file
27
uriloader/exthandler/android/nsExternalURLHandlerService.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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 NSEXTERNALURLHANDLERSERVICE_H
|
||||
#define NSEXTERNALURLHANDLERSERVICE_H
|
||||
|
||||
#include "nsIExternalURLHandlerService.h"
|
||||
|
||||
// {4BF1F8EF-D947-4BA3-9CD3-8C9A54A63A1C}
|
||||
#define NS_EXTERNALURLHANDLERSERVICE_CID \
|
||||
{0x4bf1f8ef, 0xd947, 0x4ba3, {0x9c, 0xd3, 0x8c, 0x9a, 0x54, 0xa6, 0x3a, 0x1c}}
|
||||
|
||||
class nsExternalURLHandlerService final
|
||||
: public nsIExternalURLHandlerService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIEXTERNALURLHANDLERSERVICE
|
||||
|
||||
nsExternalURLHandlerService();
|
||||
private:
|
||||
~nsExternalURLHandlerService();
|
||||
};
|
||||
|
||||
#endif // NSEXTERNALURLHANDLERSERVICE_H
|
||||
427
uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
Normal file
427
uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
Normal file
|
|
@ -0,0 +1,427 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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 "nsMIMEInfoAndroid.h"
|
||||
#include "AndroidBridge.h"
|
||||
#include "nsAndroidHandlerApp.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsStringEnumerator.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid, nsIMIMEInfo, nsIHandlerInfo)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::LaunchDefaultWithFile(nsIFile* aFile)
|
||||
{
|
||||
return LaunchWithFile(aFile);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::LoadUriInternal(nsIURI * aURI)
|
||||
{
|
||||
nsCString uriSpec;
|
||||
aURI->GetSpec(uriSpec);
|
||||
|
||||
nsCString uriScheme;
|
||||
aURI->GetScheme(uriScheme);
|
||||
|
||||
nsAutoString mimeType;
|
||||
if (mType.Equals(uriScheme) || mType.Equals(uriSpec)) {
|
||||
mimeType = EmptyString();
|
||||
} else {
|
||||
mimeType = NS_ConvertUTF8toUTF16(mType);
|
||||
}
|
||||
|
||||
if (java::GeckoAppShell::OpenUriExternal(
|
||||
NS_ConvertUTF8toUTF16(uriSpec), mimeType, EmptyString(),
|
||||
EmptyString(), EmptyString(), EmptyString())) {
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool
|
||||
nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType,
|
||||
nsMIMEInfoAndroid** aMimeInfo)
|
||||
{
|
||||
RefPtr<nsMIMEInfoAndroid> info = new nsMIMEInfoAndroid(aMimeType);
|
||||
mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
|
||||
// we don't have access to the bridge, so just assume we can handle
|
||||
// the mime type for now and let the system deal with it
|
||||
if (!bridge){
|
||||
info.forget(aMimeInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIHandlerApp* systemDefault = nullptr;
|
||||
|
||||
if (!IsUTF8(aMimeType, true))
|
||||
return false;
|
||||
|
||||
NS_ConvertUTF8toUTF16 mimeType(aMimeType);
|
||||
|
||||
bridge->GetHandlersForMimeType(mimeType,
|
||||
info->mHandlerApps, &systemDefault);
|
||||
|
||||
if (systemDefault)
|
||||
info->mPrefApp = systemDefault;
|
||||
|
||||
nsAutoCString fileExt;
|
||||
bridge->GetExtensionFromMimeType(aMimeType, fileExt);
|
||||
info->SetPrimaryExtension(fileExt);
|
||||
|
||||
uint32_t len;
|
||||
info->mHandlerApps->GetLength(&len);
|
||||
if (len == 1) {
|
||||
info.forget(aMimeInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
info.forget(aMimeInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsMIMEInfoAndroid::GetMimeInfoForFileExt(const nsACString& aFileExt,
|
||||
nsMIMEInfoAndroid **aMimeInfo)
|
||||
{
|
||||
nsCString mimeType;
|
||||
if (mozilla::AndroidBridge::Bridge())
|
||||
mozilla::AndroidBridge::Bridge()->
|
||||
GetMimeTypeFromExtensions(aFileExt, mimeType);
|
||||
|
||||
// "*/*" means that the bridge didn't know.
|
||||
if (mimeType.Equals(nsDependentCString("*/*"), nsCaseInsensitiveCStringComparator()))
|
||||
return false;
|
||||
|
||||
bool found = GetMimeInfoForMimeType(mimeType, aMimeInfo);
|
||||
(*aMimeInfo)->SetPrimaryExtension(aFileExt);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns MIME info for the aURL, which may contain the whole URL or only a protocol
|
||||
*/
|
||||
nsresult
|
||||
nsMIMEInfoAndroid::GetMimeInfoForURL(const nsACString &aURL,
|
||||
bool *found,
|
||||
nsIHandlerInfo **info)
|
||||
{
|
||||
nsMIMEInfoAndroid *mimeinfo = new nsMIMEInfoAndroid(aURL);
|
||||
NS_ADDREF(*info = mimeinfo);
|
||||
*found = true;
|
||||
|
||||
mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
|
||||
if (!bridge) {
|
||||
// we don't have access to the bridge, so just assume we can handle
|
||||
// the protocol for now and let the system deal with it
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIHandlerApp* systemDefault = nullptr;
|
||||
bridge->GetHandlersForURL(NS_ConvertUTF8toUTF16(aURL),
|
||||
mimeinfo->mHandlerApps, &systemDefault);
|
||||
|
||||
if (systemDefault)
|
||||
mimeinfo->mPrefApp = systemDefault;
|
||||
|
||||
|
||||
nsAutoCString fileExt;
|
||||
nsAutoCString mimeType;
|
||||
mimeinfo->GetType(mimeType);
|
||||
bridge->GetExtensionFromMimeType(mimeType, fileExt);
|
||||
mimeinfo->SetPrimaryExtension(fileExt);
|
||||
|
||||
uint32_t len;
|
||||
mimeinfo->mHandlerApps->GetLength(&len);
|
||||
if (len == 1) {
|
||||
// Code that calls this requires an object regardless if the OS has
|
||||
// something for us, so we return the empty object.
|
||||
*found = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetType(nsACString& aType)
|
||||
{
|
||||
aType.Assign(mType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetDescription(nsAString& aDesc)
|
||||
{
|
||||
aDesc.Assign(mDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::SetDescription(const nsAString& aDesc)
|
||||
{
|
||||
mDescription.Assign(aDesc);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetPreferredApplicationHandler(nsIHandlerApp** aApp)
|
||||
{
|
||||
*aApp = mPrefApp;
|
||||
NS_IF_ADDREF(*aApp);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::SetPreferredApplicationHandler(nsIHandlerApp* aApp)
|
||||
{
|
||||
mPrefApp = aApp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetPossibleApplicationHandlers(nsIMutableArray **aHandlerApps)
|
||||
{
|
||||
if (!mHandlerApps)
|
||||
mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||
|
||||
if (!mHandlerApps)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
*aHandlerApps = mHandlerApps;
|
||||
NS_IF_ADDREF(*aHandlerApps);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetHasDefaultHandler(bool* aHasDefault)
|
||||
{
|
||||
uint32_t len;
|
||||
*aHasDefault = false;
|
||||
if (!mHandlerApps)
|
||||
return NS_OK;
|
||||
|
||||
if (NS_FAILED(mHandlerApps->GetLength(&len)))
|
||||
return NS_OK;
|
||||
|
||||
if (len == 0)
|
||||
return NS_OK;
|
||||
|
||||
*aHasDefault = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetDefaultDescription(nsAString& aDesc)
|
||||
{
|
||||
aDesc.Assign(EmptyString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor* req)
|
||||
{
|
||||
return mPrefApp->LaunchWithURI(aURI, req);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetPreferredAction(nsHandlerInfoAction* aPrefAction)
|
||||
{
|
||||
*aPrefAction = mPrefAction;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::SetPreferredAction(nsHandlerInfoAction aPrefAction)
|
||||
{
|
||||
mPrefAction = aPrefAction;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetAlwaysAskBeforeHandling(bool* aAlwaysAsk)
|
||||
{
|
||||
*aAlwaysAsk = mAlwaysAsk;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::SetAlwaysAskBeforeHandling(bool aAlwaysAsk)
|
||||
{
|
||||
mAlwaysAsk = aAlwaysAsk;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetFileExtensions(nsIUTF8StringEnumerator** aResult)
|
||||
{
|
||||
return NS_NewUTF8StringEnumerator(aResult, &mExtensions, this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::SetFileExtensions(const nsACString & aExtensions)
|
||||
{
|
||||
mExtensions.Clear();
|
||||
nsCString extList(aExtensions);
|
||||
|
||||
int32_t breakLocation = -1;
|
||||
while ( (breakLocation = extList.FindChar(',')) != -1)
|
||||
{
|
||||
mExtensions.AppendElement(Substring(extList.get(), extList.get() + breakLocation));
|
||||
extList.Cut(0, breakLocation + 1);
|
||||
}
|
||||
if (!extList.IsEmpty())
|
||||
mExtensions.AppendElement(extList);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::ExtensionExists(const nsACString & aExtension, bool *aRetVal)
|
||||
{
|
||||
NS_ASSERTION(!aExtension.IsEmpty(), "no extension");
|
||||
|
||||
nsCString mimeType;
|
||||
if (mozilla::AndroidBridge::Bridge()) {
|
||||
mozilla::AndroidBridge::Bridge()->
|
||||
GetMimeTypeFromExtensions(aExtension, mimeType);
|
||||
}
|
||||
|
||||
// "*/*" means the bridge didn't find anything (i.e., extension doesn't exist).
|
||||
*aRetVal = !mimeType.Equals(nsDependentCString("*/*"), nsCaseInsensitiveCStringComparator());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::AppendExtension(const nsACString & aExtension)
|
||||
{
|
||||
mExtensions.AppendElement(aExtension);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetPrimaryExtension(nsACString & aPrimaryExtension)
|
||||
{
|
||||
if (!mExtensions.Length())
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
aPrimaryExtension = mExtensions[0];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::SetPrimaryExtension(const nsACString & aExtension)
|
||||
{
|
||||
uint32_t extCount = mExtensions.Length();
|
||||
uint8_t i;
|
||||
bool found = false;
|
||||
for (i=0; i < extCount; i++) {
|
||||
const nsCString& ext = mExtensions[i];
|
||||
if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
mExtensions.RemoveElementAt(i);
|
||||
}
|
||||
|
||||
mExtensions.InsertElementAt(0, aExtension);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetMIMEType(nsACString & aMIMEType)
|
||||
{
|
||||
aMIMEType.Assign(mType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::Equals(nsIMIMEInfo *aMIMEInfo, bool *aRetVal)
|
||||
{
|
||||
if (!aMIMEInfo) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsAutoCString type;
|
||||
nsresult rv = aMIMEInfo->GetMIMEType(type);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
*aRetVal = mType.Equals(type);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::GetPossibleLocalHandlers(nsIArray * *aPossibleLocalHandlers)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::LaunchWithFile(nsIFile *aFile)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
NS_NewFileURI(getter_AddRefs(uri), aFile);
|
||||
return LoadUriInternal(uri);
|
||||
}
|
||||
|
||||
nsMIMEInfoAndroid::nsMIMEInfoAndroid(const nsACString& aMIMEType) :
|
||||
mType(aMIMEType), mAlwaysAsk(true),
|
||||
mPrefAction(nsIMIMEInfo::useHelperApp)
|
||||
{
|
||||
mPrefApp = new nsMIMEInfoAndroid::SystemChooser(this);
|
||||
nsresult rv;
|
||||
mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
|
||||
mHandlerApps->AppendElement(mPrefApp, false);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid::SystemChooser, nsIHandlerApp)
|
||||
|
||||
|
||||
nsresult nsMIMEInfoAndroid::SystemChooser::GetName(nsAString & aName) {
|
||||
aName.AssignLiteral(u"Android chooser");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMIMEInfoAndroid::SystemChooser::SetName(const nsAString&) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMIMEInfoAndroid::SystemChooser::GetDetailedDescription(nsAString & aDesc) {
|
||||
aDesc.AssignLiteral(u"Android's default handler application chooser");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMIMEInfoAndroid::SystemChooser::SetDetailedDescription(const nsAString&) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXX Workaround for bug 986975 to maintain the existing broken semantics
|
||||
template<>
|
||||
struct nsIHandlerApp::COMTypeInfo<nsMIMEInfoAndroid::SystemChooser, void> {
|
||||
static const nsIID kIID;
|
||||
};
|
||||
const nsIID nsIHandlerApp::COMTypeInfo<nsMIMEInfoAndroid::SystemChooser, void>::kIID = NS_IHANDLERAPP_IID;
|
||||
|
||||
nsresult
|
||||
nsMIMEInfoAndroid::SystemChooser::Equals(nsIHandlerApp *aHandlerApp, bool *aRetVal) {
|
||||
nsCOMPtr<nsMIMEInfoAndroid::SystemChooser> info = do_QueryInterface(aHandlerApp);
|
||||
if (info)
|
||||
return mOuter->Equals(info->mOuter, aRetVal);
|
||||
*aRetVal = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMIMEInfoAndroid::SystemChooser::LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor*)
|
||||
{
|
||||
return mOuter->LoadUriInternal(aURI);
|
||||
}
|
||||
60
uriloader/exthandler/android/nsMIMEInfoAndroid.h
Normal file
60
uriloader/exthandler/android/nsMIMEInfoAndroid.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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 nsMIMEInfoAndroid_h
|
||||
#define nsMIMEInfoAndroid_h
|
||||
|
||||
#include "nsMIMEInfoImpl.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsAndroidHandlerApp.h"
|
||||
|
||||
class nsMIMEInfoAndroid final : public nsIMIMEInfo
|
||||
{
|
||||
public:
|
||||
static MOZ_MUST_USE bool
|
||||
GetMimeInfoForMimeType(const nsACString& aMimeType,
|
||||
nsMIMEInfoAndroid** aMimeInfo);
|
||||
static MOZ_MUST_USE bool
|
||||
GetMimeInfoForFileExt(const nsACString& aFileExt,
|
||||
nsMIMEInfoAndroid** aMimeInfo);
|
||||
|
||||
static MOZ_MUST_USE nsresult
|
||||
GetMimeInfoForURL(const nsACString &aURL, bool *found,
|
||||
nsIHandlerInfo **info);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMIMEINFO
|
||||
NS_DECL_NSIHANDLERINFO
|
||||
|
||||
nsMIMEInfoAndroid(const nsACString& aMIMEType);
|
||||
|
||||
private:
|
||||
~nsMIMEInfoAndroid() {}
|
||||
|
||||
virtual MOZ_MUST_USE nsresult LaunchDefaultWithFile(nsIFile* aFile);
|
||||
virtual MOZ_MUST_USE nsresult LoadUriInternal(nsIURI *aURI);
|
||||
nsCOMPtr<nsIMutableArray> mHandlerApps;
|
||||
nsCString mType;
|
||||
nsTArray<nsCString> mExtensions;
|
||||
bool mAlwaysAsk;
|
||||
nsHandlerInfoAction mPrefAction;
|
||||
nsString mDescription;
|
||||
nsCOMPtr<nsIHandlerApp> mPrefApp;
|
||||
|
||||
public:
|
||||
class SystemChooser final : public nsIHandlerApp {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHANDLERAPP
|
||||
SystemChooser(nsMIMEInfoAndroid* aOuter): mOuter(aOuter) {}
|
||||
|
||||
private:
|
||||
~SystemChooser() {}
|
||||
|
||||
nsMIMEInfoAndroid* mOuter;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* nsMIMEInfoAndroid_h */
|
||||
67
uriloader/exthandler/android/nsOSHelperAppService.cpp
Normal file
67
uriloader/exthandler/android/nsOSHelperAppService.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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 "nsOSHelperAppService.h"
|
||||
#include "nsMIMEInfoAndroid.h"
|
||||
#include "AndroidBridge.h"
|
||||
|
||||
nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService()
|
||||
{
|
||||
}
|
||||
|
||||
nsOSHelperAppService::~nsOSHelperAppService()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<nsIMIMEInfo>
|
||||
nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt,
|
||||
bool* aFound)
|
||||
{
|
||||
RefPtr<nsMIMEInfoAndroid> mimeInfo;
|
||||
*aFound = false;
|
||||
if (!aMIMEType.IsEmpty())
|
||||
*aFound =
|
||||
nsMIMEInfoAndroid::GetMimeInfoForMimeType(aMIMEType,
|
||||
getter_AddRefs(mimeInfo));
|
||||
if (!*aFound)
|
||||
*aFound =
|
||||
nsMIMEInfoAndroid::GetMimeInfoForFileExt(aFileExt,
|
||||
getter_AddRefs(mimeInfo));
|
||||
|
||||
// Code that calls this requires an object regardless if the OS has
|
||||
// something for us, so we return the empty object.
|
||||
if (!*aFound)
|
||||
mimeInfo = new nsMIMEInfoAndroid(aMIMEType);
|
||||
|
||||
return mimeInfo.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsOSHelperAppService::OSProtocolHandlerExists(const char* aScheme,
|
||||
bool* aExists)
|
||||
{
|
||||
*aExists = mozilla::AndroidBridge::Bridge()->GetHandlersForURL(NS_ConvertUTF8toUTF16(aScheme));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString &aScheme,
|
||||
bool *found,
|
||||
nsIHandlerInfo **info)
|
||||
{
|
||||
return nsMIMEInfoAndroid::GetMimeInfoForURL(aScheme, found, info);
|
||||
}
|
||||
|
||||
nsIHandlerApp*
|
||||
nsOSHelperAppService::CreateAndroidHandlerApp(const nsAString& aName,
|
||||
const nsAString& aDescription,
|
||||
const nsAString& aPackageName,
|
||||
const nsAString& aClassName,
|
||||
const nsACString& aMimeType,
|
||||
const nsAString& aAction)
|
||||
{
|
||||
return new nsAndroidHandlerApp(aName, aDescription, aPackageName,
|
||||
aClassName, aMimeType, aAction);
|
||||
}
|
||||
40
uriloader/exthandler/android/nsOSHelperAppService.h
Normal file
40
uriloader/exthandler/android/nsOSHelperAppService.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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 nsOSHelperAppService_h
|
||||
#define nsOSHelperAppService_h
|
||||
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsExternalHelperAppService.h"
|
||||
|
||||
class nsOSHelperAppService : public nsExternalHelperAppService
|
||||
{
|
||||
public:
|
||||
nsOSHelperAppService();
|
||||
virtual ~nsOSHelperAppService();
|
||||
|
||||
virtual already_AddRefed<nsIMIMEInfo>
|
||||
GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt,
|
||||
bool* aFound);
|
||||
|
||||
virtual MOZ_MUST_USE nsresult
|
||||
OSProtocolHandlerExists(const char* aScheme,
|
||||
bool* aExists);
|
||||
|
||||
NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString &aScheme,
|
||||
bool *found,
|
||||
nsIHandlerInfo **_retval);
|
||||
|
||||
static nsIHandlerApp*
|
||||
CreateAndroidHandlerApp(const nsAString& aName,
|
||||
const nsAString& aDescription,
|
||||
const nsAString& aPackageName,
|
||||
const nsAString& aClassName,
|
||||
const nsACString& aMimeType,
|
||||
const nsAString& aAction = EmptyString());
|
||||
};
|
||||
|
||||
#endif /* nsOSHelperAppService_h */
|
||||
56
uriloader/exthandler/gonk/nsOSHelperAppService.cpp
Normal file
56
uriloader/exthandler/gonk/nsOSHelperAppService.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */
|
||||
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nsOSHelperAppService.h"
|
||||
#include "nsMIMEInfoImpl.h"
|
||||
|
||||
class nsGonkMIMEInfo : public nsMIMEInfoImpl {
|
||||
public:
|
||||
nsGonkMIMEInfo(const nsACString& aMIMEType) : nsMIMEInfoImpl(aMIMEType) { }
|
||||
|
||||
protected:
|
||||
virtual nsresult LoadUriInternal(nsIURI *aURI) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
};
|
||||
|
||||
nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService()
|
||||
{
|
||||
}
|
||||
|
||||
nsOSHelperAppService::~nsOSHelperAppService()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<nsIMIMEInfo>
|
||||
nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt,
|
||||
bool* aFound)
|
||||
{
|
||||
*aFound = false;
|
||||
// Even if we return false for aFound, we need to return a working
|
||||
// nsIMIMEInfo implementation that will be used by the caller.
|
||||
RefPtr<nsGonkMIMEInfo> mimeInfo = new nsGonkMIMEInfo(aMIMEType);
|
||||
return mimeInfo.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsOSHelperAppService::OSProtocolHandlerExists(const char* aScheme,
|
||||
bool* aExists)
|
||||
{
|
||||
*aExists = false;
|
||||
return NS_OK;
|
||||
}
|
||||
39
uriloader/exthandler/gonk/nsOSHelperAppService.h
Normal file
39
uriloader/exthandler/gonk/nsOSHelperAppService.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */
|
||||
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef nsOSHelperAppService_h
|
||||
#define nsOSHelperAppService_h
|
||||
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsExternalHelperAppService.h"
|
||||
|
||||
class nsOSHelperAppService : public nsExternalHelperAppService
|
||||
{
|
||||
public:
|
||||
nsOSHelperAppService();
|
||||
virtual ~nsOSHelperAppService();
|
||||
|
||||
virtual already_AddRefed<nsIMIMEInfo>
|
||||
GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt,
|
||||
bool* aFound);
|
||||
|
||||
virtual MOZ_MUST_USE nsresult
|
||||
OSProtocolHandlerExists(const char* aScheme,
|
||||
bool* aExists);
|
||||
};
|
||||
|
||||
#endif /* nsOSHelperAppService_h */
|
||||
389
uriloader/exthandler/mac/nsDecodeAppleFile.cpp
Normal file
389
uriloader/exthandler/mac/nsDecodeAppleFile.cpp
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
/* -*- 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
|
||||
* 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 "nsDecodeAppleFile.h"
|
||||
#include "prmem.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
|
||||
NS_IMPL_ADDREF(nsDecodeAppleFile)
|
||||
NS_IMPL_RELEASE(nsDecodeAppleFile)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDecodeAppleFile)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIOutputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
|
||||
NS_INTERFACE_MAP_END_THREADSAFE
|
||||
|
||||
nsDecodeAppleFile::nsDecodeAppleFile()
|
||||
{
|
||||
m_state = parseHeaders;
|
||||
m_dataBufferLength = 0;
|
||||
m_dataBuffer = (unsigned char*) PR_MALLOC(MAX_BUFFERSIZE);
|
||||
m_entries = nullptr;
|
||||
m_rfRefNum = -1;
|
||||
m_totalDataForkWritten = 0;
|
||||
m_totalResourceForkWritten = 0;
|
||||
m_headerOk = false;
|
||||
|
||||
m_comment[0] = 0;
|
||||
memset(&m_dates, 0, sizeof(m_dates));
|
||||
memset(&m_finderInfo, 0, sizeof(m_dates));
|
||||
memset(&m_finderExtraInfo, 0, sizeof(m_dates));
|
||||
}
|
||||
|
||||
nsDecodeAppleFile::~nsDecodeAppleFile()
|
||||
{
|
||||
|
||||
PR_FREEIF(m_dataBuffer);
|
||||
if (m_entries)
|
||||
delete [] m_entries;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDecodeAppleFile::Initialize(nsIOutputStream *output, nsIFile *file)
|
||||
{
|
||||
m_output = output;
|
||||
|
||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(file);
|
||||
macFile->GetTargetFSSpec(&m_fsFileSpec);
|
||||
|
||||
m_offset = 0;
|
||||
m_dataForkOffset = 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDecodeAppleFile::Close(void)
|
||||
{
|
||||
nsresult rv;
|
||||
rv = m_output->Close();
|
||||
|
||||
int32_t i;
|
||||
|
||||
if (m_rfRefNum != -1)
|
||||
FSClose(m_rfRefNum);
|
||||
|
||||
/* Check if the file is complete and if it's the case, write file attributes */
|
||||
if (m_headerOk)
|
||||
{
|
||||
bool dataOk = true; /* It's ok if the file doesn't have a datafork, therefore set it to true by default. */
|
||||
if (m_headers.magic == APPLESINGLE_MAGIC)
|
||||
{
|
||||
for (i = 0; i < m_headers.entriesCount; i ++)
|
||||
if (ENT_DFORK == m_entries[i].id)
|
||||
{
|
||||
dataOk = (bool)(m_totalDataForkWritten == m_entries[i].length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool resourceOk = FALSE;
|
||||
for (i = 0; i < m_headers.entriesCount; i ++)
|
||||
if (ENT_RFORK == m_entries[i].id)
|
||||
{
|
||||
resourceOk = (bool)(m_totalResourceForkWritten == m_entries[i].length);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dataOk && resourceOk)
|
||||
{
|
||||
HFileInfo *fpb;
|
||||
CInfoPBRec cipbr;
|
||||
|
||||
fpb = (HFileInfo *) &cipbr;
|
||||
fpb->ioVRefNum = m_fsFileSpec.vRefNum;
|
||||
fpb->ioDirID = m_fsFileSpec.parID;
|
||||
fpb->ioNamePtr = m_fsFileSpec.name;
|
||||
fpb->ioFDirIndex = 0;
|
||||
PBGetCatInfoSync(&cipbr);
|
||||
|
||||
/* set finder info */
|
||||
memcpy(&fpb->ioFlFndrInfo, &m_finderInfo, sizeof (FInfo));
|
||||
memcpy(&fpb->ioFlXFndrInfo, &m_finderExtraInfo, sizeof (FXInfo));
|
||||
fpb->ioFlFndrInfo.fdFlags &= 0xfc00; /* clear flags maintained by finder */
|
||||
|
||||
/* set file dates */
|
||||
fpb->ioFlCrDat = m_dates.create - CONVERT_TIME;
|
||||
fpb->ioFlMdDat = m_dates.modify - CONVERT_TIME;
|
||||
fpb->ioFlBkDat = m_dates.backup - CONVERT_TIME;
|
||||
|
||||
/* update file info */
|
||||
fpb->ioDirID = fpb->ioFlParID;
|
||||
PBSetCatInfoSync(&cipbr);
|
||||
|
||||
/* set comment */
|
||||
IOParam vinfo;
|
||||
GetVolParmsInfoBuffer vp;
|
||||
DTPBRec dtp;
|
||||
|
||||
memset((void *) &vinfo, 0, sizeof (vinfo));
|
||||
vinfo.ioVRefNum = fpb->ioVRefNum;
|
||||
vinfo.ioBuffer = (Ptr) &vp;
|
||||
vinfo.ioReqCount = sizeof (vp);
|
||||
if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr && ((vp.vMAttrib >> bHasDesktopMgr) & 1))
|
||||
{
|
||||
memset((void *) &dtp, 0, sizeof (dtp));
|
||||
dtp.ioVRefNum = fpb->ioVRefNum;
|
||||
if (PBDTGetPath(&dtp) == noErr)
|
||||
{
|
||||
dtp.ioDTBuffer = (Ptr) &m_comment[1];
|
||||
dtp.ioNamePtr = fpb->ioNamePtr;
|
||||
dtp.ioDirID = fpb->ioDirID;
|
||||
dtp.ioDTReqCount = m_comment[0];
|
||||
if (PBDTSetCommentSync(&dtp) == noErr)
|
||||
PBDTFlushSync(&dtp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDecodeAppleFile::Flush(void)
|
||||
{
|
||||
return m_output->Flush();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDecodeAppleFile::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
return m_output->WriteFrom(inStr, count, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDecodeAppleFile::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
return m_output->WriteSegments(reader, closure, count, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDecodeAppleFile::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
return m_output->IsNonBlocking(aNonBlocking);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDecodeAppleFile::Write(const char *buffer, uint32_t bufferSize, uint32_t* writeCount)
|
||||
{
|
||||
/* WARNING: to simplify my life, I presume that I should get all appledouble headers in the first block,
|
||||
else I would have to implement a buffer */
|
||||
|
||||
const char * buffPtr = buffer;
|
||||
uint32_t dataCount;
|
||||
int32_t i;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
*writeCount = 0;
|
||||
|
||||
while (bufferSize > 0 && NS_SUCCEEDED(rv))
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case parseHeaders :
|
||||
dataCount = sizeof(ap_header) - m_dataBufferLength;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
|
||||
m_dataBufferLength += dataCount;
|
||||
|
||||
if (m_dataBufferLength == sizeof(ap_header))
|
||||
{
|
||||
memcpy(&m_headers, m_dataBuffer, sizeof(ap_header));
|
||||
|
||||
/* Check header to be sure we are dealing with the right kind of data, else just write it to the data fork. */
|
||||
if ((m_headers.magic == APPLEDOUBLE_MAGIC || m_headers.magic == APPLESINGLE_MAGIC) &&
|
||||
m_headers.version == VERSION && m_headers.entriesCount)
|
||||
{
|
||||
/* Just to be sure, the filler must contains only 0 */
|
||||
for (i = 0; i < 4 && m_headers.fill[i] == 0L; i ++)
|
||||
;
|
||||
if (i == 4)
|
||||
m_state = parseEntries;
|
||||
}
|
||||
m_dataBufferLength = 0;
|
||||
|
||||
if (m_state == parseHeaders)
|
||||
{
|
||||
dataCount = 0;
|
||||
m_state = parseWriteThrough;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case parseEntries :
|
||||
if (!m_entries)
|
||||
{
|
||||
m_entries = new ap_entry[m_headers.entriesCount];
|
||||
if (!m_entries)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
uint32_t entriesSize = sizeof(ap_entry) * m_headers.entriesCount;
|
||||
dataCount = entriesSize - m_dataBufferLength;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
|
||||
m_dataBufferLength += dataCount;
|
||||
|
||||
if (m_dataBufferLength == entriesSize)
|
||||
{
|
||||
for (i = 0; i < m_headers.entriesCount; i ++)
|
||||
{
|
||||
memcpy(&m_entries[i], &m_dataBuffer[i * sizeof(ap_entry)], sizeof(ap_entry));
|
||||
if (m_headers.magic == APPLEDOUBLE_MAGIC)
|
||||
{
|
||||
uint32_t offset = m_entries[i].offset + m_entries[i].length;
|
||||
if (offset > m_dataForkOffset)
|
||||
m_dataForkOffset = offset;
|
||||
}
|
||||
}
|
||||
m_headerOk = true;
|
||||
m_state = parseLookupPart;
|
||||
}
|
||||
break;
|
||||
|
||||
case parseLookupPart :
|
||||
/* which part are we parsing? */
|
||||
m_currentPartID = -1;
|
||||
for (i = 0; i < m_headers.entriesCount; i ++)
|
||||
if (m_offset == m_entries[i].offset && m_entries[i].length)
|
||||
{
|
||||
m_currentPartID = m_entries[i].id;
|
||||
m_currentPartLength = m_entries[i].length;
|
||||
m_currentPartCount = 0;
|
||||
|
||||
switch (m_currentPartID)
|
||||
{
|
||||
case ENT_DFORK : m_state = parseDataFork; break;
|
||||
case ENT_RFORK : m_state = parseResourceFork; break;
|
||||
|
||||
case ENT_COMMENT :
|
||||
case ENT_DATES :
|
||||
case ENT_FINFO :
|
||||
m_dataBufferLength = 0;
|
||||
m_state = parsePart;
|
||||
break;
|
||||
|
||||
default : m_state = parseSkipPart; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_currentPartID == -1)
|
||||
{
|
||||
/* maybe is the datafork of an appledouble file? */
|
||||
if (m_offset == m_dataForkOffset)
|
||||
{
|
||||
m_currentPartID = ENT_DFORK;
|
||||
m_currentPartLength = -1;
|
||||
m_currentPartCount = 0;
|
||||
m_state = parseDataFork;
|
||||
}
|
||||
else
|
||||
dataCount = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case parsePart :
|
||||
dataCount = m_currentPartLength - m_dataBufferLength;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
|
||||
m_dataBufferLength += dataCount;
|
||||
|
||||
if (m_dataBufferLength == m_currentPartLength)
|
||||
{
|
||||
switch (m_currentPartID)
|
||||
{
|
||||
case ENT_COMMENT :
|
||||
m_comment[0] = m_currentPartLength > 255 ? 255 : m_currentPartLength;
|
||||
memcpy(&m_comment[1], buffPtr, m_comment[0]);
|
||||
break;
|
||||
case ENT_DATES :
|
||||
if (m_currentPartLength == sizeof(m_dates))
|
||||
memcpy(&m_dates, buffPtr, m_currentPartLength);
|
||||
break;
|
||||
case ENT_FINFO :
|
||||
if (m_currentPartLength == (sizeof(m_finderInfo) + sizeof(m_finderExtraInfo)))
|
||||
{
|
||||
memcpy(&m_finderInfo, buffPtr, sizeof(m_finderInfo));
|
||||
memcpy(&m_finderExtraInfo, buffPtr + sizeof(m_finderInfo), sizeof(m_finderExtraInfo));
|
||||
}
|
||||
break;
|
||||
}
|
||||
m_state = parseLookupPart;
|
||||
}
|
||||
break;
|
||||
|
||||
case parseSkipPart :
|
||||
dataCount = m_currentPartLength - m_currentPartCount;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
else
|
||||
m_state = parseLookupPart;
|
||||
break;
|
||||
|
||||
case parseDataFork :
|
||||
if (m_headers.magic == APPLEDOUBLE_MAGIC)
|
||||
dataCount = bufferSize;
|
||||
else
|
||||
{
|
||||
dataCount = m_currentPartLength - m_currentPartCount;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
else
|
||||
m_state = parseLookupPart;
|
||||
}
|
||||
|
||||
if (m_output)
|
||||
{
|
||||
uint32_t writeCount;
|
||||
rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount);
|
||||
if (dataCount != writeCount)
|
||||
rv = NS_ERROR_FAILURE;
|
||||
m_totalDataForkWritten += dataCount;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case parseResourceFork :
|
||||
dataCount = m_currentPartLength - m_currentPartCount;
|
||||
if (dataCount > bufferSize)
|
||||
dataCount = bufferSize;
|
||||
else
|
||||
m_state = parseLookupPart;
|
||||
|
||||
if (m_rfRefNum == -1)
|
||||
{
|
||||
if (noErr != FSpOpenRF(&m_fsFileSpec, fsWrPerm, &m_rfRefNum))
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
long count = dataCount;
|
||||
if (noErr != FSWrite(m_rfRefNum, &count, buffPtr) || count != dataCount)
|
||||
return NS_ERROR_FAILURE;
|
||||
m_totalResourceForkWritten += dataCount;
|
||||
break;
|
||||
|
||||
case parseWriteThrough :
|
||||
dataCount = bufferSize;
|
||||
if (m_output)
|
||||
{
|
||||
uint32_t writeCount;
|
||||
rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount);
|
||||
if (dataCount != writeCount)
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (dataCount)
|
||||
{
|
||||
*writeCount += dataCount;
|
||||
bufferSize -= dataCount;
|
||||
buffPtr += dataCount;
|
||||
m_currentPartCount += dataCount;
|
||||
m_offset += dataCount;
|
||||
dataCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
118
uriloader/exthandler/mac/nsDecodeAppleFile.h
Normal file
118
uriloader/exthandler/mac/nsDecodeAppleFile.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/* -*- 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
|
||||
* 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 nsDecodeAppleFile_h__
|
||||
#define nsDecodeAppleFile_h__
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
/*
|
||||
** applefile definitions used
|
||||
*/
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
|
||||
#define APPLESINGLE_MAGIC 0x00051600L
|
||||
#define APPLEDOUBLE_MAGIC 0x00051607L
|
||||
#define VERSION 0x00020000
|
||||
|
||||
#define NUM_ENTRIES 6
|
||||
|
||||
#define ENT_DFORK 1L
|
||||
#define ENT_RFORK 2L
|
||||
#define ENT_NAME 3L
|
||||
#define ENT_COMMENT 4L
|
||||
#define ENT_DATES 8L
|
||||
#define ENT_FINFO 9L
|
||||
|
||||
#define CONVERT_TIME 1265437696L
|
||||
|
||||
/*
|
||||
** data type used in the header decoder.
|
||||
*/
|
||||
typedef struct ap_header
|
||||
{
|
||||
int32_t magic;
|
||||
int32_t version;
|
||||
int32_t fill[4];
|
||||
int16_t entriesCount;
|
||||
|
||||
} ap_header;
|
||||
|
||||
typedef struct ap_entry
|
||||
{
|
||||
int32_t id;
|
||||
int32_t offset;
|
||||
int32_t length;
|
||||
|
||||
} ap_entry;
|
||||
|
||||
typedef struct ap_dates
|
||||
{
|
||||
int32_t create, modify, backup, access;
|
||||
|
||||
} ap_dates;
|
||||
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
|
||||
/*
|
||||
**Error codes
|
||||
*/
|
||||
enum {
|
||||
errADNotEnoughData = -12099,
|
||||
errADNotSupported,
|
||||
errADBadVersion
|
||||
};
|
||||
|
||||
|
||||
class nsDecodeAppleFile : public nsIOutputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
|
||||
nsDecodeAppleFile();
|
||||
virtual ~nsDecodeAppleFile();
|
||||
|
||||
MOZ_MUST_USE nsresult Initialize(nsIOutputStream *output, nsIFile *file);
|
||||
|
||||
private:
|
||||
#define MAX_BUFFERSIZE 1024
|
||||
enum ParserState {parseHeaders, parseEntries, parseLookupPart, parsePart, parseSkipPart,
|
||||
parseDataFork, parseResourceFork, parseWriteThrough};
|
||||
|
||||
nsCOMPtr<nsIOutputStream> m_output;
|
||||
FSSpec m_fsFileSpec;
|
||||
SInt16 m_rfRefNum;
|
||||
|
||||
unsigned char * m_dataBuffer;
|
||||
int32_t m_dataBufferLength;
|
||||
ParserState m_state;
|
||||
ap_header m_headers;
|
||||
ap_entry * m_entries;
|
||||
int32_t m_offset;
|
||||
int32_t m_dataForkOffset;
|
||||
int32_t m_totalDataForkWritten;
|
||||
int32_t m_totalResourceForkWritten;
|
||||
bool m_headerOk;
|
||||
|
||||
int32_t m_currentPartID;
|
||||
int32_t m_currentPartLength;
|
||||
int32_t m_currentPartCount;
|
||||
|
||||
Str255 m_comment;
|
||||
ap_dates m_dates;
|
||||
FInfo m_finderInfo;
|
||||
FXInfo m_finderExtraInfo;
|
||||
};
|
||||
|
||||
#endif
|
||||
26
uriloader/exthandler/mac/nsLocalHandlerAppMac.h
Normal file
26
uriloader/exthandler/mac/nsLocalHandlerAppMac.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* 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 NSLOCALHANDLERAPPMAC_H_
|
||||
#define NSLOCALHANDLERAPPMAC_H_
|
||||
|
||||
#include "nsLocalHandlerApp.h"
|
||||
|
||||
class nsLocalHandlerAppMac : public nsLocalHandlerApp {
|
||||
|
||||
public:
|
||||
nsLocalHandlerAppMac() { }
|
||||
|
||||
nsLocalHandlerAppMac(const char16_t *aName, nsIFile *aExecutable)
|
||||
: nsLocalHandlerApp(aName, aExecutable) {}
|
||||
|
||||
nsLocalHandlerAppMac(const nsAString & aName, nsIFile *aExecutable)
|
||||
: nsLocalHandlerApp(aName, aExecutable) {}
|
||||
virtual ~nsLocalHandlerAppMac() { }
|
||||
|
||||
NS_IMETHOD LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor* aWindowContext);
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
};
|
||||
|
||||
#endif /*NSLOCALHANDLERAPPMAC_H_*/
|
||||
84
uriloader/exthandler/mac/nsLocalHandlerAppMac.mm
Normal file
84
uriloader/exthandler/mac/nsLocalHandlerAppMac.mm
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/* 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/. */
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsLocalHandlerAppMac.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
// We override this to make sure app bundles display their pretty name (without .app suffix)
|
||||
NS_IMETHODIMP nsLocalHandlerAppMac::GetName(nsAString& aName)
|
||||
{
|
||||
if (mExecutable) {
|
||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(mExecutable);
|
||||
if (macFile) {
|
||||
bool isPackage;
|
||||
(void)macFile->IsPackage(&isPackage);
|
||||
if (isPackage)
|
||||
return macFile->GetBundleDisplayName(aName);
|
||||
}
|
||||
}
|
||||
|
||||
return nsLocalHandlerApp::GetName(aName);
|
||||
}
|
||||
|
||||
/**
|
||||
* mostly copy/pasted from nsMacShellService.cpp (which is in browser/,
|
||||
* so we can't depend on it here). This code probably really wants to live
|
||||
* somewhere more central (see bug 389922).
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerAppMac::LaunchWithURI(nsIURI *aURI,
|
||||
nsIInterfaceRequestor *aWindowContext)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILocalFileMac> lfm(do_QueryInterface(mExecutable, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
CFURLRef appURL;
|
||||
rv = lfm->GetCFURL(&appURL);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsAutoCString uriSpec;
|
||||
aURI->GetAsciiSpec(uriSpec);
|
||||
|
||||
const UInt8* uriString = reinterpret_cast<const UInt8*>(uriSpec.get());
|
||||
CFURLRef uri = ::CFURLCreateWithBytes(NULL, uriString, uriSpec.Length(),
|
||||
kCFStringEncodingUTF8, NULL);
|
||||
if (!uri) {
|
||||
::CFRelease(appURL);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
CFArrayRef uris = ::CFArrayCreate(NULL, reinterpret_cast<const void**>(&uri),
|
||||
1, NULL);
|
||||
if (!uris) {
|
||||
::CFRelease(uri);
|
||||
::CFRelease(appURL);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
LSLaunchURLSpec launchSpec;
|
||||
launchSpec.appURL = appURL;
|
||||
launchSpec.itemURLs = uris;
|
||||
launchSpec.passThruParams = NULL;
|
||||
launchSpec.launchFlags = kLSLaunchDefaults;
|
||||
launchSpec.asyncRefCon = NULL;
|
||||
|
||||
OSErr err = ::LSOpenFromURLSpec(&launchSpec, NULL);
|
||||
|
||||
::CFRelease(uris);
|
||||
::CFRelease(uri);
|
||||
::CFRelease(appURL);
|
||||
|
||||
return err != noErr ? NS_ERROR_FAILURE : NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
34
uriloader/exthandler/mac/nsMIMEInfoMac.h
Normal file
34
uriloader/exthandler/mac/nsMIMEInfoMac.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* 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 nsMIMEInfoMac_h_
|
||||
#define nsMIMEInfoMac_h_
|
||||
|
||||
#include "nsMIMEInfoImpl.h"
|
||||
|
||||
class nsMIMEInfoMac : public nsMIMEInfoImpl {
|
||||
public:
|
||||
explicit nsMIMEInfoMac(const char* aMIMEType = "") : nsMIMEInfoImpl(aMIMEType) {}
|
||||
explicit nsMIMEInfoMac(const nsACString& aMIMEType) : nsMIMEInfoImpl(aMIMEType) {}
|
||||
nsMIMEInfoMac(const nsACString& aType, HandlerClass aClass) :
|
||||
nsMIMEInfoImpl(aType, aClass) {}
|
||||
|
||||
NS_IMETHOD LaunchWithFile(nsIFile* aFile);
|
||||
protected:
|
||||
virtual MOZ_MUST_USE nsresult LoadUriInternal(nsIURI *aURI);
|
||||
#ifdef DEBUG
|
||||
virtual MOZ_MUST_USE nsresult LaunchDefaultWithFile(nsIFile* aFile) {
|
||||
NS_NOTREACHED("do not call this method, use LaunchWithFile");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
#endif
|
||||
static MOZ_MUST_USE nsresult OpenApplicationWithURI(nsIFile *aApplication,
|
||||
const nsCString& aURI);
|
||||
|
||||
NS_IMETHOD GetDefaultDescription(nsAString& aDefaultDescription);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
114
uriloader/exthandler/mac/nsMIMEInfoMac.mm
Normal file
114
uriloader/exthandler/mac/nsMIMEInfoMac.mm
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
#import <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsMIMEInfoMac.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
#include "nsIFileURL.h"
|
||||
|
||||
// We override this to make sure app bundles display their pretty name (without .app suffix)
|
||||
NS_IMETHODIMP nsMIMEInfoMac::GetDefaultDescription(nsAString& aDefaultDescription)
|
||||
{
|
||||
if (mDefaultApplication) {
|
||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(mDefaultApplication);
|
||||
if (macFile) {
|
||||
bool isPackage;
|
||||
(void)macFile->IsPackage(&isPackage);
|
||||
if (isPackage)
|
||||
return macFile->GetBundleDisplayName(aDefaultDescription);
|
||||
}
|
||||
}
|
||||
|
||||
return nsMIMEInfoImpl::GetDefaultDescription(aDefaultDescription);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoMac::LaunchWithFile(nsIFile *aFile)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsCOMPtr<nsIFile> application;
|
||||
nsresult rv;
|
||||
|
||||
NS_ASSERTION(mClass == eMIMEInfo, "only MIME infos are currently allowed"
|
||||
"to pass content by value");
|
||||
|
||||
if (mPreferredAction == useHelperApp) {
|
||||
|
||||
// we don't yet support passing content by value (rather than reference)
|
||||
// to web apps. at some point, we will probably want to.
|
||||
nsCOMPtr<nsILocalHandlerApp> localHandlerApp =
|
||||
do_QueryInterface(mPreferredApplication, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = localHandlerApp->GetExecutable(getter_AddRefs(application));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
} else if (mPreferredAction == useSystemDefault) {
|
||||
application = mDefaultApplication;
|
||||
}
|
||||
else
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
// if we've already got an app, just QI so we have the launchWithDoc method
|
||||
nsCOMPtr<nsILocalFileMac> app;
|
||||
if (application) {
|
||||
app = do_QueryInterface(application, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
} else {
|
||||
// otherwise ask LaunchServices for an app directly
|
||||
nsCOMPtr<nsILocalFileMac> tempFile = do_QueryInterface(aFile, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
FSRef tempFileRef;
|
||||
tempFile->GetFSRef(&tempFileRef);
|
||||
|
||||
FSRef appFSRef;
|
||||
if (::LSGetApplicationForItem(&tempFileRef, kLSRolesAll, &appFSRef, nullptr) == noErr)
|
||||
{
|
||||
app = (do_CreateInstance("@mozilla.org/file/local;1"));
|
||||
if (!app) return NS_ERROR_FAILURE;
|
||||
app->InitWithFSRef(&appFSRef);
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
return app->LaunchWithDoc(aFile, false);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMIMEInfoMac::LoadUriInternal(nsIURI *aURI)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoCString uri;
|
||||
aURI->GetSpec(uri);
|
||||
if (!uri.IsEmpty()) {
|
||||
CFURLRef myURLRef = ::CFURLCreateWithBytes(kCFAllocatorDefault,
|
||||
(const UInt8*)uri.get(),
|
||||
strlen(uri.get()),
|
||||
kCFStringEncodingUTF8,
|
||||
NULL);
|
||||
if (myURLRef) {
|
||||
OSStatus status = ::LSOpenCFURLRef(myURLRef, NULL);
|
||||
if (status == noErr)
|
||||
rv = NS_OK;
|
||||
::CFRelease(myURLRef);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
48
uriloader/exthandler/mac/nsOSHelperAppService.h
Normal file
48
uriloader/exthandler/mac/nsOSHelperAppService.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 nsOSHelperAppService_h__
|
||||
#define nsOSHelperAppService_h__
|
||||
|
||||
// The OS helper app service is a subclass of nsExternalHelperAppService and is implemented on each
|
||||
// platform. It contains platform specific code for finding helper applications for a given mime type
|
||||
// in addition to launching those applications. This is the Mac version.
|
||||
|
||||
#include "nsExternalHelperAppService.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsMIMEInfoImpl.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsOSHelperAppService : public nsExternalHelperAppService
|
||||
{
|
||||
public:
|
||||
nsOSHelperAppService();
|
||||
virtual ~nsOSHelperAppService();
|
||||
|
||||
// override nsIExternalProtocolService methods
|
||||
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme, nsAString& _retval);
|
||||
|
||||
// method overrides --> used to hook the mime service into internet config....
|
||||
NS_IMETHOD GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt, nsIMIMEInfo ** aMIMEInfo);
|
||||
already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType, const nsACString& aFileExt, bool * aFound);
|
||||
NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString &aScheme,
|
||||
bool *found,
|
||||
nsIHandlerInfo **_retval);
|
||||
|
||||
// GetFileTokenForPath must be implemented by each platform.
|
||||
// platformAppPath --> a platform specific path to an application that we got out of the
|
||||
// rdf data source. This can be a mac file spec, a unix path or a windows path depending on the platform
|
||||
// aFile --> an nsIFile representation of that platform application path.
|
||||
virtual MOZ_MUST_USE nsresult GetFileTokenForPath(const char16_t * platformAppPath, nsIFile ** aFile);
|
||||
|
||||
MOZ_MUST_USE nsresult OSProtocolHandlerExists(const char * aScheme,
|
||||
bool * aHandlerExists);
|
||||
|
||||
private:
|
||||
uint32_t mPermissions;
|
||||
};
|
||||
|
||||
#endif // nsOSHelperAppService_h__
|
||||
569
uriloader/exthandler/mac/nsOSHelperAppService.mm
Normal file
569
uriloader/exthandler/mac/nsOSHelperAppService.mm
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "nsOSHelperAppService.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIPromptService.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsMIMEInfoMac.h"
|
||||
#include "nsEmbedCID.h"
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
// chrome URL's
|
||||
#define HELPERAPPLAUNCHER_BUNDLE_URL "chrome://global/locale/helperAppLauncher.properties"
|
||||
#define BRAND_BUNDLE_URL "chrome://branding/locale/brand.properties"
|
||||
|
||||
using mozilla::LogLevel;
|
||||
|
||||
/* This is an undocumented interface (in the Foundation framework) that has
|
||||
* been stable since at least 10.2.8 and is still present on SnowLeopard.
|
||||
* Furthermore WebKit has three public methods (in WebKitSystemInterface.h)
|
||||
* that are thin wrappers around this interface's last three methods. So
|
||||
* it's unlikely to change anytime soon. Now that we're no longer using
|
||||
* Internet Config Services, this is the only way to look up a MIME type
|
||||
* from an extension, or vice versa.
|
||||
*/
|
||||
@class NSURLFileTypeMappingsInternal;
|
||||
|
||||
@interface NSURLFileTypeMappings : NSObject
|
||||
{
|
||||
NSURLFileTypeMappingsInternal *_internal;
|
||||
}
|
||||
|
||||
+ (NSURLFileTypeMappings*)sharedMappings;
|
||||
- (NSString*)MIMETypeForExtension:(NSString*)aString;
|
||||
- (NSString*)preferredExtensionForMIMEType:(NSString*)aString;
|
||||
- (NSArray*)extensionsForMIMEType:(NSString*)aString;
|
||||
@end
|
||||
|
||||
nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService()
|
||||
{
|
||||
mode_t mask = umask(0777);
|
||||
umask(mask);
|
||||
mPermissions = 0666 & ~mask;
|
||||
}
|
||||
|
||||
nsOSHelperAppService::~nsOSHelperAppService()
|
||||
{}
|
||||
|
||||
nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, bool * aHandlerExists)
|
||||
{
|
||||
// CFStringCreateWithBytes() can fail even if we're not out of memory --
|
||||
// for example if the 'bytes' parameter is something very wierd (like "ÿÿ~"
|
||||
// aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
|
||||
// specified in the 'encoding' parameter. See bug 548719.
|
||||
CFStringRef schemeString = ::CFStringCreateWithBytes(kCFAllocatorDefault,
|
||||
(const UInt8*)aProtocolScheme,
|
||||
strlen(aProtocolScheme),
|
||||
kCFStringEncodingUTF8,
|
||||
false);
|
||||
if (schemeString) {
|
||||
// LSCopyDefaultHandlerForURLScheme() can fail to find the default handler
|
||||
// for aProtocolScheme when it's never been explicitly set (using
|
||||
// LSSetDefaultHandlerForURLScheme()). For example, Safari is the default
|
||||
// handler for the "http" scheme on a newly installed copy of OS X. But
|
||||
// this (presumably) wasn't done using LSSetDefaultHandlerForURLScheme(),
|
||||
// so LSCopyDefaultHandlerForURLScheme() will fail to find Safari. To get
|
||||
// around this we use LSCopyAllHandlersForURLScheme() instead -- which seems
|
||||
// never to fail.
|
||||
// http://lists.apple.com/archives/Carbon-dev/2007/May/msg00349.html
|
||||
// http://www.realsoftware.com/listarchives/realbasic-nug/2008-02/msg00119.html
|
||||
CFArrayRef handlerArray = ::LSCopyAllHandlersForURLScheme(schemeString);
|
||||
*aHandlerExists = !!handlerArray;
|
||||
if (handlerArray)
|
||||
::CFRelease(handlerArray);
|
||||
::CFRelease(schemeString);
|
||||
} else {
|
||||
*aHandlerExists = false;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
CFStringRef schemeCFString =
|
||||
::CFStringCreateWithBytes(kCFAllocatorDefault,
|
||||
(const UInt8 *)PromiseFlatCString(aScheme).get(),
|
||||
aScheme.Length(),
|
||||
kCFStringEncodingUTF8,
|
||||
false);
|
||||
|
||||
if (schemeCFString) {
|
||||
CFStringRef lookupCFString = ::CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:"), schemeCFString);
|
||||
|
||||
if (lookupCFString) {
|
||||
CFURLRef lookupCFURL = ::CFURLCreateWithString(NULL, lookupCFString, NULL);
|
||||
|
||||
if (lookupCFURL) {
|
||||
CFURLRef appCFURL = NULL;
|
||||
OSStatus theErr = ::LSGetApplicationForURL(lookupCFURL, kLSRolesAll, NULL, &appCFURL);
|
||||
|
||||
if (theErr == noErr) {
|
||||
CFBundleRef handlerBundle = ::CFBundleCreate(NULL, appCFURL);
|
||||
|
||||
if (handlerBundle) {
|
||||
// Get the human-readable name of the default handler bundle
|
||||
CFStringRef bundleName =
|
||||
(CFStringRef)::CFBundleGetValueForInfoDictionaryKey(handlerBundle,
|
||||
kCFBundleNameKey);
|
||||
|
||||
if (bundleName) {
|
||||
AutoTArray<UniChar, 255> buffer;
|
||||
CFIndex bundleNameLength = ::CFStringGetLength(bundleName);
|
||||
buffer.SetLength(bundleNameLength);
|
||||
::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength),
|
||||
buffer.Elements());
|
||||
_retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), bundleNameLength);
|
||||
rv = NS_OK;
|
||||
}
|
||||
|
||||
::CFRelease(handlerBundle);
|
||||
}
|
||||
|
||||
::CFRelease(appCFURL);
|
||||
}
|
||||
|
||||
::CFRelease(lookupCFURL);
|
||||
}
|
||||
|
||||
::CFRelease(lookupCFString);
|
||||
}
|
||||
|
||||
::CFRelease(schemeCFString);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t * aPlatformAppPath, nsIFile ** aFile)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILocalFileMac> localFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
CFURLRef pathAsCFURL;
|
||||
CFStringRef pathAsCFString = ::CFStringCreateWithCharacters(NULL,
|
||||
reinterpret_cast<const UniChar*>(aPlatformAppPath),
|
||||
NS_strlen(aPlatformAppPath));
|
||||
if (!pathAsCFString)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (::CFStringGetCharacterAtIndex(pathAsCFString, 0) == '/') {
|
||||
// we have a Posix path
|
||||
pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString,
|
||||
kCFURLPOSIXPathStyle, false);
|
||||
if (!pathAsCFURL) {
|
||||
::CFRelease(pathAsCFString);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if it doesn't start with a / it's not an absolute Posix path
|
||||
// let's check if it's a HFS path left over from old preferences
|
||||
|
||||
// If it starts with a ':' char, it's not an absolute HFS path
|
||||
// so bail for that, and also if it's empty
|
||||
if (::CFStringGetLength(pathAsCFString) == 0 ||
|
||||
::CFStringGetCharacterAtIndex(pathAsCFString, 0) == ':')
|
||||
{
|
||||
::CFRelease(pathAsCFString);
|
||||
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
||||
}
|
||||
|
||||
pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString,
|
||||
kCFURLHFSPathStyle, false);
|
||||
if (!pathAsCFURL) {
|
||||
::CFRelease(pathAsCFString);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
rv = localFile->InitWithCFURL(pathAsCFURL);
|
||||
::CFRelease(pathAsCFString);
|
||||
::CFRelease(pathAsCFURL);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
*aFile = localFile;
|
||||
NS_IF_ADDREF(*aFile);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt, nsIMIMEInfo ** aMIMEInfo)
|
||||
{
|
||||
return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt, aMIMEInfo);
|
||||
}
|
||||
|
||||
// Returns the MIME types an application bundle explicitly claims to handle.
|
||||
// Returns NULL if aAppRef doesn't explicitly claim to handle any MIME types.
|
||||
// If the return value is non-NULL, the caller is responsible for freeing it.
|
||||
// This isn't necessarily the same as the MIME types the application bundle
|
||||
// is registered to handle in the Launch Services database. (For example
|
||||
// the Preview application is normally registered to handle the application/pdf
|
||||
// MIME type, even though it doesn't explicitly claim to handle *any* MIME
|
||||
// types in its Info.plist. This is probably because Preview does explicitly
|
||||
// claim to handle the com.adobe.pdf UTI, and Launch Services somehow
|
||||
// translates this into a claim to support the application/pdf MIME type.
|
||||
// Launch Services doesn't provide any APIs (documented or undocumented) to
|
||||
// query which MIME types a given application is registered to handle. So any
|
||||
// app that wants this information (e.g. the Default Apps pref pane) needs to
|
||||
// iterate through the entire Launch Services database -- a process which can
|
||||
// take several seconds.)
|
||||
static CFArrayRef GetMIMETypesHandledByApp(FSRef *aAppRef)
|
||||
{
|
||||
CFURLRef appURL = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aAppRef);
|
||||
if (!appURL) {
|
||||
return NULL;
|
||||
}
|
||||
CFDictionaryRef infoDict = ::CFBundleCopyInfoDictionaryForURL(appURL);
|
||||
::CFRelease(appURL);
|
||||
if (!infoDict) {
|
||||
return NULL;
|
||||
}
|
||||
CFTypeRef cfObject = ::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes"));
|
||||
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
|
||||
::CFRelease(infoDict);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFArrayRef docTypes = static_cast<CFArrayRef>(cfObject);
|
||||
CFIndex docTypesCount = ::CFArrayGetCount(docTypes);
|
||||
if (docTypesCount == 0) {
|
||||
::CFRelease(infoDict);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFMutableArrayRef mimeTypes =
|
||||
::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||
for (CFIndex i = 0; i < docTypesCount; ++i) {
|
||||
cfObject = ::CFArrayGetValueAtIndex(docTypes, i);
|
||||
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFDictionaryGetTypeID())) {
|
||||
continue;
|
||||
}
|
||||
CFDictionaryRef typeDict = static_cast<CFDictionaryRef>(cfObject);
|
||||
|
||||
// When this key is present (on OS X 10.5 and later), its contents
|
||||
// take precedence over CFBundleTypeMIMETypes (and CFBundleTypeExtensions
|
||||
// and CFBundleTypeOSTypes).
|
||||
cfObject = ::CFDictionaryGetValue(typeDict, CFSTR("LSItemContentTypes"));
|
||||
if (cfObject && (::CFGetTypeID(cfObject) == ::CFArrayGetTypeID())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cfObject = ::CFDictionaryGetValue(typeDict, CFSTR("CFBundleTypeMIMETypes"));
|
||||
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
|
||||
continue;
|
||||
}
|
||||
CFArrayRef mimeTypeHolder = static_cast<CFArrayRef>(cfObject);
|
||||
CFArrayAppendArray(mimeTypes, mimeTypeHolder,
|
||||
::CFRangeMake(0, ::CFArrayGetCount(mimeTypeHolder)));
|
||||
}
|
||||
|
||||
::CFRelease(infoDict);
|
||||
if (!::CFArrayGetCount(mimeTypes)) {
|
||||
::CFRelease(mimeTypes);
|
||||
mimeTypes = NULL;
|
||||
}
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
// aMIMEType and aFileExt might not match, If they don't we set *aFound to
|
||||
// false and return a minimal nsIMIMEInfo structure.
|
||||
already_AddRefed<nsIMIMEInfo>
|
||||
nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt,
|
||||
bool * aFound)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL;
|
||||
|
||||
*aFound = false;
|
||||
|
||||
const nsCString& flatType = PromiseFlatCString(aMIMEType);
|
||||
const nsCString& flatExt = PromiseFlatCString(aFileExt);
|
||||
|
||||
MOZ_LOG(mLog, LogLevel::Debug, ("Mac: HelperAppService lookup for type '%s' ext '%s'\n",
|
||||
flatType.get(), flatExt.get()));
|
||||
|
||||
// Create a Mac-specific MIME info so we can use Mac-specific members.
|
||||
RefPtr<nsMIMEInfoMac> mimeInfoMac = new nsMIMEInfoMac(aMIMEType);
|
||||
|
||||
NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
OSStatus err;
|
||||
bool haveAppForType = false;
|
||||
bool haveAppForExt = false;
|
||||
bool typeAppIsDefault = false;
|
||||
bool extAppIsDefault = false;
|
||||
FSRef typeAppFSRef;
|
||||
FSRef extAppFSRef;
|
||||
|
||||
CFStringRef cfMIMEType = NULL;
|
||||
|
||||
if (!aMIMEType.IsEmpty()) {
|
||||
CFURLRef appURL = NULL;
|
||||
// CFStringCreateWithCString() can fail even if we're not out of memory --
|
||||
// for example if the 'cStr' parameter is something very weird (like "ÿÿ~"
|
||||
// aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
|
||||
// specified in the 'encoding' parameter. See bug 548719.
|
||||
cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(),
|
||||
kCFStringEncodingUTF8);
|
||||
if (cfMIMEType) {
|
||||
err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL);
|
||||
if ((err == noErr) && appURL && ::CFURLGetFSRef(appURL, &typeAppFSRef)) {
|
||||
haveAppForType = true;
|
||||
MOZ_LOG(mLog, LogLevel::Debug, ("LSCopyApplicationForMIMEType found a default application\n"));
|
||||
}
|
||||
if (appURL) {
|
||||
::CFRelease(appURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!aFileExt.IsEmpty()) {
|
||||
// CFStringCreateWithCString() can fail even if we're not out of memory --
|
||||
// for example if the 'cStr' parameter is something very wierd (like "ÿÿ~"
|
||||
// aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
|
||||
// specified in the 'encoding' parameter. See bug 548719.
|
||||
CFStringRef cfExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
|
||||
if (cfExt) {
|
||||
err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt,
|
||||
kLSRolesAll, &extAppFSRef, nullptr);
|
||||
if (err == noErr) {
|
||||
haveAppForExt = true;
|
||||
MOZ_LOG(mLog, LogLevel::Debug, ("LSGetApplicationForInfo found a default application\n"));
|
||||
}
|
||||
::CFRelease(cfExt);
|
||||
}
|
||||
}
|
||||
|
||||
if (haveAppForType && haveAppForExt) {
|
||||
// Do aMIMEType and aFileExt match?
|
||||
if (::FSCompareFSRefs((const FSRef *) &typeAppFSRef, (const FSRef *) &extAppFSRef) == noErr) {
|
||||
typeAppIsDefault = true;
|
||||
*aFound = true;
|
||||
}
|
||||
} else if (haveAppForType) {
|
||||
// If aFileExt isn't empty, it doesn't match aMIMEType.
|
||||
if (aFileExt.IsEmpty()) {
|
||||
typeAppIsDefault = true;
|
||||
*aFound = true;
|
||||
}
|
||||
} else if (haveAppForExt) {
|
||||
// If aMIMEType isn't empty, it doesn't match aFileExt, which should mean
|
||||
// that we haven't found a matching app. But make an exception for an app
|
||||
// that also explicitly claims to handle aMIMEType, or which doesn't claim
|
||||
// to handle any MIME types. This helps work around the following Apple
|
||||
// design flaw:
|
||||
//
|
||||
// Launch Services is somewhat unreliable about registering Apple apps to
|
||||
// handle MIME types. Probably this is because Apple has officially
|
||||
// deprecated support for MIME types (in favor of UTIs). As a result,
|
||||
// most of Apple's own apps don't explicitly claim to handle any MIME
|
||||
// types (instead they claim to handle one or more UTIs). So Launch
|
||||
// Services must contain logic to translate support for a given UTI into
|
||||
// support for one or more MIME types, and it doesn't always do this
|
||||
// correctly. For example DiskImageMounter isn't (by default) registered
|
||||
// to handle the application/x-apple-diskimage MIME type. See bug 675356.
|
||||
//
|
||||
// Apple has also deprecated support for file extensions, and Apple apps
|
||||
// also don't register to handle them. But for some reason Launch Services
|
||||
// is (apparently) better about translating support for a given UTI into
|
||||
// support for one or more file extensions. It's not at all clear why.
|
||||
if (aMIMEType.IsEmpty()) {
|
||||
extAppIsDefault = true;
|
||||
*aFound = true;
|
||||
} else {
|
||||
CFArrayRef extAppMIMETypes = GetMIMETypesHandledByApp(&extAppFSRef);
|
||||
if (extAppMIMETypes) {
|
||||
if (cfMIMEType) {
|
||||
if (::CFArrayContainsValue(extAppMIMETypes,
|
||||
::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)),
|
||||
cfMIMEType)) {
|
||||
extAppIsDefault = true;
|
||||
*aFound = true;
|
||||
}
|
||||
}
|
||||
::CFRelease(extAppMIMETypes);
|
||||
} else {
|
||||
extAppIsDefault = true;
|
||||
*aFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cfMIMEType) {
|
||||
::CFRelease(cfMIMEType);
|
||||
}
|
||||
|
||||
if (aMIMEType.IsEmpty()) {
|
||||
if (haveAppForExt) {
|
||||
// If aMIMEType is empty and we've found a default app for aFileExt, try
|
||||
// to get the MIME type from aFileExt. (It might also be worth doing
|
||||
// this when aMIMEType isn't empty but haveAppForType is false -- but
|
||||
// the doc for this method says that if we have a MIME type (in
|
||||
// aMIMEType), we need to give it preference.)
|
||||
NSURLFileTypeMappings *map = [NSURLFileTypeMappings sharedMappings];
|
||||
NSString *extStr = [NSString stringWithCString:flatExt.get() encoding:NSASCIIStringEncoding];
|
||||
NSString *typeStr = map ? [map MIMETypeForExtension:extStr] : NULL;
|
||||
if (typeStr) {
|
||||
nsAutoCString mimeType;
|
||||
mimeType.Assign((char *)[typeStr cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
mimeInfoMac->SetMIMEType(mimeType);
|
||||
haveAppForType = true;
|
||||
} else {
|
||||
// Sometimes the OS won't give us a MIME type for an extension that's
|
||||
// registered with Launch Services and has a default app: For example
|
||||
// Real Player registers itself for the "ogg" extension and for the
|
||||
// audio/x-ogg and application/x-ogg MIME types, but
|
||||
// MIMETypeForExtension returns nil for the "ogg" extension even on
|
||||
// systems where Real Player is installed. This is probably an Apple
|
||||
// bug. But bad things happen if we return an nsIMIMEInfo structure
|
||||
// with an empty MIME type and set *aFound to true. So in this
|
||||
// case we need to set it to false here.
|
||||
haveAppForExt = false;
|
||||
extAppIsDefault = false;
|
||||
*aFound = false;
|
||||
}
|
||||
} else {
|
||||
// Otherwise set the MIME type to a reasonable fallback.
|
||||
mimeInfoMac->SetMIMEType(NS_LITERAL_CSTRING(APPLICATION_OCTET_STREAM));
|
||||
}
|
||||
}
|
||||
|
||||
if (typeAppIsDefault || extAppIsDefault) {
|
||||
if (haveAppForExt)
|
||||
mimeInfoMac->AppendExtension(aFileExt);
|
||||
|
||||
nsCOMPtr<nsILocalFileMac> app(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
|
||||
if (!app) {
|
||||
[localPool release];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFStringRef cfAppName = NULL;
|
||||
if (typeAppIsDefault) {
|
||||
app->InitWithFSRef(&typeAppFSRef);
|
||||
::LSCopyItemAttribute((const FSRef *) &typeAppFSRef, kLSRolesAll,
|
||||
kLSItemDisplayName, (CFTypeRef *) &cfAppName);
|
||||
} else {
|
||||
app->InitWithFSRef(&extAppFSRef);
|
||||
::LSCopyItemAttribute((const FSRef *) &extAppFSRef, kLSRolesAll,
|
||||
kLSItemDisplayName, (CFTypeRef *) &cfAppName);
|
||||
}
|
||||
if (cfAppName) {
|
||||
AutoTArray<UniChar, 255> buffer;
|
||||
CFIndex appNameLength = ::CFStringGetLength(cfAppName);
|
||||
buffer.SetLength(appNameLength);
|
||||
::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength),
|
||||
buffer.Elements());
|
||||
nsAutoString appName;
|
||||
appName.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), appNameLength);
|
||||
mimeInfoMac->SetDefaultDescription(appName);
|
||||
::CFRelease(cfAppName);
|
||||
}
|
||||
|
||||
mimeInfoMac->SetDefaultApplication(app);
|
||||
mimeInfoMac->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
|
||||
} else {
|
||||
mimeInfoMac->SetPreferredAction(nsIMIMEInfo::saveToDisk);
|
||||
}
|
||||
|
||||
nsAutoCString mimeType;
|
||||
mimeInfoMac->GetMIMEType(mimeType);
|
||||
if (*aFound && !mimeType.IsEmpty()) {
|
||||
// If we have a MIME type, make sure its preferred extension is included
|
||||
// in our list.
|
||||
NSURLFileTypeMappings *map = [NSURLFileTypeMappings sharedMappings];
|
||||
NSString *typeStr = [NSString stringWithCString:mimeType.get() encoding:NSASCIIStringEncoding];
|
||||
NSString *extStr = map ? [map preferredExtensionForMIMEType:typeStr] : NULL;
|
||||
if (extStr) {
|
||||
nsAutoCString preferredExt;
|
||||
preferredExt.Assign((char *)[extStr cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
mimeInfoMac->AppendExtension(preferredExt);
|
||||
}
|
||||
|
||||
CFStringRef cfType = ::CFStringCreateWithCString(NULL, mimeType.get(), kCFStringEncodingUTF8);
|
||||
if (cfType) {
|
||||
CFStringRef cfTypeDesc = NULL;
|
||||
if (::LSCopyKindStringForMIMEType(cfType, &cfTypeDesc) == noErr) {
|
||||
AutoTArray<UniChar, 255> buffer;
|
||||
CFIndex typeDescLength = ::CFStringGetLength(cfTypeDesc);
|
||||
buffer.SetLength(typeDescLength);
|
||||
::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength),
|
||||
buffer.Elements());
|
||||
nsAutoString typeDesc;
|
||||
typeDesc.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), typeDescLength);
|
||||
mimeInfoMac->SetDescription(typeDesc);
|
||||
}
|
||||
if (cfTypeDesc) {
|
||||
::CFRelease(cfTypeDesc);
|
||||
}
|
||||
::CFRelease(cfType);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_LOG(mLog, LogLevel::Debug, ("OS gave us: type '%s' found '%i'\n", mimeType.get(), *aFound));
|
||||
|
||||
[localPool release];
|
||||
return mimeInfoMac.forget();
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString &aScheme,
|
||||
bool *found,
|
||||
nsIHandlerInfo **_retval)
|
||||
{
|
||||
NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!");
|
||||
|
||||
nsresult rv = OSProtocolHandlerExists(nsPromiseFlatCString(aScheme).get(),
|
||||
found);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsMIMEInfoMac *handlerInfo =
|
||||
new nsMIMEInfoMac(aScheme, nsMIMEInfoBase::eProtocolInfo);
|
||||
NS_ENSURE_TRUE(handlerInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(*_retval = handlerInfo);
|
||||
|
||||
if (!*found) {
|
||||
// Code that calls this requires an object regardless if the OS has
|
||||
// something for us, so we return the empty object.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString desc;
|
||||
rv = GetApplicationDescription(aScheme, desc);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetApplicationDescription failed");
|
||||
handlerInfo->SetDefaultDescription(desc);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
139
uriloader/exthandler/moz.build
Normal file
139
uriloader/exthandler/moz.build
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
TEST_DIRS += ['tests']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsCExternalHandlerService.idl',
|
||||
'nsIContentDispatchChooser.idl',
|
||||
'nsIExternalHelperAppService.idl',
|
||||
'nsIExternalProtocolService.idl',
|
||||
'nsIExternalSharingAppService.idl',
|
||||
'nsIExternalURLHandlerService.idl',
|
||||
'nsIHandlerService.idl',
|
||||
'nsIHelperAppLauncherDialog.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'exthandler'
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
osdir = 'win'
|
||||
LOCAL_INCLUDES += ['win']
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
osdir = 'mac'
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk', 'uikit'):
|
||||
osdir = CONFIG['MOZ_WIDGET_TOOLKIT']
|
||||
else:
|
||||
osdir = 'unix'
|
||||
|
||||
EXPORTS += [
|
||||
osdir + '/nsOSHelperAppService.h'
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
'ContentHandlerService.h',
|
||||
'nsExternalHelperAppService.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
EXPORTS += [ '%s/%s' % (osdir, f) for f in [
|
||||
'nsExternalSharingAppService.h',
|
||||
'nsExternalURLHandlerService.h',
|
||||
]]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'ExternalHelperAppChild.h',
|
||||
'ExternalHelperAppParent.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'ContentHandlerService.cpp',
|
||||
'ExternalHelperAppChild.cpp',
|
||||
'ExternalHelperAppParent.cpp',
|
||||
'HandlerServiceParent.cpp',
|
||||
'nsExternalHelperAppService.cpp',
|
||||
'nsExternalProtocolHandler.cpp',
|
||||
'nsLocalHandlerApp.cpp',
|
||||
'nsMIMEInfoImpl.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
UNIFIED_SOURCES += [
|
||||
'mac/nsLocalHandlerAppMac.mm',
|
||||
'mac/nsMIMEInfoMac.mm',
|
||||
'mac/nsOSHelperAppService.mm',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
|
||||
UNIFIED_SOURCES += [
|
||||
'uikit/nsLocalHandlerAppUIKit.mm',
|
||||
'uikit/nsMIMEInfoUIKit.mm',
|
||||
'uikit/nsOSHelperAppService.mm',
|
||||
]
|
||||
else:
|
||||
# These files can't be built in unified mode because they redefine LOG.
|
||||
SOURCES += [
|
||||
osdir + '/nsOSHelperAppService.cpp',
|
||||
]
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
|
||||
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
||||
UNIFIED_SOURCES += [
|
||||
'unix/nsGNOMERegistry.cpp',
|
||||
'unix/nsMIMEInfoUnix.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
UNIFIED_SOURCES += [
|
||||
'android/nsAndroidHandlerApp.cpp',
|
||||
'android/nsExternalSharingAppService.cpp',
|
||||
'android/nsExternalURLHandlerService.cpp',
|
||||
'android/nsMIMEInfoAndroid.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
UNIFIED_SOURCES += [
|
||||
'win/nsMIMEInfoWin.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_ENABLE_DBUS']:
|
||||
UNIFIED_SOURCES += [
|
||||
'nsDBusHandlerApp.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_ENABLE_CONTENTACTION']:
|
||||
UNIFIED_SOURCES += [
|
||||
'nsContentHandlerApp.cpp',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'nsHandlerService.js',
|
||||
'nsHandlerService.manifest',
|
||||
'nsWebHandlerApp.js',
|
||||
'nsWebHandlerApp.manifest',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'PExternalHelperApp.ipdl',
|
||||
'PHandlerService.ipdl',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
'/dom/ipc',
|
||||
'/netwerk/base',
|
||||
'/netwerk/protocol/http',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_ENABLE_DBUS']:
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
|
||||
58
uriloader/exthandler/nsCExternalHandlerService.idl
Normal file
58
uriloader/exthandler/nsCExternalHandlerService.idl
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/* -*- Mode: IDL; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 "nsIExternalHelperAppService.idl"
|
||||
|
||||
/*
|
||||
nsCExternalHelperApp implements:
|
||||
-------------------------
|
||||
nsIExternalHelperAppService
|
||||
*/
|
||||
|
||||
%{ C++
|
||||
|
||||
/* A7F800E0-4306-11d4-98D0-001083010E9B */
|
||||
#define NS_EXTERNALHELPERAPPSERVICE_CID \
|
||||
{ 0xa7f800e0, 0x4306, 0x11d4, { 0x98, 0xd0, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b } }
|
||||
|
||||
#define NS_EXTERNALHELPERAPPSERVICE_CONTRACTID \
|
||||
"@mozilla.org/uriloader/external-helper-app-service;1"
|
||||
|
||||
#define NS_HANDLERSERVICE_CONTRACTID \
|
||||
"@mozilla.org/uriloader/handler-service;1"
|
||||
|
||||
#define NS_EXTERNALPROTOCOLSERVICE_CONTRACTID \
|
||||
"@mozilla.org/uriloader/external-protocol-service;1"
|
||||
|
||||
#define NS_MIMESERVICE_CONTRACTID \
|
||||
"@mozilla.org/mime;1"
|
||||
|
||||
#define NS_EXTERNALPROTOCOLHANDLER_CID \
|
||||
{ 0xbd6390c8, 0xfbea, 0x11d4, {0x98, 0xf6, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b } }
|
||||
|
||||
/* 9fa83ce7-d0ab-4ed3-938e-afafee435670 */
|
||||
#define NS_BLOCKEDEXTERNALPROTOCOLHANDLER_CID \
|
||||
{ 0x9fa83ce7, 0xd0ab, 0x4ed3, {0x93, 0x8e, 0xaf, 0xaf, 0xee, 0x43, 0x56, 0x70 } }
|
||||
|
||||
/* bc0017e3-2438-47be-a567-41db58f17627 */
|
||||
#define NS_LOCALHANDLERAPP_CID \
|
||||
{ 0xbc0017e3, 0x2438, 0x47be, {0xa5, 0x67, 0x41, 0xdb, 0x58, 0xf1, 0x76, 0x27 } }
|
||||
|
||||
/*6c3c274b-4cbf-4bb5-a635-05ad2cbb6535*/
|
||||
#define NS_DBUSHANDLERAPP_CID \
|
||||
{ 0x6c3c274b, 0x4cbf, 0x4bb5, {0xa6, 0x35, 0x05, 0xad, 0x2c, 0xbb, 0x65, 0x35 } }
|
||||
|
||||
#define NS_DBUSHANDLERAPP_CONTRACTID \
|
||||
"@mozilla.org/uriloader/dbus-handler-app;1"
|
||||
|
||||
#define NS_LOCALHANDLERAPP_CONTRACTID \
|
||||
"@mozilla.org/uriloader/local-handler-app;1"
|
||||
|
||||
#define NS_WEBHANDLERAPP_CONTRACTID \
|
||||
"@mozilla.org/uriloader/web-handler-app;1"
|
||||
|
||||
%}
|
||||
|
||||
79
uriloader/exthandler/nsContentHandlerApp.cpp
Normal file
79
uriloader/exthandler/nsContentHandlerApp.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2:cin:
|
||||
* 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 "nsContentHandlerApp.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#define NS_CONTENTHANDLER_CID \
|
||||
{ 0x43ec2c82, 0xb9db, 0x4835, {0x80, 0x3f, 0x64, 0xc9, 0x72, 0x5a, 0x70, 0x28 } }
|
||||
|
||||
NS_IMPL_CLASSINFO(nsContentHandlerApp, nullptr, 0, NS_CONTENTHANDLER_CID)
|
||||
NS_IMPL_ISUPPORTS_CI(nsContentHandlerApp, nsIHandlerApp)
|
||||
|
||||
nsContentHandlerApp::nsContentHandlerApp(nsString aName, nsCString aType,
|
||||
ContentAction::Action& aAction) :
|
||||
mName(aName),
|
||||
mType(aType),
|
||||
mAction(aAction)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIHandlerInfo
|
||||
|
||||
NS_IMETHODIMP nsContentHandlerApp::GetName(nsAString& aName)
|
||||
{
|
||||
aName.Assign(mName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsContentHandlerApp::SetName(const nsAString& aName)
|
||||
{
|
||||
mName.Assign(aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsContentHandlerApp::Equals(nsIHandlerApp *aHandlerApp, bool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsContentHandlerApp::GetDetailedDescription(nsAString& aDetailedDescription)
|
||||
{
|
||||
aDetailedDescription.Assign(mDetailedDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsContentHandlerApp::SetDetailedDescription(const nsAString& aDetailedDescription)
|
||||
{
|
||||
mDetailedDescription.Assign(aDetailedDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsContentHandlerApp::LaunchWithURI(nsIURI *aURI,
|
||||
nsIInterfaceRequestor *aWindowContext)
|
||||
{
|
||||
nsAutoCString spec;
|
||||
nsresult rv = aURI->GetAsciiSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
const char* url = spec.get();
|
||||
|
||||
QList<ContentAction::Action> actions =
|
||||
ContentAction::Action::actionsForFile(QUrl(url), QString(mType.get()));
|
||||
for (int i = 0; i < actions.size(); ++i) {
|
||||
if (actions[i].name() == QString((QChar*)mName.get(), mName.Length())) {
|
||||
actions[i].trigger();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
30
uriloader/exthandler/nsContentHandlerApp.h
Normal file
30
uriloader/exthandler/nsContentHandlerApp.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2:cin:
|
||||
* 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 __nsContentHandlerAppImpl_h__
|
||||
#define __nsContentHandlerAppImpl_h__
|
||||
|
||||
#include <contentaction/contentaction.h>
|
||||
#include "nsString.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
|
||||
class nsContentHandlerApp : public nsIHandlerApp
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHANDLERAPP
|
||||
|
||||
nsContentHandlerApp(nsString aName, nsCString aType, ContentAction::Action& aAction);
|
||||
virtual ~nsContentHandlerApp() { }
|
||||
|
||||
protected:
|
||||
nsString mName;
|
||||
nsCString mType;
|
||||
nsString mDetailedDescription;
|
||||
|
||||
ContentAction::Action mAction;
|
||||
};
|
||||
#endif
|
||||
177
uriloader/exthandler/nsDBusHandlerApp.cpp
Normal file
177
uriloader/exthandler/nsDBusHandlerApp.cpp
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2:cin:
|
||||
* 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 <dbus/dbus.h>
|
||||
#include "mozilla/ipc/DBusConnectionDelete.h"
|
||||
#include "mozilla/ipc/DBusMessageRefPtr.h"
|
||||
#include "nsDBusHandlerApp.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
|
||||
// XXX why does nsMIMEInfoImpl have a threadsafe nsISupports? do we need one
|
||||
// here too?
|
||||
NS_IMPL_CLASSINFO(nsDBusHandlerApp, nullptr, 0, NS_DBUSHANDLERAPP_CID)
|
||||
NS_IMPL_ISUPPORTS_CI(nsDBusHandlerApp, nsIDBusHandlerApp, nsIHandlerApp)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIHandlerApp
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::GetName(nsAString& aName)
|
||||
{
|
||||
aName.Assign(mName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::SetName(const nsAString & aName)
|
||||
{
|
||||
mName.Assign(aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::SetDetailedDescription(const nsAString & aDescription)
|
||||
{
|
||||
mDetailedDescription.Assign(aDescription);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::GetDetailedDescription(nsAString& aDescription)
|
||||
{
|
||||
aDescription.Assign(mDetailedDescription);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBusHandlerApp::Equals(nsIHandlerApp *aHandlerApp, bool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aHandlerApp);
|
||||
|
||||
// If the handler app isn't a dbus handler app, then it's not the same app.
|
||||
nsCOMPtr<nsIDBusHandlerApp> dbusHandlerApp = do_QueryInterface(aHandlerApp);
|
||||
if (!dbusHandlerApp) {
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
nsAutoCString service;
|
||||
nsAutoCString method;
|
||||
|
||||
nsresult rv = dbusHandlerApp->GetService(service);
|
||||
if (NS_FAILED(rv)) {
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
rv = dbusHandlerApp->GetMethod(method);
|
||||
if (NS_FAILED(rv)) {
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*_retval = service.Equals(mService) && method.Equals(mMethod);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBusHandlerApp::LaunchWithURI(nsIURI *aURI,
|
||||
nsIInterfaceRequestor *aWindowContext)
|
||||
{
|
||||
nsAutoCString spec;
|
||||
nsresult rv = aURI->GetAsciiSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
const char* uri = spec.get();
|
||||
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
|
||||
mozilla::UniquePtr<DBusConnection, mozilla::DBusConnectionDelete>
|
||||
connection(dbus_bus_get_private(DBUS_BUS_SESSION, &err));
|
||||
|
||||
if (dbus_error_is_set(&err)) {
|
||||
dbus_error_free(&err);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (nullptr == connection) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
dbus_connection_set_exit_on_disconnect(connection.get(),false);
|
||||
|
||||
RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
|
||||
dbus_message_new_method_call(mService.get(),
|
||||
mObjpath.get(),
|
||||
mInterface.get(),
|
||||
mMethod.get()));
|
||||
|
||||
if (!msg) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
dbus_message_set_no_reply(msg, true);
|
||||
|
||||
DBusMessageIter iter;
|
||||
dbus_message_iter_init_append(msg, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uri);
|
||||
|
||||
if (dbus_connection_send(connection.get(), msg, nullptr)) {
|
||||
dbus_connection_flush(connection.get());
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIDBusHandlerApp
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::GetService(nsACString & aService)
|
||||
{
|
||||
aService.Assign(mService);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::SetService(const nsACString & aService)
|
||||
{
|
||||
mService.Assign(aService);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::GetMethod(nsACString & aMethod)
|
||||
{
|
||||
aMethod.Assign(mMethod);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::SetMethod(const nsACString & aMethod)
|
||||
{
|
||||
mMethod.Assign(aMethod);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::GetDBusInterface(nsACString & aInterface)
|
||||
{
|
||||
aInterface.Assign(mInterface);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::SetDBusInterface(const nsACString & aInterface)
|
||||
{
|
||||
mInterface.Assign(aInterface);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::GetObjectPath(nsACString & aObjpath)
|
||||
{
|
||||
aObjpath.Assign(mObjpath);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDBusHandlerApp::SetObjectPath(const nsACString & aObjpath)
|
||||
{
|
||||
mObjpath.Assign(aObjpath);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
33
uriloader/exthandler/nsDBusHandlerApp.h
Normal file
33
uriloader/exthandler/nsDBusHandlerApp.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2:cin:
|
||||
* 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 __nsDBusHandlerAppImpl_h__
|
||||
#define __nsDBusHandlerAppImpl_h__
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
|
||||
class nsDBusHandlerApp : public nsIDBusHandlerApp
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHANDLERAPP
|
||||
NS_DECL_NSIDBUSHANDLERAPP
|
||||
|
||||
nsDBusHandlerApp() { }
|
||||
|
||||
protected:
|
||||
virtual ~nsDBusHandlerApp() { }
|
||||
|
||||
nsString mName;
|
||||
nsString mDetailedDescription;
|
||||
nsCString mService;
|
||||
nsCString mMethod;
|
||||
nsCString mInterface;
|
||||
nsCString mObjpath;
|
||||
|
||||
};
|
||||
#endif
|
||||
2926
uriloader/exthandler/nsExternalHelperAppService.cpp
Normal file
2926
uriloader/exthandler/nsExternalHelperAppService.cpp
Normal file
File diff suppressed because it is too large
Load diff
498
uriloader/exthandler/nsExternalHelperAppService.h
Normal file
498
uriloader/exthandler/nsExternalHelperAppService.h
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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 nsExternalHelperAppService_h__
|
||||
#define nsExternalHelperAppService_h__
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "prtime.h"
|
||||
|
||||
#include "nsIExternalHelperAppService.h"
|
||||
#include "nsIExternalProtocolService.h"
|
||||
#include "nsIWebProgressListener2.h"
|
||||
#include "nsIHelperAppLauncherDialog.h"
|
||||
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIBackgroundFileSaver.h"
|
||||
|
||||
#include "nsIHandlerService.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIPrompt.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsExternalAppHandler;
|
||||
class nsIMIMEInfo;
|
||||
class nsITransfer;
|
||||
class nsPIDOMWindowOuter;
|
||||
|
||||
/**
|
||||
* The helper app service. Responsible for handling content that Mozilla
|
||||
* itself can not handle
|
||||
*/
|
||||
class nsExternalHelperAppService
|
||||
: public nsIExternalHelperAppService,
|
||||
public nsPIExternalAppLauncher,
|
||||
public nsIExternalProtocolService,
|
||||
public nsIMIMEService,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIEXTERNALHELPERAPPSERVICE
|
||||
NS_DECL_NSPIEXTERNALAPPLAUNCHER
|
||||
NS_DECL_NSIEXTERNALPROTOCOLSERVICE
|
||||
NS_DECL_NSIMIMESERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsExternalHelperAppService();
|
||||
|
||||
/**
|
||||
* Initializes internal state. Will be called automatically when
|
||||
* this service is first instantiated.
|
||||
*/
|
||||
MOZ_MUST_USE nsresult Init();
|
||||
|
||||
/**
|
||||
* Given a mimetype and an extension, looks up a mime info from the OS.
|
||||
* The mime type is given preference. This function follows the same rules
|
||||
* as nsIMIMEService::GetFromTypeAndExtension.
|
||||
* This is supposed to be overridden by the platform-specific
|
||||
* nsOSHelperAppService!
|
||||
* @param aFileExt The file extension; may be empty. UTF-8 encoded.
|
||||
* @param [out] aFound
|
||||
* Should be set to true if the os has a mapping, to
|
||||
* false otherwise. Must not be null.
|
||||
* @return A MIMEInfo. This function must return a MIMEInfo object if it
|
||||
* can allocate one. The only justifiable reason for not
|
||||
* returning one is an out-of-memory error.
|
||||
* If null, the value of aFound is unspecified.
|
||||
*/
|
||||
virtual already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt,
|
||||
bool * aFound) = 0;
|
||||
|
||||
/**
|
||||
* Given a string identifying an application, create an nsIFile representing
|
||||
* it. This function should look in $PATH for the application.
|
||||
* The base class implementation will first try to interpret platformAppPath
|
||||
* as an absolute path, and if that fails it will look for a file next to the
|
||||
* mozilla executable. Subclasses can override this method if they want a
|
||||
* different behaviour.
|
||||
* @param platformAppPath A platform specific path to an application that we
|
||||
* got out of the rdf data source. This can be a mac
|
||||
* file spec, a unix path or a windows path depending
|
||||
* on the platform
|
||||
* @param aFile [out] An nsIFile representation of that platform
|
||||
* application path.
|
||||
*/
|
||||
virtual nsresult GetFileTokenForPath(const char16_t * platformAppPath,
|
||||
nsIFile ** aFile);
|
||||
|
||||
virtual nsresult OSProtocolHandlerExists(const char *aScheme,
|
||||
bool *aExists) = 0;
|
||||
|
||||
/**
|
||||
* Given an extension, get a MIME type string. If not overridden by
|
||||
* the OS-specific nsOSHelperAppService, will call into GetMIMEInfoFromOS
|
||||
* with an empty mimetype.
|
||||
* @return true if we successfully found a mimetype.
|
||||
*/
|
||||
virtual bool GetMIMETypeFromOSForExtension(const nsACString& aExtension,
|
||||
nsACString& aMIMEType);
|
||||
|
||||
protected:
|
||||
virtual ~nsExternalHelperAppService();
|
||||
|
||||
/**
|
||||
* Searches the "extra" array of MIMEInfo objects for an object
|
||||
* with a specific type. If found, it will modify the passed-in
|
||||
* MIMEInfo. Otherwise, it will return an error and the MIMEInfo
|
||||
* will be untouched.
|
||||
* @param aContentType The type to search for.
|
||||
* @param aMIMEInfo [inout] The mime info, if found
|
||||
*/
|
||||
nsresult FillMIMEInfoForMimeTypeFromExtras(
|
||||
const nsACString& aContentType, nsIMIMEInfo * aMIMEInfo);
|
||||
/**
|
||||
* Searches the "extra" array of MIMEInfo objects for an object
|
||||
* with a specific extension.
|
||||
*
|
||||
* Does not change the MIME Type of the MIME Info.
|
||||
*
|
||||
* @see FillMIMEInfoForMimeTypeFromExtras
|
||||
*/
|
||||
nsresult FillMIMEInfoForExtensionFromExtras(
|
||||
const nsACString& aExtension, nsIMIMEInfo * aMIMEInfo);
|
||||
|
||||
/**
|
||||
* Searches the "extra" array for a MIME type, and gets its extension.
|
||||
* @param aExtension The extension to search for
|
||||
* @param aMIMEType [out] The found MIME type.
|
||||
* @return true if the extension was found, false otherwise.
|
||||
*/
|
||||
bool GetTypeFromExtras(const nsACString& aExtension,
|
||||
nsACString& aMIMEType);
|
||||
|
||||
/**
|
||||
* Logging Module. Usage: set MOZ_LOG=HelperAppService:level, where level
|
||||
* should be 2 for errors, 3 for debug messages from the cross- platform
|
||||
* nsExternalHelperAppService, and 4 for os-specific debug messages.
|
||||
*/
|
||||
static mozilla::LazyLogModule mLog;
|
||||
|
||||
// friend, so that it can access the nspr log module.
|
||||
friend class nsExternalAppHandler;
|
||||
|
||||
/**
|
||||
* Helper function for ExpungeTemporaryFiles and ExpungeTemporaryPrivateFiles
|
||||
*/
|
||||
static void ExpungeTemporaryFilesHelper(nsCOMArray<nsIFile> &fileList);
|
||||
/**
|
||||
* Helper function for DeleteTemporaryFileOnExit and DeleteTemporaryPrivateFileWhenPossible
|
||||
*/
|
||||
static nsresult DeleteTemporaryFileHelper(nsIFile* aTemporaryFile,
|
||||
nsCOMArray<nsIFile> &aFileList);
|
||||
/**
|
||||
* Functions related to the tempory file cleanup service provided by
|
||||
* nsExternalHelperAppService
|
||||
*/
|
||||
void ExpungeTemporaryFiles();
|
||||
/**
|
||||
* Functions related to the tempory file cleanup service provided by
|
||||
* nsExternalHelperAppService (for the temporary files added during
|
||||
* the private browsing mode)
|
||||
*/
|
||||
void ExpungeTemporaryPrivateFiles();
|
||||
|
||||
/**
|
||||
* Array for the files that should be deleted
|
||||
*/
|
||||
nsCOMArray<nsIFile> mTemporaryFilesList;
|
||||
/**
|
||||
* Array for the files that should be deleted (for the temporary files
|
||||
* added during the private browsing mode)
|
||||
*/
|
||||
nsCOMArray<nsIFile> mTemporaryPrivateFilesList;
|
||||
|
||||
private:
|
||||
nsresult DoContentContentProcessHelper(const nsACString& aMimeContentType,
|
||||
nsIRequest *aRequest,
|
||||
nsIInterfaceRequestor *aContentContext,
|
||||
bool aForceSave,
|
||||
nsIInterfaceRequestor *aWindowContext,
|
||||
nsIStreamListener ** aStreamListener);
|
||||
};
|
||||
|
||||
/**
|
||||
* An external app handler is just a small little class that presents itself as
|
||||
* a nsIStreamListener. It saves the incoming data into a temp file. The handler
|
||||
* is bound to an application when it is created. When it receives an
|
||||
* OnStopRequest it launches the application using the temp file it has
|
||||
* stored the data into. We create a handler every time we have to process
|
||||
* data using a helper app.
|
||||
*/
|
||||
class nsExternalAppHandler final : public nsIStreamListener,
|
||||
public nsIHelperAppLauncher,
|
||||
public nsITimerCallback,
|
||||
public nsIBackgroundFileSaverObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSIHELPERAPPLAUNCHER
|
||||
NS_DECL_NSICANCELABLE
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSIBACKGROUNDFILESAVEROBSERVER
|
||||
|
||||
/**
|
||||
* @param aMIMEInfo MIMEInfo object, representing the type of the
|
||||
* content that should be handled
|
||||
* @param aFileExtension The extension we need to append to our temp file,
|
||||
* INCLUDING the ".". e.g. .mp3
|
||||
* @param aContentContext dom Window context, as passed to DoContent.
|
||||
* @param aWindowContext Top level window context used in dialog parenting,
|
||||
* as passed to DoContent. This parameter may be null,
|
||||
* in which case dialogs will be parented to
|
||||
* aContentContext.
|
||||
* @param mExtProtSvc nsExternalHelperAppService on creation
|
||||
* @param aFileName The filename to use
|
||||
* @param aReason A constant from nsIHelperAppLauncherDialog indicating
|
||||
* why the request is handled by a helper app.
|
||||
*/
|
||||
nsExternalAppHandler(nsIMIMEInfo * aMIMEInfo, const nsCSubstring& aFileExtension,
|
||||
nsIInterfaceRequestor * aContentContext,
|
||||
nsIInterfaceRequestor * aWindowContext,
|
||||
nsExternalHelperAppService * aExtProtSvc,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aReason, bool aForceSave);
|
||||
|
||||
/**
|
||||
* Clean up after the request was diverted to the parent process.
|
||||
*/
|
||||
void DidDivertRequest(nsIRequest *request);
|
||||
|
||||
/**
|
||||
* Apply content conversions if needed.
|
||||
*/
|
||||
void MaybeApplyDecodingForExtension(nsIRequest *request);
|
||||
|
||||
protected:
|
||||
~nsExternalAppHandler();
|
||||
|
||||
nsIInterfaceRequestor* GetDialogParent() {
|
||||
return mWindowContext ? mWindowContext : mContentContext;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> mTempFile;
|
||||
nsCOMPtr<nsIURI> mSourceUrl;
|
||||
nsString mTempFileExtension;
|
||||
nsString mTempLeafName;
|
||||
|
||||
/**
|
||||
* The MIME Info for this load. Will never be null.
|
||||
*/
|
||||
nsCOMPtr<nsIMIMEInfo> mMimeInfo;
|
||||
|
||||
/**
|
||||
* The dom window associated with this request to handle content.
|
||||
*/
|
||||
nsCOMPtr<nsIInterfaceRequestor> mContentContext;
|
||||
|
||||
/**
|
||||
* If set, the parent window helper app dialogs and file pickers
|
||||
* should use in parenting. If null, we use mContentContext.
|
||||
*/
|
||||
nsCOMPtr<nsIInterfaceRequestor> mWindowContext;
|
||||
|
||||
/**
|
||||
* Used to close the window on a timer, to avoid any exceptions that are
|
||||
* thrown if we try to close the window before it's fully loaded.
|
||||
*/
|
||||
nsCOMPtr<nsPIDOMWindowOuter> mWindowToClose;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
/**
|
||||
* The following field is set if we were processing an http channel that had
|
||||
* a content disposition header which specified the SUGGESTED file name we
|
||||
* should present to the user in the save to disk dialog.
|
||||
*/
|
||||
nsString mSuggestedFileName;
|
||||
|
||||
/**
|
||||
* If set, this handler should forcibly save the file to disk regardless of
|
||||
* MIME info settings or anything else, without ever popping up the
|
||||
* unknown content type handling dialog.
|
||||
*/
|
||||
bool mForceSave;
|
||||
|
||||
/**
|
||||
* The canceled flag is set if the user canceled the launching of this
|
||||
* application before we finished saving the data to a temp file.
|
||||
*/
|
||||
bool mCanceled;
|
||||
|
||||
/**
|
||||
* This is set based on whether the channel indicates that a new window
|
||||
* was opened specifically for this download. If so, then we
|
||||
* close it.
|
||||
*/
|
||||
bool mShouldCloseWindow;
|
||||
|
||||
/**
|
||||
* True if a stop request has been issued.
|
||||
*/
|
||||
bool mStopRequestIssued;
|
||||
|
||||
bool mIsFileChannel;
|
||||
|
||||
/**
|
||||
* One of the REASON_ constants from nsIHelperAppLauncherDialog. Indicates the
|
||||
* reason the dialog was shown (unknown content type, server requested it,
|
||||
* etc).
|
||||
*/
|
||||
uint32_t mReason;
|
||||
|
||||
/**
|
||||
* Track the executable-ness of the temporary file.
|
||||
*/
|
||||
bool mTempFileIsExecutable;
|
||||
|
||||
PRTime mTimeDownloadStarted;
|
||||
int64_t mContentLength;
|
||||
int64_t mProgress; /**< Number of bytes received (for sending progress notifications). */
|
||||
|
||||
/**
|
||||
* When we are told to save the temp file to disk (in a more permament
|
||||
* location) before we are done writing the content to a temp file, then
|
||||
* we need to remember the final destination until we are ready to use it.
|
||||
*/
|
||||
nsCOMPtr<nsIFile> mFinalFileDestination;
|
||||
|
||||
uint32_t mBufferSize;
|
||||
|
||||
/**
|
||||
* This object handles saving the data received from the network to a
|
||||
* temporary location first, and then move the file to its final location,
|
||||
* doing all the input/output on a background thread.
|
||||
*/
|
||||
nsCOMPtr<nsIBackgroundFileSaver> mSaver;
|
||||
|
||||
/**
|
||||
* Stores the SHA-256 hash associated with the file that we downloaded.
|
||||
*/
|
||||
nsAutoCString mHash;
|
||||
/**
|
||||
* Stores the signature information of the downloaded file in an nsIArray of
|
||||
* nsIX509CertList of nsIX509Cert. If the file is unsigned this will be
|
||||
* empty.
|
||||
*/
|
||||
nsCOMPtr<nsIArray> mSignatureInfo;
|
||||
/**
|
||||
* Stores the redirect information associated with the channel.
|
||||
*/
|
||||
nsCOMPtr<nsIArray> mRedirects;
|
||||
/**
|
||||
* Creates the temporary file for the download and an output stream for it.
|
||||
* Upon successful return, both mTempFile and mSaver will be valid.
|
||||
*/
|
||||
nsresult SetUpTempFile(nsIChannel * aChannel);
|
||||
/**
|
||||
* When we download a helper app, we are going to retarget all load
|
||||
* notifications into our own docloader and load group instead of
|
||||
* using the window which initiated the load....RetargetLoadNotifications
|
||||
* contains that information...
|
||||
*/
|
||||
void RetargetLoadNotifications(nsIRequest *request);
|
||||
/**
|
||||
* Once the user tells us how they want to dispose of the content
|
||||
* create an nsITransfer so they know what's going on. If this fails, the
|
||||
* caller MUST call Cancel.
|
||||
*/
|
||||
nsresult CreateTransfer();
|
||||
|
||||
/**
|
||||
* If we fail to create the necessary temporary file to initiate a transfer
|
||||
* we will report the failure by creating a failed nsITransfer.
|
||||
*/
|
||||
nsresult CreateFailedTransfer(bool aIsPrivateBrowsing);
|
||||
|
||||
/*
|
||||
* The following two functions are part of the split of SaveToDisk
|
||||
* to make it async, and works as following:
|
||||
*
|
||||
* SaveToDisk -------> RequestSaveDestination
|
||||
* .
|
||||
* .
|
||||
* v
|
||||
* ContinueSave <------- SaveDestinationAvailable
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is called by SaveToDisk to decide what's the final
|
||||
* file destination chosen by the user or by auto-download settings.
|
||||
*/
|
||||
void RequestSaveDestination(const nsAFlatString &aDefaultFile,
|
||||
const nsAFlatString &aDefaultFileExt);
|
||||
|
||||
/**
|
||||
* When SaveToDisk is called, it possibly delegates to RequestSaveDestination
|
||||
* to decide the file destination. ContinueSave must then be called when
|
||||
* the final destination is finally known.
|
||||
* @param aFile The file that was chosen as the final destination.
|
||||
* Must not be null.
|
||||
*/
|
||||
nsresult ContinueSave(nsIFile* aFile);
|
||||
|
||||
/**
|
||||
* After we're done prompting the user for any information, if the original
|
||||
* channel had a refresh url associated with it (which might point to a
|
||||
* "thank you for downloading" kind of page, then process that....It is safe
|
||||
* to invoke this method multiple times. We'll clear mOriginalChannel after
|
||||
* it's called and this ensures we won't call it again....
|
||||
*/
|
||||
void ProcessAnyRefreshTags();
|
||||
|
||||
/**
|
||||
* Notify our nsITransfer object that we are done with the download. This is
|
||||
* always called after the target file has been closed.
|
||||
*
|
||||
* @param aStatus
|
||||
* NS_OK for success, or a failure code if the download failed.
|
||||
* A partially downloaded file may still be available in this case.
|
||||
*/
|
||||
void NotifyTransfer(nsresult aStatus);
|
||||
|
||||
/**
|
||||
* Helper routine that searches a pref string for a given mime type
|
||||
*/
|
||||
bool GetNeverAskFlagFromPref(const char * prefName, const char * aContentType);
|
||||
|
||||
/**
|
||||
* Helper routine to ensure mSuggestedFileName is "correct";
|
||||
* this ensures that mTempFileExtension only contains an extension when it
|
||||
* is different from mSuggestedFileName's extension.
|
||||
*/
|
||||
void EnsureSuggestedFileName();
|
||||
|
||||
typedef enum { kReadError, kWriteError, kLaunchError } ErrorType;
|
||||
/**
|
||||
* Utility function to send proper error notification to web progress listener
|
||||
*/
|
||||
void SendStatusChange(ErrorType type, nsresult aStatus, nsIRequest *aRequest, const nsAFlatString &path);
|
||||
|
||||
/**
|
||||
* Closes the window context if it does not have a refresh header
|
||||
* and it never displayed content before the external helper app
|
||||
* service was invoked.
|
||||
*/
|
||||
nsresult MaybeCloseWindow();
|
||||
|
||||
/**
|
||||
* Set in nsHelperDlgApp.js. This is always null after the user has chosen an
|
||||
* action.
|
||||
*/
|
||||
nsCOMPtr<nsIWebProgressListener2> mDialogProgressListener;
|
||||
/**
|
||||
* Set once the user has chosen an action. This is null after the download
|
||||
* has been canceled or completes.
|
||||
*/
|
||||
nsCOMPtr<nsITransfer> mTransfer;
|
||||
|
||||
nsCOMPtr<nsIChannel> mOriginalChannel; /**< in the case of a redirect, this will be the pre-redirect channel. */
|
||||
nsCOMPtr<nsIHelperAppLauncherDialog> mDialog;
|
||||
|
||||
/**
|
||||
* Keep request alive in case when helper non-modal dialog shown.
|
||||
* Thus in OnStopRequest the mRequest will not be set to null (it will be set to null further).
|
||||
*/
|
||||
bool mKeepRequestAlive;
|
||||
|
||||
/**
|
||||
* The request that's being loaded. Initialized in OnStartRequest.
|
||||
* Nulled out in OnStopRequest or once we know what we're doing
|
||||
* with the data, whichever happens later.
|
||||
*/
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
|
||||
RefPtr<nsExternalHelperAppService> mExtProtSvc;
|
||||
};
|
||||
|
||||
#endif // nsExternalHelperAppService_h__
|
||||
561
uriloader/exthandler/nsExternalProtocolHandler.cpp
Normal file
561
uriloader/exthandler/nsExternalProtocolHandler.cpp
Normal file
|
|
@ -0,0 +1,561 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:set ts=2 sts=2 sw=2 et cin:
|
||||
*
|
||||
* 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 "nsIURI.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsExternalProtocolHandler.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrompt.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "nsExternalHelperAppService.h"
|
||||
|
||||
// used to dispatch urls to default protocol handlers
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsIExternalProtocolService.h"
|
||||
#include "nsIChildChannel.h"
|
||||
#include "nsIParentChannel.h"
|
||||
|
||||
class nsILoadInfo;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// a stub channel implemenation which will map calls to AsyncRead and OpenInputStream
|
||||
// to calls in the OS for loading the url.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsExtProtocolChannel : public nsIChannel,
|
||||
public nsIChildChannel,
|
||||
public nsIParentChannel
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSICHANNEL
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSICHILDCHANNEL
|
||||
NS_DECL_NSIPARENTCHANNEL
|
||||
|
||||
nsExtProtocolChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo);
|
||||
|
||||
private:
|
||||
virtual ~nsExtProtocolChannel();
|
||||
|
||||
nsresult OpenURL();
|
||||
void Finish(nsresult aResult);
|
||||
|
||||
nsCOMPtr<nsIURI> mUrl;
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
nsresult mStatus;
|
||||
nsLoadFlags mLoadFlags;
|
||||
bool mWasOpened;
|
||||
// Set true (as a result of ConnectParent invoked from child process)
|
||||
// when this channel is on the parent process and is being used as
|
||||
// a redirect target channel. It turns AsyncOpen into a no-op since
|
||||
// we do it on the child.
|
||||
bool mConnectedParent;
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
nsCOMPtr<nsILoadInfo> mLoadInfo;
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF(nsExtProtocolChannel)
|
||||
NS_IMPL_RELEASE(nsExtProtocolChannel)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsExtProtocolChannel)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequest)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChildChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIParentChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_END_THREADSAFE
|
||||
|
||||
nsExtProtocolChannel::nsExtProtocolChannel(nsIURI* aURI,
|
||||
nsILoadInfo* aLoadInfo)
|
||||
: mUrl(aURI)
|
||||
, mOriginalURI(aURI)
|
||||
, mStatus(NS_OK)
|
||||
, mLoadFlags(nsIRequest::LOAD_NORMAL)
|
||||
, mWasOpened(false)
|
||||
, mConnectedParent(false)
|
||||
, mLoadInfo(aLoadInfo)
|
||||
{
|
||||
}
|
||||
|
||||
nsExtProtocolChannel::~nsExtProtocolChannel()
|
||||
{}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
|
||||
{
|
||||
NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
|
||||
{
|
||||
mLoadGroup = aLoadGroup;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
|
||||
{
|
||||
NS_IF_ADDREF(*aCallbacks = mCallbacks);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
|
||||
{
|
||||
mCallbacks = aCallbacks;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExtProtocolChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
|
||||
{
|
||||
*aSecurityInfo = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetOriginalURI(nsIURI* *aURI)
|
||||
{
|
||||
NS_ADDREF(*aURI = mOriginalURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetOriginalURI(nsIURI* aURI)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
mOriginalURI = aURI;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetURI(nsIURI* *aURI)
|
||||
{
|
||||
*aURI = mUrl;
|
||||
NS_IF_ADDREF(*aURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsExtProtocolChannel::OpenURL()
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
|
||||
|
||||
if (extProtService)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
nsAutoCString urlScheme;
|
||||
mUrl->GetScheme(urlScheme);
|
||||
bool haveHandler = false;
|
||||
extProtService->ExternalProtocolHandlerExists(urlScheme.get(), &haveHandler);
|
||||
NS_ASSERTION(haveHandler, "Why do we have a channel for this url if we don't support the protocol?");
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> aggCallbacks;
|
||||
rv = NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
|
||||
getter_AddRefs(aggCallbacks));
|
||||
if (NS_FAILED(rv)) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
rv = extProtService->LoadURI(mUrl, aggCallbacks);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// despite success, we need to abort this channel, at the very least
|
||||
// to make it clear to the caller that no on{Start,Stop}Request
|
||||
// should be expected.
|
||||
rv = NS_ERROR_NO_CONTENT;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
mCallbacks = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::Open(nsIInputStream **_retval)
|
||||
{
|
||||
return OpenURL();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::Open2(nsIInputStream** aStream)
|
||||
{
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return Open(aStream);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
||||
{
|
||||
if (mConnectedParent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
NS_ENSURE_ARG_POINTER(listener);
|
||||
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
|
||||
|
||||
mWasOpened = true;
|
||||
|
||||
return OpenURL();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen2(nsIStreamListener *aListener)
|
||||
{
|
||||
nsCOMPtr<nsIStreamListener> listener = aListener;
|
||||
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AsyncOpen(listener, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
||||
{
|
||||
*aLoadFlags = mLoadFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
|
||||
{
|
||||
mLoadFlags = aLoadFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetContentType(nsACString &aContentType)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetContentType(const nsACString &aContentType)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetContentCharset(nsACString &aContentCharset)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetContentCharset(const nsACString &aContentCharset)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetContentDisposition(uint32_t *aContentDisposition)
|
||||
{
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetContentDisposition(uint32_t aContentDisposition)
|
||||
{
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
|
||||
{
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
|
||||
{
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
|
||||
{
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetContentLength(int64_t * aContentLength)
|
||||
{
|
||||
*aContentLength = -1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExtProtocolChannel::SetContentLength(int64_t aContentLength)
|
||||
{
|
||||
NS_NOTREACHED("SetContentLength");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetOwner(nsISupports * *aPrincipal)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetOwner(nsISupports * aPrincipal)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetLoadInfo(nsILoadInfo **aLoadInfo)
|
||||
{
|
||||
NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetLoadInfo(nsILoadInfo *aLoadInfo)
|
||||
{
|
||||
mLoadInfo = aLoadInfo;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// From nsIRequest
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetName(nsACString &result)
|
||||
{
|
||||
return mUrl->GetSpec(result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::IsPending(bool *result)
|
||||
{
|
||||
*result = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetStatus(nsresult *status)
|
||||
{
|
||||
*status = mStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::Cancel(nsresult status)
|
||||
{
|
||||
mStatus = status;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::Suspend()
|
||||
{
|
||||
NS_NOTREACHED("Suspend");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::Resume()
|
||||
{
|
||||
NS_NOTREACHED("Resume");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// From nsIChildChannel
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::ConnectParent(uint32_t registrarId)
|
||||
{
|
||||
mozilla::dom::ContentChild::GetSingleton()->
|
||||
SendExtProtocolChannelConnectParent(registrarId);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::CompleteRedirectSetup(nsIStreamListener *listener,
|
||||
nsISupports *context)
|
||||
{
|
||||
// For redirects to external protocols we AsyncOpen on the child
|
||||
// (not the parent) because child channel has the right docshell
|
||||
// (which is needed for the select dialog).
|
||||
return AsyncOpen(listener, context);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// From nsIParentChannel (derives from nsIStreamListener)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetParentListener(HttpChannelParentListener* aListener)
|
||||
{
|
||||
// This is called as part of the connect parent operation from
|
||||
// ContentParent::RecvExtProtocolChannelConnectParent. Setting
|
||||
// this flag tells this channel to not proceed and makes AsyncOpen
|
||||
// just no-op. Actual operation will happen from the child process
|
||||
// via CompleteRedirectSetup call on the child channel.
|
||||
mConnectedParent = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::NotifyTrackingProtectionDisabled()
|
||||
{
|
||||
// nothing to do
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::Delete()
|
||||
{
|
||||
// nothing to do
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::OnStartRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext)
|
||||
{
|
||||
// no data is expected
|
||||
MOZ_CRASH("No data expected from external protocol channel");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::OnStopRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsresult aStatusCode)
|
||||
{
|
||||
// no data is expected
|
||||
MOZ_CRASH("No data expected from external protocol channel");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::OnDataAvailable(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsIInputStream *aInputStream,
|
||||
uint64_t aOffset,
|
||||
uint32_t aCount)
|
||||
{
|
||||
// no data is expected
|
||||
MOZ_CRASH("No data expected from external protocol channel");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// the default protocol handler implementation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsExternalProtocolHandler::nsExternalProtocolHandler()
|
||||
{
|
||||
m_schemeName = "default";
|
||||
}
|
||||
|
||||
|
||||
nsExternalProtocolHandler::~nsExternalProtocolHandler()
|
||||
{}
|
||||
|
||||
NS_IMPL_ADDREF(nsExternalProtocolHandler)
|
||||
NS_IMPL_RELEASE(nsExternalProtocolHandler)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsExternalProtocolHandler)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIProtocolHandler)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIExternalProtocolHandler)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END_THREADSAFE
|
||||
|
||||
NS_IMETHODIMP nsExternalProtocolHandler::GetScheme(nsACString &aScheme)
|
||||
{
|
||||
aScheme = m_schemeName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExternalProtocolHandler::GetDefaultPort(int32_t *aDefaultPort)
|
||||
{
|
||||
*aDefaultPort = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExternalProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
|
||||
{
|
||||
// don't override anything.
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
// returns TRUE if the OS can handle this protocol scheme and false otherwise.
|
||||
bool nsExternalProtocolHandler::HaveExternalProtocolHandler(nsIURI * aURI)
|
||||
{
|
||||
MOZ_ASSERT(aURI);
|
||||
nsAutoCString scheme;
|
||||
aURI->GetScheme(scheme);
|
||||
|
||||
nsCOMPtr<nsIExternalProtocolService> extProtSvc(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
|
||||
if (!extProtSvc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool haveHandler = false;
|
||||
extProtSvc->ExternalProtocolHandlerExists(scheme.get(), &haveHandler);
|
||||
return haveHandler;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExternalProtocolHandler::GetProtocolFlags(uint32_t *aUritype)
|
||||
{
|
||||
// Make it norelative since it is a simple uri
|
||||
*aUritype = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE |
|
||||
URI_NON_PERSISTABLE | URI_DOES_NOT_RETURN_DATA;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExternalProtocolHandler::NewURI(const nsACString &aSpec,
|
||||
const char *aCharset, // ignore charset info
|
||||
nsIURI *aBaseURI,
|
||||
nsIURI **_retval)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = uri->SetSpec(aSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_retval = uri);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExternalProtocolHandler::NewChannel2(nsIURI* aURI,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** aRetval)
|
||||
{
|
||||
NS_ENSURE_TRUE(aURI, NS_ERROR_UNKNOWN_PROTOCOL);
|
||||
NS_ENSURE_TRUE(aRetval, NS_ERROR_UNKNOWN_PROTOCOL);
|
||||
|
||||
// Only try to return a channel if we have a protocol handler for the url.
|
||||
// nsOSHelperAppService::LoadUriInternal relies on this to check trustedness
|
||||
// for some platforms at least. (win uses ::ShellExecute and unix uses
|
||||
// gnome_url_show.)
|
||||
if (!HaveExternalProtocolHandler(aURI)) {
|
||||
return NS_ERROR_UNKNOWN_PROTOCOL;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel = new nsExtProtocolChannel(aURI, aLoadInfo);
|
||||
channel.forget(aRetval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExternalProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
|
||||
{
|
||||
return NewChannel2(aURI, nullptr, _retval);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// External protocol handler interface implementation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
NS_IMETHODIMP nsExternalProtocolHandler::ExternalAppExistsForScheme(const nsACString& aScheme, bool *_retval)
|
||||
{
|
||||
nsCOMPtr<nsIExternalProtocolService> extProtSvc(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
|
||||
if (extProtSvc)
|
||||
return extProtSvc->ExternalProtocolHandlerExists(
|
||||
PromiseFlatCString(aScheme).get(), _retval);
|
||||
|
||||
// In case we don't have external protocol service.
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
38
uriloader/exthandler/nsExternalProtocolHandler.h
Normal file
38
uriloader/exthandler/nsExternalProtocolHandler.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 nsExternalProtocolHandler_h___
|
||||
#define nsExternalProtocolHandler_h___
|
||||
|
||||
#include "nsIExternalProtocolHandler.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIExternalProtocolService.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIURI;
|
||||
|
||||
// protocol handlers need to support weak references if we want the netlib nsIOService to cache them.
|
||||
class nsExternalProtocolHandler final : public nsIExternalProtocolHandler, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIPROTOCOLHANDLER
|
||||
NS_DECL_NSIEXTERNALPROTOCOLHANDLER
|
||||
|
||||
nsExternalProtocolHandler();
|
||||
|
||||
protected:
|
||||
~nsExternalProtocolHandler();
|
||||
|
||||
// helper function
|
||||
bool HaveExternalProtocolHandler(nsIURI * aURI);
|
||||
nsCString m_schemeName;
|
||||
};
|
||||
|
||||
#endif // nsExternalProtocolHandler_h___
|
||||
|
||||
1429
uriloader/exthandler/nsHandlerService.js
Normal file
1429
uriloader/exthandler/nsHandlerService.js
Normal file
File diff suppressed because it is too large
Load diff
2
uriloader/exthandler/nsHandlerService.manifest
Normal file
2
uriloader/exthandler/nsHandlerService.manifest
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
component {32314cc8-22f7-4f7f-a645-1a45453ba6a6} nsHandlerService.js
|
||||
contract @mozilla.org/uriloader/handler-service;1 {32314cc8-22f7-4f7f-a645-1a45453ba6a6} process=main
|
||||
45
uriloader/exthandler/nsIContentDispatchChooser.idl
Normal file
45
uriloader/exthandler/nsIContentDispatchChooser.idl
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* 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"
|
||||
|
||||
interface nsIHandlerInfo;
|
||||
interface nsIHelperAppLauncher;
|
||||
interface nsIURI;
|
||||
interface nsIInterfaceRequestor;
|
||||
|
||||
/**
|
||||
* This is used to ask a user what they would like to do with a given piece of
|
||||
* content.
|
||||
*/
|
||||
[scriptable, uuid(456ca3b2-02be-4f97-89a2-08c08d3ad88f)]
|
||||
interface nsIContentDispatchChooser : nsISupports {
|
||||
/**
|
||||
* This request is passed to the helper app dialog because Gecko can not
|
||||
* handle content of this type.
|
||||
*/
|
||||
const unsigned long REASON_CANNOT_HANDLE = 0;
|
||||
|
||||
/**
|
||||
* Asks the user what to do with the content.
|
||||
*
|
||||
* @param aHander
|
||||
* The interface describing the details of how this content should or
|
||||
* can be handled.
|
||||
* @param aWindowContext
|
||||
* The parent window context to show this chooser. This can be null,
|
||||
* and some implementations may not care about it. Generally, you'll
|
||||
* want to pass an nsIDOMWindow in so the chooser can be properly
|
||||
* parented when opened.
|
||||
* @param aURI
|
||||
* The URI of the resource that we are asking about.
|
||||
* @param aReason
|
||||
* The reason why we are asking (see above).
|
||||
*/
|
||||
void ask(in nsIHandlerInfo aHandler,
|
||||
in nsIInterfaceRequestor aWindowContext,
|
||||
in nsIURI aURI,
|
||||
in unsigned long aReason);
|
||||
};
|
||||
|
||||
154
uriloader/exthandler/nsIExternalHelperAppService.idl
Normal file
154
uriloader/exthandler/nsIExternalHelperAppService.idl
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 "nsICancelable.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIRequest;
|
||||
interface nsIStreamListener;
|
||||
interface nsIFile;
|
||||
interface nsIMIMEInfo;
|
||||
interface nsIWebProgressListener2;
|
||||
interface nsIInterfaceRequestor;
|
||||
|
||||
/**
|
||||
* The external helper app service is used for finding and launching
|
||||
* platform specific external applications for a given mime content type.
|
||||
*/
|
||||
[scriptable, uuid(1E4F3AE1-B737-431F-A95D-31FA8DA70199)]
|
||||
interface nsIExternalHelperAppService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Binds an external helper application to a stream listener. The caller
|
||||
* should pump data into the returned stream listener. When the OnStopRequest
|
||||
* is issued, the stream listener implementation will launch the helper app
|
||||
* with this data.
|
||||
* @param aMimeContentType The content type of the incoming data
|
||||
* @param aRequest The request corresponding to the incoming data
|
||||
* @param aContentContext Used in processing content document refresh
|
||||
* headers after target content is downloaded. Note in e10s land
|
||||
* this is likely a CPOW that points to a window in the child process.
|
||||
* @param aForceSave True to always save this content to disk, regardless of
|
||||
* nsIMIMEInfo and other such influences.
|
||||
* @param aWindowContext Used in parenting helper app dialogs, usually
|
||||
* points to the parent browser window. This parameter may be null,
|
||||
* in which case dialogs will be parented to aContentContext.
|
||||
* @return A nsIStreamListener which the caller should pump the data into.
|
||||
*/
|
||||
nsIStreamListener doContent (in ACString aMimeContentType,
|
||||
in nsIRequest aRequest,
|
||||
in nsIInterfaceRequestor aContentContext,
|
||||
in boolean aForceSave,
|
||||
[optional] in nsIInterfaceRequestor aWindowContext);
|
||||
|
||||
/**
|
||||
* Returns true if data from a URL with this extension combination
|
||||
* is to be decoded from aEncodingType prior to saving or passing
|
||||
* off to helper apps, false otherwise.
|
||||
*/
|
||||
boolean applyDecodingForExtension(in AUTF8String aExtension,
|
||||
in ACString aEncodingType);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a private interface shared between external app handlers and the platform specific
|
||||
* external helper app service
|
||||
*/
|
||||
[scriptable, uuid(6613e2e7-feab-4e3a-bb1f-b03200d544ec)]
|
||||
interface nsPIExternalAppLauncher : nsISupports
|
||||
{
|
||||
/**
|
||||
* mscott --> eventually I should move this into a new service so other
|
||||
* consumers can add temporary files they want deleted on exit.
|
||||
* @param aTemporaryFile A temporary file we should delete on exit.
|
||||
*/
|
||||
void deleteTemporaryFileOnExit(in nsIFile aTemporaryFile);
|
||||
/**
|
||||
* Delete a temporary file created inside private browsing mode when
|
||||
* the private browsing mode has ended.
|
||||
*/
|
||||
void deleteTemporaryPrivateFileWhenPossible(in nsIFile aTemporaryFile);
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper app launcher is a small object created to handle the launching
|
||||
* of an external application.
|
||||
*
|
||||
* Note that cancelling the load via the nsICancelable interface will release
|
||||
* the reference to the launcher dialog.
|
||||
*/
|
||||
[scriptable, uuid(acf2a516-7d7f-4771-8b22-6c4a559c088e)]
|
||||
interface nsIHelperAppLauncher : nsICancelable
|
||||
{
|
||||
/**
|
||||
* The mime info object associated with the content type this helper app
|
||||
* launcher is currently attempting to load
|
||||
*/
|
||||
readonly attribute nsIMIMEInfo MIMEInfo;
|
||||
|
||||
/**
|
||||
* The source uri
|
||||
*/
|
||||
readonly attribute nsIURI source;
|
||||
|
||||
/**
|
||||
* The suggested name for this file
|
||||
*/
|
||||
readonly attribute AString suggestedFileName;
|
||||
|
||||
/**
|
||||
* Saves the final destination of the file. Does not actually perform the
|
||||
* save.
|
||||
* NOTE: This will release the reference to the
|
||||
* nsIHelperAppLauncherDialog.
|
||||
*/
|
||||
void saveToDisk(in nsIFile aNewFileLocation, in boolean aRememberThisPreference);
|
||||
|
||||
/**
|
||||
* Remembers that aApplication should be used to launch this content. Does
|
||||
* not actually launch the application.
|
||||
* NOTE: This will release the reference to the nsIHelperAppLauncherDialog.
|
||||
* @param aApplication nsIFile corresponding to the location of the application to use.
|
||||
* @param aRememberThisPreference TRUE if we should remember this choice.
|
||||
*/
|
||||
void launchWithApplication(in nsIFile aApplication, in boolean aRememberThisPreference);
|
||||
|
||||
/**
|
||||
* Callback invoked by nsIHelperAppLauncherDialog::promptForSaveToFileAsync
|
||||
* after the user has chosen a file through the File Picker (or dismissed it).
|
||||
* @param aFile The file that was chosen by the user (or null if dialog was dismissed).
|
||||
*/
|
||||
void saveDestinationAvailable(in nsIFile aFile);
|
||||
|
||||
/**
|
||||
* The following methods are used by the progress dialog to get or set
|
||||
* information on the current helper app launcher download.
|
||||
* This reference will be released when the download is finished (after the
|
||||
* listener receives the STATE_STOP notification).
|
||||
*/
|
||||
void setWebProgressListener(in nsIWebProgressListener2 aWebProgressListener);
|
||||
|
||||
/**
|
||||
* The file we are saving to
|
||||
*/
|
||||
readonly attribute nsIFile targetFile;
|
||||
|
||||
/**
|
||||
* The executable-ness of the target file
|
||||
*/
|
||||
readonly attribute boolean targetFileIsExecutable;
|
||||
|
||||
/**
|
||||
* Time when the download started
|
||||
*/
|
||||
readonly attribute PRTime timeDownloadStarted;
|
||||
|
||||
/**
|
||||
* The download content length, or -1 if the length is not available.
|
||||
*/
|
||||
readonly attribute int64_t contentLength;
|
||||
};
|
||||
135
uriloader/exthandler/nsIExternalProtocolService.idl
Normal file
135
uriloader/exthandler/nsIExternalProtocolService.idl
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIFile;
|
||||
interface nsIInterfaceRequestor;
|
||||
interface nsIHandlerInfo;
|
||||
|
||||
/**
|
||||
* The external protocol service is used for finding and launching
|
||||
* web handlers (a la registerProtocolHandler in the HTML5 draft) or
|
||||
* platform-specific applications for handling particular protocols.
|
||||
*
|
||||
* You can ask the external protocol service if it has an external
|
||||
* handler for a given protocol scheme. And you can ask it to load
|
||||
* the url using the default handler.
|
||||
*/
|
||||
[scriptable, uuid(70f93b7a-3ec6-4bcb-b093-92d9984c9f83)]
|
||||
interface nsIExternalProtocolService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Check whether a handler for a specific protocol exists. Specifically,
|
||||
* this looks to see whether there are any known possible application handlers
|
||||
* in either the nsIHandlerService datastore or registered with the OS.
|
||||
*
|
||||
* @param aProtocolScheme The scheme from a url: http, ftp, mailto, etc.
|
||||
*
|
||||
* @return true if we have a handler and false otherwise.
|
||||
*
|
||||
* XXX shouldn't aProtocolScheme be an ACString like nsIURI::scheme?
|
||||
*/
|
||||
boolean externalProtocolHandlerExists(in string aProtocolScheme);
|
||||
|
||||
/**
|
||||
* Check whether a handler for a specific protocol is "exposed" as a visible
|
||||
* feature of the current application.
|
||||
*
|
||||
* An exposed protocol handler is one that can be used in all contexts. A
|
||||
* non-exposed protocol handler is one that can only be used internally by the
|
||||
* application. For example, a non-exposed protocol would not be loaded by the
|
||||
* application in response to a link click or a X-remote openURL command.
|
||||
* Instead, it would be deferred to the system's external protocol handler.
|
||||
* XXX shouldn't aProtocolScheme be an ACString like nsIURI::scheme?
|
||||
*/
|
||||
boolean isExposedProtocol(in string aProtocolScheme);
|
||||
|
||||
/**
|
||||
* Retrieve the handler for the given protocol. If neither the application
|
||||
* nor the OS knows about a handler for the protocol, the object this method
|
||||
* returns will represent a default handler for unknown content.
|
||||
*
|
||||
* @param aProtocolScheme the scheme from a URL: http, ftp, mailto, etc.
|
||||
*
|
||||
* Note: aProtocolScheme should not include a trailing colon, which is part
|
||||
* of the URI syntax, not part of the scheme itself (i.e. pass "mailto" not
|
||||
* "mailto:").
|
||||
*
|
||||
* @return the handler, if any; otherwise a default handler
|
||||
*/
|
||||
nsIHandlerInfo getProtocolHandlerInfo(in ACString aProtocolScheme);
|
||||
|
||||
/**
|
||||
* Given a scheme, looks up the protocol info from the OS. This should be
|
||||
* overridden by each OS's implementation.
|
||||
*
|
||||
* @param aScheme The protocol scheme we are looking for.
|
||||
* @param aFound Was an OS default handler for this scheme found?
|
||||
* @return An nsIHanderInfo for the protocol.
|
||||
*/
|
||||
nsIHandlerInfo getProtocolHandlerInfoFromOS(in ACString aProtocolScheme,
|
||||
out boolean aFound);
|
||||
|
||||
/**
|
||||
* Set some sane defaults for a protocol handler object.
|
||||
*
|
||||
* @param aHandlerInfo nsIHandlerInfo object, as returned by
|
||||
* getProtocolHandlerInfoFromOS
|
||||
* @param aOSHandlerExists was the object above created for an extant
|
||||
* OS default handler? This is generally the
|
||||
* value of the aFound out param from
|
||||
* getProtocolHandlerInfoFromOS.
|
||||
*/
|
||||
void setProtocolHandlerDefaults(in nsIHandlerInfo aHandlerInfo,
|
||||
in boolean aOSHandlerExists);
|
||||
|
||||
/**
|
||||
* Used to load a url via an external protocol handler (if one exists)
|
||||
*
|
||||
* @param aURL The url to load
|
||||
*
|
||||
* @deprecated Use LoadURI instead (See Bug 389565 for removal)
|
||||
*/
|
||||
[deprecated] void loadUrl(in nsIURI aURL);
|
||||
|
||||
/**
|
||||
* Used to load a URI via an external application. Might prompt the user for
|
||||
* permission to load the external application.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI to load
|
||||
*
|
||||
* @param aWindowContext
|
||||
* The window to parent the dialog against, and, if a web handler
|
||||
* is chosen, it is loaded in this window as well. This parameter
|
||||
* may be ultimately passed nsIURILoader.openURI in the case of a
|
||||
* web handler, and aWindowContext is null or not present, web
|
||||
* handlers will fail. We need to do better than that; bug 394483
|
||||
* filed in order to track.
|
||||
*
|
||||
* @note Embedders that do not expose the http protocol should not currently
|
||||
* use web-based protocol handlers, as handoff won't work correctly
|
||||
* (bug 394479).
|
||||
*/
|
||||
void loadURI(in nsIURI aURI,
|
||||
[optional] in nsIInterfaceRequestor aWindowContext);
|
||||
|
||||
/**
|
||||
* Gets a human-readable description for the application responsible for
|
||||
* handling a specific protocol.
|
||||
*
|
||||
* @param aScheme The scheme to look up. For example, "mms".
|
||||
*
|
||||
* @throw NS_ERROR_NOT_IMPLEMENTED
|
||||
* If getting descriptions for protocol helpers is not supported
|
||||
* @throw NS_ERROR_NOT_AVAILABLE
|
||||
* If no protocol helper exists for this scheme, or if it is not
|
||||
* possible to get a description for it.
|
||||
*/
|
||||
AString getApplicationDescription(in AUTF8String aScheme);
|
||||
};
|
||||
28
uriloader/exthandler/nsIExternalSharingAppService.idl
Normal file
28
uriloader/exthandler/nsIExternalSharingAppService.idl
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* 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 "nsIMIMEInfo.idl"
|
||||
|
||||
%{C++
|
||||
#define NS_EXTERNALSHARINGAPPSERVICE_CONTRACTID "@mozilla.org/uriloader/external-sharing-app-service;1"
|
||||
%}
|
||||
|
||||
|
||||
[scriptable, uuid(7111f769-53ec-41fd-b314-613661d5b6ba)]
|
||||
interface nsISharingHandlerApp : nsIHandlerApp
|
||||
{
|
||||
void share(in AString data, [optional] in AString title);
|
||||
};
|
||||
|
||||
[scriptable, uuid(cf7d04e5-3892-482e-81bb-073dc1c83f76)]
|
||||
interface nsIExternalSharingAppService : nsISupports {
|
||||
void shareWithDefault(in AString data, in AString mime,
|
||||
[optional] in AString title);
|
||||
|
||||
void getSharingApps(in AString aMIMEType,
|
||||
[optional] out unsigned long aLen,
|
||||
[array, size_is(aLen), retval] out nsISharingHandlerApp handlerApps);
|
||||
};
|
||||
|
||||
|
||||
26
uriloader/exthandler/nsIExternalURLHandlerService.idl
Normal file
26
uriloader/exthandler/nsIExternalURLHandlerService.idl
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* 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 "nsIMIMEInfo.idl"
|
||||
|
||||
/**
|
||||
* The external URL handler service is used for finding
|
||||
* platform-specific applications for handling particular URLs.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(56c5c7d3-6fd3-43f8-9429-4397e111453a)]
|
||||
interface nsIExternalURLHandlerService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Given a URL, looks up the handler info from the OS. This should be
|
||||
* overridden by each OS's implementation.
|
||||
*
|
||||
* @param aURL The URL we are looking for.
|
||||
* @param aFound Was an OS default handler for this URL found?
|
||||
* @return An nsIHanderInfo for the protocol.
|
||||
*/
|
||||
nsIHandlerInfo getURLHandlerInfoFromOS(in nsIURI aURL,
|
||||
out boolean aFound);
|
||||
|
||||
};
|
||||
117
uriloader/exthandler/nsIHandlerService.idl
Normal file
117
uriloader/exthandler/nsIHandlerService.idl
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/* 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"
|
||||
|
||||
interface nsIHandlerInfo;
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
[scriptable, uuid(53f0ad17-ec62-46a1-adbc-efccc06babcd)]
|
||||
interface nsIHandlerService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Retrieve a list of all handlers in the datastore. This list is not
|
||||
* guaranteed to be in any particular order, and callers should not assume
|
||||
* it will remain in the same order in the future.
|
||||
*
|
||||
* @returns a list of all handlers in the datastore
|
||||
*/
|
||||
nsISimpleEnumerator enumerate();
|
||||
|
||||
/**
|
||||
* Fill a handler info object with information from the datastore.
|
||||
*
|
||||
* Note: because of the way the external helper app service currently mixes
|
||||
* OS and user handler info in the same handler info object, this method
|
||||
* takes an existing handler info object (probably retrieved from the OS)
|
||||
* and "fills it in" with information from the datastore, overriding any
|
||||
* existing properties on the object with properties from the datastore.
|
||||
*
|
||||
* Ultimately, however, we're going to separate OS and user handler info
|
||||
* into separate objects, at which point this method should be renamed to
|
||||
* something like "get" or "retrieve", take a class and type (or perhaps
|
||||
* a type whose class can be determined by querying the type, for example
|
||||
* an nsIContentType which is also an nsIMIMEType or an nsIProtocolScheme),
|
||||
* and return a handler info object representing only the user info.
|
||||
*
|
||||
* Note: if you specify an override type, then the service will fill in
|
||||
* the handler info object with information about that type instead of
|
||||
* the type specified by the object's nsIHandlerInfo::type attribute.
|
||||
*
|
||||
* This is useful when you are trying to retrieve information about a MIME
|
||||
* type that doesn't exist in the datastore, but you have a file extension
|
||||
* for that type, and nsIHandlerService::getTypeFromExtension returns another
|
||||
* MIME type that does exist in the datastore and can handle that extension.
|
||||
*
|
||||
* For example, the user clicks on a link, and the content has a MIME type
|
||||
* that isn't in the datastore, but the link has a file extension, and that
|
||||
* extension is associated with another MIME type in the datastore (perhaps
|
||||
* an unofficial MIME type preceded an official one, like with image/x-png
|
||||
* and image/png).
|
||||
*
|
||||
* In that situation, you can call this method to fill in the handler info
|
||||
* object with information about that other type by passing the other type
|
||||
* as the aOverrideType parameter.
|
||||
*
|
||||
* @param aHandlerInfo the handler info object
|
||||
* @param aOverrideType a type to use instead of aHandlerInfo::type
|
||||
*
|
||||
* Note: if there is no information in the datastore about this type,
|
||||
* this method throws NS_ERROR_NOT_AVAILABLE. Callers are encouraged to
|
||||
* check exists() before calling fillHandlerInfo(), to prevent spamming the
|
||||
* console with XPCOM exception errors.
|
||||
*/
|
||||
void fillHandlerInfo(in nsIHandlerInfo aHandlerInfo,
|
||||
in ACString aOverrideType);
|
||||
|
||||
/**
|
||||
* Save the preferred action, preferred handler, possible handlers, and
|
||||
* always ask properties of the given handler info object to the datastore.
|
||||
* Updates an existing record or creates a new one if necessary.
|
||||
*
|
||||
* Note: if preferred action is undefined or invalid, then we assume
|
||||
* the default value nsIHandlerInfo::useHelperApp.
|
||||
*
|
||||
* @param aHandlerInfo the handler info object
|
||||
*/
|
||||
void store(in nsIHandlerInfo aHandlerInfo);
|
||||
|
||||
/**
|
||||
* Whether or not a record for the given handler info object exists
|
||||
* in the datastore. If the datastore is corrupt (or some other error
|
||||
* is caught in the implementation), false will be returned.
|
||||
*
|
||||
* @param aHandlerInfo a handler info object
|
||||
*
|
||||
* @returns whether or not a record exists
|
||||
*/
|
||||
boolean exists(in nsIHandlerInfo aHandlerInfo);
|
||||
|
||||
/**
|
||||
* Remove the given handler info object from the datastore. Deletes all
|
||||
* records associated with the object, including the preferred handler, info,
|
||||
* and type records plus the entry in the list of types, if they exist.
|
||||
* Otherwise, it does nothing and does not return an error.
|
||||
*
|
||||
* @param aHandlerInfo the handler info object
|
||||
*/
|
||||
void remove(in nsIHandlerInfo aHandlerInfo);
|
||||
|
||||
/**
|
||||
* Get the MIME type mapped to the given file extension in the datastore.
|
||||
*
|
||||
* XXX If we ever support extension -> protocol scheme mappings, then this
|
||||
* method should work for those as well.
|
||||
*
|
||||
* Note: in general, you should use nsIMIMEService::getTypeFromExtension
|
||||
* to get a MIME type from a file extension, as that method checks a variety
|
||||
* of other sources besides just the datastore. Use this only when you want
|
||||
* to specifically get only the mapping available in the datastore.
|
||||
*
|
||||
* @param aFileExtension the file extension
|
||||
*
|
||||
* @returns the MIME type, if any; otherwise returns an empty string ("").
|
||||
*/
|
||||
ACString getTypeFromExtension(in ACString aFileExtension);
|
||||
};
|
||||
89
uriloader/exthandler/nsIHelperAppLauncherDialog.idl
Normal file
89
uriloader/exthandler/nsIHelperAppLauncherDialog.idl
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/* -*- 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
|
||||
* 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"
|
||||
|
||||
interface nsIHelperAppLauncher;
|
||||
interface nsIFile;
|
||||
|
||||
/**
|
||||
* This interface is used to display a confirmation dialog before
|
||||
* launching a "helper app" to handle content not handled by
|
||||
* Mozilla.
|
||||
*
|
||||
* Usage: Clients (of which there is one: the nsIExternalHelperAppService
|
||||
* implementation in mozilla/uriloader/exthandler) create an instance of
|
||||
* this interface (using the contract ID) and then call the show() method.
|
||||
*
|
||||
* The dialog is shown non-modally. The implementation of the dialog
|
||||
* will access methods of the nsIHelperAppLauncher passed in to show()
|
||||
* in order to cause a "save to disk" or "open using" action.
|
||||
*/
|
||||
[scriptable, uuid(bfc739f3-8d75-4034-a6f8-1039a5996bad)]
|
||||
interface nsIHelperAppLauncherDialog : nsISupports {
|
||||
/**
|
||||
* This request is passed to the helper app dialog because Gecko can not
|
||||
* handle content of this type.
|
||||
*/
|
||||
const unsigned long REASON_CANTHANDLE = 0;
|
||||
|
||||
/**
|
||||
* The server requested external handling.
|
||||
*/
|
||||
const unsigned long REASON_SERVERREQUEST = 1;
|
||||
|
||||
/**
|
||||
* Gecko detected that the type sent by the server (e.g. text/plain) does
|
||||
* not match the actual type.
|
||||
*/
|
||||
const unsigned long REASON_TYPESNIFFED = 2;
|
||||
|
||||
/**
|
||||
* Show confirmation dialog for launching application (or "save to
|
||||
* disk") for content specified by aLauncher.
|
||||
*
|
||||
* @param aLauncher
|
||||
* A nsIHelperAppLauncher to be invoked when a file is selected.
|
||||
* @param aWindowContext
|
||||
* Window associated with action.
|
||||
* @param aReason
|
||||
* One of the constants from above. It indicates why the dialog is
|
||||
* shown. Implementors should treat unknown reasons like
|
||||
* REASON_CANTHANDLE.
|
||||
*/
|
||||
void show(in nsIHelperAppLauncher aLauncher,
|
||||
in nsISupports aWindowContext,
|
||||
in unsigned long aReason);
|
||||
|
||||
/**
|
||||
* Async invoke a save-to-file dialog instead of the full fledged helper app
|
||||
* dialog. When the file is chosen (or the dialog is closed), the callback
|
||||
* in aLauncher (aLauncher.saveDestinationAvailable) is called with the
|
||||
* selected file.
|
||||
*
|
||||
* @param aLauncher
|
||||
* A nsIHelperAppLauncher to be invoked when a file is selected.
|
||||
* @param aWindowContext
|
||||
* Window associated with action.
|
||||
* @param aDefaultFileName
|
||||
* Default file name to provide (can be null)
|
||||
* @param aSuggestedFileExtension
|
||||
* Sugested file extension
|
||||
* @param aForcePrompt
|
||||
* Set to true to force prompting the user for thet file
|
||||
* name/location, otherwise perferences may control if the user is
|
||||
* prompted.
|
||||
*/
|
||||
void promptForSaveToFileAsync(in nsIHelperAppLauncher aLauncher,
|
||||
in nsISupports aWindowContext,
|
||||
in wstring aDefaultFileName,
|
||||
in wstring aSuggestedFileExtension,
|
||||
in boolean aForcePrompt);
|
||||
};
|
||||
|
||||
|
||||
%{C++
|
||||
#define NS_HELPERAPPLAUNCHERDLG_CONTRACTID "@mozilla.org/helperapplauncherdialog;1"
|
||||
%}
|
||||
179
uriloader/exthandler/nsLocalHandlerApp.cpp
Normal file
179
uriloader/exthandler/nsLocalHandlerApp.cpp
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2:cin:
|
||||
* 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 "nsLocalHandlerApp.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIProcess.h"
|
||||
|
||||
// XXX why does nsMIMEInfoImpl have a threadsafe nsISupports? do we need one
|
||||
// here too?
|
||||
NS_IMPL_ISUPPORTS(nsLocalHandlerApp, nsILocalHandlerApp, nsIHandlerApp)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIHandlerApp
|
||||
|
||||
NS_IMETHODIMP nsLocalHandlerApp::GetName(nsAString& aName)
|
||||
{
|
||||
if (mName.IsEmpty() && mExecutable) {
|
||||
// Don't want to cache this, just in case someone resets the app
|
||||
// without changing the description....
|
||||
mExecutable->GetLeafName(aName);
|
||||
} else {
|
||||
aName.Assign(mName);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsLocalHandlerApp::SetName(const nsAString & aName)
|
||||
{
|
||||
mName.Assign(aName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::SetDetailedDescription(const nsAString & aDescription)
|
||||
{
|
||||
mDetailedDescription.Assign(aDescription);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::GetDetailedDescription(nsAString& aDescription)
|
||||
{
|
||||
aDescription.Assign(mDetailedDescription);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::Equals(nsIHandlerApp *aHandlerApp, bool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aHandlerApp);
|
||||
|
||||
*_retval = false;
|
||||
|
||||
// If the handler app isn't a local handler app, then it's not the same app.
|
||||
nsCOMPtr <nsILocalHandlerApp> localHandlerApp = do_QueryInterface(aHandlerApp);
|
||||
if (!localHandlerApp)
|
||||
return NS_OK;
|
||||
|
||||
// If either handler app doesn't have an executable, then they aren't
|
||||
// the same app.
|
||||
nsCOMPtr<nsIFile> executable;
|
||||
nsresult rv = localHandlerApp->GetExecutable(getter_AddRefs(executable));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Equality for two empty nsIHandlerApp
|
||||
if (!executable && !mExecutable) {
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// At least one is set so they are not equal
|
||||
if (!mExecutable || !executable)
|
||||
return NS_OK;
|
||||
|
||||
// Check the command line parameter list lengths
|
||||
uint32_t len;
|
||||
localHandlerApp->GetParameterCount(&len);
|
||||
if (mParameters.Length() != len)
|
||||
return NS_OK;
|
||||
|
||||
// Check the command line params lists
|
||||
for (uint32_t idx = 0; idx < mParameters.Length(); idx++) {
|
||||
nsAutoString param;
|
||||
if (NS_FAILED(localHandlerApp->GetParameter(idx, param)) ||
|
||||
!param.Equals(mParameters[idx]))
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return executable->Equals(mExecutable, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::LaunchWithURI(nsIURI *aURI,
|
||||
nsIInterfaceRequestor *aWindowContext)
|
||||
{
|
||||
// pass the entire URI to the handler.
|
||||
nsAutoCString spec;
|
||||
aURI->GetAsciiSpec(spec);
|
||||
return LaunchWithIProcess(spec);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLocalHandlerApp::LaunchWithIProcess(const nsCString& aArg)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIProcess> process = do_CreateInstance(NS_PROCESS_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (NS_FAILED(rv = process->Init(mExecutable)))
|
||||
return rv;
|
||||
|
||||
const char *string = aArg.get();
|
||||
|
||||
return process->Run(false, &string, 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsILocalHandlerApp
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::GetExecutable(nsIFile **aExecutable)
|
||||
{
|
||||
NS_IF_ADDREF(*aExecutable = mExecutable);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::SetExecutable(nsIFile *aExecutable)
|
||||
{
|
||||
mExecutable = aExecutable;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::GetParameterCount(uint32_t *aParameterCount)
|
||||
{
|
||||
*aParameterCount = mParameters.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::ClearParameters()
|
||||
{
|
||||
mParameters.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::AppendParameter(const nsAString & aParam)
|
||||
{
|
||||
mParameters.AppendElement(aParam);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::GetParameter(uint32_t parameterIndex, nsAString & _retval)
|
||||
{
|
||||
if (mParameters.Length() <= parameterIndex)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
_retval.Assign(mParameters[parameterIndex]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerApp::ParameterExists(const nsAString & aParam, bool *_retval)
|
||||
{
|
||||
*_retval = mParameters.Contains(aParam);
|
||||
return NS_OK;
|
||||
}
|
||||
60
uriloader/exthandler/nsLocalHandlerApp.h
Normal file
60
uriloader/exthandler/nsLocalHandlerApp.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2:cin:
|
||||
* 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 __nsLocalHandlerAppImpl_h__
|
||||
#define __nsLocalHandlerAppImpl_h__
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsLocalHandlerApp : public nsILocalHandlerApp
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHANDLERAPP
|
||||
NS_DECL_NSILOCALHANDLERAPP
|
||||
|
||||
nsLocalHandlerApp() { }
|
||||
|
||||
nsLocalHandlerApp(const char16_t *aName, nsIFile *aExecutable)
|
||||
: mName(aName), mExecutable(aExecutable) { }
|
||||
|
||||
nsLocalHandlerApp(const nsAString & aName, nsIFile *aExecutable)
|
||||
: mName(aName), mExecutable(aExecutable) { }
|
||||
|
||||
protected:
|
||||
virtual ~nsLocalHandlerApp() { }
|
||||
|
||||
nsString mName;
|
||||
nsString mDetailedDescription;
|
||||
nsTArray<nsString> mParameters;
|
||||
nsCOMPtr<nsIFile> mExecutable;
|
||||
|
||||
/**
|
||||
* Launches this application with a single argument (typically either
|
||||
* a file path or a URI spec). This is meant as a helper method for
|
||||
* implementations of (e.g.) LaunchWithURI.
|
||||
*
|
||||
* @param aApp The application to launch (may not be null)
|
||||
* @param aArg The argument to pass on the command line
|
||||
*/
|
||||
nsresult LaunchWithIProcess(const nsCString &aArg);
|
||||
};
|
||||
|
||||
// any platforms that need a platform-specific class instead of just
|
||||
// using nsLocalHandlerApp need to add an include and a typedef here.
|
||||
#ifdef XP_MACOSX
|
||||
# ifndef NSLOCALHANDLERAPPMAC_H_
|
||||
# include "mac/nsLocalHandlerAppMac.h"
|
||||
typedef nsLocalHandlerAppMac PlatformLocalHandlerApp_t;
|
||||
# endif
|
||||
#else
|
||||
typedef nsLocalHandlerApp PlatformLocalHandlerApp_t;
|
||||
#endif
|
||||
|
||||
#endif // __nsLocalHandlerAppImpl_h__
|
||||
435
uriloader/exthandler/nsMIMEInfoImpl.cpp
Normal file
435
uriloader/exthandler/nsMIMEInfoImpl.cpp
Normal file
|
|
@ -0,0 +1,435 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* 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 "nsMIMEInfoImpl.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsStringEnumerator.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsIURILoader.h"
|
||||
#include "nsCURILoader.h"
|
||||
|
||||
// nsISupports methods
|
||||
NS_IMPL_ADDREF(nsMIMEInfoBase)
|
||||
NS_IMPL_RELEASE(nsMIMEInfoBase)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsMIMEInfoBase)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIHandlerInfo)
|
||||
// This is only an nsIMIMEInfo if it's a MIME handler.
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMIMEInfo, mClass == eMIMEInfo)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHandlerInfo)
|
||||
NS_INTERFACE_MAP_END_THREADSAFE
|
||||
|
||||
// nsMIMEInfoImpl methods
|
||||
|
||||
// Constructors for a MIME handler.
|
||||
nsMIMEInfoBase::nsMIMEInfoBase(const char *aMIMEType) :
|
||||
mSchemeOrType(aMIMEType),
|
||||
mClass(eMIMEInfo),
|
||||
mPreferredAction(nsIMIMEInfo::saveToDisk),
|
||||
mAlwaysAskBeforeHandling(true)
|
||||
{
|
||||
}
|
||||
|
||||
nsMIMEInfoBase::nsMIMEInfoBase(const nsACString& aMIMEType) :
|
||||
mSchemeOrType(aMIMEType),
|
||||
mClass(eMIMEInfo),
|
||||
mPreferredAction(nsIMIMEInfo::saveToDisk),
|
||||
mAlwaysAskBeforeHandling(true)
|
||||
{
|
||||
}
|
||||
|
||||
// Constructor for a handler that lets the caller specify whether this is a
|
||||
// MIME handler or a protocol handler. In the long run, these will be distinct
|
||||
// classes (f.e. nsMIMEInfo and nsProtocolInfo), but for now we reuse this class
|
||||
// for both and distinguish between the two kinds of handlers via the aClass
|
||||
// argument to this method, which can be either eMIMEInfo or eProtocolInfo.
|
||||
nsMIMEInfoBase::nsMIMEInfoBase(const nsACString& aType, HandlerClass aClass) :
|
||||
mSchemeOrType(aType),
|
||||
mClass(aClass),
|
||||
mPreferredAction(nsIMIMEInfo::saveToDisk),
|
||||
mAlwaysAskBeforeHandling(true)
|
||||
{
|
||||
}
|
||||
|
||||
nsMIMEInfoBase::~nsMIMEInfoBase()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetFileExtensions(nsIUTF8StringEnumerator** aResult)
|
||||
{
|
||||
return NS_NewUTF8StringEnumerator(aResult, &mExtensions, this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::ExtensionExists(const nsACString& aExtension, bool *_retval)
|
||||
{
|
||||
NS_ASSERTION(!aExtension.IsEmpty(), "no extension");
|
||||
bool found = false;
|
||||
uint32_t extCount = mExtensions.Length();
|
||||
if (extCount < 1) return NS_OK;
|
||||
|
||||
for (uint8_t i=0; i < extCount; i++) {
|
||||
const nsCString& ext = mExtensions[i];
|
||||
if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*_retval = found;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetPrimaryExtension(nsACString& _retval)
|
||||
{
|
||||
if (!mExtensions.Length())
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
_retval = mExtensions[0];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::SetPrimaryExtension(const nsACString& aExtension)
|
||||
{
|
||||
NS_ASSERTION(!aExtension.IsEmpty(), "no extension");
|
||||
uint32_t extCount = mExtensions.Length();
|
||||
uint8_t i;
|
||||
bool found = false;
|
||||
for (i=0; i < extCount; i++) {
|
||||
const nsCString& ext = mExtensions[i];
|
||||
if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
mExtensions.RemoveElementAt(i);
|
||||
}
|
||||
|
||||
mExtensions.InsertElementAt(0, aExtension);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::AppendExtension(const nsACString& aExtension)
|
||||
{
|
||||
mExtensions.AppendElement(aExtension);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetType(nsACString& aType)
|
||||
{
|
||||
if (mSchemeOrType.IsEmpty())
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
aType = mSchemeOrType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetMIMEType(nsACString& aMIMEType)
|
||||
{
|
||||
if (mSchemeOrType.IsEmpty())
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
aMIMEType = mSchemeOrType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetDescription(nsAString& aDescription)
|
||||
{
|
||||
aDescription = mDescription;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::SetDescription(const nsAString& aDescription)
|
||||
{
|
||||
mDescription = aDescription;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::Equals(nsIMIMEInfo *aMIMEInfo, bool *_retval)
|
||||
{
|
||||
if (!aMIMEInfo) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsAutoCString type;
|
||||
nsresult rv = aMIMEInfo->GetMIMEType(type);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
*_retval = mSchemeOrType.Equals(type);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::SetFileExtensions(const nsACString& aExtensions)
|
||||
{
|
||||
mExtensions.Clear();
|
||||
nsCString extList( aExtensions );
|
||||
|
||||
int32_t breakLocation = -1;
|
||||
while ( (breakLocation= extList.FindChar(',') )!= -1)
|
||||
{
|
||||
mExtensions.AppendElement(Substring(extList.get(), extList.get() + breakLocation));
|
||||
extList.Cut(0, breakLocation+1 );
|
||||
}
|
||||
if ( !extList.IsEmpty() )
|
||||
mExtensions.AppendElement( extList );
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetDefaultDescription(nsAString& aDefaultDescription)
|
||||
{
|
||||
aDefaultDescription = mDefaultAppDescription;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetPreferredApplicationHandler(nsIHandlerApp ** aPreferredAppHandler)
|
||||
{
|
||||
*aPreferredAppHandler = mPreferredApplication;
|
||||
NS_IF_ADDREF(*aPreferredAppHandler);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::SetPreferredApplicationHandler(nsIHandlerApp * aPreferredAppHandler)
|
||||
{
|
||||
mPreferredApplication = aPreferredAppHandler;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetPossibleApplicationHandlers(nsIMutableArray ** aPossibleAppHandlers)
|
||||
{
|
||||
if (!mPossibleApplications)
|
||||
mPossibleApplications = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||
|
||||
if (!mPossibleApplications)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
*aPossibleAppHandlers = mPossibleApplications;
|
||||
NS_IF_ADDREF(*aPossibleAppHandlers);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetPreferredAction(nsHandlerInfoAction * aPreferredAction)
|
||||
{
|
||||
*aPreferredAction = mPreferredAction;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::SetPreferredAction(nsHandlerInfoAction aPreferredAction)
|
||||
{
|
||||
mPreferredAction = aPreferredAction;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetAlwaysAskBeforeHandling(bool * aAlwaysAsk)
|
||||
{
|
||||
*aAlwaysAsk = mAlwaysAskBeforeHandling;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::SetAlwaysAskBeforeHandling(bool aAlwaysAsk)
|
||||
{
|
||||
mAlwaysAskBeforeHandling = aAlwaysAsk;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsMIMEInfoBase::GetLocalFileFromURI(nsIURI *aURI, nsIFile **aFile)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(aURI, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = fileUrl->GetFile(getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
file.forget(aFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::LaunchWithFile(nsIFile* aFile)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// it doesn't make any sense to call this on protocol handlers
|
||||
NS_ASSERTION(mClass == eMIMEInfo,
|
||||
"nsMIMEInfoBase should have mClass == eMIMEInfo");
|
||||
|
||||
if (mPreferredAction == useSystemDefault) {
|
||||
return LaunchDefaultWithFile(aFile);
|
||||
}
|
||||
|
||||
if (mPreferredAction == useHelperApp) {
|
||||
if (!mPreferredApplication)
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
// at the moment, we only know how to hand files off to local handlers
|
||||
nsCOMPtr<nsILocalHandlerApp> localHandler =
|
||||
do_QueryInterface(mPreferredApplication, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIFile> executable;
|
||||
rv = localHandler->GetExecutable(getter_AddRefs(executable));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString path;
|
||||
aFile->GetNativePath(path);
|
||||
return LaunchWithIProcess(executable, path);
|
||||
}
|
||||
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI,
|
||||
nsIInterfaceRequestor* aWindowContext)
|
||||
{
|
||||
// for now, this is only being called with protocol handlers; that
|
||||
// will change once we get to more general registerContentHandler
|
||||
// support
|
||||
NS_ASSERTION(mClass == eProtocolInfo,
|
||||
"nsMIMEInfoBase should be a protocol handler");
|
||||
|
||||
if (mPreferredAction == useSystemDefault) {
|
||||
return LoadUriInternal(aURI);
|
||||
}
|
||||
|
||||
if (mPreferredAction == useHelperApp) {
|
||||
if (!mPreferredApplication)
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
return mPreferredApplication->LaunchWithURI(aURI, aWindowContext);
|
||||
}
|
||||
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
void
|
||||
nsMIMEInfoBase::CopyBasicDataTo(nsMIMEInfoBase* aOther)
|
||||
{
|
||||
aOther->mSchemeOrType = mSchemeOrType;
|
||||
aOther->mDefaultAppDescription = mDefaultAppDescription;
|
||||
aOther->mExtensions = mExtensions;
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<nsIProcess>
|
||||
nsMIMEInfoBase::InitProcess(nsIFile* aApp, nsresult* aResult)
|
||||
{
|
||||
NS_ASSERTION(aApp, "Unexpected null pointer, fix caller");
|
||||
|
||||
nsCOMPtr<nsIProcess> process = do_CreateInstance(NS_PROCESS_CONTRACTID,
|
||||
aResult);
|
||||
if (NS_FAILED(*aResult))
|
||||
return nullptr;
|
||||
|
||||
*aResult = process->Init(aApp);
|
||||
if (NS_FAILED(*aResult))
|
||||
return nullptr;
|
||||
|
||||
return process.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, const nsCString& aArg)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIProcess> process = InitProcess(aApp, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
const char *string = aArg.get();
|
||||
|
||||
return process->Run(false, &string, 1);
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, const nsString& aArg)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIProcess> process = InitProcess(aApp, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
const char16_t *string = aArg.get();
|
||||
|
||||
return process->Runw(false, &string, 1);
|
||||
}
|
||||
|
||||
// nsMIMEInfoImpl implementation
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoImpl::GetDefaultDescription(nsAString& aDefaultDescription)
|
||||
{
|
||||
if (mDefaultAppDescription.IsEmpty() && mDefaultApplication) {
|
||||
// Don't want to cache this, just in case someone resets the app
|
||||
// without changing the description....
|
||||
mDefaultApplication->GetLeafName(aDefaultDescription);
|
||||
} else {
|
||||
aDefaultDescription = mDefaultAppDescription;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoImpl::GetHasDefaultHandler(bool * _retval)
|
||||
{
|
||||
*_retval = !mDefaultAppDescription.IsEmpty();
|
||||
if (mDefaultApplication) {
|
||||
bool exists;
|
||||
*_retval = NS_SUCCEEDED(mDefaultApplication->Exists(&exists)) && exists;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMIMEInfoImpl::LaunchDefaultWithFile(nsIFile* aFile)
|
||||
{
|
||||
if (!mDefaultApplication)
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
nsAutoCString nativePath;
|
||||
aFile->GetNativePath(nativePath);
|
||||
|
||||
return LaunchWithIProcess(mDefaultApplication, nativePath);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::GetPossibleLocalHandlers(nsIArray **_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
196
uriloader/exthandler/nsMIMEInfoImpl.h
Normal file
196
uriloader/exthandler/nsMIMEInfoImpl.h
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 et: */
|
||||
/* 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 __nsmimeinfoimpl_h___
|
||||
#define __nsmimeinfoimpl_h___
|
||||
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIProcess.h"
|
||||
|
||||
/**
|
||||
* UTF8 moz-icon URI string for the default handler application's icon, if
|
||||
* available.
|
||||
*/
|
||||
#define PROPERTY_DEFAULT_APP_ICON_URL "defaultApplicationIconURL"
|
||||
/**
|
||||
* UTF8 moz-icon URI string for the user's preferred handler application's
|
||||
* icon, if available.
|
||||
*/
|
||||
#define PROPERTY_CUSTOM_APP_ICON_URL "customApplicationIconURL"
|
||||
|
||||
/**
|
||||
* Basic implementation of nsIMIMEInfo. Incomplete - it is meant to be
|
||||
* subclassed, and GetHasDefaultHandler as well as LaunchDefaultWithFile need to
|
||||
* be implemented.
|
||||
*/
|
||||
class nsMIMEInfoBase : public nsIMIMEInfo {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
// I'd use NS_DECL_NSIMIMEINFO, but I don't want GetHasDefaultHandler
|
||||
NS_IMETHOD GetFileExtensions(nsIUTF8StringEnumerator **_retval) override;
|
||||
NS_IMETHOD SetFileExtensions(const nsACString & aExtensions) override;
|
||||
NS_IMETHOD ExtensionExists(const nsACString & aExtension, bool *_retval) override;
|
||||
NS_IMETHOD AppendExtension(const nsACString & aExtension) override;
|
||||
NS_IMETHOD GetPrimaryExtension(nsACString & aPrimaryExtension) override;
|
||||
NS_IMETHOD SetPrimaryExtension(const nsACString & aPrimaryExtension) override;
|
||||
NS_IMETHOD GetType(nsACString & aType) override;
|
||||
NS_IMETHOD GetMIMEType(nsACString & aMIMEType) override;
|
||||
NS_IMETHOD GetDescription(nsAString & aDescription) override;
|
||||
NS_IMETHOD SetDescription(const nsAString & aDescription) override;
|
||||
NS_IMETHOD Equals(nsIMIMEInfo *aMIMEInfo, bool *_retval) override;
|
||||
NS_IMETHOD GetPreferredApplicationHandler(nsIHandlerApp * *aPreferredAppHandler) override;
|
||||
NS_IMETHOD SetPreferredApplicationHandler(nsIHandlerApp * aPreferredAppHandler) override;
|
||||
NS_IMETHOD GetPossibleApplicationHandlers(nsIMutableArray * *aPossibleAppHandlers) override;
|
||||
NS_IMETHOD GetDefaultDescription(nsAString & aDefaultDescription) override;
|
||||
NS_IMETHOD LaunchWithFile(nsIFile *aFile) override;
|
||||
NS_IMETHOD LaunchWithURI(nsIURI *aURI,
|
||||
nsIInterfaceRequestor *aWindowContext) override;
|
||||
NS_IMETHOD GetPreferredAction(nsHandlerInfoAction *aPreferredAction) override;
|
||||
NS_IMETHOD SetPreferredAction(nsHandlerInfoAction aPreferredAction) override;
|
||||
NS_IMETHOD GetAlwaysAskBeforeHandling(bool *aAlwaysAskBeforeHandling) override;
|
||||
NS_IMETHOD SetAlwaysAskBeforeHandling(bool aAlwaysAskBeforeHandling) override;
|
||||
NS_IMETHOD GetPossibleLocalHandlers(nsIArray **_retval) override;
|
||||
|
||||
enum HandlerClass {
|
||||
eMIMEInfo,
|
||||
eProtocolInfo
|
||||
};
|
||||
|
||||
// nsMIMEInfoBase methods
|
||||
explicit nsMIMEInfoBase(const char *aMIMEType = "");
|
||||
explicit nsMIMEInfoBase(const nsACString& aMIMEType);
|
||||
nsMIMEInfoBase(const nsACString& aType, HandlerClass aClass);
|
||||
|
||||
void SetMIMEType(const nsACString & aMIMEType) { mSchemeOrType = aMIMEType; }
|
||||
|
||||
void SetDefaultDescription(const nsString& aDesc) { mDefaultAppDescription = aDesc; }
|
||||
|
||||
/**
|
||||
* Copies basic data of this MIME Info Implementation to the given other
|
||||
* MIME Info. The data consists of the MIME Type, the (default) description,
|
||||
* the MacOS type and creator, and the extension list (this object's
|
||||
* extension list will replace aOther's list, not append to it). This
|
||||
* function also ensures that aOther's primary extension will be the same as
|
||||
* the one of this object.
|
||||
*/
|
||||
void CopyBasicDataTo(nsMIMEInfoBase* aOther);
|
||||
|
||||
/**
|
||||
* Return whether this MIMEInfo has any extensions
|
||||
*/
|
||||
bool HasExtensions() const { return mExtensions.Length() != 0; }
|
||||
|
||||
protected:
|
||||
virtual ~nsMIMEInfoBase(); // must be virtual, as the the base class's Release should call the subclass's destructor
|
||||
|
||||
/**
|
||||
* Launch the default application for the given file.
|
||||
* For even more control over the launching, override launchWithFile.
|
||||
* Also see the comment about nsIMIMEInfo in general, above.
|
||||
*
|
||||
* @param aFile The file that should be opened
|
||||
*/
|
||||
virtual nsresult LaunchDefaultWithFile(nsIFile* aFile) = 0;
|
||||
|
||||
/**
|
||||
* Loads the URI with the OS default app.
|
||||
*
|
||||
* @param aURI The URI to pass off to the OS.
|
||||
*/
|
||||
virtual nsresult LoadUriInternal(nsIURI *aURI) = 0;
|
||||
|
||||
static already_AddRefed<nsIProcess> InitProcess(nsIFile* aApp,
|
||||
nsresult* aResult);
|
||||
|
||||
/**
|
||||
* This method can be used to launch the file or URI with a single
|
||||
* argument (typically either a file path or a URI spec). This is
|
||||
* meant as a helper method for implementations of
|
||||
* LaunchWithURI/LaunchDefaultWithFile.
|
||||
*
|
||||
* @param aApp The application to launch (may not be null)
|
||||
* @param aArg The argument to pass on the command line
|
||||
*/
|
||||
static nsresult LaunchWithIProcess(nsIFile* aApp,
|
||||
const nsCString &aArg);
|
||||
static nsresult LaunchWithIProcess(nsIFile* aApp,
|
||||
const nsString &aArg);
|
||||
|
||||
/**
|
||||
* Given a file: nsIURI, return the associated nsIFile
|
||||
*
|
||||
* @param aURI the file: URI in question
|
||||
* @param aFile the associated nsIFile (out param)
|
||||
*/
|
||||
static nsresult GetLocalFileFromURI(nsIURI *aURI,
|
||||
nsIFile **aFile);
|
||||
|
||||
// member variables
|
||||
nsTArray<nsCString> mExtensions; ///< array of file extensions associated w/ this MIME obj
|
||||
nsString mDescription; ///< human readable description
|
||||
nsCString mSchemeOrType;
|
||||
HandlerClass mClass;
|
||||
nsCOMPtr<nsIHandlerApp> mPreferredApplication;
|
||||
nsCOMPtr<nsIMutableArray> mPossibleApplications;
|
||||
nsHandlerInfoAction mPreferredAction; ///< preferred action to associate with this type
|
||||
nsString mPreferredAppDescription;
|
||||
nsString mDefaultAppDescription;
|
||||
bool mAlwaysAskBeforeHandling;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is a complete implementation of nsIMIMEInfo, and contains all necessary
|
||||
* methods. However, depending on your platform you may want to use a different
|
||||
* way of launching applications. This class stores the default application in a
|
||||
* member variable and provides a function for setting it. For local
|
||||
* applications, launching is done using nsIProcess, native path of the file to
|
||||
* open as first argument.
|
||||
*/
|
||||
class nsMIMEInfoImpl : public nsMIMEInfoBase {
|
||||
public:
|
||||
explicit nsMIMEInfoImpl(const char *aMIMEType = "") : nsMIMEInfoBase(aMIMEType) {}
|
||||
explicit nsMIMEInfoImpl(const nsACString& aMIMEType) : nsMIMEInfoBase(aMIMEType) {}
|
||||
nsMIMEInfoImpl(const nsACString& aType, HandlerClass aClass) :
|
||||
nsMIMEInfoBase(aType, aClass) {}
|
||||
virtual ~nsMIMEInfoImpl() {}
|
||||
|
||||
// nsIMIMEInfo methods
|
||||
NS_IMETHOD GetHasDefaultHandler(bool *_retval);
|
||||
NS_IMETHOD GetDefaultDescription(nsAString& aDefaultDescription);
|
||||
|
||||
// additional methods
|
||||
/**
|
||||
* Sets the default application. Supposed to be only called by the OS Helper
|
||||
* App Services; the default application is immutable after it is first set.
|
||||
*/
|
||||
void SetDefaultApplication(nsIFile* aApp) { if (!mDefaultApplication) mDefaultApplication = aApp; }
|
||||
|
||||
protected:
|
||||
// nsMIMEInfoBase methods
|
||||
/**
|
||||
* The base class implementation is to use LaunchWithIProcess in combination
|
||||
* with mDefaultApplication. Subclasses can override that behaviour.
|
||||
*/
|
||||
virtual nsresult LaunchDefaultWithFile(nsIFile* aFile);
|
||||
|
||||
/**
|
||||
* Loads the URI with the OS default app. This should be overridden by each
|
||||
* OS's implementation.
|
||||
*/
|
||||
virtual nsresult LoadUriInternal(nsIURI *aURI) = 0;
|
||||
|
||||
nsCOMPtr<nsIFile> mDefaultApplication; ///< default application associated with this type.
|
||||
};
|
||||
|
||||
#endif //__nsmimeinfoimpl_h___
|
||||
172
uriloader/exthandler/nsWebHandlerApp.js
Normal file
172
uriloader/exthandler/nsWebHandlerApp.js
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/* 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/. */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Constants
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsWebHandler class
|
||||
|
||||
function nsWebHandlerApp() {}
|
||||
|
||||
nsWebHandlerApp.prototype = {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsWebHandler
|
||||
|
||||
classDescription: "A web handler for protocols and content",
|
||||
classID: Components.ID("8b1ae382-51a9-4972-b930-56977a57919d"),
|
||||
contractID: "@mozilla.org/uriloader/web-handler-app;1",
|
||||
|
||||
_name: null,
|
||||
_detailedDescription: null,
|
||||
_uriTemplate: null,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIHandlerApp
|
||||
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
|
||||
set name(aName) {
|
||||
this._name = aName;
|
||||
},
|
||||
|
||||
get detailedDescription() {
|
||||
return this._detailedDescription;
|
||||
},
|
||||
|
||||
set detailedDescription(aDesc) {
|
||||
this._detailedDescription = aDesc;
|
||||
},
|
||||
|
||||
equals: function(aHandlerApp) {
|
||||
if (!aHandlerApp)
|
||||
throw Cr.NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (aHandlerApp instanceof Ci.nsIWebHandlerApp &&
|
||||
aHandlerApp.uriTemplate &&
|
||||
this.uriTemplate &&
|
||||
aHandlerApp.uriTemplate == this.uriTemplate)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
launchWithURI: function nWHA__launchWithURI(aURI, aWindowContext) {
|
||||
|
||||
// XXX need to strip passwd & username from URI to handle, as per the
|
||||
// WhatWG HTML5 draft. nsSimpleURL, which is what we're going to get,
|
||||
// can't do this directly. Ideally, we'd fix nsStandardURL to make it
|
||||
// possible to turn off all of its quirks handling, and use that...
|
||||
|
||||
// encode the URI to be handled
|
||||
var escapedUriSpecToHandle = encodeURIComponent(aURI.spec);
|
||||
|
||||
// insert the encoded URI and create the object version
|
||||
var uriSpecToSend = this.uriTemplate.replace("%s", escapedUriSpecToHandle);
|
||||
var ioService = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var uriToSend = ioService.newURI(uriSpecToSend, null, null);
|
||||
|
||||
// if we have a window context, use the URI loader to load there
|
||||
if (aWindowContext) {
|
||||
try {
|
||||
// getInterface throws if the object doesn't implement the given
|
||||
// interface, so this try/catch statement is more of an if.
|
||||
// If aWindowContext refers to a remote docshell, send the load
|
||||
// request to the correct process.
|
||||
aWindowContext.getInterface(Ci.nsIRemoteWindowContext)
|
||||
.openURI(uriToSend);
|
||||
return;
|
||||
} catch (e) {
|
||||
if (e.result != Cr.NS_NOINTERFACE) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// create a channel from this URI
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: uriToSend,
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
channel.loadFlags = Ci.nsIChannel.LOAD_DOCUMENT_URI;
|
||||
|
||||
// load the channel
|
||||
var uriLoader = Cc["@mozilla.org/uriloader;1"].
|
||||
getService(Ci.nsIURILoader);
|
||||
// XXX ideally, whether to pass the IS_CONTENT_PREFERRED flag should be
|
||||
// passed in from above. Practically, the flag is probably a reasonable
|
||||
// default since browsers don't care much, and link click is likely to be
|
||||
// the more interesting case for non-browser apps. See
|
||||
// <https://bugzilla.mozilla.org/show_bug.cgi?id=392957#c9> for details.
|
||||
uriLoader.openURI(channel, Ci.nsIURILoader.IS_CONTENT_PREFERRED,
|
||||
aWindowContext);
|
||||
return;
|
||||
}
|
||||
|
||||
// since we don't have a window context, hand it off to a browser
|
||||
var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
|
||||
// get browser dom window
|
||||
var browserDOMWin = windowMediator.getMostRecentWindow("navigator:browser")
|
||||
.QueryInterface(Ci.nsIDOMChromeWindow)
|
||||
.browserDOMWindow;
|
||||
|
||||
// if we got an exception, there are several possible reasons why:
|
||||
// a) this gecko embedding doesn't provide an nsIBrowserDOMWindow
|
||||
// implementation (i.e. doesn't support browser-style functionality),
|
||||
// so we need to kick the URL out to the OS default browser. This is
|
||||
// the subject of bug 394479.
|
||||
// b) this embedding does provide an nsIBrowserDOMWindow impl, but
|
||||
// there doesn't happen to be a browser window open at the moment; one
|
||||
// should be opened. It's not clear whether this situation will really
|
||||
// ever occur in real life. If it does, the only API that I can find
|
||||
// that seems reasonably likely to work for most embedders is the
|
||||
// command line handler.
|
||||
// c) something else went wrong
|
||||
//
|
||||
// it's not clear how one would differentiate between the three cases
|
||||
// above, so for now we don't catch the exception
|
||||
|
||||
// openURI
|
||||
browserDOMWin.openURI(uriToSend,
|
||||
null, // no window.opener
|
||||
Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_NEW);
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIWebHandlerApp
|
||||
|
||||
get uriTemplate() {
|
||||
return this._uriTemplate;
|
||||
},
|
||||
|
||||
set uriTemplate(aURITemplate) {
|
||||
this._uriTemplate = aURITemplate;
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsISupports
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebHandlerApp, Ci.nsIHandlerApp])
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Module
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsWebHandlerApp]);
|
||||
|
||||
2
uriloader/exthandler/nsWebHandlerApp.manifest
Normal file
2
uriloader/exthandler/nsWebHandlerApp.manifest
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
component {8b1ae382-51a9-4972-b930-56977a57919d} nsWebHandlerApp.js
|
||||
contract @mozilla.org/uriloader/web-handler-app;1 {8b1ae382-51a9-4972-b930-56977a57919d}
|
||||
11
uriloader/exthandler/tests/Makefile.in
Normal file
11
uriloader/exthandler/tests/Makefile.in
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# 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 $(topsrcdir)/config/rules.mk
|
||||
|
||||
# need the executable for running the xpcshell unit tests
|
||||
ifneq (,$(SIMPLE_PROGRAMS))
|
||||
libs::
|
||||
$(INSTALL) $(SIMPLE_PROGRAMS) $(DEPTH)/_tests/xpcshell/$(relativesrcdir)/unit
|
||||
endif
|
||||
24
uriloader/exthandler/tests/WriteArgument.cpp
Normal file
24
uriloader/exthandler/tests/WriteArgument.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include <stdio.h>
|
||||
#include "prenv.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
const char* value = PR_GetEnv("WRITE_ARGUMENT_FILE");
|
||||
|
||||
if (!value)
|
||||
return 2;
|
||||
|
||||
FILE* outfile = fopen(value, "w");
|
||||
if (!outfile)
|
||||
return 3;
|
||||
|
||||
// We only need to write out the first argument (no newline).
|
||||
fputs(argv[argc -1], outfile);
|
||||
|
||||
fclose(outfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
8
uriloader/exthandler/tests/mochitest/browser.ini
Normal file
8
uriloader/exthandler/tests/mochitest/browser.ini
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
support-files =
|
||||
protocolHandler.html
|
||||
|
||||
[browser_download_always_ask_preferred_app.js]
|
||||
[browser_remember_download_option.js]
|
||||
[browser_web_protocol_handlers.js]
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
add_task(function*() {
|
||||
// Create mocked objects for test
|
||||
let launcher = createMockedObjects(false);
|
||||
// Open helper app dialog with mocked launcher
|
||||
let dlg = yield* openHelperAppDialog(launcher);
|
||||
let doc = dlg.document;
|
||||
let location = doc.getElementById("source");
|
||||
let expectedValue = launcher.source.prePath;
|
||||
if (location.value != expectedValue) {
|
||||
info("Waiting for dialog to be populated.");
|
||||
yield BrowserTestUtils.waitForAttribute("value", location, expectedValue);
|
||||
}
|
||||
is(doc.getElementById("mode").selectedItem.id, "open", "Should be opening the file.");
|
||||
ok(!dlg.document.getElementById("openHandler").selectedItem.hidden,
|
||||
"Should not have selected a hidden item.");
|
||||
let helperAppDialogHiddenPromise = BrowserTestUtils.windowClosed(dlg);
|
||||
doc.documentElement.cancelDialog();
|
||||
yield helperAppDialogHiddenPromise;
|
||||
});
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
add_task(function*() {
|
||||
// create mocked objects
|
||||
let launcher = createMockedObjects(true);
|
||||
|
||||
// open helper app dialog with mocked launcher
|
||||
let dlg = yield* openHelperAppDialog(launcher);
|
||||
|
||||
let doc = dlg.document;
|
||||
|
||||
// Set remember choice
|
||||
ok(!doc.getElementById("rememberChoice").checked,
|
||||
"Remember choice checkbox should be not checked.");
|
||||
doc.getElementById("rememberChoice").checked = true;
|
||||
|
||||
// Make sure the mock handler information is not in nsIHandlerService
|
||||
ok(!gHandlerSvc.exists(launcher.MIMEInfo), "Should not be in nsIHandlerService.");
|
||||
|
||||
// close the dialog by pushing the ok button.
|
||||
let dialogClosedPromise = BrowserTestUtils.windowClosed(dlg);
|
||||
// Make sure the ok button is enabled, since the ok button might be disabled by
|
||||
// EnableDelayHelper mechanism. Please refer the detailed
|
||||
// https://dxr.mozilla.org/mozilla-central/source/toolkit/components/prompts/src/SharedPromptUtils.jsm#53
|
||||
doc.documentElement.getButton("accept").disabled = false;
|
||||
doc.documentElement.acceptDialog();
|
||||
yield dialogClosedPromise;
|
||||
|
||||
// check the mocked handler information is saved in nsIHandlerService
|
||||
ok(gHandlerSvc.exists(launcher.MIMEInfo), "Should be in nsIHandlerService.");
|
||||
// check the extension.
|
||||
var mimeType = gHandlerSvc.getTypeFromExtension("abc");
|
||||
is(mimeType, launcher.MIMEInfo.type, "Got correct mime type.");
|
||||
var handlerInfos = gHandlerSvc.enumerate();
|
||||
while (handlerInfos.hasMoreElements()) {
|
||||
let handlerInfo = handlerInfos.getNext().QueryInterface(Ci.nsIHandlerInfo);
|
||||
if (handlerInfo.type == launcher.MIMEInfo.type) {
|
||||
// check the alwaysAskBeforeHandling
|
||||
ok(!handlerInfo.alwaysAskBeforeHandling,
|
||||
"Should turn off the always ask.");
|
||||
// check the preferredApplicationHandler
|
||||
ok(handlerInfo.preferredApplicationHandler.equals(
|
||||
launcher.MIMEInfo.preferredApplicationHandler),
|
||||
"Should be equal to the mockedHandlerApp.");
|
||||
// check the perferredAction
|
||||
is(handlerInfo.preferredAction, launcher.MIMEInfo.preferredAction,
|
||||
"Should be equal to Ci.nsIHandlerInfo.useHelperApp.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
let testURL = "http://example.com/browser/" +
|
||||
"uriloader/exthandler/tests/mochitest/protocolHandler.html";
|
||||
|
||||
add_task(function*() {
|
||||
// Load a page registering a protocol handler.
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
browser.loadURI(testURL);
|
||||
yield BrowserTestUtils.browserLoaded(browser, testURL);
|
||||
|
||||
// Register the protocol handler by clicking the notificationbar button.
|
||||
let notificationValue = "Protocol Registration: testprotocol";
|
||||
let getNotification = () =>
|
||||
gBrowser.getNotificationBox().getNotificationWithValue(notificationValue);
|
||||
yield BrowserTestUtils.waitForCondition(getNotification);
|
||||
let notification = getNotification();
|
||||
let button =
|
||||
notification.getElementsByClassName("notification-button-default")[0];
|
||||
ok(button, "got registration button");
|
||||
button.click();
|
||||
|
||||
// Set the new handler as default.
|
||||
const protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
|
||||
getService(Ci.nsIExternalProtocolService);
|
||||
let protoInfo = protoSvc.getProtocolHandlerInfo("testprotocol");
|
||||
is(protoInfo.preferredAction, protoInfo.useHelperApp,
|
||||
"using a helper application is the preferred action");
|
||||
ok(!protoInfo.preferredApplicationHandler, "no preferred handler is set");
|
||||
let handlers = protoInfo.possibleApplicationHandlers;
|
||||
is(1, handlers.length, "only one handler registered for testprotocol");
|
||||
let handler = handlers.queryElementAt(0, Ci.nsIHandlerApp);
|
||||
ok(handler instanceof Ci.nsIWebHandlerApp, "the handler is a web handler");
|
||||
is(handler.uriTemplate, "https://example.com/foobar?uri=%s",
|
||||
"correct url template")
|
||||
protoInfo.preferredApplicationHandler = handler;
|
||||
protoInfo.alwaysAskBeforeHandling = false;
|
||||
const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].
|
||||
getService(Ci.nsIHandlerService);
|
||||
handlerSvc.store(protoInfo);
|
||||
|
||||
// Middle-click a testprotocol link and check the new tab is correct
|
||||
let link = "#link";
|
||||
const expectedURL = "https://example.com/foobar?uri=testprotocol%3Atest";
|
||||
|
||||
let promiseTabOpened =
|
||||
BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter(link, {button: 1}, browser);
|
||||
let tab = yield promiseTabOpened;
|
||||
gBrowser.selectedTab = tab;
|
||||
is(gURLBar.value, expectedURL,
|
||||
"the expected URL is displayed in the location bar");
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
|
||||
// Shift-click the testprotocol link and check the new window.
|
||||
let newWindowPromise = BrowserTestUtils.waitForNewWindow();
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter(link, {shiftKey: true},
|
||||
browser);
|
||||
let win = yield newWindowPromise;
|
||||
yield BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
yield BrowserTestUtils.waitForCondition(() => win.gBrowser.currentURI.spec == expectedURL);
|
||||
is(win.gURLBar.value, expectedURL,
|
||||
"the expected URL is displayed in the location bar");
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
|
||||
// Click the testprotocol link and check the url in the current tab.
|
||||
let loadPromise = BrowserTestUtils.browserLoaded(browser);
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter(link, {}, browser);
|
||||
yield loadPromise;
|
||||
yield BrowserTestUtils.waitForCondition(() => gURLBar.value != testURL);
|
||||
is(gURLBar.value, expectedURL,
|
||||
"the expected URL is displayed in the location bar");
|
||||
|
||||
// Cleanup.
|
||||
protoInfo.preferredApplicationHandler = null;
|
||||
handlers.removeElementAt(0);
|
||||
handlerSvc.store(protoInfo);
|
||||
});
|
||||
30
uriloader/exthandler/tests/mochitest/handlerApp.xhtml
Normal file
30
uriloader/exthandler/tests/mochitest/handlerApp.xhtml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Pseudo Web Handler App</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="onLoad()">
|
||||
Pseudo Web Handler App
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
function onLoad() {
|
||||
|
||||
// if we have a window.opener, this must be the windowContext
|
||||
// instance of this test. check that we got the URI right and clean up.
|
||||
if (window.opener) {
|
||||
window.opener.is(location.search,
|
||||
"?uri=" + encodeURIComponent(window.opener.testURI),
|
||||
"uri passed to web-handler app");
|
||||
window.opener.SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.close();
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
110
uriloader/exthandler/tests/mochitest/handlerApps.js
Normal file
110
uriloader/exthandler/tests/mochitest/handlerApps.js
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/* 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/. */
|
||||
|
||||
// handlerApp.xhtml grabs this for verification purposes via window.opener
|
||||
var testURI = "webcal://127.0.0.1/rheeeeet.html";
|
||||
|
||||
const Cc = SpecialPowers.Cc;
|
||||
|
||||
function test() {
|
||||
|
||||
// set up the web handler object
|
||||
var webHandler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
|
||||
createInstance(SpecialPowers.Ci.nsIWebHandlerApp);
|
||||
webHandler.name = "Test Web Handler App";
|
||||
webHandler.uriTemplate =
|
||||
"http://mochi.test:8888/tests/uriloader/exthandler/tests/mochitest/" +
|
||||
"handlerApp.xhtml?uri=%s";
|
||||
|
||||
// set up the uri to test with
|
||||
var ioService = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(SpecialPowers.Ci.nsIIOService);
|
||||
var uri = ioService.newURI(testURI, null, null);
|
||||
|
||||
// create a window, and launch the handler in it
|
||||
var newWindow = window.open("", "handlerWindow", "height=300,width=300");
|
||||
var windowContext =
|
||||
SpecialPowers.wrap(newWindow).QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
|
||||
getInterface(SpecialPowers.Ci.nsIWebNavigation).
|
||||
QueryInterface(SpecialPowers.Ci.nsIDocShell);
|
||||
|
||||
webHandler.launchWithURI(uri, windowContext);
|
||||
|
||||
// if we get this far without an exception, we've at least partly passed
|
||||
// (remaining check in handlerApp.xhtml)
|
||||
ok(true, "webHandler launchWithURI (existing window/tab) started");
|
||||
|
||||
// make the web browser launch in its own window/tab
|
||||
webHandler.launchWithURI(uri);
|
||||
|
||||
// if we get this far without an exception, we've passed
|
||||
ok(true, "webHandler launchWithURI (new window/tab) test started");
|
||||
|
||||
// set up the local handler object
|
||||
var localHandler = Cc["@mozilla.org/uriloader/local-handler-app;1"].
|
||||
createInstance(SpecialPowers.Ci.nsILocalHandlerApp);
|
||||
localHandler.name = "Test Local Handler App";
|
||||
|
||||
// get a local app that we know will be there and do something sane
|
||||
var osString = Cc["@mozilla.org/xre/app-info;1"].
|
||||
getService(SpecialPowers.Ci.nsIXULRuntime).OS;
|
||||
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(SpecialPowers.Ci.nsIDirectoryServiceProvider);
|
||||
if (osString == "WINNT") {
|
||||
var windowsDir = dirSvc.getFile("WinD", {});
|
||||
var exe = windowsDir.clone().QueryInterface(SpecialPowers.Ci.nsILocalFile);
|
||||
exe.appendRelativePath("SYSTEM32\\HOSTNAME.EXE");
|
||||
|
||||
} else if (osString == "Darwin") {
|
||||
var localAppsDir = dirSvc.getFile("LocApp", {});
|
||||
exe = localAppsDir.clone();
|
||||
exe.append("iCal.app"); // lingers after the tests finish, but this seems
|
||||
// seems better than explicitly killing it, since
|
||||
// developers who run the tests locally may well
|
||||
// information in their running copy of iCal
|
||||
|
||||
if (navigator.userAgent.match(/ SeaMonkey\//)) {
|
||||
// SeaMonkey tinderboxes don't like to have iCal lingering (and focused)
|
||||
// on next test suite run(s).
|
||||
todo(false, "On SeaMonkey, testing OS X as generic Unix. (Bug 749872)");
|
||||
|
||||
// assume a generic UNIX variant
|
||||
exe = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(SpecialPowers.Ci.nsILocalFile);
|
||||
exe.initWithPath("/bin/echo");
|
||||
}
|
||||
} else {
|
||||
// assume a generic UNIX variant
|
||||
exe = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(SpecialPowers.Ci.nsILocalFile);
|
||||
exe.initWithPath("/bin/echo");
|
||||
}
|
||||
|
||||
localHandler.executable = exe;
|
||||
localHandler.launchWithURI(ioService.newURI(testURI, null, null));
|
||||
|
||||
// if we get this far without an exception, we've passed
|
||||
ok(true, "localHandler launchWithURI test");
|
||||
|
||||
// if we ever decide that killing iCal is the right thing to do, change
|
||||
// the if statement below from "NOTDarwin" to "Darwin"
|
||||
if (osString == "NOTDarwin") {
|
||||
|
||||
var killall = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(SpecialPowers.Ci.nsILocalFile);
|
||||
killall.initWithPath("/usr/bin/killall");
|
||||
|
||||
var process = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(SpecialPowers.Ci.nsIProcess);
|
||||
process.init(killall);
|
||||
|
||||
var args = ['iCal'];
|
||||
process.run(false, args, args.length);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
}
|
||||
|
||||
test();
|
||||
105
uriloader/exthandler/tests/mochitest/head.js
Normal file
105
uriloader/exthandler/tests/mochitest/head.js
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
var gMimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
|
||||
var gHandlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService);
|
||||
|
||||
function createMockedHandlerApp() {
|
||||
// Mock the executable
|
||||
let mockedExecutable = FileUtils.getFile("TmpD", ["mockedExecutable"]);
|
||||
if (!mockedExecutable.exists()) {
|
||||
mockedExecutable.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o755);
|
||||
}
|
||||
|
||||
// Mock the handler app
|
||||
let mockedHandlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]
|
||||
.createInstance(Ci.nsILocalHandlerApp);
|
||||
mockedHandlerApp.executable = mockedExecutable;
|
||||
mockedHandlerApp.detailedDescription = "Mocked handler app";
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// remove the mocked executable from disk.
|
||||
if (mockedExecutable.exists()) {
|
||||
mockedExecutable.remove(true);
|
||||
}
|
||||
});
|
||||
|
||||
return mockedHandlerApp;
|
||||
}
|
||||
|
||||
function createMockedObjects(createHandlerApp) {
|
||||
// Mock the mime info
|
||||
let internalMockedMIME = gMimeSvc.getFromTypeAndExtension("text/x-test-handler", null);
|
||||
internalMockedMIME.alwaysAskBeforeHandling = true;
|
||||
internalMockedMIME.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
|
||||
internalMockedMIME.appendExtension("abc");
|
||||
if (createHandlerApp) {
|
||||
let mockedHandlerApp = createMockedHandlerApp();
|
||||
internalMockedMIME.description = mockedHandlerApp.detailedDescription;
|
||||
internalMockedMIME.possibleApplicationHandlers.appendElement(mockedHandlerApp, false);
|
||||
internalMockedMIME.preferredApplicationHandler = mockedHandlerApp;
|
||||
}
|
||||
|
||||
// Proxy for the mocked MIME info for faking the read-only attributes
|
||||
let mockedMIME = new Proxy(internalMockedMIME, {
|
||||
get: function (target, property) {
|
||||
switch (property) {
|
||||
case "hasDefaultHandler":
|
||||
return true;
|
||||
case "defaultDescription":
|
||||
return "Default description";
|
||||
default:
|
||||
return target[property];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Mock the launcher:
|
||||
let mockedLauncher = {
|
||||
MIMEInfo: mockedMIME,
|
||||
source: Services.io.newURI("http://www.mozilla.org/", null, null),
|
||||
suggestedFileName: "test_download_dialog.abc",
|
||||
targetFileIsExecutable: false,
|
||||
saveToDisk() {},
|
||||
cancel() {},
|
||||
launchWithApplication() {},
|
||||
setWebProgressListener() {},
|
||||
saveDestinationAvailable() {},
|
||||
contentLength: 42,
|
||||
targetFile: null, // never read
|
||||
// PRTime is microseconds since epoch, Date.now() returns milliseconds:
|
||||
timeDownloadStarted: Date.now() * 1000,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable, Ci.nsIHelperAppLauncher])
|
||||
};
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// remove the mocked mime info from database.
|
||||
let mockHandlerInfo = gMimeSvc.getFromTypeAndExtension("text/x-test-handler", null);
|
||||
if (gHandlerSvc.exists(mockHandlerInfo)) {
|
||||
gHandlerSvc.remove(mockHandlerInfo);
|
||||
}
|
||||
});
|
||||
|
||||
return mockedLauncher;
|
||||
}
|
||||
|
||||
function* openHelperAppDialog(launcher) {
|
||||
let helperAppDialog = Cc["@mozilla.org/helperapplauncherdialog;1"].
|
||||
createInstance(Ci.nsIHelperAppLauncherDialog);
|
||||
|
||||
let helperAppDialogShownPromise = BrowserTestUtils.domWindowOpened();
|
||||
try {
|
||||
helperAppDialog.show(launcher, window, "foopy");
|
||||
} catch (ex) {
|
||||
ok(false, "Trying to show unknownContentType.xul failed with exception: " + ex);
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
let dlg = yield helperAppDialogShownPromise;
|
||||
|
||||
yield BrowserTestUtils.waitForEvent(dlg, "load", false);
|
||||
|
||||
is(dlg.location.href, "chrome://mozapps/content/downloads/unknownContentType.xul",
|
||||
"Got correct dialog");
|
||||
|
||||
return dlg;
|
||||
}
|
||||
10
uriloader/exthandler/tests/mochitest/mochitest.ini
Normal file
10
uriloader/exthandler/tests/mochitest/mochitest.ini
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
handlerApp.xhtml
|
||||
handlerApps.js
|
||||
unsafeBidi_chromeScript.js
|
||||
unsafeBidiFileName.sjs
|
||||
|
||||
[test_handlerApps.xhtml]
|
||||
skip-if = (toolkit == 'android' || os == 'mac') || e10s # OS X: bug 786938
|
||||
[test_unsafeBidiChars.xhtml]
|
||||
16
uriloader/exthandler/tests/mochitest/protocolHandler.html
Normal file
16
uriloader/exthandler/tests/mochitest/protocolHandler.html
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Protocol handler</title>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<meta content="utf-8" http-equiv="encoding">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
navigator.registerProtocolHandler("testprotocol",
|
||||
"https://example.com/foobar?uri=%s",
|
||||
"Test Protocol");
|
||||
</script>
|
||||
<a id="link" href="testprotocol:test">testprotocol link</a>
|
||||
</body>
|
||||
</html>
|
||||
12
uriloader/exthandler/tests/mochitest/test_handlerApps.xhtml
Normal file
12
uriloader/exthandler/tests/mochitest/test_handlerApps.xhtml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Test for Handler Apps </title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="handlerApps.js"/>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Test for Handling of unsafe bidi chars</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<iframe id="test"></iframe>
|
||||
<script type="text/javascript">
|
||||
<![CDATA[
|
||||
|
||||
var unsafeBidiChars = [
|
||||
"\xe2\x80\xaa", // LRE
|
||||
"\xe2\x80\xab", // RLE
|
||||
"\xe2\x80\xac", // PDF
|
||||
"\xe2\x80\xad", // LRO
|
||||
"\xe2\x80\xae" // RLO
|
||||
];
|
||||
|
||||
var tests = [
|
||||
"{1}.test",
|
||||
"{1}File.test",
|
||||
"Fi{1}le.test",
|
||||
"File{1}.test",
|
||||
"File.{1}test",
|
||||
"File.te{1}st",
|
||||
"File.test{1}",
|
||||
"File.{1}",
|
||||
];
|
||||
|
||||
function replace(name, x) {
|
||||
return name.replace(/\{1\}/, x);
|
||||
}
|
||||
|
||||
function sanitize(name) {
|
||||
return replace(name, '_');
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
let url = SimpleTest.getTestFileURL("unsafeBidi_chromeScript.js");
|
||||
let chromeScript = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
for (let test of tests) {
|
||||
for (let char of unsafeBidiChars) {
|
||||
let promiseName = new Promise(function(resolve) {
|
||||
chromeScript.addMessageListener("suggestedFileName",
|
||||
function listener(data) {
|
||||
chromeScript.removeMessageListener("suggestedFileName", listener);
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
let name = replace(test, char);
|
||||
let expected = sanitize(test);
|
||||
document.getElementById("test").src =
|
||||
"unsafeBidiFileName.sjs?name=" + encodeURIComponent(name);
|
||||
is((yield promiseName), expected, "got the expected sanitized name");
|
||||
}
|
||||
}
|
||||
|
||||
let promise = new Promise(function(resolve) {
|
||||
chromeScript.addMessageListener("unregistered", function listener() {
|
||||
chromeScript.removeMessageListener("unregistered", listener);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
chromeScript.sendAsyncMessage("unregister");
|
||||
yield promise;
|
||||
|
||||
chromeScript.destroy();
|
||||
});
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
14
uriloader/exthandler/tests/mochitest/unsafeBidiFileName.sjs
Normal file
14
uriloader/exthandler/tests/mochitest/unsafeBidiFileName.sjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* 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/. */
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
|
||||
if (!request.queryString.match(/^name=/))
|
||||
return;
|
||||
var name = decodeURIComponent(request.queryString.substring(5));
|
||||
|
||||
response.setHeader("Content-Type", "application/octet-stream; name=\"" + name + "\"");
|
||||
response.setHeader("Content-Disposition", "inline; filename=\"" + name + "\"");
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const HELPERAPP_DIALOG_CONTRACT = "@mozilla.org/helperapplauncherdialog;1";
|
||||
const HELPERAPP_DIALOG_CID =
|
||||
Components.ID(Cc[HELPERAPP_DIALOG_CONTRACT].number);
|
||||
|
||||
const FAKE_CID = Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(Ci.nsIUUIDGenerator).generateUUID();
|
||||
|
||||
function HelperAppLauncherDialog() {}
|
||||
HelperAppLauncherDialog.prototype = {
|
||||
show: function(aLauncher, aWindowContext, aReason) {
|
||||
sendAsyncMessage("suggestedFileName", aLauncher.suggestedFileName);
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
|
||||
};
|
||||
|
||||
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.registerFactory(FAKE_CID, "", HELPERAPP_DIALOG_CONTRACT,
|
||||
XPCOMUtils._getFactory(HelperAppLauncherDialog));
|
||||
|
||||
addMessageListener("unregister", function() {
|
||||
registrar.registerFactory(HELPERAPP_DIALOG_CID, "",
|
||||
HELPERAPP_DIALOG_CONTRACT, null);
|
||||
sendAsyncMessage("unregistered");
|
||||
});
|
||||
24
uriloader/exthandler/tests/moz.build
Normal file
24
uriloader/exthandler/tests/moz.build
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini']
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['mochitest/browser.ini']
|
||||
|
||||
# The encoding test is already implemented in the Downloads API by a set of
|
||||
# test cases with the string "content_encoding" in their names.
|
||||
if not CONFIG['MOZ_JSDOWNLOADS']:
|
||||
XPCSHELL_TESTS_MANIFESTS += ['unit_ipc/xpcshell.ini']
|
||||
|
||||
GeckoSimplePrograms([
|
||||
'WriteArgument',
|
||||
], linkage=None)
|
||||
|
||||
USE_LIBS += [
|
||||
'nspr',
|
||||
]
|
||||
163
uriloader/exthandler/tests/unit/head_handlerService.js
Normal file
163
uriloader/exthandler/tests/unit/head_handlerService.js
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/* 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/. */
|
||||
|
||||
// Inspired by the Places infrastructure in head_bookmarks.js
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
var Cu = Components.utils;
|
||||
|
||||
var HandlerServiceTest = {
|
||||
//**************************************************************************//
|
||||
// Convenience Getters
|
||||
|
||||
__dirSvc: null,
|
||||
get _dirSvc() {
|
||||
if (!this.__dirSvc)
|
||||
this.__dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties).
|
||||
QueryInterface(Ci.nsIDirectoryService);
|
||||
return this.__dirSvc;
|
||||
},
|
||||
|
||||
__consoleSvc: null,
|
||||
get _consoleSvc() {
|
||||
if (!this.__consoleSvc)
|
||||
this.__consoleSvc = Cc["@mozilla.org/consoleservice;1"].
|
||||
getService(Ci.nsIConsoleService);
|
||||
return this.__consoleSvc;
|
||||
},
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// nsISupports
|
||||
|
||||
interfaces: [Ci.nsIDirectoryServiceProvider, Ci.nsISupports],
|
||||
|
||||
QueryInterface: function HandlerServiceTest_QueryInterface(iid) {
|
||||
if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// Initialization & Destruction
|
||||
|
||||
init: function HandlerServiceTest_init() {
|
||||
// Register ourselves as a directory provider for the datasource file
|
||||
// if there isn't one registered already.
|
||||
try {
|
||||
this._dirSvc.get("UMimTyp", Ci.nsIFile);
|
||||
} catch (ex) {
|
||||
this._dirSvc.registerProvider(this);
|
||||
this._providerRegistered = true;
|
||||
}
|
||||
|
||||
// Delete the existing datasource file, if any, so we start from scratch.
|
||||
// We also do this after finishing the tests, so there shouldn't be an old
|
||||
// file lying around, but just in case we delete it here as well.
|
||||
this._deleteDatasourceFile();
|
||||
|
||||
// Turn on logging so we can troubleshoot problems with the tests.
|
||||
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
prefBranch.setBoolPref("browser.contentHandling.log", true);
|
||||
},
|
||||
|
||||
destroy: function HandlerServiceTest_destroy() {
|
||||
// Delete the existing datasource file, if any, so we don't leave test files
|
||||
// lying around and we start from scratch the next time.
|
||||
this._deleteDatasourceFile();
|
||||
// Unregister the directory service provider
|
||||
if (this._providerRegistered)
|
||||
this._dirSvc.unregisterProvider(this);
|
||||
},
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// nsIDirectoryServiceProvider
|
||||
|
||||
getFile: function HandlerServiceTest_getFile(property, persistent) {
|
||||
this.log("getFile: requesting " + property);
|
||||
|
||||
persistent.value = true;
|
||||
|
||||
if (property == "UMimTyp") {
|
||||
var datasourceFile = this._dirSvc.get("CurProcD", Ci.nsIFile);
|
||||
datasourceFile.append("mimeTypes.rdf");
|
||||
return datasourceFile;
|
||||
}
|
||||
|
||||
// This causes extraneous errors to show up in the log when the directory
|
||||
// service asks us first for CurProcD and MozBinD. I wish there was a way
|
||||
// to suppress those errors.
|
||||
this.log("the following NS_ERROR_FAILURE exception in " +
|
||||
"nsIDirectoryServiceProvider::getFile is expected, " +
|
||||
"as we don't provide the '" + property + "' file");
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
},
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// Utilities
|
||||
|
||||
/**
|
||||
* Delete the datasource file.
|
||||
*/
|
||||
_deleteDatasourceFile: function HandlerServiceTest__deleteDatasourceFile() {
|
||||
var file = this._dirSvc.get("UMimTyp", Ci.nsIFile);
|
||||
if (file.exists())
|
||||
file.remove(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the contents of the datasource as a serialized string. Useful for
|
||||
* debugging problems with test failures, i.e.:
|
||||
*
|
||||
* HandlerServiceTest.log(HandlerServiceTest.getDatasourceContents());
|
||||
*
|
||||
* @returns {string} the serialized datasource
|
||||
*/
|
||||
getDatasourceContents: function HandlerServiceTest_getDatasourceContents() {
|
||||
var rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
|
||||
|
||||
var ioService = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var fileHandler = ioService.getProtocolHandler("file").
|
||||
QueryInterface(Ci.nsIFileProtocolHandler);
|
||||
var fileURL = fileHandler.getURLSpecFromFile(this.getDatasourceFile());
|
||||
var ds = rdf.GetDataSourceBlocking(fileURL);
|
||||
|
||||
var outputStream = {
|
||||
data: "",
|
||||
close: function() {},
|
||||
flush: function() {},
|
||||
write: function (buffer,count) {
|
||||
this.data += buffer;
|
||||
return count;
|
||||
},
|
||||
writeFrom: function (stream,count) {},
|
||||
isNonBlocking: false
|
||||
};
|
||||
|
||||
ds.QueryInterface(Components.interfaces.nsIRDFXMLSource);
|
||||
ds.Serialize(outputStream);
|
||||
|
||||
return outputStream.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Log a message to the console and the test log.
|
||||
*/
|
||||
log: function HandlerServiceTest_log(message) {
|
||||
message = "*** HandlerServiceTest: " + message;
|
||||
this._consoleSvc.logStringMessage(message);
|
||||
print(message);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
HandlerServiceTest.init();
|
||||
2
uriloader/exthandler/tests/unit/mailcap
Normal file
2
uriloader/exthandler/tests/unit/mailcap
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
text/plain; cat '%s'; needsterminal
|
||||
text/plain; sed '%s'
|
||||
5
uriloader/exthandler/tests/unit/tail_handlerService.js
Normal file
5
uriloader/exthandler/tests/unit/tail_handlerService.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/* 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/. */
|
||||
|
||||
HandlerServiceTest.destroy();
|
||||
26
uriloader/exthandler/tests/unit/test_badMIMEType.js
Normal file
26
uriloader/exthandler/tests/unit/test_badMIMEType.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
function run_test() {
|
||||
// "text/plain" has an 0xFF character appended to it. This means it's an
|
||||
// invalid string, which is tricky to enter using a text editor (I used
|
||||
// emacs' hexl-mode). It also means an ordinary text editor might drop it
|
||||
// or convert it to something that *is* valid (in UTF8). So we measure
|
||||
// its length to make sure this hasn't happened.
|
||||
var badMimeType = "text/plainÿ";
|
||||
do_check_eq(badMimeType.length, 11);
|
||||
|
||||
try {
|
||||
var type = Cc["@mozilla.org/mime;1"].
|
||||
getService(Ci.nsIMIMEService).
|
||||
getFromTypeAndExtension(badMimeType, "txt");
|
||||
} catch (e if (e instanceof Ci.nsIException &&
|
||||
e.result == Cr.NS_ERROR_NOT_AVAILABLE)) {
|
||||
// This is an expected exception, thrown if the type can't be determined
|
||||
} finally {
|
||||
}
|
||||
// Not crashing is good enough
|
||||
do_check_eq(true, true);
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
/**
|
||||
* Test for bug 508030 <https://bugzilla.mozilla.org/show_bug.cgi?id=508030>:
|
||||
* nsIMIMEService.getTypeFromExtension fails to find a match in the
|
||||
* "ext-to-type-mapping" category if the provided extension is not lowercase.
|
||||
*/
|
||||
function run_test() {
|
||||
// --- Common services ---
|
||||
|
||||
const mimeService = Cc["@mozilla.org/mime;1"].
|
||||
getService(Ci.nsIMIMEService);
|
||||
|
||||
const categoryManager = Cc["@mozilla.org/categorymanager;1"].
|
||||
getService(Ci.nsICategoryManager);
|
||||
|
||||
// --- Test procedure ---
|
||||
|
||||
const kTestExtension = "testextension";
|
||||
const kTestExtensionMixedCase = "testExtensIon";
|
||||
const kTestMimeType = "application/x-testextension";
|
||||
|
||||
// Ensure that the test extension is not initially recognized by the operating
|
||||
// system or the "ext-to-type-mapping" category.
|
||||
try {
|
||||
// Try and get the MIME type associated with the extension.
|
||||
mimeService.getTypeFromExtension(kTestExtension);
|
||||
// The line above should have thrown an exception.
|
||||
do_throw("nsIMIMEService.getTypeFromExtension succeeded unexpectedly");
|
||||
} catch (e if (e instanceof Ci.nsIException &&
|
||||
e.result == Cr.NS_ERROR_NOT_AVAILABLE)) {
|
||||
// This is an expected exception, thrown if the type can't be determined.
|
||||
// Any other exception would cause the test to fail.
|
||||
}
|
||||
|
||||
// Add a temporary category entry mapping the extension to the MIME type.
|
||||
categoryManager.addCategoryEntry("ext-to-type-mapping", kTestExtension,
|
||||
kTestMimeType, false, true);
|
||||
|
||||
// Check that the mapping is recognized in the simple case.
|
||||
var type = mimeService.getTypeFromExtension(kTestExtension);
|
||||
do_check_eq(type, kTestMimeType);
|
||||
|
||||
// Check that the mapping is recognized even if the extension has mixed case.
|
||||
type = mimeService.getTypeFromExtension(kTestExtensionMixedCase);
|
||||
do_check_eq(type, kTestMimeType);
|
||||
|
||||
// Clean up after ourselves.
|
||||
categoryManager.deleteCategoryEntry("ext-to-type-mapping", kTestExtension, false);
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
/**
|
||||
* Test for bug 484579 <https://bugzilla.mozilla.org/show_bug.cgi?id=484579>:
|
||||
* nsIMIMEService.getTypeFromExtension may fail unexpectedly on Windows when
|
||||
* "Content Type" is empty in the registry.
|
||||
*/
|
||||
function run_test() {
|
||||
// --- Preliminary platform check ---
|
||||
|
||||
// If this test is not running on the Windows platform, stop now, before
|
||||
// calling XPCOMUtils.generateQI during the MockWindowsRegKey declaration.
|
||||
if (mozinfo.os != "win")
|
||||
return;
|
||||
|
||||
// --- Modified nsIWindowsRegKey implementation ---
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
/**
|
||||
* Constructs a new mock registry key by wrapping the provided object.
|
||||
*
|
||||
* This mock implementation is tailored for this test, and forces consumers
|
||||
* of the readStringValue method to believe that the "Content Type" value of
|
||||
* the ".txt" key under HKEY_CLASSES_ROOT is an empty string.
|
||||
*
|
||||
* The same value read from "HKEY_LOCAL_MACHINE\SOFTWARE\Classes" is not
|
||||
* affected.
|
||||
*
|
||||
* @param aWrappedObject An actual nsIWindowsRegKey implementation.
|
||||
*/
|
||||
function MockWindowsRegKey(aWrappedObject) {
|
||||
this._wrappedObject = aWrappedObject;
|
||||
|
||||
// This function creates a forwarding function for wrappedObject
|
||||
function makeForwardingFunction(functionName) {
|
||||
return function() {
|
||||
return aWrappedObject[functionName].apply(aWrappedObject, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
// Forward all the functions that are not explicitly overridden
|
||||
for (var propertyName in aWrappedObject) {
|
||||
if (!(propertyName in this)) {
|
||||
if (typeof aWrappedObject[propertyName] == "function") {
|
||||
this[propertyName] = makeForwardingFunction(propertyName);
|
||||
} else {
|
||||
this[propertyName] = aWrappedObject[propertyName];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MockWindowsRegKey.prototype = {
|
||||
// --- Overridden nsISupports interface functions ---
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowsRegKey]),
|
||||
|
||||
// --- Overridden nsIWindowsRegKey interface functions ---
|
||||
|
||||
open: function(aRootKey, aRelPath, aMode) {
|
||||
// Remember the provided root key and path
|
||||
this._rootKey = aRootKey;
|
||||
this._relPath = aRelPath;
|
||||
|
||||
// Create the actual registry key
|
||||
return this._wrappedObject.open(aRootKey, aRelPath, aMode);
|
||||
},
|
||||
|
||||
openChild: function(aRelPath, aMode) {
|
||||
// Open the child key and wrap it
|
||||
var innerKey = this._wrappedObject.openChild(aRelPath, aMode);
|
||||
var key = new MockWindowsRegKey(innerKey);
|
||||
|
||||
// Set the properties of the child key and return it
|
||||
key._rootKey = this._rootKey;
|
||||
key._relPath = this._relPath + aRelPath;
|
||||
return key;
|
||||
},
|
||||
|
||||
createChild: function(aRelPath, aMode) {
|
||||
// Create the child key and wrap it
|
||||
var innerKey = this._wrappedObject.createChild(aRelPath, aMode);
|
||||
var key = new MockWindowsRegKey(innerKey);
|
||||
|
||||
// Set the properties of the child key and return it
|
||||
key._rootKey = this._rootKey;
|
||||
key._relPath = this._relPath + aRelPath;
|
||||
return key;
|
||||
},
|
||||
|
||||
get childCount() {
|
||||
return this._wrappedObject.childCount;
|
||||
},
|
||||
|
||||
get valueCount() {
|
||||
return this._wrappedObject.valueCount;
|
||||
},
|
||||
|
||||
readStringValue: function(aName) {
|
||||
// If this is the key under test, return a fake value
|
||||
if (this._rootKey == Ci.nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT &&
|
||||
this._relPath.toLowerCase() == ".txt" &&
|
||||
aName.toLowerCase() == "content type") {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Return the real value in the registry
|
||||
return this._wrappedObject.readStringValue(aName);
|
||||
}
|
||||
};
|
||||
|
||||
// --- Mock nsIWindowsRegKey factory ---
|
||||
|
||||
var componentRegistrar = Components.manager.
|
||||
QueryInterface(Ci.nsIComponentRegistrar);
|
||||
|
||||
var originalWindowsRegKeyCID;
|
||||
var mockWindowsRegKeyFactory;
|
||||
|
||||
const kMockCID = Components.ID("{9b23dfe9-296b-4740-ba1c-d39c9a16e55e}");
|
||||
const kWindowsRegKeyContractID = "@mozilla.org/windows-registry-key;1";
|
||||
const kWindowsRegKeyClassName = "nsWindowsRegKey";
|
||||
|
||||
function registerMockWindowsRegKeyFactory() {
|
||||
mockWindowsRegKeyFactory = {
|
||||
createInstance: function(aOuter, aIid) {
|
||||
if (aOuter != null)
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
var innerKey = originalWindowsRegKeyFactory.createInstance(null, aIid);
|
||||
var key = new MockWindowsRegKey(innerKey);
|
||||
|
||||
return key.QueryInterface(aIid);
|
||||
}
|
||||
};
|
||||
|
||||
// Preserve the original factory
|
||||
originalWindowsRegKeyCID = Cc[kWindowsRegKeyContractID].number;
|
||||
|
||||
// Register the mock factory
|
||||
componentRegistrar.registerFactory(
|
||||
kMockCID,
|
||||
"Mock Windows Registry Key Implementation",
|
||||
kWindowsRegKeyContractID,
|
||||
mockWindowsRegKeyFactory
|
||||
);
|
||||
}
|
||||
|
||||
function unregisterMockWindowsRegKeyFactory() {
|
||||
// Free references to the mock factory
|
||||
componentRegistrar.unregisterFactory(
|
||||
kMockCID,
|
||||
mockWindowsRegKeyFactory
|
||||
);
|
||||
|
||||
// Restore the original factory
|
||||
componentRegistrar.registerFactory(
|
||||
Components.ID(originalWindowsRegKeyCID),
|
||||
"",
|
||||
kWindowsRegKeyContractID,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
// --- Test procedure ---
|
||||
|
||||
// Activate the override of the ".txt" file association data in the registry
|
||||
registerMockWindowsRegKeyFactory();
|
||||
try {
|
||||
// Try and get the MIME type associated with the extension. If this
|
||||
// operation does not throw an unexpected exception, the test succeeds.
|
||||
var type = Cc["@mozilla.org/mime;1"].
|
||||
getService(Ci.nsIMIMEService).
|
||||
getTypeFromExtension(".txt");
|
||||
} catch (e if (e instanceof Ci.nsIException &&
|
||||
e.result == Cr.NS_ERROR_NOT_AVAILABLE)) {
|
||||
// This is an expected exception, thrown if the type can't be determined
|
||||
} finally {
|
||||
// Ensure we restore the original factory when the test is finished
|
||||
unregisterMockWindowsRegKeyFactory();
|
||||
}
|
||||
}
|
||||
470
uriloader/exthandler/tests/unit/test_handlerService.js
Normal file
470
uriloader/exthandler/tests/unit/test_handlerService.js
Normal file
|
|
@ -0,0 +1,470 @@
|
|||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
//**************************************************************************//
|
||||
// Constants
|
||||
|
||||
const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].
|
||||
getService(Ci.nsIHandlerService);
|
||||
|
||||
const mimeSvc = Cc["@mozilla.org/mime;1"].
|
||||
getService(Ci.nsIMIMEService);
|
||||
|
||||
const protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
|
||||
getService(Ci.nsIExternalProtocolService);
|
||||
|
||||
const prefSvc = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService);
|
||||
|
||||
const ioService = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
const env = Cc["@mozilla.org/process/environment;1"].
|
||||
getService(Components.interfaces.nsIEnvironment);
|
||||
|
||||
const rootPrefBranch = prefSvc.getBranch("");
|
||||
|
||||
let noMailto = false;
|
||||
if (mozinfo.os == "win") {
|
||||
// Check mailto handler from registry.
|
||||
// If registry entry is nothing, no mailto handler
|
||||
let regSvc = Cc["@mozilla.org/windows-registry-key;1"].
|
||||
createInstance(Ci.nsIWindowsRegKey);
|
||||
try {
|
||||
regSvc.open(regSvc.ROOT_KEY_CLASSES_ROOT,
|
||||
"mailto",
|
||||
regSvc.ACCESS_READ);
|
||||
noMailto = false;
|
||||
} catch (ex) {
|
||||
noMailto = true;
|
||||
}
|
||||
regSvc.close();
|
||||
}
|
||||
|
||||
if (mozinfo.os == "linux") {
|
||||
// Check mailto handler from GIO
|
||||
// If there isn't one, then we have no mailto handler
|
||||
let gIOSvc = Cc["@mozilla.org/gio-service;1"].
|
||||
createInstance(Ci.nsIGIOService);
|
||||
try {
|
||||
gIOSvc.getAppForURIScheme("mailto");
|
||||
noMailto = false;
|
||||
} catch (ex) {
|
||||
noMailto = true;
|
||||
}
|
||||
}
|
||||
|
||||
//**************************************************************************//
|
||||
// Sample Data
|
||||
|
||||
// It doesn't matter whether or not this nsIFile is actually executable,
|
||||
// only that it has a path and exists. Since we don't know any executable
|
||||
// that exists on all platforms (except possibly the application being
|
||||
// tested, but there doesn't seem to be a way to get a reference to that
|
||||
// from the directory service), we use the temporary directory itself.
|
||||
var executable = HandlerServiceTest._dirSvc.get("TmpD", Ci.nsIFile);
|
||||
// XXX We could, of course, create an actual executable in the directory:
|
||||
//executable.append("localhandler");
|
||||
//if (!executable.exists())
|
||||
// executable.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o755);
|
||||
|
||||
var localHandler = {
|
||||
name: "Local Handler",
|
||||
executable: executable,
|
||||
interfaces: [Ci.nsIHandlerApp, Ci.nsILocalHandlerApp, Ci.nsISupports],
|
||||
QueryInterface: function(iid) {
|
||||
if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
var webHandler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
|
||||
createInstance(Ci.nsIWebHandlerApp);
|
||||
webHandler.name = "Web Handler";
|
||||
webHandler.uriTemplate = "http://www.example.com/?%s";
|
||||
|
||||
// FIXME: these tests create and manipulate enough variables that it would
|
||||
// make sense to move each test into its own scope so we don't run the risk
|
||||
// of one test stomping on another's data.
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// Test Default Properties
|
||||
|
||||
// Get a handler info for a MIME type that neither the application nor
|
||||
// the OS knows about and make sure its properties are set to the proper
|
||||
// default values.
|
||||
|
||||
var handlerInfo = mimeSvc.getFromTypeAndExtension("nonexistent/type", null);
|
||||
|
||||
// Make sure it's also an nsIHandlerInfo.
|
||||
do_check_true(handlerInfo instanceof Ci.nsIHandlerInfo);
|
||||
|
||||
do_check_eq(handlerInfo.type, "nonexistent/type");
|
||||
|
||||
// Deprecated property, but we should still make sure it's set correctly.
|
||||
do_check_eq(handlerInfo.MIMEType, "nonexistent/type");
|
||||
|
||||
// These properties are the ones the handler service knows how to store.
|
||||
do_check_eq(handlerInfo.preferredAction, Ci.nsIHandlerInfo.saveToDisk);
|
||||
do_check_eq(handlerInfo.preferredApplicationHandler, null);
|
||||
do_check_eq(handlerInfo.possibleApplicationHandlers.length, 0);
|
||||
do_check_true(handlerInfo.alwaysAskBeforeHandling);
|
||||
|
||||
// These properties are initialized to default values by the service,
|
||||
// so we might as well make sure they're initialized to the right defaults.
|
||||
do_check_eq(handlerInfo.description, "");
|
||||
do_check_eq(handlerInfo.hasDefaultHandler, false);
|
||||
do_check_eq(handlerInfo.defaultDescription, "");
|
||||
|
||||
// test some default protocol info properties
|
||||
var haveDefaultHandlersVersion = false;
|
||||
try {
|
||||
// If we have a defaultHandlersVersion pref, then assume that we're in the
|
||||
// firefox tree and that we'll also have default handlers.
|
||||
// Bug 395131 has been filed to make this test work more generically
|
||||
// by providing our own prefs for this test rather than this icky
|
||||
// special casing.
|
||||
rootPrefBranch.getCharPref("gecko.handlerService.defaultHandlersVersion");
|
||||
haveDefaultHandlersVersion = true;
|
||||
} catch (ex) {}
|
||||
|
||||
const kExternalWarningDefault =
|
||||
"network.protocol-handler.warn-external-default";
|
||||
prefSvc.setBoolPref(kExternalWarningDefault, true);
|
||||
|
||||
// XXX add more thorough protocol info property checking
|
||||
|
||||
// no OS default handler exists
|
||||
var protoInfo = protoSvc.getProtocolHandlerInfo("x-moz-rheet");
|
||||
do_check_eq(protoInfo.preferredAction, protoInfo.alwaysAsk);
|
||||
do_check_true(protoInfo.alwaysAskBeforeHandling);
|
||||
|
||||
// OS default exists, injected default does not exist,
|
||||
// explicit warning pref: false
|
||||
const kExternalWarningPrefPrefix = "network.protocol-handler.warn-external.";
|
||||
prefSvc.setBoolPref(kExternalWarningPrefPrefix + "http", false);
|
||||
protoInfo = protoSvc.getProtocolHandlerInfo("http");
|
||||
do_check_eq(0, protoInfo.possibleApplicationHandlers.length);
|
||||
do_check_false(protoInfo.alwaysAskBeforeHandling);
|
||||
|
||||
// OS default exists, injected default does not exist,
|
||||
// explicit warning pref: true
|
||||
prefSvc.setBoolPref(kExternalWarningPrefPrefix + "http", true);
|
||||
protoInfo = protoSvc.getProtocolHandlerInfo("http");
|
||||
// OS handler isn't included in possibleApplicationHandlers, so length is 0
|
||||
// Once they become instances of nsILocalHandlerApp, this number will need
|
||||
// to change.
|
||||
do_check_eq(0, protoInfo.possibleApplicationHandlers.length);
|
||||
do_check_true(protoInfo.alwaysAskBeforeHandling);
|
||||
|
||||
// OS default exists, injected default exists, explicit warning pref: false
|
||||
prefSvc.setBoolPref(kExternalWarningPrefPrefix + "mailto", false);
|
||||
protoInfo = protoSvc.getProtocolHandlerInfo("mailto");
|
||||
if (haveDefaultHandlersVersion)
|
||||
do_check_eq(2, protoInfo.possibleApplicationHandlers.length);
|
||||
else
|
||||
do_check_eq(0, protoInfo.possibleApplicationHandlers.length);
|
||||
|
||||
// Win7+ or Linux's GIO might not have a default mailto: handler
|
||||
if (noMailto)
|
||||
do_check_true(protoInfo.alwaysAskBeforeHandling);
|
||||
else
|
||||
do_check_false(protoInfo.alwaysAskBeforeHandling);
|
||||
|
||||
// OS default exists, injected default exists, explicit warning pref: true
|
||||
prefSvc.setBoolPref(kExternalWarningPrefPrefix + "mailto", true);
|
||||
protoInfo = protoSvc.getProtocolHandlerInfo("mailto");
|
||||
if (haveDefaultHandlersVersion) {
|
||||
do_check_eq(2, protoInfo.possibleApplicationHandlers.length);
|
||||
// Win7+ or Linux's GIO may have no default mailto: handler. Otherwise
|
||||
// alwaysAskBeforeHandling is expected to be false here, because although
|
||||
// the pref is true, the value in RDF is false. The injected mailto handler
|
||||
// carried over the default pref value, and so when we set the pref above
|
||||
// to true it's ignored.
|
||||
if (noMailto)
|
||||
do_check_true(protoInfo.alwaysAskBeforeHandling);
|
||||
else
|
||||
do_check_false(protoInfo.alwaysAskBeforeHandling);
|
||||
|
||||
} else {
|
||||
do_check_eq(0, protoInfo.possibleApplicationHandlers.length);
|
||||
do_check_true(protoInfo.alwaysAskBeforeHandling);
|
||||
}
|
||||
|
||||
if (haveDefaultHandlersVersion) {
|
||||
// Now set the value stored in RDF to true, and the pref to false, to make
|
||||
// sure we still get the right value. (Basically, same thing as above but
|
||||
// with the values reversed.)
|
||||
prefSvc.setBoolPref(kExternalWarningPrefPrefix + "mailto", false);
|
||||
protoInfo.alwaysAskBeforeHandling = true;
|
||||
handlerSvc.store(protoInfo);
|
||||
protoInfo = protoSvc.getProtocolHandlerInfo("mailto");
|
||||
do_check_eq(2, protoInfo.possibleApplicationHandlers.length);
|
||||
do_check_true(protoInfo.alwaysAskBeforeHandling);
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// Test Round-Trip Data Integrity
|
||||
|
||||
// Test round-trip data integrity by setting the properties of the handler
|
||||
// info object to different values, telling the handler service to store the
|
||||
// object, and then retrieving a new info object for the same type and making
|
||||
// sure its properties are identical.
|
||||
|
||||
handlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
|
||||
handlerInfo.preferredApplicationHandler = localHandler;
|
||||
handlerInfo.alwaysAskBeforeHandling = false;
|
||||
|
||||
handlerSvc.store(handlerInfo);
|
||||
|
||||
handlerInfo = mimeSvc.getFromTypeAndExtension("nonexistent/type", null);
|
||||
|
||||
do_check_eq(handlerInfo.preferredAction, Ci.nsIHandlerInfo.useHelperApp);
|
||||
|
||||
do_check_neq(handlerInfo.preferredApplicationHandler, null);
|
||||
var preferredHandler = handlerInfo.preferredApplicationHandler;
|
||||
do_check_eq(typeof preferredHandler, "object");
|
||||
do_check_eq(preferredHandler.name, "Local Handler");
|
||||
do_check_true(preferredHandler instanceof Ci.nsILocalHandlerApp);
|
||||
preferredHandler.QueryInterface(Ci.nsILocalHandlerApp);
|
||||
do_check_eq(preferredHandler.executable.path, localHandler.executable.path);
|
||||
|
||||
do_check_false(handlerInfo.alwaysAskBeforeHandling);
|
||||
|
||||
// Make sure the handler service's enumerate method lists all known handlers.
|
||||
var handlerInfo2 = mimeSvc.getFromTypeAndExtension("nonexistent/type2", null);
|
||||
handlerSvc.store(handlerInfo2);
|
||||
var handlerTypes = ["nonexistent/type", "nonexistent/type2"];
|
||||
if (haveDefaultHandlersVersion) {
|
||||
handlerTypes.push("webcal");
|
||||
handlerTypes.push("mailto");
|
||||
handlerTypes.push("irc");
|
||||
handlerTypes.push("ircs");
|
||||
}
|
||||
var handlers = handlerSvc.enumerate();
|
||||
while (handlers.hasMoreElements()) {
|
||||
var handler = handlers.getNext().QueryInterface(Ci.nsIHandlerInfo);
|
||||
do_check_neq(handlerTypes.indexOf(handler.type), -1);
|
||||
handlerTypes.splice(handlerTypes.indexOf(handler.type), 1);
|
||||
}
|
||||
do_check_eq(handlerTypes.length, 0);
|
||||
|
||||
// Make sure the handler service's remove method removes a handler record.
|
||||
handlerSvc.remove(handlerInfo2);
|
||||
handlers = handlerSvc.enumerate();
|
||||
while (handlers.hasMoreElements())
|
||||
do_check_neq(handlers.getNext().QueryInterface(Ci.nsIHandlerInfo).type,
|
||||
handlerInfo2.type);
|
||||
|
||||
// Make sure we can store and retrieve a handler info object with no preferred
|
||||
// handler.
|
||||
var noPreferredHandlerInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/no-preferred-handler", null);
|
||||
handlerSvc.store(noPreferredHandlerInfo);
|
||||
noPreferredHandlerInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/no-preferred-handler", null);
|
||||
do_check_eq(noPreferredHandlerInfo.preferredApplicationHandler, null);
|
||||
|
||||
// Make sure that the handler service removes an existing handler record
|
||||
// if we store a handler info object with no preferred handler.
|
||||
var removePreferredHandlerInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/rem-preferred-handler", null);
|
||||
removePreferredHandlerInfo.preferredApplicationHandler = localHandler;
|
||||
handlerSvc.store(removePreferredHandlerInfo);
|
||||
removePreferredHandlerInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/rem-preferred-handler", null);
|
||||
removePreferredHandlerInfo.preferredApplicationHandler = null;
|
||||
handlerSvc.store(removePreferredHandlerInfo);
|
||||
removePreferredHandlerInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/rem-preferred-handler", null);
|
||||
do_check_eq(removePreferredHandlerInfo.preferredApplicationHandler, null);
|
||||
|
||||
// Make sure we can store and retrieve a handler info object with possible
|
||||
// handlers. We test both adding and removing handlers.
|
||||
|
||||
// Get a handler info and make sure it has no possible handlers.
|
||||
var possibleHandlersInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/possible-handlers", null);
|
||||
do_check_eq(possibleHandlersInfo.possibleApplicationHandlers.length, 0);
|
||||
|
||||
// Store and re-retrieve the handler and make sure it still has no possible
|
||||
// handlers.
|
||||
handlerSvc.store(possibleHandlersInfo);
|
||||
possibleHandlersInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/possible-handlers", null);
|
||||
do_check_eq(possibleHandlersInfo.possibleApplicationHandlers.length, 0);
|
||||
|
||||
// Add two handlers, store the object, re-retrieve it, and make sure it has
|
||||
// two handlers.
|
||||
possibleHandlersInfo.possibleApplicationHandlers.appendElement(localHandler,
|
||||
false);
|
||||
possibleHandlersInfo.possibleApplicationHandlers.appendElement(webHandler,
|
||||
false);
|
||||
handlerSvc.store(possibleHandlersInfo);
|
||||
possibleHandlersInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/possible-handlers", null);
|
||||
do_check_eq(possibleHandlersInfo.possibleApplicationHandlers.length, 2);
|
||||
|
||||
// Figure out which is the local and which is the web handler and the index
|
||||
// in the array of the local handler, which is the one we're going to remove
|
||||
// to test removal of a handler.
|
||||
var handler1 = possibleHandlersInfo.possibleApplicationHandlers.
|
||||
queryElementAt(0, Ci.nsIHandlerApp);
|
||||
var handler2 = possibleHandlersInfo.possibleApplicationHandlers.
|
||||
queryElementAt(1, Ci.nsIHandlerApp);
|
||||
var localPossibleHandler, webPossibleHandler, localIndex;
|
||||
if (handler1 instanceof Ci.nsILocalHandlerApp)
|
||||
[localPossibleHandler, webPossibleHandler, localIndex] = [handler1,
|
||||
handler2,
|
||||
0];
|
||||
else
|
||||
[localPossibleHandler, webPossibleHandler, localIndex] = [handler2,
|
||||
handler1,
|
||||
1];
|
||||
localPossibleHandler.QueryInterface(Ci.nsILocalHandlerApp);
|
||||
webPossibleHandler.QueryInterface(Ci.nsIWebHandlerApp);
|
||||
|
||||
// Make sure the two handlers are the ones we stored.
|
||||
do_check_eq(localPossibleHandler.name, localHandler.name);
|
||||
do_check_true(localPossibleHandler.equals(localHandler));
|
||||
do_check_eq(webPossibleHandler.name, webHandler.name);
|
||||
do_check_true(webPossibleHandler.equals(webHandler));
|
||||
|
||||
// Remove a handler, store the object, re-retrieve it, and make sure
|
||||
// it only has one handler.
|
||||
possibleHandlersInfo.possibleApplicationHandlers.removeElementAt(localIndex);
|
||||
handlerSvc.store(possibleHandlersInfo);
|
||||
possibleHandlersInfo =
|
||||
mimeSvc.getFromTypeAndExtension("nonexistent/possible-handlers", null);
|
||||
do_check_eq(possibleHandlersInfo.possibleApplicationHandlers.length, 1);
|
||||
|
||||
// Make sure the handler is the one we didn't remove.
|
||||
webPossibleHandler = possibleHandlersInfo.possibleApplicationHandlers.
|
||||
queryElementAt(0, Ci.nsIWebHandlerApp);
|
||||
do_check_eq(webPossibleHandler.name, webHandler.name);
|
||||
do_check_true(webPossibleHandler.equals(webHandler));
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// handler info command line parameters and equality
|
||||
var localApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
|
||||
createInstance(Ci.nsILocalHandlerApp);
|
||||
var handlerApp = localApp.QueryInterface(Ci.nsIHandlerApp);
|
||||
|
||||
do_check_true(handlerApp.equals(localApp));
|
||||
|
||||
localApp.executable = executable;
|
||||
|
||||
do_check_eq(0, localApp.parameterCount);
|
||||
localApp.appendParameter("-test1");
|
||||
do_check_eq(1, localApp.parameterCount);
|
||||
localApp.appendParameter("-test2");
|
||||
do_check_eq(2, localApp.parameterCount);
|
||||
do_check_true(localApp.parameterExists("-test1"));
|
||||
do_check_true(localApp.parameterExists("-test2"));
|
||||
do_check_false(localApp.parameterExists("-false"));
|
||||
localApp.clearParameters();
|
||||
do_check_eq(0, localApp.parameterCount);
|
||||
|
||||
var localApp2 = Cc["@mozilla.org/uriloader/local-handler-app;1"].
|
||||
createInstance(Ci.nsILocalHandlerApp);
|
||||
|
||||
localApp2.executable = executable;
|
||||
|
||||
localApp.clearParameters();
|
||||
do_check_true(localApp.equals(localApp2));
|
||||
|
||||
// equal:
|
||||
// cut -d 1 -f 2
|
||||
// cut -d 1 -f 2
|
||||
|
||||
localApp.appendParameter("-test1");
|
||||
localApp.appendParameter("-test2");
|
||||
localApp.appendParameter("-test3");
|
||||
localApp2.appendParameter("-test1");
|
||||
localApp2.appendParameter("-test2");
|
||||
localApp2.appendParameter("-test3");
|
||||
do_check_true(localApp.equals(localApp2));
|
||||
|
||||
// not equal:
|
||||
// cut -d 1 -f 2
|
||||
// cut -f 1 -d 2
|
||||
|
||||
localApp.clearParameters();
|
||||
localApp2.clearParameters();
|
||||
|
||||
localApp.appendParameter("-test1");
|
||||
localApp.appendParameter("-test2");
|
||||
localApp.appendParameter("-test3");
|
||||
localApp2.appendParameter("-test2");
|
||||
localApp2.appendParameter("-test1");
|
||||
localApp2.appendParameter("-test3");
|
||||
do_check_false(localApp2.equals(localApp));
|
||||
|
||||
var str;
|
||||
str = localApp.getParameter(0)
|
||||
do_check_eq(str, "-test1");
|
||||
str = localApp.getParameter(1)
|
||||
do_check_eq(str, "-test2");
|
||||
str = localApp.getParameter(2)
|
||||
do_check_eq(str, "-test3");
|
||||
|
||||
// FIXME: test round trip integrity for a protocol.
|
||||
// FIXME: test round trip integrity for a handler info with a web handler.
|
||||
|
||||
//**************************************************************************//
|
||||
// getTypeFromExtension tests
|
||||
|
||||
// test nonexistent extension
|
||||
var lolType = handlerSvc.getTypeFromExtension("lolcat");
|
||||
do_check_eq(lolType, "");
|
||||
|
||||
|
||||
// add a handler for the extension
|
||||
var lolHandler = mimeSvc.getFromTypeAndExtension("application/lolcat", null);
|
||||
|
||||
do_check_false(lolHandler.extensionExists("lolcat"));
|
||||
lolHandler.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
|
||||
lolHandler.preferredApplicationHandler = localHandler;
|
||||
lolHandler.alwaysAskBeforeHandling = false;
|
||||
|
||||
// store the handler
|
||||
do_check_false(handlerSvc.exists(lolHandler));
|
||||
handlerSvc.store(lolHandler);
|
||||
do_check_true(handlerSvc.exists(lolHandler));
|
||||
|
||||
// Get a file:// string pointing to mimeTypes.rdf
|
||||
var rdfFile = HandlerServiceTest._dirSvc.get("UMimTyp", Ci.nsIFile);
|
||||
var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler);
|
||||
var rdfFileURI = fileHandler.getURLSpecFromFile(rdfFile);
|
||||
|
||||
// Assign a file extenstion to the handler. handlerSvc.store() doesn't
|
||||
// actually store any file extensions added with setFileExtensions(), you
|
||||
// have to wade into RDF muck to do so.
|
||||
|
||||
// Based on toolkit/mozapps/downloads/content/helperApps.js :: addExtension()
|
||||
var gRDF = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
|
||||
var mimeSource = gRDF.GetUnicodeResource("urn:mimetype:application/lolcat");
|
||||
var valueProperty = gRDF.GetUnicodeResource("http://home.netscape.com/NC-rdf#fileExtensions");
|
||||
var mimeLiteral = gRDF.GetLiteral("lolcat");
|
||||
|
||||
var DS = gRDF.GetDataSourceBlocking(rdfFileURI);
|
||||
DS.Assert(mimeSource, valueProperty, mimeLiteral, true);
|
||||
|
||||
|
||||
// test now-existent extension
|
||||
lolType = handlerSvc.getTypeFromExtension("lolcat");
|
||||
do_check_eq(lolType, "application/lolcat");
|
||||
|
||||
// test mailcap entries with needsterminal are ignored on non-Windows non-Mac.
|
||||
if (mozinfo.os != "win" && mozinfo.os != "mac") {
|
||||
env.set('PERSONAL_MAILCAP', do_get_file('mailcap').path);
|
||||
handlerInfo = mimeSvc.getFromTypeAndExtension("text/plain", null);
|
||||
do_check_eq(handlerInfo.preferredAction, Ci.nsIHandlerInfo.useSystemDefault);
|
||||
do_check_eq(handlerInfo.defaultDescription, "sed");
|
||||
}
|
||||
}
|
||||
126
uriloader/exthandler/tests/unit/test_punycodeURIs.js
Normal file
126
uriloader/exthandler/tests/unit/test_punycodeURIs.js
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/* 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/. */
|
||||
|
||||
// Encoded test URI to work on all platforms/independent of file encoding
|
||||
const kTestURI = "http://\u65e5\u672c\u8a93.jp/";
|
||||
const kExpectedURI = "http://xn--wgv71a309e.jp/";
|
||||
const kOutputFile = "result.txt";
|
||||
|
||||
// Try several times in case the box we're running on is slow.
|
||||
const kMaxCheckExistAttempts = 30; // seconds
|
||||
var gCheckExistsAttempts = 0;
|
||||
|
||||
const tempDir = do_get_tempdir();
|
||||
|
||||
function checkFile() {
|
||||
// This is where we expect the output
|
||||
var tempFile = tempDir.clone();
|
||||
tempFile.append(kOutputFile);
|
||||
|
||||
if (!tempFile.exists()) {
|
||||
if (gCheckExistsAttempts >= kMaxCheckExistAttempts) {
|
||||
do_throw("Expected File " + tempFile.path + " does not exist after " +
|
||||
kMaxCheckExistAttempts + " seconds");
|
||||
}
|
||||
else {
|
||||
++gCheckExistsAttempts;
|
||||
// Wait a bit longer then try again
|
||||
do_timeout(1000, checkFile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Now read it
|
||||
var fstream =
|
||||
Components.classes["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileInputStream);
|
||||
var sstream =
|
||||
Components.classes["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
fstream.init(tempFile, -1, 0, 0);
|
||||
sstream.init(fstream);
|
||||
|
||||
// Read the first line only as that's the one we expect WriteArguments
|
||||
// to be writing the argument to.
|
||||
var data = sstream.read(4096);
|
||||
|
||||
sstream.close();
|
||||
fstream.close();
|
||||
|
||||
// Now remove the old file
|
||||
tempFile.remove(false);
|
||||
|
||||
// This currently fails on Mac with an argument like -psn_0_nnnnnn
|
||||
// This seems to be to do with how the executable is called, but I couldn't
|
||||
// find a way around it.
|
||||
// Additionally the lack of OS detection in xpcshell tests sucks, so we'll
|
||||
// have to check for the argument mac gives us.
|
||||
if (data.substring(0, 7) != "-psn_0_")
|
||||
do_check_eq(data, kExpectedURI);
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
if (mozinfo.os == "mac") {
|
||||
dump("INFO | test_punycodeURIs.js | Skipping test on mac, bug 599475")
|
||||
return;
|
||||
}
|
||||
|
||||
// set up the uri to test with
|
||||
var ioService =
|
||||
Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
|
||||
// set up the local handler object
|
||||
var localHandler =
|
||||
Components.classes["@mozilla.org/uriloader/local-handler-app;1"]
|
||||
.createInstance(Components.interfaces.nsILocalHandlerApp);
|
||||
localHandler.name = "Test Local Handler App";
|
||||
|
||||
// WriteArgument will just dump its arguments to a file for us.
|
||||
var processDir = do_get_cwd();
|
||||
var exe = processDir.clone();
|
||||
exe.append("WriteArgument");
|
||||
|
||||
if (!exe.exists()) {
|
||||
// Maybe we are on windows
|
||||
exe.leafName = "WriteArgument.exe";
|
||||
if (!exe.exists())
|
||||
do_throw("Could not locate the WriteArgument tests executable\n");
|
||||
}
|
||||
|
||||
var outFile = tempDir.clone();
|
||||
outFile.append(kOutputFile);
|
||||
|
||||
// Set an environment variable for WriteArgument to pick up
|
||||
var envSvc =
|
||||
Components.classes["@mozilla.org/process/environment;1"]
|
||||
.getService(Components.interfaces.nsIEnvironment);
|
||||
|
||||
// The Write Argument file needs to know where its libraries are, so
|
||||
// just force the path variable
|
||||
// For mac
|
||||
var greDir = HandlerServiceTest._dirSvc.get("GreD", Components.interfaces.nsIFile);
|
||||
|
||||
envSvc.set("DYLD_LIBRARY_PATH", greDir.path);
|
||||
// For Linux
|
||||
envSvc.set("LD_LIBRARY_PATH", greDir.path);
|
||||
//XXX: handle windows
|
||||
|
||||
// Now tell it where we want the file.
|
||||
envSvc.set("WRITE_ARGUMENT_FILE", outFile.path);
|
||||
|
||||
var uri = ioService.newURI(kTestURI, null, null);
|
||||
|
||||
// Just check we've got these matching, if we haven't there's a problem
|
||||
// with ascii spec or our test case.
|
||||
do_check_eq(uri.asciiSpec, kExpectedURI);
|
||||
|
||||
localHandler.executable = exe;
|
||||
localHandler.launchWithURI(uri);
|
||||
|
||||
do_test_pending();
|
||||
do_timeout(1000, checkFile);
|
||||
}
|
||||
15
uriloader/exthandler/tests/unit/xpcshell.ini
Normal file
15
uriloader/exthandler/tests/unit/xpcshell.ini
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[DEFAULT]
|
||||
head = head_handlerService.js
|
||||
tail = tail_handlerService.js
|
||||
run-sequentially = Bug 912235 - Intermittent failures
|
||||
|
||||
[test_getTypeFromExtension_ext_to_type_mapping.js]
|
||||
[test_getTypeFromExtension_with_empty_Content_Type.js]
|
||||
[test_badMIMEType.js]
|
||||
[test_handlerService.js]
|
||||
support-files = mailcap
|
||||
# Bug 676997: test consistently fails on Android
|
||||
fail-if = os == "android"
|
||||
[test_punycodeURIs.js]
|
||||
# Bug 676997: test consistently fails on Android
|
||||
fail-if = os == "android"
|
||||
231
uriloader/exthandler/tests/unit_ipc/test_encoding.js
Normal file
231
uriloader/exthandler/tests/unit_ipc/test_encoding.js
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://testing-common/MockRegistrar.js");
|
||||
|
||||
do_get_profile();
|
||||
|
||||
var DownloadListener = {
|
||||
init: function () {
|
||||
let obs = Services.obs;
|
||||
obs.addObserver(this, "dl-done", true);
|
||||
},
|
||||
|
||||
observe: function (subject, topic, data) {
|
||||
this.onFinished(subject, topic, data);
|
||||
},
|
||||
|
||||
QueryInterface: function (iid) {
|
||||
if (iid.equals(Ci.nsIObserver) ||
|
||||
iid.equals(Ci.nsISupportsWeakReference) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
DownloadListener.init();
|
||||
|
||||
function HelperAppDlg() { }
|
||||
HelperAppDlg.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
|
||||
show: function (launcher, ctx, reason, usePrivateUI) {
|
||||
launcher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToFile;
|
||||
launcher.launchWithApplication(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Override the download-manager-ui to prevent anyone from trying to open
|
||||
// a window.
|
||||
function DownloadMgrUI() { }
|
||||
DownloadMgrUI.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadManagerUI]),
|
||||
show: function (ir, aID, reason) { },
|
||||
|
||||
visible: false,
|
||||
|
||||
getAttention: function () { }
|
||||
}
|
||||
|
||||
function AlertsSVC() { }
|
||||
AlertsSVC.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]),
|
||||
showAlertNotification: function (url, title, text, clickable, cookie, listener, name) { },
|
||||
}
|
||||
|
||||
MockRegistrar.register("@mozilla.org/helperapplauncherdialog;1",
|
||||
HelperAppDlg);
|
||||
MockRegistrar.register("@mozilla.org/download-manager-ui;1",
|
||||
DownloadMgrUI);
|
||||
MockRegistrar.register("@mozilla.org/alerts-service;1",
|
||||
AlertsSVC);
|
||||
|
||||
function initChildTestEnv()
|
||||
{
|
||||
sendCommand(' \
|
||||
const Cc = Components.classes; \
|
||||
const Ci = Components.interfaces; \
|
||||
const Cr = Components.results; \
|
||||
const Cu = Components.utils; \
|
||||
Cu.import("resource://gre/modules/Services.jsm"); \
|
||||
function WindowContext() { } \
|
||||
\
|
||||
WindowContext.prototype = { \
|
||||
getInterface: function (iid) { \
|
||||
if (iid.equals(Ci.nsIInterfaceRequestor) || \
|
||||
iid.equals(Ci.nsIURIContentListener) || \
|
||||
iid.equals(Ci.nsILoadGroup) || \
|
||||
iid.equals(Ci.nsIDocumentLoader) || \
|
||||
iid.equals(Ci.nsIDOMWindow)) \
|
||||
return this; \
|
||||
\
|
||||
throw Cr.NS_ERROR_NO_INTERFACE; \
|
||||
}, \
|
||||
\
|
||||
/* nsIURIContentListener */ \
|
||||
onStartURIOpen: function (uri) { }, \
|
||||
isPreferred: function (type, desiredtype) { return false; }, \
|
||||
\
|
||||
/* nsILoadGroup */ \
|
||||
addRequest: function (request, context) { }, \
|
||||
removeRequest: function (request, context, status) { } \
|
||||
}; \
|
||||
\
|
||||
var ioservice = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);\
|
||||
var uriloader = Cc["@mozilla.org/uriloader;1"].getService(Ci.nsIURILoader);\
|
||||
');
|
||||
}
|
||||
|
||||
function testFinisher(endFunc) {
|
||||
let ef = endFunc;
|
||||
return function (file) {
|
||||
ef(file);
|
||||
runNextTest();
|
||||
}
|
||||
}
|
||||
|
||||
function runChildTestSet(set)
|
||||
{
|
||||
DownloadListener.onFinished = testFinisher(set[2]);
|
||||
sendCommand('\
|
||||
let uri = ioservice.newURI("http://localhost:4444' + set[0] + '", null, null); \
|
||||
let channel = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true}); \
|
||||
uriloader.openURI(channel, Ci.nsIURILoader.IS_CONTENT_PREFERRED, new WindowContext()); \
|
||||
');
|
||||
}
|
||||
|
||||
var httpserver = null;
|
||||
var currentTest = 0;
|
||||
function runNextTest()
|
||||
{
|
||||
if (currentTest == tests.length) {
|
||||
httpserver.stop(do_test_finished);
|
||||
return;
|
||||
}
|
||||
|
||||
let set = tests[currentTest++];
|
||||
runChildTestSet(set);
|
||||
}
|
||||
|
||||
const responseBody = [0x1f, 0x8b, 0x08, 0x00, 0x16, 0x5a, 0x8a, 0x48, 0x02,
|
||||
0x03, 0x2b, 0x49, 0x2d, 0x2e, 0xe1, 0x02, 0x00, 0xc6,
|
||||
0x35, 0xb9, 0x3b, 0x05, 0x00, 0x00, 0x00];
|
||||
|
||||
/*
|
||||
* First test: a file with Content-Type application/x-gzip and Content-Encoding gzip
|
||||
* should not be decoded in a round-trip
|
||||
*/
|
||||
function testResponse1(metadata, response) {
|
||||
response.setHeader("Content-Type", "application/x-gzip", false);
|
||||
response.setHeader("Content-Encoding", "gzip", false);
|
||||
response.setHeader("Content-Disposition", "attachment", false);
|
||||
|
||||
var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(response.bodyOutputStream);
|
||||
bos.writeByteArray(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finishTest1(subject, topic, data) {
|
||||
let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
|
||||
do_check_true(file.path.search("test1.gz") != 0);
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(file, -1, -1, 0);
|
||||
let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(fis);
|
||||
let str = bis.readByteArray(bis.available());
|
||||
do_check_matches(str, responseBody);
|
||||
}
|
||||
|
||||
/*
|
||||
* Second test: a file with Content-Type text/html and Content-Encoding gzip
|
||||
* should not be decoded in a round-trip, if its filename ends in ".gz".
|
||||
* We specify a Content-disposition header to force it to be saved as a file.
|
||||
*/
|
||||
function testResponse2(metadata, response) {
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.setHeader("Content-Encoding", "gzip", false);
|
||||
response.setHeader("Content-Disposition", "attachment", false);
|
||||
|
||||
var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(response.bodyOutputStream);
|
||||
bos.writeByteArray(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finishTest2(subject, topic, data) {
|
||||
let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
|
||||
do_check_true(file.path.search("test2.gz") != 0);
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(file, -1, -1, 0);
|
||||
let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(fis);
|
||||
let str = bis.readByteArray(bis.available());
|
||||
do_check_matches(str, responseBody);
|
||||
}
|
||||
|
||||
function testResponse3(metadata, response) {
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.setHeader("Content-Encoding", "gzip", false);
|
||||
response.setHeader("Content-Disposition", "attachment", false);
|
||||
|
||||
var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(response.bodyOutputStream);
|
||||
bos.writeByteArray(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finishTest3(subject, topic, data) {
|
||||
let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
|
||||
do_check_true(file.path.search("test3.txt") != 0);
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(file, -1, -1, 0);
|
||||
let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(fis);
|
||||
let str = bis.readByteArray(bis.available());
|
||||
let decodedBody = [ 116, 101, 115, 116, 10 ]; // 't','e','s','t','\n'
|
||||
do_check_matches(str, decodedBody);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
[ "/test1.gz", testResponse1, finishTest1 ],
|
||||
[ "/test2.gz", testResponse2, finishTest2 ],
|
||||
[ "/test3.txt", testResponse3, finishTest3 ],
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
// do_load_child_test_harness();
|
||||
httpserver = new HttpServer();
|
||||
httpserver.start(4444);
|
||||
do_test_pending();
|
||||
|
||||
initChildTestEnv();
|
||||
|
||||
for (let set of tests)
|
||||
httpserver.registerPathHandler(set[0], set[1]);
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
8
uriloader/exthandler/tests/unit_ipc/xpcshell.ini
Normal file
8
uriloader/exthandler/tests/unit_ipc/xpcshell.ini
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
|
||||
[test_encoding.js]
|
||||
# Bug 676995: test hangs consistently on Android
|
||||
# Bug 907732: thunderbird still uses legacy downloads manager.
|
||||
skip-if = (os == "android" || buildapp == '../mail')
|
||||
32
uriloader/exthandler/uikit/nsLocalHandlerAppUIKit.h
Normal file
32
uriloader/exthandler/uikit/nsLocalHandlerAppUIKit.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2:cin:
|
||||
* 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 nslocalhandlerappuikit_h_
|
||||
#define nslocalhandlerappuikit_h_
|
||||
|
||||
#include "nsLocalHandlerApp.h"
|
||||
|
||||
class nsLocalHandlerAppUIKit final : public nsLocalHandlerApp
|
||||
{
|
||||
public:
|
||||
nsLocalHandlerAppUIKit()
|
||||
{}
|
||||
~nsLocalHandlerAppUIKit()
|
||||
{}
|
||||
|
||||
nsLocalHandlerAppUIKit(const char16_t* aName, nsIFile* aExecutable)
|
||||
: nsLocalHandlerApp(aName, aExecutable)
|
||||
{}
|
||||
|
||||
nsLocalHandlerAppUIKit(const nsAString& aName, nsIFile* aExecutable)
|
||||
: nsLocalHandlerApp(aName, aExecutable)
|
||||
{}
|
||||
|
||||
|
||||
NS_IMETHOD LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor* aWindowContext);
|
||||
};
|
||||
|
||||
#endif /* nslocalhandlerappuikit_h_ */
|
||||
17
uriloader/exthandler/uikit/nsLocalHandlerAppUIKit.mm
Normal file
17
uriloader/exthandler/uikit/nsLocalHandlerAppUIKit.mm
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2:cin:
|
||||
* 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/. */
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include "nsLocalHandlerAppUIKit.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerAppUIKit::LaunchWithURI(nsIURI* aURI,
|
||||
nsIInterfaceRequestor* aWindowContext)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
37
uriloader/exthandler/uikit/nsMIMEInfoUIKit.h
Normal file
37
uriloader/exthandler/uikit/nsMIMEInfoUIKit.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2:cin:
|
||||
* 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 nsMIMEInfoUIKit_h_
|
||||
#define nsMIMEInfoUIKit_h_
|
||||
|
||||
#include "nsMIMEInfoImpl.h"
|
||||
|
||||
class nsMIMEInfoUIKit final : public nsMIMEInfoImpl
|
||||
{
|
||||
public:
|
||||
explicit nsMIMEInfoUIKit(const nsACString& aMIMEType)
|
||||
: nsMIMEInfoImpl(aMIMEType)
|
||||
{}
|
||||
nsMIMEInfoUIKit(const nsACString& aType, HandlerClass aClass)
|
||||
: nsMIMEInfoImpl(aType, aClass)
|
||||
{}
|
||||
|
||||
NS_IMETHOD LaunchWithFile(nsIFile* aFile);
|
||||
|
||||
protected:
|
||||
virtual nsresult LoadUriInternal(nsIURI* aURI);
|
||||
#ifdef DEBUG
|
||||
virtual nsresult LaunchDefaultWithFile(nsIFile* aFile)
|
||||
{
|
||||
NS_NOTREACHED("do not call this method, use LaunchWithFile");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
#endif
|
||||
static nsresult OpenApplicationWithURI(nsIFile* aApplication,
|
||||
const nsCString& aURI);
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue