Bug 673742: Allow postMessage()ing File and FileLists between same-origin windows. r=sicking

This commit is contained in:
Kyle Huey 2011-08-12 12:58:43 -04:00
parent e1aa86b64b
commit c0e19976c5
3 changed files with 173 additions and 3 deletions

View File

@ -88,6 +88,11 @@ EXPORTS = \
nsDOMMemoryReporter.h \
$(NULL)
EXPORTS_NAMESPACES = mozilla/dom
EXPORTS_mozilla/dom = \
StructuredCloneTags.h \
$(NULL)
CPPSRCS = \
nsBarProps.cpp \
nsDOMException.cpp \

View File

@ -0,0 +1,55 @@
/* ***** 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 Structured Clone Code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kyle Huey <me@kylehuey.com>
*
* 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 StructuredCloneTags_h__
#define StructuredCloneTags_h__
#include "jsapi.h"
namespace mozilla {
namespace dom {
enum StructuredCloneTags {
SCTAG_BASE = JS_SCTAG_USER_MIN,
SCTAG_DOM_BLOB,
SCTAG_DOM_FILELIST,
SCTAG_DOM_MAX
};
} // namespace dom
} // namespace mozilla
#endif // StructuredCloneTags_h__

View File

@ -179,6 +179,7 @@
#include "nsCSSProps.h"
#include "nsFileDataProtocolHandler.h"
#include "nsIDOMFile.h"
#include "nsIDOMFileList.h"
#include "nsIURIFixup.h"
#include "mozilla/FunctionTimer.h"
#include "nsCDefaultURIFixup.h"
@ -240,6 +241,8 @@
#include "mozilla/dom/indexedDB/IDBFactory.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "nsRefreshDriver.h"
#include "mozAutoDocUpdate.h"
@ -5911,7 +5914,6 @@ nsGlobalWindow::CallerInnerWindow()
return static_cast<nsGlobalWindow*>(win.get());
}
/**
* Class used to represent events generated by calls to Window.postMessage,
* which asynchronously creates and dispatches events.
@ -5949,6 +5951,12 @@ class PostMessageEvent : public nsRunnable
aBuffer.steal(&mMessage, &mMessageLen);
}
bool StoreISupports(nsISupports* aSupports)
{
mSupportsArray.AppendElement(aSupports);
return true;
}
private:
nsRefPtr<nsGlobalWindow> mSource;
nsString mCallerOrigin;
@ -5957,8 +5965,102 @@ class PostMessageEvent : public nsRunnable
nsRefPtr<nsGlobalWindow> mTargetWindow;
nsCOMPtr<nsIURI> mProvidedOrigin;
PRBool mTrustedCaller;
nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
};
namespace {
struct StructuredCloneInfo {
PostMessageEvent* event;
PRBool subsumes;
};
static JSObject*
PostMessageReadStructuredClone(JSContext* cx,
JSStructuredCloneReader* reader,
uint32 tag,
uint32 data,
void* closure)
{
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
NS_ASSERTION(scInfo, "Must have scInfo!");
if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
NS_ASSERTION(!data, "Data should be empty");
nsISupports* supports;
if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
JSObject* global = JS_GetGlobalForObject(cx, JS_GetScopeChain(cx));
if (global) {
jsval val;
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, global, supports,
&val,
getter_AddRefs(wrapper)))) {
return JSVAL_TO_OBJECT(val);
}
}
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
cx->runtime->structuredCloneCallbacks;
if (runtimeCallbacks) {
return runtimeCallbacks->read(cx, reader, tag, data, nsnull);
}
return JS_FALSE;
}
static JSBool
PostMessageWriteStructuredClone(JSContext* cx,
JSStructuredCloneWriter* writer,
JSObject* obj,
void *closure)
{
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
NS_ASSERTION(scInfo, "Must have scInfo!");
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
if (wrappedNative) {
PRUint32 scTag = 0;
nsISupports* supports = wrappedNative->Native();
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
if (blob && scInfo->subsumes)
scTag = SCTAG_DOM_BLOB;
nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
if (list && scInfo->subsumes)
scTag = SCTAG_DOM_FILELIST;
if (scTag)
return JS_WriteUint32Pair(writer, scTag, 0) &&
JS_WriteBytes(writer, &supports, sizeof(supports)) &&
scInfo->event->StoreISupports(supports);
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
cx->runtime->structuredCloneCallbacks;
if (runtimeCallbacks) {
return runtimeCallbacks->write(cx, writer, obj, nsnull);
}
return JS_FALSE;
}
JSStructuredCloneCallbacks kPostMessageCallbacks = {
PostMessageReadStructuredClone,
PostMessageWriteStructuredClone,
nsnull
};
} // anonymous namespace
NS_IMETHODIMP
PostMessageEvent::Run()
{
@ -6046,8 +6148,10 @@ PostMessageEvent::Run()
jsval messageData;
{
JSAutoRequest ar(cx);
StructuredCloneInfo scInfo;
scInfo.event = this;
if (!buffer.read(cx, &messageData, nsnull))
if (!buffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo))
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
@ -6173,8 +6277,14 @@ nsGlobalWindow::PostMessageMoz(const jsval& aMessage,
// We *must* clone the data here, or the jsval could be modified
// by script
JSAutoStructuredCloneBuffer buffer;
StructuredCloneInfo scInfo;
scInfo.event = event;
if (!buffer.write(aCx, aMessage, nsnull, nsnull))
nsIPrincipal* principal = GetPrincipal();
if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)))
return NS_ERROR_DOM_DATA_CLONE_ERR;
if (!buffer.write(aCx, aMessage, &kPostMessageCallbacks, &scInfo))
return NS_ERROR_DOM_DATA_CLONE_ERR;
event->SetJSData(buffer);