Bug 543870: Implement File.url. r=bz sr=jst

This commit is contained in:
Jonas Sicking 2010-03-02 23:51:09 -08:00
parent 5f7e96d98d
commit aeb9ba77c3
25 changed files with 949 additions and 24 deletions

View File

@ -1360,6 +1360,19 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
return NS_ERROR_DOM_BAD_URI;
}
NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
// Check for uris that are only loadable by principals that subsume them
PRBool hasFlags;
rv = NS_URIChainHasFlags(targetBaseURI,
nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
&hasFlags);
NS_ENSURE_SUCCESS(rv, rv);
if (hasFlags) {
return aPrincipal->CheckMayLoad(targetBaseURI, PR_TRUE);
}
//-- get the source scheme
nsCAutoString sourceScheme;
rv = sourceBaseURI->GetScheme(sourceScheme);
@ -1379,8 +1392,6 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
return NS_OK;
}
NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
// If the schemes don't match, the policy is specified by the protocol
// flags on the target URI. Note that the order of policy checks here is
// very important! We start from most restrictive and work our way down.
@ -1398,7 +1409,6 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
}
// Check for chrome target URI
PRBool hasFlags;
rv = NS_URIChainHasFlags(targetBaseURI,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&hasFlags);
@ -1973,6 +1983,20 @@ nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal **re
// I _think_ it's safe to not create null principals here based on aURI.
// At least all the callers would do the right thing in those cases, as far
// as I can tell. --bz
nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
if (uriPrinc) {
nsCOMPtr<nsIPrincipal> principal;
uriPrinc->GetPrincipal(getter_AddRefs(principal));
if (!principal || principal == mSystemPrincipal) {
return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
}
principal.forget(result);
return NS_OK;
}
nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
if (!codebase)
return NS_ERROR_OUT_OF_MEMORY;

View File

@ -48,6 +48,9 @@
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIWeakReference.h"
#include "nsIWeakReferenceUtils.h"
#include "nsIDocument.h"
class nsIDOMDocument;
class nsIFile;
@ -62,8 +65,9 @@ public:
NS_DECL_NSIDOMFILE
NS_DECL_NSIDOMFILEINTERNAL
nsDOMFile(nsIFile *aFile)
: mFile(aFile)
nsDOMFile(nsIFile *aFile, nsIDocument* aRelatedDoc)
: mFile(aFile),
mRelatedDoc(do_GetWeakReference(aRelatedDoc))
{}
~nsDOMFile() {}
@ -72,7 +76,9 @@ public:
private:
nsCOMPtr<nsIFile> mFile;
nsWeakPtr mRelatedDoc;
nsString mContentType;
nsString mURL;
nsCString mCharset;
nsresult GuessCharset(nsIInputStream *aStream,

View File

@ -39,7 +39,7 @@
interface nsIDOMFileError;
[scriptable, uuid(16753172-6890-4e6a-8c10-a7ff30c5ef22)]
[scriptable, uuid(b10293e1-d531-4bdd-9b2b-4d8c1c9bc633)]
interface nsIDOMFile : nsISupports
{
//fileName and fileSize are now deprecated attributes
@ -51,6 +51,8 @@ interface nsIDOMFile : nsISupports
readonly attribute unsigned long long size;
readonly attribute DOMString type;
readonly attribute DOMString url;
DOMString getAsText(in DOMString encoding); // raises(FileException) on retrieval
DOMString getAsDataURL(); // raises(FileException) on retrieval
DOMString getAsBinary(); // raises(FileException) on retrieval

View File

@ -1302,6 +1302,14 @@ public:
virtual nsISupports* GetCurrentContentSink() = 0;
/**
* Register a filedata uri as being "owned" by this document. I.e. that its
* lifetime is connected with this document. When the document goes away it
* should "kill" the uri by calling
* nsFileDataProtocolHandler::RemoveFileDataEntry
*/
virtual void RegisterFileDataUri(nsACString& aUri) = 0;
protected:
~nsIDocument()
{

View File

@ -141,6 +141,7 @@ CPPSRCS = \
nsXMLHttpRequest.cpp \
nsXMLNameSpaceMap.cpp \
Link.cpp \
nsFileDataProtocolHandler.cpp \
$(NULL)
GQI_SRCS = contentbase.gqi

View File

@ -159,7 +159,7 @@ nsCrossSiteListenerProxy::OnStartRequest(nsIRequest* aRequest,
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (channel) {
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
if (uri) {
nsXMLHttpRequest::sAccessControlCache->
RemoveEntries(uri, mRequestingPrincipal);
@ -381,7 +381,7 @@ nsCrossSiteListenerProxy::OnChannelRedirect(nsIChannel *aOldChannel,
if (NS_FAILED(rv)) {
if (nsXMLHttpRequest::sAccessControlCache) {
nsCOMPtr<nsIURI> oldURI;
aOldChannel->GetURI(getter_AddRefs(oldURI));
NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI));
if (oldURI) {
nsXMLHttpRequest::sAccessControlCache->
RemoveEntries(oldURI, mRequestingPrincipal);
@ -410,7 +410,7 @@ nsresult
nsCrossSiteListenerProxy::UpdateChannel(nsIChannel* aChannel)
{
nsCOMPtr<nsIURI> uri, originalURI;
nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -59,6 +59,8 @@
#include "nsIUnicodeDecoder.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsIUUIDGenerator.h"
#include "nsFileDataProtocolHandler.h"
#include "plbase64.h"
#include "prmem.h"
@ -158,6 +160,40 @@ nsDOMFile::GetType(nsAString &aType)
return NS_OK;
}
NS_IMETHODIMP
nsDOMFile::GetUrl(nsAString& aURL)
{
if (mURL.IsEmpty()) {
nsresult rv;
nsCOMPtr<nsIUUIDGenerator> uuidgen =
do_GetService("@mozilla.org/uuid-generator;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsID id;
rv = uuidgen->GenerateUUIDInPlace(&id);
NS_ENSURE_SUCCESS(rv, rv);
char chars[NSID_LENGTH];
id.ToProvidedString(chars);
nsCString url = NS_LITERAL_CSTRING(FILEDATA_SCHEME ":") +
Substring(chars + 1, chars + NSID_LENGTH - 2);
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mRelatedDoc);
if (doc) {
doc->RegisterFileDataUri(url);
nsFileDataProtocolHandler::AddFileDataEntry(url, mFile,
doc->NodePrincipal());
}
CopyASCIItoUTF16(url, mURL);
}
aURL = mURL;
return NS_OK;
}
NS_IMETHODIMP
nsDOMFile::GetAsText(const nsAString &aCharset, nsAString &aResult)
{

View File

@ -146,6 +146,7 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
#include "nsIDOMHTMLFormElement.h"
#include "nsIRequest.h"
#include "nsILink.h"
#include "nsFileDataProtocolHandler.h"
#include "nsICharsetAlias.h"
#include "nsIParser.h"
@ -1504,6 +1505,10 @@ nsDocument::~nsDocument()
}
mPendingTitleChangeEvent.Revoke();
for (PRUint32 i = 0; i < mFileDataUris.Length(); ++i) {
nsFileDataProtocolHandler::RemoveFileDataEntry(mFileDataUris[i]);
}
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
@ -7714,6 +7719,12 @@ nsDocument::GetCurrentContentSink()
return mParser ? mParser->GetContentSink() : nsnull;
}
void
nsDocument::RegisterFileDataUri(nsACString& aUri)
{
mFileDataUris.AppendElement(aUri);
}
void
nsIDocument::RegisterFreezableElement(nsIContent* aContent)
{

View File

@ -890,6 +890,8 @@ public:
virtual NS_HIDDEN_(void)
EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData);
nsTArray<nsCString> mFileDataUris;
#ifdef MOZ_SMIL
// Returns our (lazily-initialized) animation controller.
// If HasAnimationController is true, this is guaranteed to return non-null.
@ -937,6 +939,8 @@ public:
virtual nsISupports* GetCurrentContentSink();
virtual void RegisterFileDataUri(nsACString& aUri);
protected:
friend class nsNodeUtils;
void RegisterNamedItems(nsIContent *aContent);

View File

@ -0,0 +1,436 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsFileDataProtocolHandler.h"
#include "nsNetCID.h"
#include "nsDOMError.h"
#include "nsCOMPtr.h"
#include "nsClassHashtable.h"
#include "nsNetUtil.h"
#include "nsIURIWithPrincipal.h"
#include "nsIPrincipal.h"
#include "nsIFileChannel.h"
#include "nsISerializable.h"
#include "nsIClassInfo.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsIProgrammingLanguage.h"
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
// -----------------------------------------------------------------------
// Hash table
struct FileDataInfo
{
nsCOMPtr<nsIURI> mFileUri;
nsCOMPtr<nsIPrincipal> mPrincipal;
};
static nsClassHashtable<nsCStringHashKey, FileDataInfo>* gFileDataTable;
void
nsFileDataProtocolHandler::AddFileDataEntry(nsACString& aUri, nsIFile* aFile,
nsIPrincipal* aPrincipal)
{
if (!gFileDataTable) {
gFileDataTable = new nsClassHashtable<nsCStringHashKey, FileDataInfo>;
gFileDataTable->Init();
}
FileDataInfo* info = new FileDataInfo;
NS_NewFileURI(getter_AddRefs(info->mFileUri), aFile);
info->mPrincipal = aPrincipal;
gFileDataTable->Put(aUri, info);
}
void
nsFileDataProtocolHandler::RemoveFileDataEntry(nsACString& aUri)
{
if (gFileDataTable) {
gFileDataTable->Remove(aUri);
if (gFileDataTable->Count() == 0) {
delete gFileDataTable;
gFileDataTable = nsnull;
}
}
}
static FileDataInfo*
GetFileDataInfo(const nsACString& aUri)
{
NS_ASSERTION(StringBeginsWith(aUri,
NS_LITERAL_CSTRING(FILEDATA_SCHEME ":")),
"Bad URI");
if (!gFileDataTable) {
return nsnull;
}
FileDataInfo* res;
gFileDataTable->Get(aUri, &res);
return res;
}
// -----------------------------------------------------------------------
// Uri
#define NS_FILEDATAURI_CID \
{ 0xf5475c51, 0x59a7, 0x4757, \
{ 0xb3, 0xd9, 0xe2, 0x11, 0xa9, 0x41, 0x08, 0x72 } }
static NS_DEFINE_CID(kFILEDATAURICID, NS_FILEDATAURI_CID);
// Use an extra base object to avoid having to manually retype all the
// nsIURI methods. I wish we could just inherit from nsSimpleURI instead.
class nsFileDataURI_base : public nsIURI,
public nsIMutable
{
public:
nsFileDataURI_base(nsIURI* aSimpleURI) :
mSimpleURI(aSimpleURI)
{
mMutable = do_QueryInterface(mSimpleURI);
NS_ASSERTION(aSimpleURI && mMutable, "This isn't going to work out");
}
virtual ~nsFileDataURI_base() {}
// For use only from deserialization
nsFileDataURI_base() {}
NS_FORWARD_NSIURI(mSimpleURI->)
NS_FORWARD_NSIMUTABLE(mMutable->)
protected:
nsCOMPtr<nsIURI> mSimpleURI;
nsCOMPtr<nsIMutable> mMutable;
};
class nsFileDataURI : public nsFileDataURI_base,
public nsIURIWithPrincipal,
public nsISerializable,
public nsIClassInfo
{
public:
nsFileDataURI(nsIPrincipal* aPrincipal, nsIURI* aSimpleURI) :
nsFileDataURI_base(aSimpleURI), mPrincipal(aPrincipal)
{}
virtual ~nsFileDataURI() {}
// For use only from deserialization
nsFileDataURI() : nsFileDataURI_base() {}
NS_DECL_ISUPPORTS
NS_DECL_NSIURIWITHPRINCIPAL
NS_DECL_NSISERIALIZABLE
NS_DECL_NSICLASSINFO
// Override Clone() and Equals()
NS_IMETHOD Clone(nsIURI** aClone);
NS_IMETHOD Equals(nsIURI* aOther, PRBool *aResult);
nsCOMPtr<nsIPrincipal> mPrincipal;
};
NS_IMPL_ADDREF(nsFileDataURI)
NS_IMPL_RELEASE(nsFileDataURI)
NS_INTERFACE_MAP_BEGIN(nsFileDataURI)
NS_INTERFACE_MAP_ENTRY(nsIURI)
NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
NS_INTERFACE_MAP_ENTRY(nsISerializable)
NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
NS_INTERFACE_MAP_ENTRY(nsIMutable)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURI)
if (aIID.Equals(kFILEDATAURICID))
foundInterface = static_cast<nsIURI*>(this);
else
NS_INTERFACE_MAP_END
// nsIURIWithPrincipal methods:
NS_IMETHODIMP
nsFileDataURI::GetPrincipal(nsIPrincipal** aPrincipal)
{
NS_IF_ADDREF(*aPrincipal = mPrincipal);
return NS_OK;
}
NS_IMETHODIMP
nsFileDataURI::GetPrincipalUri(nsIURI** aUri)
{
if (mPrincipal) {
mPrincipal->GetURI(aUri);
}
else {
*aUri = nsnull;
}
return NS_OK;
}
// nsISerializable methods:
NS_IMETHODIMP
nsFileDataURI::Read(nsIObjectInputStream* aStream)
{
nsresult rv = aStream->ReadObject(PR_TRUE, getter_AddRefs(mSimpleURI));
NS_ENSURE_SUCCESS(rv, rv);
mMutable = do_QueryInterface(mSimpleURI);
NS_ENSURE_TRUE(mMutable, NS_ERROR_UNEXPECTED);
return NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(mPrincipal));
}
NS_IMETHODIMP
nsFileDataURI::Write(nsIObjectOutputStream* aStream)
{
nsresult rv = aStream->WriteCompoundObject(mSimpleURI, NS_GET_IID(nsIURI),
PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
NS_GET_IID(nsIPrincipal),
PR_TRUE);
}
// nsIURI methods:
NS_IMETHODIMP
nsFileDataURI::Clone(nsIURI** aClone)
{
nsCOMPtr<nsIURI> simpleClone;
nsresult rv = mSimpleURI->Clone(getter_AddRefs(simpleClone));
NS_ENSURE_SUCCESS(rv, rv);
nsIURI* newURI = new nsFileDataURI(mPrincipal, simpleClone);
NS_ENSURE_TRUE(newURI, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*aClone = newURI);
return NS_OK;
}
NS_IMETHODIMP
nsFileDataURI::Equals(nsIURI* aOther, PRBool *aResult)
{
if (!aOther) {
*aResult = PR_FALSE;
return NS_OK;
}
nsRefPtr<nsFileDataURI> otherFileDataUri;
aOther->QueryInterface(kFILEDATAURICID, getter_AddRefs(otherFileDataUri));
if (!otherFileDataUri) {
*aResult = PR_FALSE;
return NS_OK;
}
nsresult rv = mPrincipal->Equals(otherFileDataUri->mPrincipal, aResult);
NS_ENSURE_SUCCESS(rv, rv);
if (!*aResult) {
return NS_OK;
}
return mSimpleURI->Equals(otherFileDataUri->mSimpleURI, aResult);
}
// nsIClassInfo methods:
NS_IMETHODIMP
nsFileDataURI::GetInterfaces(PRUint32 *count, nsIID * **array)
{
*count = 0;
*array = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsFileDataURI::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
{
*_retval = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsFileDataURI::GetContractID(char * *aContractID)
{
// Make sure to modify any subclasses as needed if this ever
// changes.
*aContractID = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsFileDataURI::GetClassDescription(char * *aClassDescription)
{
*aClassDescription = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsFileDataURI::GetClassID(nsCID * *aClassID)
{
// Make sure to modify any subclasses as needed if this ever
// changes to not call the virtual GetClassIDNoAlloc.
*aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
NS_ENSURE_TRUE(*aClassID, NS_ERROR_OUT_OF_MEMORY);
return GetClassIDNoAlloc(*aClassID);
}
NS_IMETHODIMP
nsFileDataURI::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
{
*aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
return NS_OK;
}
NS_IMETHODIMP
nsFileDataURI::GetFlags(PRUint32 *aFlags)
{
*aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
return NS_OK;
}
NS_IMETHODIMP
nsFileDataURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
{
*aClassIDNoAlloc = kFILEDATAURICID;
return NS_OK;
}
// -----------------------------------------------------------------------
// Protocol handler
NS_IMPL_ISUPPORTS1(nsFileDataProtocolHandler, nsIProtocolHandler)
NS_IMETHODIMP
nsFileDataProtocolHandler::GetScheme(nsACString &result)
{
result.AssignLiteral(FILEDATA_SCHEME);
return NS_OK;
}
NS_IMETHODIMP
nsFileDataProtocolHandler::GetDefaultPort(PRInt32 *result)
{
*result = -1;
return NS_OK;
}
NS_IMETHODIMP
nsFileDataProtocolHandler::GetProtocolFlags(PRUint32 *result)
{
*result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_SUBSUMERS |
URI_IS_LOCAL_RESOURCE | URI_NON_PERSISTABLE;
return NS_OK;
}
NS_IMETHODIMP
nsFileDataProtocolHandler::NewURI(const nsACString& aSpec,
const char *aCharset,
nsIURI *aBaseURI,
nsIURI **aResult)
{
*aResult = nsnull;
nsresult rv;
FileDataInfo* info =
GetFileDataInfo(aSpec);
nsCOMPtr<nsIURI> inner = do_CreateInstance(kSimpleURICID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = inner->SetSpec(aSpec);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsFileDataURI> uri =
new nsFileDataURI(info ? info->mPrincipal : nsnull, inner);
NS_TryToSetImmutable(uri);
*aResult = uri.forget().get();
return NS_OK;
}
NS_IMETHODIMP
nsFileDataProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
{
*result = nsnull;
nsCString spec;
uri->GetSpec(spec);
FileDataInfo* info =
GetFileDataInfo(spec);
if (!info) {
return NS_ERROR_DOM_BAD_URI;
}
#ifdef DEBUG
{
nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(uri);
nsCOMPtr<nsIPrincipal> principal;
uriPrinc->GetPrincipal(getter_AddRefs(principal));
NS_ASSERTION(info->mPrincipal == principal, "Wrong principal!");
}
#endif
nsCOMPtr<nsIChannel> channel;
nsresult rv = NS_NewChannel(getter_AddRefs(channel), info->mFileUri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupports> owner = do_QueryInterface(info->mPrincipal);
channel->SetOwner(owner);
channel->SetOriginalURI(uri);
channel.forget(result);
return NS_OK;
}
NS_IMETHODIMP
nsFileDataProtocolHandler::AllowPort(PRInt32 port, const char *scheme,
PRBool *_retval)
{
// don't override anything.
*_retval = PR_FALSE;
return NS_OK;
}

View File

@ -0,0 +1,70 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsFileDataProtocolHandler_h___
#define nsFileDataProtocolHandler_h___
#include "nsIProtocolHandler.h"
#define FILEDATA_SCHEME "moz-filedata"
class nsIFile;
class nsIPrincipal;
class nsFileDataProtocolHandler : public nsIProtocolHandler
{
public:
NS_DECL_ISUPPORTS
// nsIProtocolHandler methods:
NS_DECL_NSIPROTOCOLHANDLER
// nsFileDataProtocolHandler methods:
nsFileDataProtocolHandler() {}
virtual ~nsFileDataProtocolHandler() {}
// Methods for managing uri->file mapping
static void AddFileDataEntry(nsACString& aUri, nsIFile* aFile,
nsIPrincipal* aPrincipal);
static void RemoveFileDataEntry(nsACString& aUri);
};
#define NS_FILEDATAPROTOCOLHANDLER_CID \
{ 0xb43964aa, 0xa078, 0x44b2, \
{ 0xb0, 0x6b, 0xfd, 0x4d, 0x1b, 0x17, 0x2e, 0x66 } }
#endif /* nsFileDataProtocolHandler_h___ */

View File

@ -363,7 +363,7 @@ nsACProxyListener::AddResultToCache(nsIRequest *aRequest)
// syntax.
nsCOMPtr<nsIURI> uri;
http->GetURI(getter_AddRefs(uri));
NS_GetFinalChannelURI(http, getter_AddRefs(uri));
// PR_Now gives microseconds
PRTime expirationTime = PR_Now() + (PRUint64)age * PR_USEC_PER_SEC;
@ -1549,17 +1549,11 @@ CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel)
{
NS_ASSERTION(!IsSystemPrincipal(aPrincipal), "Shouldn't get here!");
nsCOMPtr<nsIURI> channelURI, originalURI;
nsresult rv = aChannel->GetURI(getter_AddRefs(channelURI));
NS_ENSURE_SUCCESS(rv, PR_FALSE);
rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
nsCOMPtr<nsIURI> channelURI;
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
NS_ENSURE_SUCCESS(rv, PR_FALSE);
rv = aPrincipal->CheckMayLoad(channelURI, PR_FALSE);
if (NS_SUCCEEDED(rv) && originalURI != channelURI) {
rv = aPrincipal->CheckMayLoad(originalURI, PR_FALSE);
}
return NS_SUCCEEDED(rv);
return NS_SUCCEEDED(aPrincipal->CheckMayLoad(channelURI, PR_FALSE));
}
nsresult
@ -2494,7 +2488,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
// Check to see if this initial OPTIONS request has already been cached
// in our special Access Control Cache.
nsCOMPtr<nsIURI> uri;
rv = mChannel->GetURI(getter_AddRefs(uri));
rv = NS_GetFinalChannelURI(mChannel, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsAccessControlLRUCache::CacheEntry* entry =

View File

@ -326,6 +326,11 @@ _TEST_FILES = test_bug5141.html \
test_classList.html \
test_bug514487.html \
test_range_bounds.html \
test_bug543870.html \
file_bug543870_img.jpg \
file_bug543870_inner.html \
file_bug543870_doc.html \
file_bug543870_text.txt \
test_bug475156.html \
bug475156.sjs \
test_bug544642.html \

View File

@ -0,0 +1,6 @@
<!doctype html>
<html>
<body>
<p>This here is a document!</p>
<img id=img src="file_bug543870_img.jpg">
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,63 @@
<!doctype html>
<html>
<script type="application/javascript;version=1.8">
var img;
var iframe;
addEventListener("message", function(e) {
mess = JSON.parse(e.data);
if ("img" in mess)
img.src = mess.img;
else if ("iframe" in mess)
iframe.src = mess.iframe;
else if ("xhr" in mess) {
let xhr = new XMLHttpRequest();
xhr.onload = function() {
sendItUp({ text: xhr.responseText });
}
try {
xhr.open("GET", mess.xhr);
xhr.send();
}
catch (ex) {
sendItUp({ didThrow: true });
}
}
}, false);
function sendItUp(obj) {
window.parent.postMessage(JSON.stringify(obj), "*");
}
function imgNotifyParent(e) {
sendItUp({ type: e.type,
width: e.target.width,
height: e.target.height });
}
function iframeNotifyParent(e) {
res = { type: e.type };
try {
res.text = e.target.contentDocument.getElementsByTagName("p")[0].textContent;
} catch (ex) {}
try {
res.imgWidth = e.target.contentDocument.getElementById("img").width;
} catch (ex) {}
sendItUp(res);
}
onload = function() {
img = document.getElementById('img');
img.onerror = img.onload = imgNotifyParent;
iframe = document.getElementById('iframe');
iframe.onerror = iframe.onload = iframeNotifyParent;
}
</script>
<body>
<img id=img>
<iframe id=iframe></iframe>
</html>

View File

@ -0,0 +1 @@
Yarr, here be plaintext file, ya landlubber

View File

@ -0,0 +1,162 @@
<!DOCTYPE HTML>
<html>
<head>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<title>Test for Cross Site XMLHttpRequest</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="gen.next()">
<p id="display">
<iframe id=inner></iframe>
<iframe id=iframe></iframe>
<img id=img onload="gen.send(event);">
<input type=file id=fileList>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.8">
window.addEventListener("message", function(e) {
gen.send(JSON.parse(e.data));
}, false);
const innerSameSiteURI = "file_bug543870_inner.html";
const innerCrossSiteURI = "http://example.com/tests/content/base/test/file_bug543870_inner.html"
gen = runTest();
SimpleTest.waitForExplicitFinish();
function runTest() {
inner = document.getElementById('inner');
img = document.getElementById('img');
iframe = document.getElementById('iframe');
inner.onload = function() { gen.send("inner loaded"); };
// Attempt to load a image in this document
var file = getFile("file_bug543870_img.jpg");
img.src = file.url;
var e = (yield);
is(e.type, "load", "loaded successfully");
is(img.width, 120, "correct width");
is(img.height, 90, "correct height");
// Attempt to load an image in a different same-origin document
inner.src = innerSameSiteURI;
yield;
inner.contentWindow.postMessage(JSON.stringify({img:file.url}), "*");
var res = (yield);
is(res.type, "load", "loaded successfully");
is(res.width, 120, "correct width");
is(res.height, 90, "correct height");
// Attempt to load an image in a different cross-origin document
inner.src = innerCrossSiteURI;
yield;
inner.contentWindow.postMessage(JSON.stringify({img:file.url}), "*");
var res = (yield);
is(res.type, "error", "failed successfully");
isnot(res.width, 120, "correct error width");
isnot(res.height, 90, "correct error height");
// Attempt to load a HTML document in an iframe in this document
iframe.onload = function() { gen.next(); };
iframe.src = "file_bug543870_doc.html";
yield;
is(iframe.contentDocument.getElementsByTagName("p")[0].textContent,
"This here is a document!",
"iframe loaded successfully");
is(iframe.contentDocument.getElementById("img").width, 120,
"image in iframe width");
is(iframe.contentDocument.getElementById("img").height, 90,
"image in iframe height");
// Attempt to load a HTML document in an iframe in this document, using file url
file = getFile("file_bug543870_doc.html");
iframe.src = file.url;
yield;
is(iframe.contentDocument.getElementsByTagName("p")[0].textContent,
"This here is a document!",
"iframe loaded successfully");
isnot(iframe.contentDocument.getElementById("img").width, 120,
"failed image in iframe width");
isnot(iframe.contentDocument.getElementById("img").height, 90,
"failed image in iframe height");
// Attempt to load a HTML document in an iframe in inner document
inner.src = innerSameSiteURI;
is((yield), "inner loaded", "correct gen.next()");
inner.contentWindow.postMessage(JSON.stringify({iframe:"file_bug543870_doc.html"}), "*");
var res = (yield);
is(res.type, "load", "loaded successfully");
is(res.text, "This here is a document!", "loaded successfully");
is(res.imgWidth, 120, "correct width");
// Attempt to load a HTML document in an iframe in inner document, using file url
inner.contentWindow.postMessage(JSON.stringify({iframe:file.url}), "*");
var res = (yield);
is(res.type, "load", "loaded successfully");
is(res.text, "This here is a document!", "loaded successfully");
isnot(res.imgWidth, 120, "correct width");
// Attempt to load a HTML document in an iframe in inner cross-site document, using file url
inner.src = innerCrossSiteURI;
is((yield), "inner loaded", "correct gen.next()");
inner.contentWindow.postMessage(JSON.stringify({iframe:file.url}), "*");
var res = (yield);
is(res.type, "error", "load failed successfully");
// Attempt to load file url using XHR
file = getFile("file_bug543870_text.txt");
xhr = new XMLHttpRequest;
xhr.onload = function() { gen.send("XHR finished"); };
xhr.open("GET", file.url);
xhr.send();
is((yield), "XHR finished", "correct gen.next()");
xhr.responseText == "Yarr, here be plaintext file, ya landlubber\n";
// Attempt to load file url using XHR in inner document
inner.src = innerSameSiteURI;
is((yield), "inner loaded", "correct gen.next()");
inner.contentWindow.postMessage(JSON.stringify({xhr:file.url}), "*");
var res = (yield);
is(res.didThrow, undefined, "load successful");
is(res.text, "Yarr, here be plaintext file, ya landlubber\n", "load successful");
// Attempt to load file url using XHR
inner.src = innerCrossSiteURI;
is((yield), "inner loaded", "correct gen.next()");
inner.contentWindow.postMessage(JSON.stringify({xhr:file.url}), "*");
var res = (yield);
is(res.didThrow, true, "load failed successfully");
SimpleTest.finish();
yield;
}
var basePath = "";
function getFile(name) {
if (!basePath) {
let xhr = new XMLHttpRequest;
xhr.open("GET", "/dynamic/getMyDirectory.sjs", false);
xhr.send();
basePath = xhr.responseText;
}
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var fileList = document.getElementById('fileList');
fileList.value = basePath + name;
return fileList.files[0];
}
</script>
</pre>
</body>
</html>

View File

@ -254,7 +254,13 @@ nsDOMDataTransfer::GetFiles(nsIDOMFileList** aFileList)
if (!file)
continue;
nsRefPtr<nsDOMFile> domFile = new nsDOMFile(file);
nsCOMPtr<nsIDocument> targetDoc;
nsCOMPtr<nsINode> targetNode = do_QueryInterface(mDragTarget);
if (targetNode) {
targetDoc = targetNode->GetOwnerDoc();
}
nsRefPtr<nsDOMFile> domFile = new nsDOMFile(file, targetDoc);
NS_ENSURE_TRUE(domFile, NS_ERROR_OUT_OF_MEMORY);
if (!mFiles->Append(domFile))

View File

@ -1080,10 +1080,12 @@ nsHTMLInputElement::UpdateFileList()
if (mFileList) {
mFileList->Clear();
nsIDocument* doc = GetOwnerDoc();
nsCOMArray<nsIFile> files;
GetFileArray(files);
for (PRUint32 i = 0; i < (PRUint32)files.Count(); ++i) {
nsRefPtr<nsDOMFile> domFile = new nsDOMFile(files[i]);
nsRefPtr<nsDOMFile> domFile = new nsDOMFile(files[i], doc);
if (domFile) {
if (!mFileList->Append(domFile)) {
return NS_ERROR_FAILURE;

View File

@ -116,6 +116,7 @@
#include "nsDOMException.h"
#include "nsDOMFileReader.h"
#include "nsFormData.h"
#include "nsFileDataProtocolHandler.h"
#include "nsGlobalWindowCommands.h"
#include "nsIControllerCommandTable.h"
#include "nsJSProtocolHandler.h"
@ -291,6 +292,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMSerializer)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsXMLHttpRequest, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDOMFileReader, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFormData)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFileDataProtocolHandler)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMParser)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsDOMStorageManager,
nsDOMStorageManager::GetInstance)
@ -1420,6 +1422,11 @@ static const nsModuleComponentInfo gComponents[] = {
NS_FORMDATA_CONTRACTID,
nsFormDataConstructor },
{ "FileData Protocol Handler",
NS_FILEDATAPROTOCOLHANDLER_CID,
NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX FILEDATA_SCHEME,
nsFileDataProtocolHandlerConstructor },
{ "XMLHttpRequest",
NS_XMLHTTPREQUEST_CID,
NS_XMLHTTPREQUEST_CONTRACTID,

View File

@ -133,6 +133,7 @@ XPIDLSRCS = \
nsINetUtil.idl \
nsIProxiedChannel.idl \
nsIRandomGenerator.idl \
nsIURIWithPrincipal.idl \
$(NULL)
EXPORTS = \

View File

@ -159,7 +159,7 @@ interface nsIProtocolHandler : nsISupports
/**
* +-------------------------------------------------------------------+
* | |
* | ALL PROTOCOL HANDLERS MUST SET ONE OF THE FOLLOWING FOUR FLAGS. |
* | ALL PROTOCOL HANDLERS MUST SET ONE OF THE FOLLOWING FIVE FLAGS. |
* | |
* +-------------------------------------------------------------------+
*
@ -167,7 +167,7 @@ interface nsIProtocolHandler : nsISupports
* protocol. Note that if a URI is nested, only the flags for the
* innermost URI matter. See nsINestedURI.
*
* If none of these four flags are set, the URI must be treated as if it
* If none of these five flags are set, the URI must be treated as if it
* had the URI_LOADABLE_BY_ANYONE flag set, for compatibility with protocol
* handlers written against Gecko 1.8 or earlier. In this case, there may
* be run-time warning messages indicating that a "default insecure"
@ -209,6 +209,13 @@ interface nsIProtocolHandler : nsISupports
*/
const unsigned long URI_IS_LOCAL_FILE = (1<<9);
/**
* The URIs for this protocol can be loaded only by callers with a
* principal that subsumes this uri. For example, privileged code and
* websites that are same origin as this uri.
*/
const unsigned long URI_LOADABLE_BY_SUBSUMERS = (1<<14);
/**
* Loading channels from this protocol has side-effects that make
* it unsuitable for saving to a local file.
@ -234,6 +241,8 @@ interface nsIProtocolHandler : nsISupports
*/
const unsigned long URI_OPENING_EXECUTES_SCRIPT = (1<<13);
// Note that 1 << 14 is used above
/**
* This protocol handler can be proxied via a proxy (socks or http)
* (e.g., irc, smtp, http, etc.). If the protocol supports transparent

View File

@ -0,0 +1,59 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIPrincipal;
interface nsIURI;
/**
* nsIURIWithPrincipal is implemented by URIs which are associated with a
* specific principal.
*/
[scriptable, uuid(626a5c0c-bfd8-4531-8b47-a8451b0daa33)]
interface nsIURIWithPrincipal : nsISupports
{
/**
* The principal associated with the resource returned when loading this
* uri.
*/
readonly attribute nsIPrincipal principal;
/**
* The uri for the principal.
*/
readonly attribute nsIURI principalUri;
};

View File

@ -88,6 +88,7 @@
#include "nsInterfaceRequestorAgg.h"
#include "nsInt64.h"
#include "nsINetUtil.h"
#include "nsIURIWithPrincipal.h"
#include "nsIAuthPrompt.h"
#include "nsIAuthPrompt2.h"
#include "nsIAuthPromptAdapterFactory.h"
@ -1561,6 +1562,17 @@ NS_SecurityCompareURIs(nsIURI* aSourceURI,
nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI);
nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
// If either uri is an nsIURIWithPrincipal
nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(sourceBaseURI);
if (uriPrinc) {
uriPrinc->GetPrincipalUri(getter_AddRefs(sourceBaseURI));
}
uriPrinc = do_QueryInterface(targetBaseURI);
if (uriPrinc) {
uriPrinc->GetPrincipalUri(getter_AddRefs(targetBaseURI));
}
if (!sourceBaseURI || !targetBaseURI)
return PR_FALSE;