import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1198458: Webrtc updated to branch 43; pull made 2015-09-29 09:00AM PDT rs=jesup (c45a789c99)
- Bug 1159489: WebRTC bitrate limits for video depend on input resolution and framerate r=pkerr (e3691a247c)
- Bug 1132318: merge SelectSendFrameRate with SelectSendResolution r=bwc (bcc232994c)
- Bug 1182289: Clean up dispatches in WebrtcGmpVideoEncoder/Decoder. r=jesup, a=abillings (b5e2030b07)
- Bug 1167306: Fix preprocessor goof that disabled the load manager and some preference handling. r=jesup (0cc0dee688)
- Bug 1198458: Rollup of changes previously applied to media/webrtc/trunk/webrtc and fixes to those rs=jesup r=froyd,jib,bwc,jesup,gcp,sotaro,pkerr,pehrsons (fe384d5e63)
- Bug 1198458 Unbreak build on BSDs by fixing non-POSIX thread includes/usage. r=jesup (4ad8e88c17)
- Bug 1198458: Fix typo in merges in OMX rs=bustage,kwierso on a CLOSED TREE (211b3b1a3f)
- Bug 1226146: fix sndio audio_device backend after webrtc 43 landing in bug 1198458 r=jesup NPOTB (2b10ba3e86)
- Bug 1231106 - Make BSDs fall-through to ASSERT as well. r=jesup (775d4fedae)
- Bug 1231109 - Drop FreeBSD checks for unsupported versions. r=jld r=jesup (3cd55166fd)
- Bug 1161079: Fix VideoCodecStats to allow for collecting encoder and decoder stats r=jib (1f98af8939)
- add limits to fix gcc12 compile (d78098980f)
- Bug 1193495 - Part 1: Test case. r=mt (add2ded009)
- Bug 1193495 - Part 2: Maintain clones of supported codecs for each level, and do necessary checking to prevent payload-type clashes. r=mt (d45a24dba7)
- Bug 1191301 - Re-enable the use of media.navigator.video.use_tmmbr pref. r=bwc (d2723821d4)
- Bug 1094447 - Use UDP/TLS/RTP/SAVPF for audio/video m-lines. r=drno (e8e1dafd0a)
- Bug 1173599 - a=imageattr support. r=mt (612fc343d7)
- Bug 1173601 - Add a=simulcast support. r=mt (7c5303bacb)
- Bug 1203246 - Factor track negotiation stuff out of JsepSessionImpl, and other simplification. r=mt (b71c809b78)
- Bug 1212907 - a=rid support. r=mt (7479ab6984)
- Bug 1212908 - Update a=simulcast to match new grammar in 03 draft. r=mt (e205d3b0dd)
- Bug 1192390 - Part 1: Lay architectural groundwork for simulcast negotiation. r=mt r=jesup (e75dda3139)
- Bug 1223160 - added SDP parser file reader. r=bwc (6752195791)
- Bug 1192390 - Part 2: Simulcast and RID negotiation. r=mt (51b151ef52)
- fix some warnings stuff (fed8f513a8)
- Bug 1161317: Fix bug where sendonly video RTCP would be treated as outgoing RTP r=jesup (e24371fbe0)
- Bug 1226347: Import cherry-pick of AEC changes from 43->48 (delay-agnostic AEC). r=pkerr (d3a074f4d8)
- Bug 1226347 - Part 2: Allow control of AEC via prefs. r=rjesup (58f142005b)
- Bug 1228788 - Force QT device release to happen on the main thread. r=jesup (885e9d1236)
- Bug 1162218 - Make worker idle thread timeouts more strict, r=baku. (a7d2106987)
- No bug. Remove a stray debugging printf of mine. r=me. (77b84cda62)
- minor (22564a666e)
- Bug 1224237 - Remove the !baseURL check from ServiceWorkerContainer::Register;r=bkelly (8b13c4dc49)
- Bug 1196157 - Marks left by performance marks should print the domain of the application and not the complete URL. r=baku (d133708d8d)
- Bug 1211970 - "Muted errors in workers are not correctly reported to the console". r=bz (42c15275f4)
- Bug 1208559 - Tests. r=bholley (e16a30caa5)
-  Bug 1045891 - Tests for child-src r=ckerschb (90aa832cd0)
- Bug 1223647: CSP erroneously inherited into dedicated workers. r=ckerschb (6fd8d9bfc9)
- Bug 1218433 - Use AsyncOpen2 in dom/workers/ScriptLoader.cpp - part 1, r=sicking (a7e9187e52)
- Bug 1218433 - Use AsyncOpen2 in dom/workers/ScriptLoader.cpp - part 3 - WPT, r=sicking, r=Ms2ger (e5e3c69f6a)
- Bug 1218433 - Use AsyncOpen2 in dom/workers/ScriptLoader.cpp - part 2 - WPT, r=sicking, r=Ms2ger (1dd2d871ec)
- Bug 1211967 - Fix how we report errors when loading a worker from a data url, r=bz (8517368daa)
- nsRefPtr - RefPtr (34bb404530)
- Bug 1231055 - Fix tags usage in PluginProvider. r=dtownsend (870b0e71eb)
- bug 1228792 - remove use of array comprehensions r=mossop (3e31f18e83)
- bug 1228792 - use standard version of catch r=mossop (f306557ca2)
- Bug 1228009. Geolocation code needs to handle failures on its ErrorResults. r=smaug (8778a9e264)
- Bug 1228707. Add a away to call Web IDL callbacks while ignoring any errors from them, and use it in a few places. r=smaug (a414e0d711)
- Bug 1201692. Add a fast path to ExplicitChildIterator::Seek for the common case of seeking an actual DOM child of the parent node. r=wchen (01234ad43a)
- Bug 1202186 - use nsISensitiveInfoHidden for console methods, r=baku (888b4506ad)
- Bug 1223774 - Console API should check if the outer window exists, r=smaug (e0d7f408dc)
- Bug 1200551 - Handle multiple %c formatters without a string between them by using only the last one for styling;r=baku,r=past (463550117a)
- Bug 1213719 - Back out bug 1170314 for duplicate functionality. r=smaug (ae74e0ad52)
- Bug 1154076 followup: Mark ConsoleRunnable::Run() as override. rs=ehsan (337181faab)
- Bug 1127703 - "Support iteration on FormData" r=bz (4ddd461e99)
- Bug 1230509 - BlobImplFile should return false in IsDateUnknown and IsSizeUnknown, r=bz (1079bfe2ab)
- Bug 1198095 - FileReader should dispatch an error if the blob changes size in the meantime the read is executed, r=bz (263993a172)
- Bug 1231094 - patch 1 - nsDOMFileReader to mozilla::dom::FileReader, r=sicking (aa8c3ff373)
- Bug 1231094 - patch 2 - Get rid of FileIOObject, r=sicking (44af1e17dd)
- Bug 1231100 - Get rid of nsIDOMFileReader - patch 1, r=sicking (c909d9d793)
- Bug 1231100 - Get rid of nsIDOMFileReader - patch 2, r=sicking (4d3da1c566)
- Bug 1161183: Don't show the add-on version in the list view. r=dao (002d8f6fb1)
- Bug 1229519: Fix toolkit/modules to pass eslint checks. r=mak (8bbd9c8fe0)
This commit is contained in:
2023-04-06 15:48:27 +08:00
parent d2c557abe9
commit 2e02aab9a7
2203 changed files with 124894 additions and 112212 deletions
+2 -3
View File
@@ -10,6 +10,7 @@ const Cu = Components.utils;
const Ci = Components.interfaces;
const Cc = Components.classes;
Cu.importGlobalProperties(['FileReader']);
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
@@ -198,9 +199,7 @@ var LogCapture = {
try {
this.ensureLoaded();
let fr = Cc["@mozilla.org/files/filereader;1"]
.createInstance(Ci.nsIDOMFileReader);
let fr = new FileReader();
fr.onload = function(evt) {
deferred.resolve(new Uint8Array(evt.target.result));
};
+1
View File
@@ -164,6 +164,7 @@ bool isInIgnoredNamespaceForImplicitCtor(const Decl *decl) {
name == "__gnu_cxx" || // gnu C++ lib
name == "boost" || // boost
name == "webrtc" || // upstream webrtc
name == "rtc" || // upstream webrtc 'base' package
name.substr(0, 4) == "icu_" || // icu
name == "google" || // protobuf
name == "google_breakpad" || // breakpad
+8 -4
View File
@@ -5,6 +5,8 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
gyp_vars = {
'lsan': 0,
'asan': 0,
'build_with_mozilla': 1,
'build_with_chromium': 0,
'use_official_google_api_keys': 0,
@@ -27,14 +29,14 @@ gyp_vars = {
'build_libyuv': 0,
'build_libvpx': 0,
'build_ssl': 0,
'build_json': 0,
'build_icu': 0,
'build_opus': 0,
'libyuv_dir': '/media/libyuv',
'yuv_disable_avx2': 0 if CONFIG['HAVE_X86_AVX2'] else 1,
# don't use openssl
'use_openssl': 0,
# saves 4MB when webrtc_trace is off
'enable_lazy_trace_alloc': 1 if CONFIG['RELEASE_BUILD'] else 0,
'use_x11': 1 if CONFIG['MOZ_X11'] else 0,
'use_glib': 1 if CONFIG['GLIB_LIBS'] else 0,
@@ -60,7 +62,9 @@ gyp_vars = {
'include_opus': 1,
'include_g722': 1,
'include_ilbc': 0,
'include_isac': 0,
# We turn on ISAC because the AGC uses parts of it, and depend on the
# linker to throw away uneeded bits.
'include_isac': 1,
'include_pcm16b': 1,
}
+2 -3
View File
@@ -15,7 +15,7 @@ Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Webapps.jsm");
Cu.import("resource://gre/modules/MessageBroadcaster.jsm");
Cu.importGlobalProperties(['File']);
Cu.importGlobalProperties(['File', 'FileReader']);
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
@@ -255,8 +255,7 @@ this.ImportExport = {
debug("_writeBlobToTempFile");
let path;
return new Promise((aResolve, aReject) => {
let reader = Cc['@mozilla.org/files/filereader;1']
.createInstance(Ci.nsIDOMFileReader);
let reader = new FileReader();
reader.onloadend = () => {
path = OS.Path.join(OS.Constants.Path.tmpDir, "app-blob.zip");
debug("onloadend path=" + path);
+2 -1
View File
@@ -32,7 +32,8 @@ public:
nsTArray<RefPtr<BlobImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; }
already_AddRefed<Blob> GetBlobInternal(nsISupports* aParent,
const nsACString& aContentType);
const nsACString& aContentType,
ErrorResult& aRv);
protected:
bool ExpandBufferSize(uint64_t aSize)
+24
View File
@@ -190,6 +190,30 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
}
}
void
ExplicitChildIterator::Seek(nsIContent* aChildToFind)
{
if (aChildToFind->GetParent() == mParent &&
!aChildToFind->IsRootOfAnonymousSubtree()) {
// Fast path: just point ourselves to aChildToFind, which is a
// normal DOM child of ours.
MOZ_ASSERT(!ShadowRoot::IsShadowInsertionPoint(aChildToFind));
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind));
mChild = aChildToFind;
mIndexInInserted = 0;
mShadowIterator = nullptr;
mDefaultChild = nullptr;
mIsFirst = false;
return;
}
// Can we add more fast paths here based on whether the parent of aChildToFind
// is a shadow insertion point or content insertion point?
// Slow path: just walk all our kids.
Seek(aChildToFind, nullptr);
}
nsIContent*
ExplicitChildIterator::Get()
{
+10 -2
View File
@@ -60,16 +60,24 @@ public:
nsIContent* GetNextChild();
// Looks for aChildToFind respecting insertion points until aChildToFind
// Looks for aChildToFind respecting insertion points until aChildToFind is
// found. This version can take shortcuts that the two-argument version
// can't, so can be faster (and in fact can be O(1) instead of O(N) in many
// cases).
void Seek(nsIContent* aChildToFind);
// Looks for aChildToFind respecting insertion points until aChildToFind is found.
// or aBound is found. If aBound is nullptr then the seek is unbounded. Returns
// whether aChildToFind was found as an explicit child prior to encountering
// aBound.
bool Seek(nsIContent* aChildToFind, nsIContent* aBound = nullptr)
bool Seek(nsIContent* aChildToFind, nsIContent* aBound)
{
// It would be nice to assert that we find aChildToFind, but bz thinks that
// we might not find aChildToFind when called from ContentInserted
// if first-letter frames are about.
// We can't easily take shortcuts here because we'd have to have a way to
// compare aChildToFind to aBound.
nsIContent* child;
do {
child = GetNextChild();
+32 -26
View File
@@ -18,6 +18,7 @@
#include "nsDOMNavigationTiming.h"
#include "nsGlobalWindow.h"
#include "nsJSUtils.h"
#include "nsNetUtil.h"
#include "nsPerformance.h"
#include "ScriptSettings.h"
#include "WorkerPrivate.h"
@@ -34,15 +35,12 @@
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadContext.h"
#include "nsIProgrammingLanguage.h"
#include "nsISensitiveInfoHiddenURI.h"
#include "nsIServiceManager.h"
#include "nsISupportsPrimitives.h"
#include "nsIWebNavigation.h"
#include "nsIXPConnect.h"
#ifdef MOZ_ENABLE_PROFILER_SPS
#include "nsIProfiler.h"
#endif
// The maximum allowed number of concurrent timers per page.
#define MAX_PAGE_TIMERS 10000
@@ -240,7 +238,7 @@ public:
}
private:
NS_IMETHOD Run()
NS_IMETHOD Run() override
{
AssertIsOnMainThread();
@@ -311,7 +309,9 @@ private:
MOZ_ASSERT(aWindow->IsInnerWindow());
nsPIDOMWindow* outerWindow = aWindow->GetOuterWindow();
MOZ_ASSERT(outerWindow);
if (NS_WARN_IF(!outerWindow)) {
return;
}
RunConsole(jsapi.cx(), outerWindow, aWindow);
}
@@ -697,9 +697,13 @@ Console::Console(nsPIDOMWindow* aWindow)
MOZ_ASSERT(mWindow->IsInnerWindow());
mInnerID = mWindow->WindowID();
// Without outerwindow any console message coming from this object will not
// shown in the devtools webconsole. But this should be fine because
// probably we are shutting down, or the window is CCed/GCed.
nsPIDOMWindow* outerWindow = mWindow->GetOuterWindow();
MOZ_ASSERT(outerWindow);
mOuterID = outerWindow->WindowID();
if (outerWindow) {
mOuterID = outerWindow->WindowID();
}
}
if (NS_IsMainThread()) {
@@ -829,23 +833,6 @@ Console::TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData)
return;
}
#ifdef MOZ_ENABLE_PROFILER_SPS
if (aData.isString() && NS_IsMainThread()) {
if (!mProfiler) {
mProfiler = do_GetService("@mozilla.org/tools/profiler;1");
}
if (mProfiler) {
bool active = false;
if (NS_SUCCEEDED(mProfiler->IsActive(&active)) && active) {
nsAutoJSString stringValue;
if (stringValue.init(aCx, aData)) {
mProfiler->AddMarker(NS_ConvertUTF16toUTF8(stringValue).get());
}
}
}
}
#endif
Method(aCx, MethodTimeStamp, NS_LITERAL_STRING("timeStamp"), data);
}
@@ -1222,6 +1209,19 @@ Console::ProcessCallData(ConsoleCallData* aData)
event.mLevel = aData->mMethodString;
event.mFilename = frame.mFilename;
nsCOMPtr<nsIURI> filenameURI;
nsAutoCString pass;
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(filenameURI), frame.mFilename)) &&
NS_SUCCEEDED(filenameURI->GetPassword(pass)) && !pass.IsEmpty()) {
nsCOMPtr<nsISensitiveInfoHiddenURI> safeURI = do_QueryInterface(filenameURI);
nsAutoCString spec;
if (safeURI &&
NS_SUCCEEDED(safeURI->GetSensitiveInfoHiddenSpec(spec))) {
CopyUTF8toUTF16(spec, event.mFilename);
}
}
event.mLineNumber = frame.mLineNumber;
event.mColumnNumber = frame.mColumnNumber;
event.mFunctionName = frame.mFunctionName;
@@ -1389,7 +1389,7 @@ FlushOutput(JSContext* aCx, Sequence<JS::Value>& aSequence, nsString &aOutput)
return true;
}
} // anonymous namespace
} // namespace
bool
Console::ProcessArguments(JSContext* aCx,
@@ -1519,6 +1519,12 @@ Console::ProcessArguments(JSContext* aCx,
case 'c':
{
// If there isn't any output but there's already a style, then
// discard the previous style and use the next one instead.
if (output.IsEmpty() && !aStyles.IsEmpty()) {
aStyles.TruncateLength(aStyles.Length() - 1);
}
if (!FlushOutput(aCx, aSequence, output)) {
return false;
}
-4
View File
@@ -20,7 +20,6 @@
class nsIConsoleAPIStorage;
class nsIPrincipal;
class nsIProfiler;
namespace mozilla {
namespace dom {
@@ -205,9 +204,6 @@ private:
nsCOMPtr<nsPIDOMWindow> mWindow;
nsCOMPtr<nsIConsoleAPIStorage> mStorage;
RefPtr<JSObjectHolder> mSandbox;
#ifdef MOZ_ENABLE_PROFILER_SPS
nsCOMPtr<nsIProfiler> mProfiler;
#endif
nsDataHashtable<nsStringHashKey, DOMHighResTimeStamp> mTimerRegistry;
nsDataHashtable<nsStringHashKey, uint32_t> mCounterRegistry;
+24 -9
View File
@@ -257,7 +257,7 @@ Blob::ToFile()
}
already_AddRefed<File>
Blob::ToFile(const nsAString& aName) const
Blob::ToFile(const nsAString& aName, ErrorResult& aRv) const
{
nsAutoTArray<RefPtr<BlobImpl>, 1> blobImpls;
blobImpls.AppendElement(mImpl);
@@ -266,7 +266,10 @@ Blob::ToFile(const nsAString& aName) const
mImpl->GetType(contentType);
RefPtr<MultipartBlobImpl> impl =
new MultipartBlobImpl(blobImpls, aName, contentType);
MultipartBlobImpl::Create(blobImpls, aName, contentType, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<File> file = new File(mParent, impl);
return file.forget();
@@ -347,7 +350,11 @@ Blob::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl();
impl->InitializeBlob();
impl->InitializeBlob(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
MOZ_ASSERT(!impl->IsFile());
RefPtr<Blob> blob = Blob::Create(aGlobal.GetAsSupports(), impl);
@@ -851,7 +858,7 @@ BlobImplFile::GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv) con
uint64_t
BlobImplFile::GetSize(ErrorResult& aRv)
{
if (IsSizeUnknown()) {
if (BlobImplBase::IsSizeUnknown()) {
NS_ASSERTION(mWholeFile,
"Should only use lazy size when using the whole file");
int64_t fileSize;
@@ -902,7 +909,7 @@ int64_t
BlobImplFile::GetLastModified(ErrorResult& aRv)
{
NS_ASSERTION(mIsFile, "Should only be called on files");
if (IsDateUnknown()) {
if (BlobImplBase::IsDateUnknown()) {
PRTime msecs;
aRv = mFile->GetLastModifiedTime(&msecs);
if (NS_WARN_IF(aRv.Failed())) {
@@ -1121,11 +1128,19 @@ BlobImplTemporaryBlob::GetInternalStream(nsIInputStream** aStream,
// BlobSet implementation
already_AddRefed<Blob>
BlobSet::GetBlobInternal(nsISupports* aParent, const nsACString& aContentType)
BlobSet::GetBlobInternal(nsISupports* aParent,
const nsACString& aContentType,
ErrorResult& aRv)
{
RefPtr<Blob> blob = Blob::Create(aParent,
new MultipartBlobImpl(GetBlobImpls(),
NS_ConvertASCIItoUTF16(aContentType)));
RefPtr<BlobImpl> blobImpl =
MultipartBlobImpl::Create(GetBlobImpls(),
NS_ConvertASCIItoUTF16(aContentType),
aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<Blob> blob = Blob::Create(aParent, blobImpl);
return blob.forget();
}
+6 -1
View File
@@ -118,7 +118,8 @@ public:
// This method creates a new File object with the given name and the same
// BlobImpl.
already_AddRefed<File> ToFile(const nsAString& aName) const;
already_AddRefed<File> ToFile(const nsAString& aName,
ErrorResult& aRv) const;
already_AddRefed<Blob>
CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
@@ -798,6 +799,10 @@ public:
virtual void LookupAndCacheIsDirectory() override;
// We always have size and date for this kind of blob.
virtual bool IsSizeUnknown() const override { return false; }
virtual bool IsDateUnknown() const override { return false; }
protected:
virtual ~BlobImplFile() {
if (mFile && mIsTemporary) {
-246
View File
@@ -1,246 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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 "FileIOObject.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/ProgressEvent.h"
#include "mozilla/EventDispatcher.h"
#include "nsComponentManagerUtils.h"
#include "nsError.h"
#include "nsIDOMEvent.h"
#define ERROR_STR "error"
#define ABORT_STR "abort"
#define PROGRESS_STR "progress"
namespace mozilla {
namespace dom {
const uint64_t kUnknownSize = uint64_t(-1);
NS_IMPL_ADDREF_INHERITED(FileIOObject, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(FileIOObject, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileIOObject)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_CLASS(FileIOObject)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FileIOObject,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressNotifier)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileIOObject,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressNotifier)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_EVENT_HANDLER(FileIOObject, abort)
NS_IMPL_EVENT_HANDLER(FileIOObject, error)
NS_IMPL_EVENT_HANDLER(FileIOObject, progress)
FileIOObject::FileIOObject()
: mProgressEventWasDelayed(false),
mTimerIsActive(false),
mReadyState(0),
mTotal(0), mTransferred(0)
{}
FileIOObject::~FileIOObject()
{}
void
FileIOObject::StartProgressEventTimer()
{
if (!mProgressNotifier) {
mProgressNotifier = do_CreateInstance(NS_TIMER_CONTRACTID);
}
if (mProgressNotifier) {
mProgressEventWasDelayed = false;
mTimerIsActive = true;
mProgressNotifier->Cancel();
mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL,
nsITimer::TYPE_ONE_SHOT);
}
}
void
FileIOObject::ClearProgressEventTimer()
{
mProgressEventWasDelayed = false;
mTimerIsActive = false;
if (mProgressNotifier) {
mProgressNotifier->Cancel();
}
}
void
FileIOObject::DispatchError(nsresult rv, nsAString& finalEvent)
{
// Set the status attribute, and dispatch the error event
switch (rv) {
case NS_ERROR_FILE_NOT_FOUND:
mError = new DOMError(GetOwner(), NS_LITERAL_STRING("NotFoundError"));
break;
case NS_ERROR_FILE_ACCESS_DENIED:
mError = new DOMError(GetOwner(), NS_LITERAL_STRING("SecurityError"));
break;
default:
mError = new DOMError(GetOwner(), NS_LITERAL_STRING("NotReadableError"));
break;
}
// Dispatch error event to signify load failure
DispatchProgressEvent(NS_LITERAL_STRING(ERROR_STR));
DispatchProgressEvent(finalEvent);
}
nsresult
FileIOObject::DispatchProgressEvent(const nsAString& aType)
{
ProgressEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mLoaded = mTransferred;
if (mTotal != kUnknownSize) {
init.mLengthComputable = true;
init.mTotal = mTotal;
} else {
init.mLengthComputable = false;
init.mTotal = 0;
}
RefPtr<ProgressEvent> event =
ProgressEvent::Constructor(this, aType, init);
event->SetTrusted(true);
return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
}
// nsITimerCallback
NS_IMETHODIMP
FileIOObject::Notify(nsITimer* aTimer)
{
nsresult rv;
mTimerIsActive = false;
if (mProgressEventWasDelayed) {
rv = DispatchProgressEvent(NS_LITERAL_STRING("progress"));
NS_ENSURE_SUCCESS(rv, rv);
StartProgressEventTimer();
}
return NS_OK;
}
// InputStreamCallback
NS_IMETHODIMP
FileIOObject::OnInputStreamReady(nsIAsyncInputStream* aStream)
{
if (mReadyState != 1 || aStream != mAsyncStream) {
return NS_OK;
}
uint64_t aCount;
nsresult rv = aStream->Available(&aCount);
if (NS_SUCCEEDED(rv) && aCount) {
rv = DoReadData(aStream, aCount);
}
if (NS_SUCCEEDED(rv)) {
rv = DoAsyncWait(aStream);
}
if (NS_FAILED(rv) || !aCount) {
if (rv == NS_BASE_STREAM_CLOSED) {
rv = NS_OK;
}
return OnLoadEnd(rv);
}
mTransferred += aCount;
//Notify the timer is the appropriate timeframe has passed
if (mTimerIsActive) {
mProgressEventWasDelayed = true;
} else {
rv = DispatchProgressEvent(NS_LITERAL_STRING(PROGRESS_STR));
NS_ENSURE_SUCCESS(rv, rv);
StartProgressEventTimer();
}
return NS_OK;
}
nsresult
FileIOObject::OnLoadEnd(nsresult aStatus)
{
// Cancel the progress event timer
ClearProgressEventTimer();
// FileIOObject must be in DONE stage after an operation
mReadyState = 2;
nsString successEvent, termEvent;
nsresult rv = DoOnLoadEnd(aStatus, successEvent, termEvent);
NS_ENSURE_SUCCESS(rv, rv);
// Set the status field as appropriate
if (NS_FAILED(aStatus)) {
DispatchError(aStatus, termEvent);
return NS_OK;
}
// Dispatch event to signify end of a successful operation
DispatchProgressEvent(successEvent);
DispatchProgressEvent(termEvent);
return NS_OK;
}
nsresult
FileIOObject::DoAsyncWait(nsIAsyncInputStream* aStream)
{
return aStream->AsyncWait(this,
/* aFlags*/ 0,
/* aRequestedCount */ 0,
NS_GetCurrentThread());
}
void
FileIOObject::Abort(ErrorResult& aRv)
{
if (mReadyState != 1) {
// XXX The spec doesn't say this
aRv.Throw(NS_ERROR_DOM_FILE_ABORT_ERR);
return;
}
ClearProgressEventTimer();
mReadyState = 2; // There are DONE constants on multiple interfaces,
// but they all have value 2.
// XXX The spec doesn't say this
mError = new DOMError(GetOwner(), NS_LITERAL_STRING("AbortError"));
nsString finalEvent;
DoAbort(finalEvent);
// Dispatch the events
DispatchProgressEvent(NS_LITERAL_STRING(ABORT_STR));
DispatchProgressEvent(finalEvent);
}
} // namespace dom
} // namespace mozilla
-103
View File
@@ -1,103 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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 FileIOObject_h__
#define FileIOObject_h__
#include "mozilla/DOMEventTargetHelper.h"
#include "nsIFile.h"
#include "nsITimer.h"
#include "nsCOMPtr.h"
#include "nsIAsyncInputStream.h"
#include "mozilla/dom/DOMError.h"
#define NS_PROGRESS_EVENT_INTERVAL 50
namespace mozilla {
class ErrorResult;
namespace dom {
extern const uint64_t kUnknownSize;
// A common base class for FileReader and FileSaver
class FileIOObject : public DOMEventTargetHelper,
public nsIInputStreamCallback,
public nsITimerCallback
{
public:
FileIOObject();
NS_DECL_ISUPPORTS_INHERITED
// Common methods
void Abort(ErrorResult& aRv);
uint16_t ReadyState() const
{
return mReadyState;
}
DOMError* GetError() const
{
return mError;
}
NS_METHOD GetOnabort(JSContext* aCx, JS::MutableHandle<JS::Value> aValue);
NS_METHOD SetOnabort(JSContext* aCx, JS::Handle<JS::Value> aValue);
NS_METHOD GetOnerror(JSContext* aCx, JS::MutableHandle<JS::Value> aValue);
NS_METHOD SetOnerror(JSContext* aCx, JS::Handle<JS::Value> aValue);
NS_METHOD GetOnprogress(JSContext* aCx, JS::MutableHandle<JS::Value> aValue);
NS_METHOD SetOnprogress(JSContext* aCx, JS::Handle<JS::Value> aValue);
IMPL_EVENT_HANDLER(abort)
IMPL_EVENT_HANDLER(error)
IMPL_EVENT_HANDLER(progress)
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileIOObject, DOMEventTargetHelper)
protected:
virtual ~FileIOObject();
// Implemented by the derived class to do whatever it needs to do for abort
virtual void DoAbort(nsAString& aEvent) = 0;
virtual nsresult DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount) = 0;
virtual nsresult DoOnLoadEnd(nsresult aStatus, nsAString& aSuccessEvent,
nsAString& aTerminationEvent) = 0;
nsresult OnLoadEnd(nsresult aStatus);
nsresult DoAsyncWait(nsIAsyncInputStream* aStream);
void StartProgressEventTimer();
void ClearProgressEventTimer();
void DispatchError(nsresult rv, nsAString& finalEvent);
nsresult DispatchProgressEvent(const nsAString& aType);
nsCOMPtr<nsITimer> mProgressNotifier;
bool mProgressEventWasDelayed;
bool mTimerIsActive;
nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
RefPtr<DOMError> mError;
uint16_t mReadyState;
uint64_t mTotal;
uint64_t mTransferred;
};
} // namespace dom
} // namespace mozilla
#endif
@@ -4,7 +4,7 @@
* 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 "nsDOMFileReader.h"
#include "FileReader.h"
#include "nsContentCID.h"
#include "nsContentUtils.h"
@@ -22,6 +22,7 @@
#include "mozilla/dom/EncodingUtils.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileReaderBinding.h"
#include "mozilla/dom/ProgressEvent.h"
#include "xpcpublic.h"
#include "nsDOMJSUtils.h"
@@ -30,226 +31,137 @@
#include "nsITransport.h"
#include "nsIStreamTransportService.h"
using namespace mozilla;
using namespace mozilla::dom;
namespace mozilla {
namespace dom {
#define ABORT_STR "abort"
#define LOAD_STR "load"
#define LOADSTART_STR "loadstart"
#define LOADEND_STR "loadend"
#define ERROR_STR "error"
#define PROGRESS_STR "progress"
const uint64_t kUnknownSize = uint64_t(-1);
static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileReader)
NS_IMPL_CYCLE_COLLECTION_CLASS(FileReader)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMFileReader,
FileIOObject)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FileReader,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBlob)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressNotifier)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMFileReader,
FileIOObject)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileReader,
DOMEventTargetHelper)
tmp->mResultArrayBuffer = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBlob)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressNotifier)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsDOMFileReader,
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(FileReader,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMFileReader)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsIDOMFileReader)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileReader)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END_INHERITING(FileIOObject)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(nsDOMFileReader, FileIOObject)
NS_IMPL_RELEASE_INHERITED(nsDOMFileReader, FileIOObject)
NS_IMPL_EVENT_HANDLER(nsDOMFileReader, load)
NS_IMPL_EVENT_HANDLER(nsDOMFileReader, loadend)
NS_IMPL_EVENT_HANDLER(nsDOMFileReader, loadstart)
NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, abort, FileIOObject)
NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, progress, FileIOObject)
NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, error, FileIOObject)
NS_IMPL_ADDREF_INHERITED(FileReader, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(FileReader, DOMEventTargetHelper)
void
nsDOMFileReader::RootResultArrayBuffer()
FileReader::RootResultArrayBuffer()
{
mozilla::HoldJSObjects(this);
}
//nsDOMFileReader constructors/initializers
//FileReader constructors/initializers
nsDOMFileReader::nsDOMFileReader()
: mFileData(nullptr),
mDataLen(0), mDataFormat(FILE_AS_BINARY),
mResultArrayBuffer(nullptr)
FileReader::FileReader(nsPIDOMWindow* aWindow)
: DOMEventTargetHelper(aWindow)
, mFileData(nullptr)
, mDataLen(0)
, mDataFormat(FILE_AS_BINARY)
, mResultArrayBuffer(nullptr)
, mProgressEventWasDelayed(false)
, mTimerIsActive(false)
, mReadyState(EMPTY)
, mTotal(0)
, mTransferred(0)
{
SetDOMStringToNull(mResult);
}
nsDOMFileReader::~nsDOMFileReader()
FileReader::~FileReader()
{
FreeFileData();
mResultArrayBuffer = nullptr;
mozilla::DropJSObjects(this);
DropJSObjects(this);
}
/**
* This Init method is called from the factory constructor.
*/
nsresult
nsDOMFileReader::Init()
/* static */ already_AddRefed<FileReader>
FileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
// Instead of grabbing some random global from the context stack,
// let's use the default one (junk scope) for now.
// We should move away from this Init...
BindToOwner(xpc::NativeGlobal(xpc::PrivilegedJunkScope()));
return NS_OK;
}
/* static */ already_AddRefed<nsDOMFileReader>
nsDOMFileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
RefPtr<nsDOMFileReader> fileReader = new nsDOMFileReader();
// The owner can be null when this object is used by chrome code.
nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aGlobal.GetAsSupports());
if (!owner) {
NS_WARNING("Unexpected owner");
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
RefPtr<FileReader> fileReader = new FileReader(owner);
if (!owner && nsContentUtils::IsCallerChrome()) {
// Instead of grabbing some random global from the context stack,
// let's use the default one (junk scope) for now.
// We should move away from this Init...
fileReader->BindToOwner(xpc::NativeGlobal(xpc::PrivilegedJunkScope()));
}
fileReader->BindToOwner(owner);
return fileReader.forget();
}
// nsIInterfaceRequestor
NS_IMETHODIMP
nsDOMFileReader::GetInterface(const nsIID & aIID, void **aResult)
FileReader::GetInterface(const nsIID & aIID, void **aResult)
{
return QueryInterface(aIID, aResult);
}
// nsIDOMFileReader
NS_IMETHODIMP
nsDOMFileReader::GetReadyState(uint16_t *aReadyState)
{
*aReadyState = ReadyState();
return NS_OK;
}
void
nsDOMFileReader::GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv)
{
aRv = GetResult(aCx, aResult);
}
NS_IMETHODIMP
nsDOMFileReader::GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult)
FileReader::GetResult(JSContext* aCx,
JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv)
{
JS::Rooted<JS::Value> result(aCx);
if (mDataFormat == FILE_AS_ARRAYBUFFER) {
if (mReadyState == nsIDOMFileReader::DONE && mResultArrayBuffer) {
if (mReadyState == DONE && mResultArrayBuffer) {
result.setObject(*mResultArrayBuffer);
} else {
result.setNull();
}
if (!JS_WrapValue(aCx, &result)) {
return NS_ERROR_FAILURE;
aRv.Throw(NS_ERROR_FAILURE);
return;
}
aResult.set(result);
return NS_OK;
return;
}
nsString tmpResult = mResult;
if (!xpc::StringToJsval(aCx, tmpResult, aResult)) {
return NS_ERROR_FAILURE;
aRv.Throw(NS_ERROR_FAILURE);
return;
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMFileReader::GetError(nsISupports** aError)
{
NS_IF_ADDREF(*aError = GetError());
return NS_OK;
}
NS_IMETHODIMP
nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aBlob, JSContext* aCx)
{
NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
ErrorResult rv;
RefPtr<Blob> blob = static_cast<Blob*>(aBlob);
ReadAsArrayBuffer(aCx, *blob, rv);
return rv.StealNSResult();
}
NS_IMETHODIMP
nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aBlob)
{
NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
ErrorResult rv;
RefPtr<Blob> blob = static_cast<Blob*>(aBlob);
ReadAsBinaryString(*blob, rv);
return rv.StealNSResult();
}
NS_IMETHODIMP
nsDOMFileReader::ReadAsText(nsIDOMBlob* aBlob,
const nsAString &aCharset)
{
NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
ErrorResult rv;
RefPtr<Blob> blob = static_cast<Blob*>(aBlob);
ReadAsText(*blob, aCharset, rv);
return rv.StealNSResult();
}
NS_IMETHODIMP
nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aBlob)
{
NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
ErrorResult rv;
RefPtr<Blob> blob = static_cast<Blob*>(aBlob);
ReadAsDataURL(*blob, rv);
return rv.StealNSResult();
}
NS_IMETHODIMP
nsDOMFileReader::Abort()
{
ErrorResult rv;
FileIOObject::Abort(rv);
return rv.StealNSResult();
}
/* virtual */ void
nsDOMFileReader::DoAbort(nsAString& aEvent)
{
// Revert status and result attributes
SetDOMStringToNull(mResult);
mResultArrayBuffer = nullptr;
mAsyncStream = nullptr;
mBlob = nullptr;
//Clean up memory buffer
FreeFileData();
// Tell the base class which event to dispatch
aEvent = NS_LITERAL_STRING(LOADEND_STR);
}
static
NS_METHOD
static NS_IMETHODIMP
ReadFuncBinaryString(nsIInputStream* in,
void* closure,
const char* fromRawSegment,
@@ -271,11 +183,10 @@ ReadFuncBinaryString(nsIInputStream* in,
}
nsresult
nsDOMFileReader::DoOnLoadEnd(nsresult aStatus,
nsAString& aSuccessEvent,
nsAString& aTerminationEvent)
FileReader::DoOnLoadEnd(nsresult aStatus,
nsAString& aSuccessEvent,
nsAString& aTerminationEvent)
{
// Make sure we drop all the objects that could hold files open now.
nsCOMPtr<nsIAsyncInputStream> stream;
mAsyncStream.swap(stream);
@@ -283,25 +194,34 @@ nsDOMFileReader::DoOnLoadEnd(nsresult aStatus,
RefPtr<Blob> blob;
mBlob.swap(blob);
aSuccessEvent = NS_LITERAL_STRING(LOAD_STR);
aTerminationEvent = NS_LITERAL_STRING(LOADEND_STR);
// Clear out the data if necessary
if (NS_FAILED(aStatus)) {
FreeFileData();
return NS_OK;
}
// In case we read a different number of bytes, we can assume that the
// underlying storage has changed. We should not continue.
if (mDataLen != mTotal) {
DispatchError(NS_ERROR_FAILURE, aTerminationEvent);
FreeFileData();
return NS_ERROR_FAILURE;
}
aSuccessEvent = NS_LITERAL_STRING(LOAD_STR);
aTerminationEvent = NS_LITERAL_STRING(LOADEND_STR);
nsresult rv = NS_OK;
switch (mDataFormat) {
case FILE_AS_ARRAYBUFFER: {
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mozilla::DOMEventTargetHelper::GetParentObject()))) {
if (NS_WARN_IF(!jsapi.Init(DOMEventTargetHelper::GetParentObject()))) {
FreeFileData();
return NS_ERROR_FAILURE;
}
RootResultArrayBuffer();
mResultArrayBuffer = JS_NewArrayBufferWithContents(jsapi.cx(), mTotal, mFileData);
mResultArrayBuffer = JS_NewArrayBufferWithContents(jsapi.cx(), mDataLen, mFileData);
if (!mResultArrayBuffer) {
JS_ClearPendingException(jsapi.cx());
rv = NS_ERROR_OUT_OF_MEMORY;
@@ -336,15 +256,14 @@ nsDOMFileReader::DoOnLoadEnd(nsresult aStatus,
}
nsresult
nsDOMFileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount)
FileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount)
{
MOZ_ASSERT(aStream);
if (mDataFormat == FILE_AS_BINARY) {
//Continuously update our binary string as data comes in
uint32_t oldLen = mResult.Length();
NS_ASSERTION(mResult.Length() == mDataLen,
"unexpected mResult length");
NS_ASSERTION(mResult.Length() == mDataLen, "unexpected mResult length");
if (uint64_t(oldLen) + aCount > UINT32_MAX)
return NS_ERROR_OUT_OF_MEMORY;
char16_t *buf = nullptr;
@@ -379,18 +298,21 @@ nsDOMFileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount)
// Helper methods
void
nsDOMFileReader::ReadFileContent(Blob& aBlob,
const nsAString &aCharset,
eDataFormat aDataFormat,
ErrorResult& aRv)
FileReader::ReadFileContent(Blob& aBlob,
const nsAString &aCharset,
eDataFormat aDataFormat,
ErrorResult& aRv)
{
//Implicit abort to clear any other activity going on
Abort();
ErrorResult error;
Abort(error);
error.SuppressException();
mError = nullptr;
SetDOMStringToNull(mResult);
mTransferred = 0;
mTotal = 0;
mReadyState = nsIDOMFileReader::EMPTY;
mReadyState = EMPTY;
FreeFileData();
mBlob = &aBlob;
@@ -398,7 +320,6 @@ nsDOMFileReader::ReadFileContent(Blob& aBlob,
CopyUTF16toUTF8(aCharset, mCharset);
nsresult rv;
nsCOMPtr<nsIStreamTransportService> sts =
do_GetService(kStreamTransportServiceCID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -413,23 +334,21 @@ nsDOMFileReader::ReadFileContent(Blob& aBlob,
}
nsCOMPtr<nsITransport> transport;
rv = sts->CreateInputTransport(stream,
/* aStartOffset */ 0,
/* aReadLimit */ -1,
/* aCloseWhenDone */ true,
getter_AddRefs(transport));
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
aRv = sts->CreateInputTransport(stream,
/* aStartOffset */ 0,
/* aReadLimit */ -1,
/* aCloseWhenDone */ true,
getter_AddRefs(transport));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
nsCOMPtr<nsIInputStream> wrapper;
rv = transport->OpenInputStream(/* aFlags */ 0,
/* aSegmentSize */ 0,
/* aSegmentCount */ 0,
getter_AddRefs(wrapper));
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
aRv = transport->OpenInputStream(/* aFlags */ 0,
/* aSegmentSize */ 0,
/* aSegmentCount */ 0,
getter_AddRefs(wrapper));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@@ -442,14 +361,16 @@ nsDOMFileReader::ReadFileContent(Blob& aBlob,
return;
}
rv = DoAsyncWait(mAsyncStream);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
aRv = mAsyncStream->AsyncWait(this,
/* aFlags*/ 0,
/* aRequestedCount */ 0,
NS_GetCurrentThread());
if (NS_WARN_IF(aRv.Failed())) {
return;
}
//FileReader should be in loading state here
mReadyState = nsIDOMFileReader::LOADING;
mReadyState = LOADING;
DispatchProgressEvent(NS_LITERAL_STRING(LOADSTART_STR));
if (mDataFormat == FILE_AS_ARRAYBUFFER) {
@@ -462,11 +383,11 @@ nsDOMFileReader::ReadFileContent(Blob& aBlob,
}
nsresult
nsDOMFileReader::GetAsText(Blob *aBlob,
const nsACString &aCharset,
const char *aFileData,
uint32_t aDataLen,
nsAString& aResult)
FileReader::GetAsText(Blob *aBlob,
const nsACString &aCharset,
const char *aFileData,
uint32_t aDataLen,
nsAString& aResult)
{
// The BOM sniffing is baked into the "decode" part of the Encoding
// Standard, which the File API references.
@@ -502,14 +423,14 @@ nsDOMFileReader::GetAsText(Blob *aBlob,
}
nsresult
nsDOMFileReader::GetAsDataURL(Blob *aBlob,
const char *aFileData,
uint32_t aDataLen,
nsAString& aResult)
FileReader::GetAsDataURL(Blob *aBlob,
const char *aFileData,
uint32_t aDataLen,
nsAString& aResult)
{
aResult.AssignLiteral("data:");
nsString contentType;
nsAutoString contentType;
aBlob->GetType(contentType);
if (!contentType.IsEmpty()) {
aResult.Append(contentType);
@@ -530,7 +451,197 @@ nsDOMFileReader::GetAsDataURL(Blob *aBlob,
}
/* virtual */ JSObject*
nsDOMFileReader::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
FileReader::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return FileReaderBinding::Wrap(aCx, this, aGivenProto);
}
void
FileReader::StartProgressEventTimer()
{
if (!mProgressNotifier) {
mProgressNotifier = do_CreateInstance(NS_TIMER_CONTRACTID);
}
if (mProgressNotifier) {
mProgressEventWasDelayed = false;
mTimerIsActive = true;
mProgressNotifier->Cancel();
mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL,
nsITimer::TYPE_ONE_SHOT);
}
}
void
FileReader::ClearProgressEventTimer()
{
mProgressEventWasDelayed = false;
mTimerIsActive = false;
if (mProgressNotifier) {
mProgressNotifier->Cancel();
}
}
void
FileReader::DispatchError(nsresult rv, nsAString& finalEvent)
{
// Set the status attribute, and dispatch the error event
switch (rv) {
case NS_ERROR_FILE_NOT_FOUND:
mError = new DOMError(GetOwner(), NS_LITERAL_STRING("NotFoundError"));
break;
case NS_ERROR_FILE_ACCESS_DENIED:
mError = new DOMError(GetOwner(), NS_LITERAL_STRING("SecurityError"));
break;
default:
mError = new DOMError(GetOwner(), NS_LITERAL_STRING("NotReadableError"));
break;
}
// Dispatch error event to signify load failure
DispatchProgressEvent(NS_LITERAL_STRING(ERROR_STR));
DispatchProgressEvent(finalEvent);
}
nsresult
FileReader::DispatchProgressEvent(const nsAString& aType)
{
ProgressEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mLoaded = mTransferred;
if (mTotal != kUnknownSize) {
init.mLengthComputable = true;
init.mTotal = mTotal;
} else {
init.mLengthComputable = false;
init.mTotal = 0;
}
RefPtr<ProgressEvent> event =
ProgressEvent::Constructor(this, aType, init);
event->SetTrusted(true);
return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
}
// nsITimerCallback
NS_IMETHODIMP
FileReader::Notify(nsITimer* aTimer)
{
nsresult rv;
mTimerIsActive = false;
if (mProgressEventWasDelayed) {
rv = DispatchProgressEvent(NS_LITERAL_STRING("progress"));
NS_ENSURE_SUCCESS(rv, rv);
StartProgressEventTimer();
}
return NS_OK;
}
// InputStreamCallback
NS_IMETHODIMP
FileReader::OnInputStreamReady(nsIAsyncInputStream* aStream)
{
if (mReadyState != LOADING || aStream != mAsyncStream) {
return NS_OK;
}
uint64_t aCount;
nsresult rv = aStream->Available(&aCount);
if (NS_SUCCEEDED(rv) && aCount) {
rv = DoReadData(aStream, aCount);
}
if (NS_SUCCEEDED(rv)) {
rv = aStream->AsyncWait(this,
/* aFlags*/ 0,
/* aRequestedCount */ 0,
NS_GetCurrentThread());
}
if (NS_FAILED(rv) || !aCount) {
if (rv == NS_BASE_STREAM_CLOSED) {
rv = NS_OK;
}
return OnLoadEnd(rv);
}
mTransferred += aCount;
//Notify the timer is the appropriate timeframe has passed
if (mTimerIsActive) {
mProgressEventWasDelayed = true;
} else {
rv = DispatchProgressEvent(NS_LITERAL_STRING(PROGRESS_STR));
NS_ENSURE_SUCCESS(rv, rv);
StartProgressEventTimer();
}
return NS_OK;
}
nsresult
FileReader::OnLoadEnd(nsresult aStatus)
{
// Cancel the progress event timer
ClearProgressEventTimer();
// FileReader must be in DONE stage after an operation
mReadyState = DONE;
nsAutoString successEvent, termEvent;
nsresult rv = DoOnLoadEnd(aStatus, successEvent, termEvent);
NS_ENSURE_SUCCESS(rv, rv);
// Set the status field as appropriate
if (NS_FAILED(aStatus)) {
DispatchError(aStatus, termEvent);
return NS_OK;
}
// Dispatch event to signify end of a successful operation
DispatchProgressEvent(successEvent);
DispatchProgressEvent(termEvent);
return NS_OK;
}
void
FileReader::Abort(ErrorResult& aRv)
{
if (mReadyState != LOADING) {
// XXX The spec doesn't say this
aRv.Throw(NS_ERROR_DOM_FILE_ABORT_ERR);
return;
}
ClearProgressEventTimer();
mReadyState = DONE;
// XXX The spec doesn't say this
mError = new DOMError(GetOwner(), NS_LITERAL_STRING("AbortError"));
// Revert status and result attributes
SetDOMStringToNull(mResult);
mResultArrayBuffer = nullptr;
mAsyncStream = nullptr;
mBlob = nullptr;
//Clean up memory buffer
FreeFileData();
// Dispatch the events
DispatchProgressEvent(NS_LITERAL_STRING(ABORT_STR));
DispatchProgressEvent(NS_LITERAL_STRING(LOADEND_STR));
}
} // dom namespace
} // mozilla namespace
@@ -4,70 +4,55 @@
* 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 nsDOMFileReader_h__
#define nsDOMFileReader_h__
#ifndef mozilla_dom_FileReader_h
#define mozilla_dom_FileReader_h
#include "mozilla/Attributes.h"
#include "nsISupportsUtils.h"
#include "nsString.h"
#include "nsWeakReference.h"
#include "nsIStreamListener.h"
#include "nsIInterfaceRequestor.h"
#include "nsJSUtils.h"
#include "nsTArray.h"
#include "prtime.h"
#include "nsITimer.h"
#include "nsIAsyncInputStream.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/DOMError.h"
#include "nsIDOMFileReader.h"
#include "nsIDOMFileList.h"
#include "nsCOMPtr.h"
#include "nsIAsyncInputStream.h"
#include "nsIStreamListener.h"
#include "nsISupportsUtils.h"
#include "nsIInterfaceRequestor.h"
#include "nsITimer.h"
#include "nsJSUtils.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsWeakReference.h"
#include "prtime.h"
#include "FileIOObject.h"
#define NS_PROGRESS_EVENT_INTERVAL 50
namespace mozilla {
namespace dom {
class Blob;
} // namespace dom
} // namespace mozilla
class nsDOMFileReader final : public mozilla::dom::FileIOObject,
public nsIDOMFileReader,
public nsIInterfaceRequestor,
public nsSupportsWeakReference
extern const uint64_t kUnknownSize;
class FileReader final : public DOMEventTargetHelper,
public nsIInterfaceRequestor,
public nsSupportsWeakReference,
public nsIInputStreamCallback,
public nsITimerCallback
{
typedef mozilla::ErrorResult ErrorResult;
typedef mozilla::dom::GlobalObject GlobalObject;
typedef mozilla::dom::Blob Blob;
public:
nsDOMFileReader();
explicit FileReader(nsPIDOMWindow* aWindow);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMFILEREADER
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper)
// nsIInterfaceRequestor
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSIINTERFACEREQUESTOR
// FileIOObject overrides
virtual void DoAbort(nsAString& aEvent) override;
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(FileReader, DOMEventTargetHelper)
virtual nsresult DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount) override;
virtual nsresult DoOnLoadEnd(nsresult aStatus, nsAString& aSuccessEvent,
nsAString& aTerminationEvent) override;
nsPIDOMWindow* GetParentObject() const
{
return GetOwner();
}
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// WebIDL
static already_AddRefed<nsDOMFileReader>
static already_AddRefed<FileReader>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
void ReadAsArrayBuffer(JSContext* aCx, Blob& aBlob, ErrorResult& aRv)
{
@@ -84,23 +69,26 @@ public:
ReadFileContent(aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
}
using FileIOObject::Abort;
void Abort(ErrorResult& aRv);
// Inherited ReadyState().
uint16_t ReadyState() const
{
return static_cast<uint16_t>(mReadyState);
}
DOMError* GetError() const
{
return mError;
}
void GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv);
using FileIOObject::GetError;
IMPL_EVENT_HANDLER(loadstart)
using FileIOObject::GetOnprogress;
using FileIOObject::SetOnprogress;
IMPL_EVENT_HANDLER(progress)
IMPL_EVENT_HANDLER(load)
using FileIOObject::GetOnabort;
using FileIOObject::SetOnabort;
using FileIOObject::GetOnerror;
using FileIOObject::SetOnerror;
IMPL_EVENT_HANDLER(abort)
IMPL_EVENT_HANDLER(error)
IMPL_EVENT_HANDLER(loadend)
void ReadAsBinaryString(Blob& aBlob, ErrorResult& aRv)
@@ -108,15 +96,15 @@ public:
ReadFileContent(aBlob, EmptyString(), FILE_AS_BINARY, aRv);
}
private:
virtual ~FileReader();
nsresult Init();
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMFileReader,
FileIOObject)
void RootResultArrayBuffer();
protected:
virtual ~nsDOMFileReader();
// This must be in sync with dom/webidl/FileReader.webidl
enum eReadyState {
EMPTY = 0,
LOADING = 1,
DONE = 2
};
enum eDataFormat {
FILE_AS_ARRAYBUFFER,
@@ -125,6 +113,8 @@ protected:
FILE_AS_DATAURL
};
void RootResultArrayBuffer();
void ReadFileContent(Blob& aBlob,
const nsAString &aCharset, eDataFormat aDataFormat,
ErrorResult& aRv);
@@ -134,7 +124,20 @@ protected:
nsresult GetAsDataURL(Blob *aBlob, const char *aFileData,
uint32_t aDataLen, nsAString &aResult);
void FreeFileData() {
nsresult OnLoadEnd(nsresult aStatus);
void StartProgressEventTimer();
void ClearProgressEventTimer();
void DispatchError(nsresult rv, nsAString& finalEvent);
nsresult DispatchProgressEvent(const nsAString& aType);
nsresult DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount);
nsresult DoOnLoadEnd(nsresult aStatus, nsAString& aSuccessEvent,
nsAString& aTerminationEvent);
void FreeFileData()
{
moz_free(mFileData);
mFileData = nullptr;
mDataLen = 0;
@@ -150,6 +153,22 @@ protected:
nsString mResult;
JS::Heap<JSObject*> mResultArrayBuffer;
nsCOMPtr<nsITimer> mProgressNotifier;
bool mProgressEventWasDelayed;
bool mTimerIsActive;
nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
RefPtr<DOMError> mError;
eReadyState mReadyState;
uint64_t mTotal;
uint64_t mTransferred;
};
#endif
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_FileReader_h
+54 -13
View File
@@ -25,6 +25,37 @@ using namespace mozilla::dom;
NS_IMPL_ISUPPORTS_INHERITED0(MultipartBlobImpl, BlobImpl)
/* static */ already_AddRefed<MultipartBlobImpl>
MultipartBlobImpl::Create(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
const nsAString& aName,
const nsAString& aContentType,
ErrorResult& aRv)
{
RefPtr<MultipartBlobImpl> blobImpl =
new MultipartBlobImpl(aBlobImpls, aName, aContentType);
blobImpl->SetLengthAndModifiedDate(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return blobImpl.forget();
}
/* static */ already_AddRefed<MultipartBlobImpl>
MultipartBlobImpl::Create(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
const nsAString& aContentType,
ErrorResult& aRv)
{
RefPtr<MultipartBlobImpl> blobImpl =
new MultipartBlobImpl(aBlobImpls, aContentType);
blobImpl->SetLengthAndModifiedDate(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return blobImpl.forget();
}
void
MultipartBlobImpl::GetInternalStream(nsIInputStream** aStream,
ErrorResult& aRv)
@@ -125,15 +156,19 @@ MultipartBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
}
// we can create our blob now
RefPtr<BlobImpl> impl =
new MultipartBlobImpl(blobImpls, aContentType);
RefPtr<BlobImpl> impl = Create(blobImpls, aContentType, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return impl.forget();
}
void
MultipartBlobImpl::InitializeBlob()
MultipartBlobImpl::InitializeBlob(ErrorResult& aRv)
{
SetLengthAndModifiedDate();
SetLengthAndModifiedDate(aRv);
NS_WARN_IF(aRv.Failed());
}
void
@@ -187,11 +222,12 @@ MultipartBlobImpl::InitializeBlob(
mBlobImpls = blobSet.GetBlobImpls();
SetLengthAndModifiedDate();
SetLengthAndModifiedDate(aRv);
NS_WARN_IF(aRv.Failed());
}
void
MultipartBlobImpl::SetLengthAndModifiedDate()
MultipartBlobImpl::SetLengthAndModifiedDate(ErrorResult& aRv)
{
MOZ_ASSERT(mLength == UINT64_MAX);
MOZ_ASSERT(mLastModificationDate == INT64_MAX);
@@ -208,16 +244,19 @@ MultipartBlobImpl::SetLengthAndModifiedDate()
MOZ_ASSERT(!blob->IsDateUnknown());
#endif
ErrorResult error;
uint64_t subBlobLength = blob->GetSize(error);
MOZ_ALWAYS_TRUE(!error.Failed());
uint64_t subBlobLength = blob->GetSize(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
MOZ_ASSERT(UINT64_MAX - subBlobLength >= totalLength);
totalLength += subBlobLength;
if (blob->IsFile()) {
int64_t partLastModified = blob->GetLastModified(error);
MOZ_ALWAYS_TRUE(!error.Failed());
int64_t partLastModified = blob->GetLastModified(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (lastModified < partLastModified) {
lastModified = partLastModified;
@@ -314,7 +353,8 @@ MultipartBlobImpl::InitializeChromeFile(Blob& aBlob,
blobSet.AppendBlobImpl(aBlob.Impl());
mBlobImpls = blobSet.GetBlobImpls();
SetLengthAndModifiedDate();
SetLengthAndModifiedDate(aRv);
NS_WARN_IF(aRv.Failed());
}
void
@@ -385,7 +425,8 @@ MultipartBlobImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
blobSet.AppendBlobImpl(static_cast<File*>(blob.get())->Impl());
mBlobImpls = blobSet.GetBlobImpls();
SetLengthAndModifiedDate();
SetLengthAndModifiedDate(aRv);
NS_WARN_IF(aRv.Failed());
}
void
+28 -19
View File
@@ -25,25 +25,17 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// Create as a file
MultipartBlobImpl(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
const nsAString& aName,
const nsAString& aContentType)
: BlobImplBase(aName, aContentType, UINT64_MAX),
mBlobImpls(aBlobImpls),
mIsFromNsIFile(false)
{
SetLengthAndModifiedDate();
}
static already_AddRefed<MultipartBlobImpl>
Create(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
const nsAString& aName,
const nsAString& aContentType,
ErrorResult& aRv);
// Create as a blob
MultipartBlobImpl(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
const nsAString& aContentType)
: BlobImplBase(aContentType, UINT64_MAX),
mBlobImpls(aBlobImpls),
mIsFromNsIFile(false)
{
SetLengthAndModifiedDate();
}
static already_AddRefed<MultipartBlobImpl>
Create(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
const nsAString& aContentType,
ErrorResult& aRv);
// Create as a file to be later initialized
explicit MultipartBlobImpl(const nsAString& aName)
@@ -59,7 +51,7 @@ public:
{
}
void InitializeBlob();
void InitializeBlob(ErrorResult& aRv);
void InitializeBlob(
JSContext* aCx,
@@ -120,9 +112,26 @@ public:
virtual bool MayBeClonedToOtherThreads() const override;
protected:
MultipartBlobImpl(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
const nsAString& aName,
const nsAString& aContentType)
: BlobImplBase(aName, aContentType, UINT64_MAX),
mBlobImpls(aBlobImpls),
mIsFromNsIFile(false)
{
}
MultipartBlobImpl(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
const nsAString& aContentType)
: BlobImplBase(aContentType, UINT64_MAX),
mBlobImpls(aBlobImpls),
mIsFromNsIFile(false)
{
}
virtual ~MultipartBlobImpl() {}
void SetLengthAndModifiedDate();
void SetLengthAndModifiedDate(ErrorResult& aRv);
nsTArray<RefPtr<BlobImpl>> mBlobImpls;
bool mIsFromNsIFile;
+1 -1
View File
@@ -316,7 +316,7 @@ ShadowRoot::DistributeSingleNode(nsIContent* aContent)
if (!isIndexFound) {
// We have still not found an index in the insertion point,
// thus it must be at the end.
MOZ_ASSERT(childIterator.Seek(aContent),
MOZ_ASSERT(childIterator.Seek(aContent, nullptr),
"Trying to match a node that is not a candidate to be matched");
insertionPoint->AppendMatchedNode(aContent);
}
+66 -19
View File
@@ -556,7 +556,8 @@ namespace {
// Recursive!
already_AddRefed<BlobImpl>
EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
PBackgroundChild* aManager = nullptr)
PBackgroundChild* aManager,
ErrorResult& aRv)
{
MOZ_ASSERT(aBlobImpl);
RefPtr<BlobImpl> blobImpl = aBlobImpl;
@@ -605,7 +606,11 @@ EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
RefPtr<BlobImpl>& newSubBlobImpl = newSubBlobImpls[index];
newSubBlobImpl = EnsureBlobForBackgroundManager(subBlobImpl, aManager);
newSubBlobImpl = EnsureBlobForBackgroundManager(subBlobImpl, aManager, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
MOZ_ASSERT(newSubBlobImpl);
if (subBlobImpl != newSubBlobImpl) {
@@ -621,9 +626,14 @@ EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
nsString name;
blobImpl->GetName(name);
blobImpl = new MultipartBlobImpl(newSubBlobImpls, name, contentType);
blobImpl = MultipartBlobImpl::Create(newSubBlobImpls, name,
contentType, aRv);
} else {
blobImpl = new MultipartBlobImpl(newSubBlobImpls, contentType);
blobImpl = MultipartBlobImpl::Create(newSubBlobImpls, contentType, aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
@@ -641,7 +651,13 @@ ReadBlob(JSContext* aCx,
MOZ_ASSERT(aIndex < aHolder->BlobImpls().Length());
RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[aIndex];
blobImpl = EnsureBlobForBackgroundManager(blobImpl);
ErrorResult rv;
blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return nullptr;
}
MOZ_ASSERT(blobImpl);
// RefPtr<File> needs to go out of scope before toObjectOrNull() is
@@ -669,7 +685,14 @@ WriteBlob(JSStructuredCloneWriter* aWriter,
MOZ_ASSERT(aBlob);
MOZ_ASSERT(aHolder);
RefPtr<BlobImpl> blobImpl = EnsureBlobForBackgroundManager(aBlob->Impl());
ErrorResult rv;
RefPtr<BlobImpl> blobImpl =
EnsureBlobForBackgroundManager(aBlob->Impl(), nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return false;
}
MOZ_ASSERT(blobImpl);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
@@ -715,7 +738,13 @@ ReadFileList(JSContext* aCx,
RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[index];
MOZ_ASSERT(blobImpl->IsFile());
blobImpl = EnsureBlobForBackgroundManager(blobImpl);
ErrorResult rv;
blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return nullptr;
}
MOZ_ASSERT(blobImpl);
RefPtr<File> file = File::Create(aHolder->ParentDuringRead(), blobImpl);
@@ -754,14 +783,22 @@ WriteFileList(JSStructuredCloneWriter* aWriter,
return false;
}
ErrorResult rv;
nsTArray<RefPtr<BlobImpl>> blobImpls;
for (uint32_t i = 0; i < aFileList->Length(); ++i) {
RefPtr<BlobImpl> blobImpl =
EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl());
MOZ_ASSERT(blobImpl);
EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl(), nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return false;
}
aHolder->BlobImpls().AppendElement(blobImpl);
MOZ_ASSERT(blobImpl);
blobImpls.AppendElement(blobImpl);
}
aHolder->BlobImpls().AppendElements(blobImpls);
return true;
}
@@ -805,7 +842,12 @@ ReadFormData(JSContext* aCx,
File::Create(aHolder->ParentDuringRead(), blobImpl);
MOZ_ASSERT(file);
formData->Append(name, *file, thirdArg);
ErrorResult rv;
formData->Append(name, *file, thirdArg, rv);
if (NS_WARN_IF(rv.Failed())) {
return nullptr;
}
} else {
MOZ_ASSERT(tag == 0);
@@ -817,7 +859,11 @@ ReadFormData(JSContext* aCx,
return nullptr;
}
formData->Append(name, value);
ErrorResult rv;
formData->Append(name, value, rv);
if (NS_WARN_IF(rv.Failed())) {
return nullptr;
}
}
}
@@ -866,16 +912,16 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
{ }
static bool
Write(const nsString& aName, bool isFile, const nsString& aValue,
File* aFile, void* aClosure)
Write(const nsString& aName, const OwningFileOrUSVString& aValue,
void* aClosure)
{
Closure* closure = static_cast<Closure*>(aClosure);
if (!WriteString(closure->mWriter, aName)) {
return false;
}
if (isFile) {
BlobImpl* blobImpl = aFile->Impl();
if (aValue.IsFile()) {
BlobImpl* blobImpl = aValue.GetAsFile()->Impl();
if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
closure->mHolder->BlobImpls().Length())) {
return false;
@@ -886,9 +932,10 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
}
size_t charSize = sizeof(nsString::char_type);
if (!JS_WriteUint32Pair(closure->mWriter, 0, aValue.Length()) ||
!JS_WriteBytes(closure->mWriter, aValue.get(),
aValue.Length() * charSize)) {
if (!JS_WriteUint32Pair(closure->mWriter, 0,
aValue.GetAsUSVString().Length()) ||
!JS_WriteBytes(closure->mWriter, aValue.GetAsUSVString().get(),
aValue.GetAsUSVString().Length() * charSize)) {
return false;
}
+2
View File
@@ -9,6 +9,8 @@
#include "nsGlobalWindow.h"
#include "mozilla/Hal.h"
using namespace mozilla::dom;
/**
* This class is used by nsGlobalWindow to implement window.orientation
* and window.onorientationchange. This class is defined in its own file
+2 -3
View File
@@ -16,7 +16,6 @@ XPIDL_SOURCES += [
'nsIDOMDOMCursor.idl',
'nsIDOMDOMRequest.idl',
'nsIDOMFileList.idl',
'nsIDOMFileReader.idl',
'nsIDOMFormData.idl',
'nsIDOMParser.idl',
'nsIDOMSerializer.idl',
@@ -179,6 +178,7 @@ EXPORTS.mozilla.dom += [
'EventSource.h',
'File.h',
'FileList.h',
'FileReader.h',
'FragmentOrElement.h',
'FromParser.h',
'ImageEncoder.h',
@@ -243,8 +243,8 @@ UNIFIED_SOURCES += [
'Element.cpp',
'EventSource.cpp',
'File.cpp',
'FileIOObject.cpp',
'FileList.cpp',
'FileReader.cpp',
'FragmentOrElement.cpp',
'ImageEncoder.cpp',
'ImportManager.cpp',
@@ -271,7 +271,6 @@ UNIFIED_SOURCES += [
'nsDOMAttributeMap.cpp',
'nsDOMCaretPosition.cpp',
'nsDOMClassInfo.cpp',
'nsDOMFileReader.cpp',
'nsDOMMutationObserver.cpp',
'nsDOMNavigationTiming.cpp',
'nsDOMScriptObjectFactory.cpp',
-16
View File
@@ -6616,22 +6616,6 @@ nsContentUtils::FindInternalContentViewer(const nsACString& aType,
return nullptr;
}
bool
nsContentUtils::GetContentSecurityPolicy(nsIContentSecurityPolicy** aCSP)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsCOMPtr<nsIContentSecurityPolicy> csp;
nsresult rv = SubjectPrincipal()->GetCsp(getter_AddRefs(csp));
if (NS_FAILED(rv)) {
NS_ERROR("CSP: Failed to get CSP from principal.");
return false;
}
csp.forget(aCSP);
return true;
}
// static
bool
nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
-5
View File
@@ -505,11 +505,6 @@ public:
return sSecurityManager;
}
/**
* Get the ContentSecurityPolicy for a JS context.
**/
static bool GetContentSecurityPolicy(nsIContentSecurityPolicy** aCSP);
// Returns the subject principal. Guaranteed to return non-null. May only
// be called when nsContentUtils is initialized.
static nsIPrincipal* SubjectPrincipal();
+1 -2
View File
@@ -2282,8 +2282,7 @@ struct InterfaceShimEntry {
// interface that has interface constants that sites might be getting off
// of Ci.
const InterfaceShimEntry kInterfaceShimMap[] =
{ { "nsIDOMFileReader", "FileReader" },
{ "nsIXMLHttpRequest", "XMLHttpRequest" },
{ { "nsIXMLHttpRequest", "XMLHttpRequest" },
{ "nsIDOMDOMException", "DOMException" },
{ "nsIDOMNode", "Node" },
{ "nsIDOMCSSPrimitiveValue", "CSSPrimitiveValue" },
+1 -2
View File
@@ -846,8 +846,7 @@ nsDOMMutationObserver::HandleMutation()
}
ClearPendingRecords();
mozilla::ErrorResult rv;
mCallback->Call(this, mutations, *this, rv);
mCallback->Call(this, mutations, *this);
}
class AsyncMutationHandler : public nsRunnable
+73 -34
View File
@@ -25,7 +25,8 @@ namespace {
// Implements steps 3 and 4 of the "create an entry" algorithm of FormData.
already_AddRefed<File>
CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename)
CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename,
ErrorResult& aRv)
{
// Step 3 "If value is a Blob object and not a File object, set value to
// a new File object, representing the same bytes, whose name attribute value
@@ -47,10 +48,15 @@ CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename)
filename = NS_LITERAL_STRING("blob");
}
return aBlob.ToFile(filename);
RefPtr<File> file = aBlob.ToFile(filename, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return file.forget();
}
} // anonymous namespace
} // namespace
// -------------------------------------------------------------------------
// nsISupports
@@ -61,7 +67,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
ImplCycleCollectionUnlink(tmp->mFormData[i].fileValue);
ImplCycleCollectionUnlink(tmp->mFormData[i].value);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@@ -71,8 +77,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormData)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
ImplCycleCollectionTraverse(cb,tmp->mFormData[i].fileValue,
"mFormData[i].fileValue", 0);
ImplCycleCollectionTraverse(cb, tmp->mFormData[i].value,
"mFormData[i].GetAsFile()", 0);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
@@ -101,16 +107,22 @@ nsFormData::GetEncodedSubmission(nsIURI* aURI,
}
void
nsFormData::Append(const nsAString& aName, const nsAString& aValue)
nsFormData::Append(const nsAString& aName, const nsAString& aValue,
ErrorResult& aRv)
{
AddNameValuePair(aName, aValue);
}
void
nsFormData::Append(const nsAString& aName, Blob& aBlob,
const Optional<nsAString>& aFilename)
const Optional<nsAString>& aFilename,
ErrorResult& aRv)
{
RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename);
RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
AddNameFilePair(aName, file);
}
@@ -126,24 +138,13 @@ nsFormData::Delete(const nsAString& aName)
}
}
void
nsFormData::ExtractValue(const FormDataTuple& aTuple,
OwningFileOrUSVString* aOutValue)
{
if (aTuple.valueIsFile) {
aOutValue->SetAsFile() = aTuple.fileValue;
} else {
aOutValue->SetAsUSVString() = aTuple.stringValue;
}
}
void
nsFormData::Get(const nsAString& aName,
Nullable<OwningFileOrUSVString>& aOutValue)
{
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
if (aName.Equals(mFormData[i].name)) {
ExtractValue(mFormData[i], &aOutValue.SetValue());
aOutValue.SetValue() = mFormData[i].value;
return;
}
}
@@ -158,7 +159,7 @@ nsFormData::GetAll(const nsAString& aName,
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
if (aName.Equals(mFormData[i].name)) {
OwningFileOrUSVString* element = aValues.AppendElement();
ExtractValue(mFormData[i], element);
*element = mFormData[i].value;
}
}
}
@@ -207,28 +208,54 @@ nsFormData::RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName)
void
nsFormData::Set(const nsAString& aName, Blob& aBlob,
const Optional<nsAString>& aFilename)
const Optional<nsAString>& aFilename,
ErrorResult& aRv)
{
FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
if (tuple) {
RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename);
RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
SetNameFilePair(tuple, aName, file);
} else {
Append(aName, aBlob, aFilename);
Append(aName, aBlob, aFilename, aRv);
}
}
void
nsFormData::Set(const nsAString& aName, const nsAString& aValue)
nsFormData::Set(const nsAString& aName, const nsAString& aValue,
ErrorResult& aRv)
{
FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
if (tuple) {
SetNameValuePair(tuple, aName, aValue);
} else {
Append(aName, aValue);
Append(aName, aValue, aRv);
}
}
uint32_t
nsFormData::GetIterableLength() const
{
return mFormData.Length();
}
const nsAString&
nsFormData::GetKeyAtIndex(uint32_t aIndex) const
{
MOZ_ASSERT(aIndex < mFormData.Length());
return mFormData[aIndex].name;
}
const OwningFileOrUSVString&
nsFormData::GetValueAtIndex(uint32_t aIndex) const
{
MOZ_ASSERT(aIndex < mFormData.Length());
return mFormData[aIndex].value;
}
// -------------------------------------------------------------------------
// nsIDOMFormData
@@ -252,7 +279,12 @@ nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
RefPtr<Blob> blob = static_cast<Blob*>(domBlob.get());
if (domBlob) {
Optional<nsAString> temp;
Append(aName, *blob, temp);
ErrorResult rv;
Append(aName, *blob, temp, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
return NS_OK;
}
}
@@ -265,7 +297,12 @@ nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
nsString valAsString;
valAsString.Adopt(stringData, stringLen);
Append(aName, valAsString);
ErrorResult error;
Append(aName, valAsString, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
return NS_OK;
}
@@ -297,11 +334,13 @@ nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
if (mFormData[i].valueIsFile) {
fs.AddNameFilePair(mFormData[i].name, mFormData[i].fileValue);
}
else {
fs.AddNameValuePair(mFormData[i].name, mFormData[i].stringValue);
if (mFormData[i].value.IsFile()) {
fs.AddNameFilePair(mFormData[i].name, mFormData[i].value.GetAsFile());
} else if (mFormData[i].value.IsUSVString()) {
fs.AddNameValuePair(mFormData[i].name,
mFormData[i].value.GetAsUSVString());
} else {
fs.AddNameFilePair(mFormData[i].name, nullptr);
}
}
+24 -20
View File
@@ -37,13 +37,12 @@ private:
typedef mozilla::dom::Blob Blob;
typedef mozilla::dom::File File;
typedef mozilla::dom::OwningFileOrUSVString OwningFileOrUSVString;
struct FormDataTuple
{
nsString name;
nsString stringValue;
RefPtr<File> fileValue;
bool valueIsFile;
OwningFileOrUSVString value;
};
// Returns the FormDataTuple to modify. This may be null, in which case
@@ -57,8 +56,7 @@ private:
{
MOZ_ASSERT(aData);
aData->name = aName;
aData->stringValue = aValue;
aData->valueIsFile = false;
aData->value.SetAsUSVString() = aValue;
}
void SetNameFilePair(FormDataTuple* aData,
@@ -67,12 +65,11 @@ private:
{
MOZ_ASSERT(aData);
aData->name = aName;
aData->fileValue = aFile;
aData->valueIsFile = true;
if (aFile) {
aData->value.SetAsFile() = aFile;
}
}
void ExtractValue(const FormDataTuple& aTuple,
mozilla::dom::OwningFileOrUSVString* aOutValue);
public:
explicit nsFormData(nsISupports* aOwner = nullptr);
@@ -96,16 +93,24 @@ public:
Constructor(const mozilla::dom::GlobalObject& aGlobal,
const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement,
mozilla::ErrorResult& aRv);
void Append(const nsAString& aName, const nsAString& aValue);
void Append(const nsAString& aName, const nsAString& aValue,
mozilla::ErrorResult& aRv);
void Append(const nsAString& aName, Blob& aBlob,
const mozilla::dom::Optional<nsAString>& aFilename);
const mozilla::dom::Optional<nsAString>& aFilename,
mozilla::ErrorResult& aRv);
void Delete(const nsAString& aName);
void Get(const nsAString& aName, mozilla::dom::Nullable<mozilla::dom::OwningFileOrUSVString>& aOutValue);
void GetAll(const nsAString& aName, nsTArray<mozilla::dom::OwningFileOrUSVString>& aValues);
void Get(const nsAString& aName, mozilla::dom::Nullable<OwningFileOrUSVString>& aOutValue);
void GetAll(const nsAString& aName, nsTArray<OwningFileOrUSVString>& aValues);
bool Has(const nsAString& aName);
void Set(const nsAString& aName, Blob& aBlob,
const mozilla::dom::Optional<nsAString>& aFilename);
void Set(const nsAString& aName, const nsAString& aValue);
const mozilla::dom::Optional<nsAString>& aFilename,
mozilla::ErrorResult& aRv);
void Set(const nsAString& aName, const nsAString& aValue,
mozilla::ErrorResult& aRv);
uint32_t GetIterableLength() const;
const nsAString& GetKeyAtIndex(uint32_t aIndex) const;
const OwningFileOrUSVString& GetValueAtIndex(uint32_t aIndex) const;
// nsFormSubmission
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
@@ -120,9 +125,9 @@ public:
virtual nsresult AddNameFilePair(const nsAString& aName,
File* aFile) override;
typedef bool (*FormDataEntryCallback)(const nsString& aName, bool aIsFile,
const nsString& aValue,
File* aFile, void* aClosure);
typedef bool (*FormDataEntryCallback)(const nsString& aName,
const OwningFileOrUSVString& aValue,
void* aClosure);
uint32_t
Length() const
@@ -137,8 +142,7 @@ public:
{
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
FormDataTuple& tuple = mFormData[i];
if (!aFunc(tuple.name, tuple.valueIsFile, tuple.stringValue,
tuple.fileValue, aClosure)) {
if (!aFunc(tuple.name, tuple.value, aClosure)) {
return false;
}
}
-47
View File
@@ -1,47 +0,0 @@
/* -*- 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/. */
#include "nsIDOMEventTarget.idl"
interface nsIDOMEventListener;
interface nsIDOMBlob;
[builtinclass, uuid(2f34c719-bc14-4546-9fb9-2bab75e56e45)]
interface nsIDOMFileReader : nsIDOMEventTarget
{
[implicit_jscontext]
void readAsArrayBuffer(in nsIDOMBlob filedata);
void readAsBinaryString(in nsIDOMBlob filedata);
void readAsText(in nsIDOMBlob filedata, [optional] in DOMString encoding);
void readAsDataURL(in nsIDOMBlob file);
void abort();
const unsigned short EMPTY = 0;
const unsigned short LOADING = 1;
const unsigned short DONE = 2;
readonly attribute unsigned short readyState;
[implicit_jscontext]
readonly attribute jsval result;
// This is a DOMError
readonly attribute nsISupports error;
[implicit_jscontext] attribute jsval onloadstart;
[implicit_jscontext] attribute jsval onprogress;
[implicit_jscontext] attribute jsval onload;
[implicit_jscontext] attribute jsval onabort;
[implicit_jscontext] attribute jsval onerror;
[implicit_jscontext] attribute jsval onloadend;
};
%{ C++
#define NS_FILEREADER_CID \
{0x06aa7c21, 0xfe05, 0x4cf2, \
{0xb1, 0xc4, 0x0c, 0x71, 0x26, 0xa4, 0xf7, 0x13}}
#define NS_FILEREADER_CONTRACTID \
"@mozilla.org/files/filereader;1"
%}
+15 -8
View File
@@ -795,7 +795,7 @@ nsXMLHttpRequest::CreateResponseParsedJSON(JSContext* aCx)
}
void
nsXMLHttpRequest::CreatePartialBlob()
nsXMLHttpRequest::CreatePartialBlob(ErrorResult& aRv)
{
if (mDOMBlob) {
// Use progress info to determine whether load is complete, but use
@@ -804,9 +804,8 @@ nsXMLHttpRequest::CreatePartialBlob()
if (mLoadTotal == mLoadTransferred) {
mResponseBlob = mDOMBlob;
} else {
ErrorResult rv;
mResponseBlob = mDOMBlob->CreateSlice(0, mDataAvailable,
EmptyString(), rv);
EmptyString(), aRv);
}
return;
}
@@ -821,7 +820,7 @@ nsXMLHttpRequest::CreatePartialBlob()
mChannel->GetContentType(contentType);
}
mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType);
mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType, aRv);
}
NS_IMETHODIMP nsXMLHttpRequest::GetResponseType(nsAString& aResponseType)
@@ -1015,7 +1014,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx,
}
if (!mResponseBlob) {
CreatePartialBlob();
CreatePartialBlob(aRv);
}
}
@@ -1687,8 +1686,10 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
}
// If we have the document, use it
if (doc) {
// If we have the document, use it. Unfortunately, for dedicated workers
// 'doc' ends up being the parent document, which is not the document
// that we want to use. So make sure to avoid using 'doc' in that situation.
if (doc && doc->NodePrincipal() == mPrincipal) {
rv = NS_NewChannel(getter_AddRefs(mChannel),
uri,
doc,
@@ -2221,8 +2222,14 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult
// Also, no-store response cannot be written in persistent cache.
nsAutoCString contentType;
mChannel->GetContentType(contentType);
mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType);
ErrorResult rv;
mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType, rv);
mBlobSet = nullptr;
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
}
NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty");
+1 -1
View File
@@ -605,7 +605,7 @@ protected:
uint32_t count,
uint32_t *writeCount);
nsresult CreateResponseParsedJSON(JSContext* aCx);
void CreatePartialBlob();
void CreatePartialBlob(ErrorResult& aRv);
bool CreateDOMBlob(nsIRequest *request);
// Change the state of the object with this. The broadcast argument
// determines if the onreadystatechange listener should be called.
+26
View File
@@ -0,0 +1,26 @@
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.importGlobalProperties(["File"]);
function createFileWithData(message) {
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var testFile = dirSvc.get("ProfD", Ci.nsIFile);
testFile.append("fileAPItestfileBug1198095");
var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(message, message.length);
outStream.close();
var domFile = new File(testFile);
return domFile;
}
addMessageListener("file.open", function (message) {
sendAsyncMessage("file.opened", createFileWithData(message));
});
addMessageListener("file.modify", function (message) {
sendAsyncMessage("file.modified", createFileWithData(message));
});
+2
View File
@@ -257,6 +257,7 @@ support-files =
referrer_change_server.sjs
file_change_policy_redirect.html
empty_worker.js
file_bug1198095.js
[test_anonymousContent_api.html]
[test_anonymousContent_append_after_reflow.html]
@@ -846,3 +847,4 @@ skip-if = e10s || os != 'linux' || buildapp != 'browser'
skip-if = buildapp == 'b2g' #no ssl support
[test_document.all_iteration.html]
[test_performance_translate.html]
[test_bug1198095.html]
+77
View File
@@ -0,0 +1,77 @@
<!DOCTYPE HTML>
<html>
<head>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1198095
-->
<title>Test for Bug 1198095</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1198095">Mozilla Bug 1198095</a>
<pre id="test">
<script class="testbody" type="text/javascript;version=1.7">
var fileData1 = '1234567890';
var fileData2 = '43210';
var r, firstBlob;
var openerURL = SimpleTest.getTestFileURL("file_bug1198095.js");
var opener = SpecialPowers.loadChromeScript(openerURL);
opener.addMessageListener("file.opened", onFileOpened);
opener.addMessageListener("file.modified", onFileModified);
opener.sendAsyncMessage("file.open", fileData1);
function onLoadEnd1(e) {
e.target.removeEventListener('loadend', onLoadEnd1);
is(e.target, r, "Target and r are ok");
ok(e.target.readyState, FileReader.DONE, "The file has been read.");
ok(e.target.result instanceof ArrayBuffer, "The result is an ArrayBuffer");
var view = new Uint8Array(e.target.result);
is(view.length, fileData1.length, "File data length matches");
for (var i = 0; i < fileData1.length; ++i) {
is(String.fromCharCode(view[i]), fileData1[i], "Byte matches");
}
opener.sendAsyncMessage("file.modify", fileData2);
}
function onLoadEnd2(e) {
e.target.removeEventListener('loadend', onLoadEnd2);
ok(false, "This method should not be called - loadEnd2!");
}
function onError1(e) {
ok(false, "This method should not be called - error1!");
}
function onError2(e) {
e.target.removeEventListener('error', onError2);
SimpleTest.finish();
}
function onFileOpened(blob) {
firstBlob = blob;
r = new FileReader();
r.addEventListener("loadend", onLoadEnd1, false);
r.addEventListener("error", onError1, false);
r.readAsArrayBuffer(firstBlob);
}
function onFileModified(blob) {
r.addEventListener("loadend", onLoadEnd2, false);
r.removeEventListener('error', onError1);
r.addEventListener("error", onError2, false);
r.readAsArrayBuffer(firstBlob);
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body> </html>
@@ -26,9 +26,7 @@
return;
}
let reader =
Components.classes["@mozilla.org/files/filereader;1"]
.createInstance(Components.interfaces.nsIDOMFileReader);
let reader = new FileReader();
reader.addEventListener("load", function() {
let response = reader.result == "this is a great success!" ?
message.json :
-1
View File
@@ -513,7 +513,6 @@ DOMInterfaces = {
},
'FileReader': {
'nativeType': 'nsDOMFileReader',
'implicitJSContext': [ 'readAsArrayBuffer' ],
},
+56 -2
View File
@@ -14542,16 +14542,33 @@ class CGCallback(CGClass):
assert args[0].name == "cx" and args[0].argType == "JSContext*"
assert args[1].name == "aThisVal" and args[1].argType == "JS::Handle<JS::Value>"
args = args[2:]
# Now remember which index the ErrorResult argument is at;
# we'll need this below.
assert args[-1].name == "aRv" and args[-1].argType == "ErrorResult&"
rvIndex = len(args) - 1
assert rvIndex >= 0
# Record the names of all the arguments, so we can use them when we call
# the private method.
argnames = [arg.name for arg in args]
argnamesWithThis = ["s.GetContext()", "thisValJS"] + argnames
argnamesWithoutThis = ["s.GetContext()", "JS::UndefinedHandleValue"] + argnames
# Now that we've recorded the argnames for our call to our private
# method, insert our optional arguments for the execution reason and for
# deciding whether the CallSetup should re-throw exceptions on aRv.
# method, insert our optional argument for the execution reason.
args.append(Argument("const char*", "aExecutionReason",
"nullptr"))
# Make copies of the arg list for the two "without rv" overloads. Note
# that those don't need aExceptionHandling or aCompartment arguments
# because those would make not sense anyway: the only sane thing to do
# with exceptions in the "without rv" cases is to report them.
argsWithoutRv = list(args)
argsWithoutRv.pop(rvIndex)
argsWithoutThisAndRv = list(argsWithoutRv)
# Add the potional argument for deciding whether the CallSetup should
# re-throw exceptions on aRv.
args.append(Argument("ExceptionHandling", "aExceptionHandling",
"eReportExceptions"))
# And the argument for communicating when exceptions should really be
@@ -14563,6 +14580,22 @@ class CGCallback(CGClass):
# And now insert our template argument.
argsWithoutThis = list(args)
args.insert(0, Argument("const T&", "thisVal"))
argsWithoutRv.insert(0, Argument("const T&", "thisVal"))
argnamesWithoutThisAndRv = [arg.name for arg in argsWithoutThisAndRv]
argnamesWithoutThisAndRv.insert(rvIndex, "rv");
# If we just leave things like that, and have no actual arguments in the
# IDL, we will end up trying to call the templated "without rv" overload
# with "rv" as the thisVal. That's no good. So explicitly append the
# aExceptionHandling and aCompartment values we need to end up matching
# the signature of our non-templated "with rv" overload.
argnamesWithoutThisAndRv.extend(["eReportExceptions", "nullptr"])
argnamesWithoutRv = [arg.name for arg in argsWithoutRv]
# Note that we need to insert at rvIndex + 1, since we inserted a
# thisVal arg at the start.
argnamesWithoutRv.insert(rvIndex + 1, "rv")
errorReturn = method.getDefaultRetval()
setupCall = fill(
@@ -14602,6 +14635,20 @@ class CGCallback(CGClass):
errorReturn=errorReturn,
methodName=method.name,
callArgs=", ".join(argnamesWithoutThis))
bodyWithThisWithoutRv = fill(
"""
IgnoredErrorResult rv;
return ${methodName}(${callArgs});
""",
methodName=method.name,
callArgs=", ".join(argnamesWithoutRv))
bodyWithoutThisAndRv = fill(
"""
IgnoredErrorResult rv;
return ${methodName}(${callArgs});
""",
methodName=method.name,
callArgs=", ".join(argnamesWithoutThisAndRv))
return [ClassMethod(method.name, method.returnType, args,
bodyInHeader=True,
@@ -14610,6 +14657,13 @@ class CGCallback(CGClass):
ClassMethod(method.name, method.returnType, argsWithoutThis,
bodyInHeader=True,
body=bodyWithoutThis),
ClassMethod(method.name, method.returnType, argsWithoutRv,
bodyInHeader=True,
templateArgs=["typename T"],
body=bodyWithThisWithoutRv),
ClassMethod(method.name, method.returnType, argsWithoutThisAndRv,
bodyInHeader=True,
body=bodyWithoutThisAndRv),
method]
def deps(self):
+10
View File
@@ -398,6 +398,16 @@ private:
void operator=(const ErrorResult&) = delete;
};
// A class for use when an ErrorResult should just automatically be ignored.
class IgnoredErrorResult : public ErrorResult
{
public:
~IgnoredErrorResult()
{
SuppressException();
}
};
/******************************************************************************
** Macros for checking results
******************************************************************************/
+11 -3
View File
@@ -203,7 +203,9 @@ public:
bool URLParamsIterator(const nsString& aName,
const nsString& aValue) override
{
mFormData->Append(aName, aValue);
ErrorResult rv;
mFormData->Append(aName, aValue, rv);
MOZ_ASSERT(!rv.Failed());
return true;
}
@@ -392,7 +394,9 @@ private:
NS_ConvertUTF8toUTF16 name(mName);
if (mFilename.IsVoid()) {
mFormData->Append(name, NS_ConvertUTF8toUTF16(body));
ErrorResult rv;
mFormData->Append(name, NS_ConvertUTF8toUTF16(body), rv);
MOZ_ASSERT(!rv.Failed());
} else {
// Unfortunately we've to copy the data first since all our strings are
// going to free it. We also need fallible alloc, so we can't just use
@@ -417,7 +421,11 @@ private:
NS_ConvertUTF8toUTF16(mFilename),
NS_ConvertUTF8toUTF16(mContentType), /* aLastModifiedDate */ 0);
Optional<nsAString> dummy;
mFormData->Append(name, *file, dummy);
ErrorResult rv;
mFormData->Append(name, *file, dummy, rv);
if (NS_WARN_IF(rv.Failed())) {
return false;
}
}
return true;
+2 -4
View File
@@ -330,8 +330,7 @@ PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback)
PositionErrorCallback* callback = aCallback.GetWebIDLCallback();
if (callback) {
ErrorResult err;
callback->Call(*this, err);
callback->Call(*this);
}
} else {
nsIDOMGeoPositionErrorCallback* callback = aCallback.GetXPCOMCallback();
@@ -654,11 +653,10 @@ nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
nsAutoMicroTask mt;
if (mCallback.HasWebIDLCallback()) {
ErrorResult err;
PositionCallback* callback = mCallback.GetWebIDLCallback();
MOZ_ASSERT(callback);
callback->Call(*wrapped, err);
callback->Call(*wrapped);
} else {
nsIDOMGeoPositionCallback* callback = mCallback.GetXPCOMCallback();
+2 -7
View File
@@ -42,14 +42,9 @@
// test loading with relative url - this should fail since we are
// sandboxed and have a null principal
try {
var worker_js = new Worker('file_iframe_sandbox_worker.js');
} catch (e) {
ok(e.name === "SecurityError", "a worker in a sandboxed document should throw when loading from a relative URI");
}
var worker_js = new Worker('file_iframe_sandbox_worker.js');
worker_js.onerror = function(error) {
ok(false, "a worker in a sandboxed document should not tell the load error via error event");
ok(true, "a worker in a sandboxed document should tell the load error via error event");
}
worker_js.addEventListener('message', function(event) {
+51
View File
@@ -105,6 +105,56 @@ function testFilename() {
is(f.get("file3").name, "", "File's filename is returned even if empty.");
}
function testIterable() {
var fd = new FormData();
fd.set('1','2');
fd.set('2','4');
fd.set('3','6');
fd.set('4','8');
fd.set('5','10');
var key_iter = fd.keys();
var value_iter = fd.values();
var entries_iter = fd.entries();
for (var i = 0; i < 5; ++i) {
var v = i + 1;
var key = key_iter.next();
var value = value_iter.next();
var entry = entries_iter.next();
is(key.value, v.toString(), "Correct Key iterator: " + v.toString());
ok(!key.done, "key.done is false");
is(value.value, (v * 2).toString(), "Correct Value iterator: " + (v * 2).toString());
ok(!value.done, "value.done is false");
is(entry.value[0], v.toString(), "Correct Entry 0 iterator: " + v.toString());
is(entry.value[1], (v * 2).toString(), "Correct Entry 1 iterator: " + (v * 2).toString());
ok(!entry.done, "entry.done is false");
}
var last = key_iter.next();
ok(last.done, "Nothing more to read.");
is(last.value, undefined, "Undefined is the last key");
last = value_iter.next();
ok(last.done, "Nothing more to read.");
is(last.value, undefined, "Undefined is the last value");
last = entries_iter.next();
ok(last.done, "Nothing more to read.");
key_iter = fd.keys();
key_iter.next();
key_iter.next();
fd.delete('1');
fd.delete('2');
fd.delete('3');
fd.delete('4');
fd.delete('5');
last = key_iter.next();
ok(last.done, "Nothing more to read.");
is(last.value, undefined, "Undefined is the last key");
}
function testSend(doneCb) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "form_submit_server.sjs");
@@ -161,6 +211,7 @@ function runTest(doneCb) {
testSet();
testIterate();
testFilename();
testIterable();
// Finally, send an XHR and verify the response matches.
testSend(doneCb);
}
@@ -50,11 +50,6 @@ function childFrameScript() {
sendAsyncMessage(mmName, { op: "done", result: result });
}
function createFileReader() {
return Cc["@mozilla.org/files/filereader;1"]
.createInstance(Ci.nsIDOMFileReader);
}
function grabAndContinue(arg) {
testGenerator.send(arg);
}
@@ -78,7 +73,7 @@ function childFrameScript() {
info("Reading blob");
let reader = createFileReader();
let reader = new FileReader();
reader.addEventListener("load", grabAndContinue);
reader.readAsText(blob);
@@ -94,7 +89,7 @@ function childFrameScript() {
info("Reading slice");
reader = createFileReader();
reader = new FileReader();
reader.addEventListener("load", grabAndContinue);
reader.readAsText(slice);
@@ -155,7 +150,7 @@ function childFrameScript() {
info("Reading blob");
reader = createFileReader();
reader = new FileReader();
reader.addEventListener("load", grabAndContinue);
reader.readAsText(blob);
@@ -190,7 +185,7 @@ function childFrameScript() {
info("Reading Slice");
reader = createFileReader();
reader = new FileReader();
reader.addEventListener("load", grabAndContinue);
reader.readAsText(slice);
@@ -3,14 +3,9 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
let disableWorkerTest = "This test uses SpecialPowers";
var disableWorkerTest = "This test uses SpecialPowers";
let testGenerator = testSteps();
function createFileReader() {
return SpecialPowers.Cc["@mozilla.org/files/filereader;1"]
.createInstance(SpecialPowers.Ci.nsIDOMFileReader);
}
var testGenerator = testSteps();
function testSteps()
{
@@ -48,7 +43,7 @@ function testSteps()
is(file.size, fileData.length, "Correct size");
is(file.type, fileType, "Correct type");
let fileReader = createFileReader();
let fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(file);
@@ -85,7 +80,7 @@ function testSteps()
is(file.size, fileData.length, "Correct size");
is(file.type, fileType, "Correct type");
fileReader = createFileReader();
fileReader = new FileReader();
fileReader.onload = grabEventAndContinueHandler;
fileReader.readAsText(file);
@@ -52,7 +52,7 @@ if (!this.runTest) {
enableExperimental();
}
Cu.importGlobalProperties(["indexedDB", "Blob", "File"]);
Cu.importGlobalProperties(["indexedDB", "Blob", "File", "FileReader"]);
do_test_pending();
testGenerator.next();
@@ -342,12 +342,6 @@ function getFile(name, type, str)
return new File([str], name, {type: type});
}
function getFileReader()
{
return SpecialPowers.Cc["@mozilla.org/files/filereader;1"]
.createInstance(SpecialPowers.Ci.nsIDOMFileReader);
}
function compareBuffers(buffer1, buffer2)
{
if (buffer1.byteLength != buffer2.byteLength) {
@@ -391,7 +385,7 @@ function verifyBlob(blob1, blob2)
}
if (!buffer2) {
let reader = getFileReader();
let reader = new FileReader();
reader.readAsArrayBuffer(blob2);
reader.onload = function(event) {
buffer2 = event.target.result;
@@ -403,7 +397,7 @@ function verifyBlob(blob1, blob2)
}
}
let reader = getFileReader();
let reader = new FileReader();
reader.readAsArrayBuffer(blob1);
reader.onload = function(event) {
buffer1 = event.target.result;
+8 -4
View File
@@ -904,13 +904,17 @@ CreateBlobImpl(const nsTArray<BlobData>& aBlobDatas,
MOZ_ASSERT(!isMutable);
}
ErrorResult rv;
RefPtr<BlobImpl> blobImpl;
if (!hasRecursed && aMetadata.IsFile()) {
blobImpl =
new MultipartBlobImpl(blobImpls, aMetadata.mName, aMetadata.mContentType);
blobImpl = MultipartBlobImpl::Create(blobImpls, aMetadata.mName,
aMetadata.mContentType, rv);
} else {
blobImpl =
new MultipartBlobImpl(blobImpls, aMetadata.mContentType);
blobImpl = MultipartBlobImpl::Create(blobImpls, aMetadata.mContentType, rv);
}
if (NS_WARN_IF(rv.Failed())) {
return nullptr;
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
@@ -44,11 +44,6 @@ function childFrameScript() {
sendAsyncMessage(messageName, { op: "done", result: result });
}
function createFileReader() {
return Cc["@mozilla.org/files/filereader;1"]
.createInstance(Ci.nsIDOMFileReader);
}
function grabAndContinue(arg) {
testGenerator.send(arg);
}
@@ -65,7 +60,7 @@ function childFrameScript() {
info("Reading blob");
let reader = createFileReader();
let reader = new FileReader();
reader.addEventListener("load", grabAndContinue);
reader.readAsText(blob);
@@ -84,7 +79,7 @@ function childFrameScript() {
info("Reading slice");
reader = createFileReader();
reader = new FileReader();
reader.addEventListener("load", grabAndContinue);
reader.readAsText(slice);
+5
View File
@@ -301,6 +301,11 @@ if CONFIG['MOZ_WEBRTC']:
DEFINES['MOZILLA_INTERNAL_API'] = True
if CONFIG['OS_TARGET'] == 'WINNT':
DEFINES['WEBRTC_WIN'] = True
else:
DEFINES['WEBRTC_POSIX'] = True
if CONFIG['MOZ_OMX_DECODER']:
DEFINES['MOZ_OMX_DECODER'] = True
+17 -6
View File
@@ -45,12 +45,18 @@ enum BufferState
bool
OMXCodecReservation::ReserveOMXCodec()
{
if (mClient) {
// Already tried reservation.
return false;
if (!mClient) {
mClient = new mozilla::MediaSystemResourceClient(mType);
} else {
if (mOwned) {
//CODEC_ERROR("OMX Reservation: (%d) already owned", (int) mType);
return true;
}
//CODEC_ERROR("OMX Reservation: (%d) already NOT owned", (int) mType);
}
mClient = new mozilla::MediaSystemResourceClient(mType);
return mClient->AcquireSyncNoWait(); // don't wait if resrouce is not available
mOwned = mClient->AcquireSyncNoWait(); // don't wait if resource is not available
//CODEC_ERROR("OMX Reservation: (%d) Acquire was %s", (int) mType, mOwned ? "Successful" : "Failed");
return mOwned;
}
void
@@ -59,7 +65,12 @@ OMXCodecReservation::ReleaseOMXCodec()
if (!mClient) {
return;
}
mClient->ReleaseResource();
//CODEC_ERROR("OMX Reservation: Releasing resource: (%d) %s", (int) mType, mOwned ? "Owned" : "Not owned");
if (mOwned) {
mClient->ReleaseResource();
mClient = nullptr;
mOwned = false;
}
}
OMXAudioEncoder*
+2 -1
View File
@@ -26,7 +26,7 @@ namespace android {
class OMXCodecReservation : public RefBase
{
public:
OMXCodecReservation(bool aEncoder)
OMXCodecReservation(bool aEncoder) : mOwned(false)
{
mType = aEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
mozilla::MediaSystemResourceType::VIDEO_DECODER;
@@ -45,6 +45,7 @@ public:
private:
mozilla::MediaSystemResourceType mType;
bool mOwned; // We already own this resource
RefPtr<mozilla::MediaSystemResourceClient> mClient;
};
+1 -1
View File
@@ -647,7 +647,7 @@ bool
CamerasChild::RecvDeliverFrame(const int& capEngine,
const int& capId,
mozilla::ipc::Shmem&& shmem,
const int& size,
const size_t& size,
const uint32_t& time_stamp,
const int64_t& ntp_time,
const int64_t& render_time)
+3 -3
View File
@@ -85,7 +85,7 @@ public:
// IPC messages recevied, received on the PBackground thread
// these are the actual callbacks with data
virtual bool RecvDeliverFrame(const int&, const int&, mozilla::ipc::Shmem&&,
const int&, const uint32_t&, const int64_t&,
const size_t&, const uint32_t&, const int64_t&,
const int64_t&) override;
virtual bool RecvFrameSizeChange(const int&, const int&,
const int& w, const int& h) override;
@@ -159,9 +159,9 @@ private:
Mutex mRequestMutex;
// Hold to wait for an async response to our calls
Monitor mReplyMonitor;
// Async resposne valid?
// Async response valid?
bool mReceivedReply;
// Aynsc reponses data contents;
// Async responses data contents;
bool mReplySuccess;
int mReplyInteger;
webrtc::CaptureCapability mReplyCapability;
+21 -4
View File
@@ -16,6 +16,8 @@
#include "nsThreadUtils.h"
#include "nsXPCOM.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#undef LOG
#undef LOG_ENABLED
mozilla::LazyLogModule gCamerasParentLog("CamerasParent");
@@ -90,7 +92,7 @@ public:
int cap_id,
ShmemBuffer buffer,
unsigned char* altbuffer,
int size,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time)
@@ -136,7 +138,7 @@ private:
int mCapId;
ShmemBuffer mBuffer;
mozilla::UniquePtr<unsigned char[]> mAlternateBuffer;
int mSize;
size_t mSize;
uint32_t mTimeStamp;
int64_t mNtpTime;
int64_t mRenderTime;
@@ -184,6 +186,7 @@ CamerasParent::DispatchToVideoCaptureThread(nsRunnable *event)
void
CamerasParent::StopVideoCapture()
{
LOG((__PRETTY_FUNCTION__));
// We are called from the main thread (xpcom-shutdown) or
// from PBackground (when the Actor shuts down).
// Shut down the WebRTC stack (on the capture thread)
@@ -232,7 +235,7 @@ CamerasParent::DeliverFrameOverIPC(CaptureEngine cap_engine,
int cap_id,
ShmemBuffer buffer,
unsigned char* altbuffer,
int size,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time)
@@ -280,7 +283,7 @@ CamerasParent::GetBuffer(size_t aSize)
int
CallbackHelper::DeliverFrame(unsigned char* buffer,
int size,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time,
@@ -309,6 +312,17 @@ CallbackHelper::DeliverFrame(unsigned char* buffer,
thread->Dispatch(runnable, NS_DISPATCH_NORMAL);
return 0;
}
// XXX!!! FIX THIS -- we should move to pure DeliverI420Frame
int
CallbackHelper::DeliverI420Frame(const webrtc::I420VideoFrame& webrtc_frame)
{
return DeliverFrame(const_cast<uint8_t*>(webrtc_frame.buffer(webrtc::kYPlane)),
CalcBufferSize(webrtc::kI420, webrtc_frame.width(), webrtc_frame.height()),
webrtc_frame.timestamp(),
webrtc_frame.ntp_time_ms(),
webrtc_frame.render_time_ms(),
(void*) webrtc_frame.native_handle());
}
bool
CamerasParent::RecvReleaseFrame(mozilla::ipc::Shmem&& s) {
@@ -393,6 +407,7 @@ CamerasParent::SetupEngine(CaptureEngine aCapEngine)
void
CamerasParent::CloseEngines()
{
LOG((__PRETTY_FUNCTION__));
if (!mWebRTCAlive) {
return;
}
@@ -686,10 +701,12 @@ CamerasParent::RecvReleaseCaptureDevice(const int& aCapEngine,
RefPtr<nsIRunnable> ipc_runnable =
media::NewRunnableFrom([self, error, numdev]() -> nsresult {
if (self->IsShuttingDown()) {
LOG(("In Shutdown, not Releasing"));
return NS_ERROR_FAILURE;
}
if (error) {
Unused << self->SendReplyFailure();
LOG(("Failed to free device nr %d", numdev));
return NS_ERROR_FAILURE;
} else {
Unused << self->SendReplySuccess();
+3 -2
View File
@@ -41,11 +41,12 @@ public:
virtual int FrameSizeChange(unsigned int w, unsigned int h,
unsigned int streams) override;
virtual int DeliverFrame(unsigned char* buffer,
int size,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time,
void *handle) override;
virtual int DeliverI420Frame(const webrtc::I420VideoFrame& webrtc_frame) override;
virtual bool IsTextureSupported() override { return false; };
friend CamerasParent;
@@ -108,7 +109,7 @@ public:
int cap_id,
ShmemBuffer buffer,
unsigned char* altbuffer,
int size,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time);
-8
View File
@@ -170,14 +170,6 @@ LoadManagerSingleton::AddObserver(webrtc::CPULoadStateObserver * aObserver)
LOG(("LoadManager - Adding Observer"));
MutexAutoLock lock(mLock);
mObservers.AppendElement(aObserver);
if (mObservers.Length() == 1) {
if (!mLoadMonitor) {
mLoadMonitor = new LoadMonitor(mLoadMeasurementInterval);
mLoadMonitor->Init(mLoadMonitor);
mLoadMonitor->SetLoadChangeCallback(this);
mLastStateChange = TimeStamp::Now();
}
}
}
void
+1
View File
@@ -10,6 +10,7 @@
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "nsIAsyncShutdown.h"
#include "base/task.h"
namespace mozilla {
namespace media {
+1 -1
View File
@@ -27,7 +27,7 @@ child:
async FrameSizeChange(int capEngine, int cap_id, int w, int h);
// transfers ownership of |buffer| from parent to child
async DeliverFrame(int capEngine, int cap_id,
Shmem buffer, int size, uint32_t time_stamp,
Shmem buffer, size_t size, uint32_t time_stamp,
int64_t ntp_time, int64_t render_time);
async ReplyNumberOfCaptureDevices(int numdev);
async ReplyNumberOfCapabilities(int numdev);
+5
View File
@@ -26,6 +26,11 @@ if CONFIG['MOZ_WEBRTC']:
'/media/webrtc/signaling',
'/media/webrtc/trunk',
]
if CONFIG['OS_TARGET'] == 'WINNT':
DEFINES['WEBRTC_WIN'] = True
else:
DEFINES['WEBRTC_POSIX'] = True
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
EXPORTS += [
@@ -271,7 +271,7 @@ MediaEngineRemoteVideoSource::FrameSizeChange(unsigned int w, unsigned int h,
int
MediaEngineRemoteVideoSource::DeliverFrame(unsigned char* buffer,
int size,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time,
@@ -283,7 +283,7 @@ MediaEngineRemoteVideoSource::DeliverFrame(unsigned char* buffer,
return 0;
}
if (mWidth*mHeight + 2*(((mWidth+1)/2)*((mHeight+1)/2)) != size) {
if ((size_t) (mWidth*mHeight + 2*(((mWidth+1)/2)*((mHeight+1)/2))) != size) {
MOZ_ASSERT(false, "Wrong size frame in DeliverFrame!");
return 0;
}
@@ -38,6 +38,10 @@
#include "NullTransport.h"
namespace webrtc {
class I420VideoFrame;
}
namespace mozilla {
/**
@@ -53,11 +57,13 @@ public:
virtual int FrameSizeChange(unsigned int w, unsigned int h,
unsigned int streams) override;
virtual int DeliverFrame(unsigned char* buffer,
int size,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time,
void *handle) override;
// XXX!!!! FIX THIS
virtual int DeliverI420Frame(const webrtc::I420VideoFrame& webrtc_frame) override { return 0; };
virtual bool IsTextureSupported() override { return false; };
// MediaEngineCameraVideoSource
+1 -1
View File
@@ -251,7 +251,7 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
JNIEnv* const env = jni::GetEnvForThread();
MOZ_ALWAYS_TRUE(!env->GetJavaVM(&jvm));
if (webrtc::VoiceEngine::SetAndroidObjects(jvm, env, (void*)context) != 0) {
if (webrtc::VoiceEngine::SetAndroidObjects(jvm, (void*)context) != 0) {
LOG(("VoiceEngine:SetAndroidObjects Failed"));
return;
}
+4
View File
@@ -20,6 +20,10 @@ EXPORTS += [
]
if CONFIG['MOZ_WEBRTC']:
if CONFIG['OS_TARGET'] == 'WINNT':
DEFINES['WEBRTC_WIN'] = True
else:
DEFINES['WEBRTC_POSIX'] = True
EXPORTS += ['AudioOutputObserver.h',
'MediaEngineRemoteVideoSource.h',
'MediaEngineWebRTC.h']
+2 -3
View File
@@ -8,7 +8,7 @@
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.importGlobalProperties(['Blob']);
Cu.importGlobalProperties(['Blob', 'FileReader']);
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
@@ -1303,8 +1303,7 @@ SendTransaction.prototype = Object.create(CancellableTransaction.prototype, {
return;
}
let fileReader = Cc["@mozilla.org/files/filereader;1"]
.createInstance(Ci.nsIDOMFileReader);
let fileReader = new FileReader();
fileReader.addEventListener("loadend", (aEvent) => {
let arrayBuffer = aEvent.target.result;
aPart.content = new Uint8Array(arrayBuffer);
@@ -0,0 +1,61 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
</head>
<body>
<iframe id="testframe"> </iframe>
<script type="text/javascript">
page_id = window.location.hash.substring(1);
function executeTest(ev) {
testframe = document.getElementById('testframe');
testframe.contentWindow.postMessage({id:page_id, message:"execute"}, 'http://mochi.test:8888');
}
function reportError(ev) {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
cleanup();
}
function recvMessage(ev) {
if (ev.data.id == page_id) {
window.parent.postMessage({id:ev.data.id, message:ev.data.message}, 'http://mochi.test:8888');
cleanup();
}
}
function cleanup() {
testframe = document.getElementById('testframe');
window.removeEventListener('message', recvMessage);
testframe.removeEventListener('load', executeTest);
testframe.removeEventListener('error', reportError);
}
window.addEventListener('message', recvMessage, false);
try {
// Please note that file_testserver.sjs?foo does not return a response.
// For testing purposes this is not necessary because we only want to check
// whether CSP allows or blocks the load.
src = "file_testserver.sjs";
src += "?file=" + escape("tests/dom/security/test/csp/file_child-src_inner_frame.html");
src += "#" + escape(page_id);
testframe = document.getElementById('testframe');
testframe.addEventListener('load', executeTest, false);
testframe.addEventListener('error', reportError, false);
testframe.src = src;
}
catch (e) {
if (e.message.match(/Failed to load script/)) {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
} else {
window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
}
}
</script>
</body>
</html>
@@ -0,0 +1,21 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
</head>
<body>
<iframe id="innermosttestframe"> </iframe>
<script type="text/javascript">
page_id = window.location.hash.substring(1);
function recvMessage(ev) {
if (ev.data.id == page_id) {
window.parent.postMessage({id:ev.data.id, message:'allowed'}, 'http://mochi.test:8888');
window.removeEventListener('message', recvMessage);
}
}
window.addEventListener('message', recvMessage, false);
</script>
</body>
</html>
@@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
</head>
<body>
<script type="text/javascript">
page_id = window.location.hash.substring(1);
try {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(
'file_child-src_service_worker.js'
+ "#"
+ page_id
).then(function(reg)
{
// registration worked
window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
}).catch(function(error) {
// registration failed
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
});
};
} catch(ex) {
window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
}
</script>
</body>
</html>
@@ -0,0 +1,3 @@
this.addEventListener('install', function(event) {
close();
});
@@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
</head>
<body>
<script type="text/javascript">
page_id = window.location.hash.substring(1);
var redir = 'none';
page_id.split('_').forEach(function (val) {
var [name, value] = val.split('-');
if (name == 'redir') {
redir = unescape(value);
}
});
try {
worker = new SharedWorker('file_redirect_worker.sjs?path='
+ escape("/tests/dom/security/test/csp/file_child-src_shared_worker.js")
+ "&redir=" + redir
+ "&page_id=" + page_id,
page_id);
worker.port.start();
worker.onerror = function(evt) {
evt.preventDefault();
window.parent.postMessage({id:page_id, message:"blocked"},
'http://mochi.test:8888');
}
worker.port.onmessage = function(ev) {
window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
};
worker.onerror = function() {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
};
worker.port.postMessage('foo');
}
catch (e) {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
}
</script>
</body>
</html>
@@ -0,0 +1,34 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
</head>
<body>
<script type="text/javascript">
page_id = window.location.hash.substring(1);
try {
worker = new SharedWorker(
'file_testserver.sjs?file='+
escape("tests/dom/security/test/csp/file_child-src_shared_worker.js"),
page_id);
worker.port.start();
worker.onerror = function(evt) {
evt.preventDefault();
window.parent.postMessage({id:page_id, message:"blocked"},
'http://mochi.test:8888');
}
worker.port.onmessage = function(ev) {
window.parent.postMessage({id:page_id, message:"allowed"},
'http://mochi.test:8888');
};
worker.port.postMessage('foo');
}
catch (e) {
window.parent.postMessage({id:page_id, message:"blocked"},
'http://mochi.test:8888');
}
</script>
</body>
</html>
@@ -0,0 +1,8 @@
onconnect = function(e) {
var port = e.ports[0];
port.addEventListener('message', function(e) {
port.postMessage('success');
});
port.start();
}
@@ -0,0 +1,37 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
</head>
<body>
<script type="text/javascript">
var page_id = window.location.hash.substring(1);
var shared_worker = "onconnect = function(e) { " +
"var port = e.ports[0];" +
"port.addEventListener('message'," +
"function(e) { port.postMessage('success'); });" +
"port.start(); }";
try {
var worker = new SharedWorker('data:application/javascript;charset=UTF-8,'+
escape(shared_worker), page_id);
worker.port.start();
worker.onerror = function(evt) {
evt.preventDefault();
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
}
worker.port.onmessage = function(ev) {
window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
};
worker.port.postMessage('foo');
}
catch (e) {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
}
</script>
</body>
</html>
@@ -0,0 +1,50 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
</head>
<body>
<script type="text/javascript">
var page_id = window.location.hash.substring(1);
var redir = 'none';
page_id.split('_').forEach(function (val) {
var [name, value] = val.split('-');
if (name == 'redir') {
redir = unescape(value);
}
});
try {
worker = new Worker('file_redirect_worker.sjs?path='
+ escape("/tests/dom/security/test/csp/file_child-src_worker.js")
+ "&redir=" + redir
+ "&page_id=" + page_id
);
worker.onerror = function(error) {
var msg = error.message;
if (msg.match(/^: NetworkError/) || msg.match(/Failed to load script/)) {
// this means CSP blocked it
msg = "blocked";
}
window.parent.postMessage({id:page_id, message:msg}, 'http://mochi.test:8888');
error.preventDefault();
};
worker.onmessage = function(ev) {
window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
};
worker.postMessage('foo');
}
catch (e) {
if (e.message.match(/Failed to load script/)) {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
} else {
window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
}
}
</script>
</body>
</html>
@@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
</head>
<body>
<script type="text/javascript">
page_id = window.location.hash.substring(1);
try {
worker = new Worker('file_testserver.sjs?file='+escape("tests/dom/security/test/csp/file_child-src_worker.js"));
worker.onerror = function(e) {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
e.preventDefault();
}
worker.onmessage = function(ev) {
window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
}
worker.postMessage('foo');
}
catch (e) {
if (e.message.match(/Failed to load script/)) {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
} else {
window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
}
}
</script>
</body>
</html>
@@ -0,0 +1,4 @@
onmessage = function(e) {
postMessage('worker');
};
@@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
</head>
<body>
<script type="text/javascript">
page_id = window.location.hash.substring(1);
try {
worker = new Worker('data:application/javascript;charset=UTF-8,'+escape('onmessage = function(e) { postMessage("worker"); };'));
worker.onerror = function(e) {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
e.preventDefault();
}
worker.onmessage = function(ev) {
window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
}
worker.postMessage('foo');
}
catch (e) {
if (e.message.match(/Failed to load script/)) {
window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
} else {
console.log(e);
window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
}
}
</script>
</body>
</html>
@@ -1 +1 @@
Content-Security-Policy: default-src 'self' ; style-src 'unsafe-inline' 'self'
Content-Security-Policy: default-src 'self' blob: ; style-src 'unsafe-inline' 'self'
+25 -13
View File
@@ -1,16 +1,28 @@
// some javascript for the CSP XHR tests
//
function doXHR(uri) {
try {
var xhr = new XMLHttpRequest();
xhr.open("GET", uri);
xhr.send();
} catch(ex) {}
}
doXHR("http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_good");
doXHR("http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_bad");
fetch("http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=fetch_good");
fetch("http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=fetch_bad");
navigator.sendBeacon("http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=beacon_good");
try {
var xhr_good = new XMLHttpRequest();
var xhr_good_uri ="http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_good";
xhr_good.open("GET", xhr_good_uri, true);
xhr_good.send(null);
} catch(e) {}
navigator.sendBeacon("http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=beacon_bad");
} catch(ex) {}
try {
var xhr_bad = new XMLHttpRequest();
var xhr_bad_uri ="http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_bad";
xhr_bad.open("GET", xhr_bad_uri, true);
xhr_bad.send(null);
} catch(e) {}
new Worker("file_main_worker.js").postMessage({inherited : false});
var blobxhr = new XMLHttpRequest();
blobxhr.open("GET", "file_main_worker.js")
blobxhr.responseType = "blob";
blobxhr.send();
blobxhr.onload = () => {
new Worker(URL.createObjectURL(blobxhr.response)).postMessage({inherited : true});
}
+28
View File
@@ -0,0 +1,28 @@
function doXHR(uri) {
try {
var xhr = new XMLHttpRequest();
xhr.open("GET", uri);
xhr.send();
} catch(ex) {}
}
var sameBase = "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=";
var crossBase = "http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=";
onmessage = (e) => {
for (base of [sameBase, crossBase]) {
var prefix;
var suffix;
if (e.data.inherited) {
prefix = base + "worker_inherited_"
suffix = base == sameBase ? "_good" : "_bad";
}
else {
prefix = base + "worker_"
suffix = base == sameBase ? "_same_good" : "_cross_good";
}
doXHR(prefix + "xhr" + suffix);
fetch(prefix + "fetch" + suffix);
try { importScripts(prefix + "script" + suffix); } catch(ex) {}
}
}
@@ -0,0 +1,34 @@
// SJS file to serve resources for CSP redirect tests
// This file redirects to a specified resource.
const THIS_SITE = "http://mochi.test:8888";
const OTHER_SITE = "http://example.com";
function handleRequest(request, response)
{
var query = {};
request.queryString.split('&').forEach(function (val) {
var [name, value] = val.split('=');
query[name] = unescape(value);
});
var resource = query['path'];
response.setHeader("Cache-Control", "no-cache", false);
var loc = '';
// redirect to a resource on this site
if (query["redir"] == "same") {
loc = THIS_SITE+resource+"#"+query['page_id']
}
// redirect to a resource on a different site
else if (query["redir"] == "other") {
loc = OTHER_SITE+resource+"#"+query['page_id']
}
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", loc, false);
response.write('<html><head><meta http-equiv="refresh" content="0; url='+loc+'">');
return;
}
+12 -11
View File
@@ -11,17 +11,18 @@ var thisSite = "http://mochi.test:8888";
var otherSite = "http://example.com";
var page = "/tests/dom/security/test/csp/file_redirects_page.sjs";
var tests = { "font-src": thisSite+page+"?testid=font-src&csp=1",
"frame-src": thisSite+page+"?testid=frame-src&csp=1",
"img-src": thisSite+page+"?testid=img-src&csp=1",
"media-src": thisSite+page+"?testid=media-src&csp=1",
"object-src": thisSite+page+"?testid=object-src&csp=1",
"script-src": thisSite+page+"?testid=script-src&csp=1",
"style-src": thisSite+page+"?testid=style-src&csp=1",
"worker": thisSite+page+"?testid=worker&csp=1",
"xhr-src": thisSite+page+"?testid=xhr-src&csp=1",
"script-src-from-worker": thisSite+page+"?testid=script-src-from-worker&csp=1",
"img-src-from-css": thisSite+page+"?testid=img-src-from-css&csp=1",
var tests = { "font-src": thisSite+page+"?testid=font-src",
"frame-src": thisSite+page+"?testid=frame-src",
"img-src": thisSite+page+"?testid=img-src",
"media-src": thisSite+page+"?testid=media-src",
"object-src": thisSite+page+"?testid=object-src",
"script-src": thisSite+page+"?testid=script-src",
"style-src": thisSite+page+"?testid=style-src",
"worker": thisSite+page+"?testid=worker",
"xhr-src": thisSite+page+"?testid=xhr-src",
"from-worker": thisSite+page+"?testid=from-worker",
"from-blob-worker": thisSite+page+"?testid=from-blob-worker",
"img-src-from-css": thisSite+page+"?testid=img-src-from-css",
};
var container = document.getElementById("container");
+26 -8
View File
@@ -14,9 +14,13 @@ function handleRequest(request, response)
var resource = "/tests/dom/security/test/csp/file_redirects_resource.sjs";
// CSP header value
if (query["csp"] == 1) {
response.setHeader("Content-Security-Policy", "default-src 'self' ; style-src 'self' 'unsafe-inline'", false);
var additional = ""
if (query['testid'] == "worker") {
additional = "; script-src 'self' 'unsafe-inline'";
}
response.setHeader("Content-Security-Policy",
"default-src 'self' blob: ; style-src 'self' 'unsafe-inline'" + additional,
false);
// downloadable font that redirects to another site
if (query["testid"] == "font-src") {
@@ -61,13 +65,13 @@ function handleRequest(request, response)
// external stylesheet that redirects to another site
if (query["testid"] == "style-src") {
response.write('<link rel="stylesheet" type="text/css" href="'+resource+'?res=style&redir=other&id=style-src-redir"></script>');
response.write('<link rel="stylesheet" type="text/css" href="'+resource+'?res=style&redir=other&id=style-src-redir"></link>');
return;
}
// worker script resource that redirects to another site
if (query["testid"] == "worker") {
response.write('<script src="'+resource+'?res=worker&redir=other&id=worker-redir"></script>');
response.write('<script>var worker = new Worker("'+resource+'?res=worker&redir=other&id=worker-redir");</script>');
return;
}
@@ -84,13 +88,27 @@ function handleRequest(request, response)
return;
}
if (query["testid"] == "script-src-from-worker") {
if (query["testid"] == "from-worker") {
// loads a script; launches a worker; that worker uses importscript; which then gets redirected
// So it's:
// <script "res=loadWorkerThatImports">
// .. loads Worker("res=importScriptWorker")
// <script src="res=loadWorkerThatMakesRequests">
// .. loads Worker("res=makeRequestsWorker")
// .. calls importScript("res=script")
response.write('<script src="'+resource+'?res=loadWorkerThatImports&id=script-src-redir-from-worker"></script>');
// .. calls xhr("res=xhr-resp")
// .. calls fetch("res=xhr-resp")
response.write('<script src="'+resource+'?res=loadWorkerThatMakesRequests&id=from-worker"></script>');
return;
}
if (query["testid"] == "from-blob-worker") {
// loads a script; launches a worker; that worker uses importscript; which then gets redirected
// So it's:
// <script src="res=loadBlobWorkerThatMakesRequests">
// .. loads Worker("res=makeRequestsWorker")
// .. calls importScript("res=script")
// .. calls xhr("res=xhr-resp")
// .. calls fetch("res=xhr-resp")
response.write('<script src="'+resource+'?res=loadBlobWorkerThatMakesRequests&id=from-blob-worker"></script>');
return;
}
}
@@ -102,38 +102,45 @@ function handleRequest(request, response)
// script that loads an internal worker that uses importScripts on a redirect
// to an external script.
if (query["res"] == "loadWorkerThatImports") {
if (query["res"] == "loadWorkerThatMakesRequests") {
// this creates a worker (same origin) that imports a redirecting script.
let workerURL = thisSite + resource + '?res=importScriptWorker&id=' + query["id"];
let workerURL = thisSite + resource + '?res=makeRequestsWorker&id=' + query["id"];
response.setHeader("Content-Type", "application/javascript", false);
response.write("var w=new Worker('" + workerURL + "'); w.onmessage=function(event){ alert(event.data); }");
response.write("new Worker('" + workerURL + "');");
return;
}
// script that loads an internal worker that uses importScripts on a redirect
// to an external script.
if (query["res"] == "loadBlobWorkerThatMakesRequests") {
// this creates a worker (same origin) that imports a redirecting script.
let workerURL = thisSite + resource + '?res=makeRequestsWorker&id=' + query["id"];
response.setHeader("Content-Type", "application/javascript", false);
response.write("var x = new XMLHttpRequest(); x.open('GET', '" + workerURL + "'); ");
response.write("x.responseType = 'blob'; x.send(); ");
response.write("x.onload = () => { new Worker(URL.createObjectURL(x.response)); };");
return;
}
// source for a worker that simply calls importScripts on a script that
// redirects.
if (query["res"] == "importScriptWorker") {
if (query["res"] == "makeRequestsWorker") {
// this is code for a worker that imports a redirected script.
let scriptURL = thisSite + resource + "?redir=other&res=script&id=" + query["id"];
let scriptURL = thisSite + resource + "?redir=other&res=script&id=script-src-redir-" + query["id"];
let xhrURL = thisSite + resource + "?redir=other&res=xhr-resp&id=xhr-src-redir-" + query["id"];
let fetchURL = thisSite + resource + "?redir=other&res=xhr-resp&id=fetch-src-redir-" + query["id"];
response.setHeader("Content-Type", "application/javascript", false);
response.write("importScripts('" + scriptURL + "');");
response.write("try { importScripts('" + scriptURL + "'); } catch(ex) {} ");
response.write("var x = new XMLHttpRequest(); x.open('GET', '" + xhrURL + "'); x.send();");
response.write("fetch('" + fetchURL + "');");
return;
}
// script that invokes XHR
if (query["res"] == "xhr") {
response.setHeader("Content-Type", "text/html", false);
var resp = 'var x = new XMLHttpRequest(); x.open("GET", "' + otherSite +
resource+'?res=xhr-resp&testid=xhr-src-redir", false); ' +
'x.send(null);';
response.write(resp);
return;
}
if (query["res"] == "xhr") {
response.setHeader("Content-Type", "text/html", false);
var resp = 'var x = new XMLHttpRequest(); x.open("GET", "' + otherSite +
resource+'?res=xhr-resp&testid=xhr-src-redir", false); ' +
response.setHeader("Content-Type", "application/javascript", false);
var resp = 'var x = new XMLHttpRequest();x.open("GET", "' + thisSite +
resource+'?redir=other&res=xhr-resp&id=xhr-src-redir", false);\n' +
'x.send(null);';
response.write(resp);
return;
@@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1208559 - ServiceWorker registration not governed by CSP</title>
</head>
<body>
<script>
function finish(status) {
window.parent.postMessage({result: status}, "*");
}
navigator.serviceWorker.ready.then(finish.bind(null, 'allowed'),
finish.bind(null, 'blocked'));
navigator.serviceWorker
.register("file_service_worker.js", {scope: "."})
.then(null, finish.bind(null, 'blocked'));
</script>
</body>
</html>
@@ -0,0 +1 @@
dump("service workers: hello world");
@@ -1,9 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 949706 - CSP: Correct handling of web workers importing scripts that get redirected</title>
</head>
<body>
<script src="file_worker_redirect.sjs?stage_0_script_loads_worker"></script>
</body>
</html>
@@ -1,37 +0,0 @@
// testserver customized for the needs of:
// Bug 949706 - CSP: Correct handling of web workers importing scripts that get redirected
function handleRequest(request, response)
{
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/html", false);
var query = request.queryString;
if (query === "stage_0_script_loads_worker") {
var newWorker =
"var myWorker = new Worker(\"file_worker_redirect.sjs?stage_1_worker_import_scripts\");" +
"myWorker.onmessage = function (event) { parent.checkResult(\"allowed\"); };" +
"myWorker.onerror = function (event) { parent.checkResult(\"blocked\"); };";
response.write(newWorker);
return;
}
if (query === "stage_1_worker_import_scripts") {
response.write("importScripts(\"file_worker_redirect.sjs?stage_2_redirect_imported_script\");");
return;
}
if (query === "stage_2_redirect_imported_script") {
var newLocation =
"http://test1.example.com/tests/dom/security/test/csp/file_worker_redirect.sjs?stage_3_target_script";
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", newLocation, false);
return;
}
if (query === "stage_3_target_script") {
response.write("postMessage(\"imported script loaded\");");
return;
}
}
+23 -3
View File
@@ -43,6 +43,7 @@ support-files =
file_main.html
file_main.html^headers^
file_main.js
file_main_worker.js
file_web_manifest.html
file_web_manifest_remote.html
file_web_manifest_https.html
@@ -115,8 +116,6 @@ support-files =
file_multi_policy_injection_bypass_2.html^headers^
file_null_baseuri.html
file_form-action.html
file_worker_redirect.html
file_worker_redirect.sjs
file_referrerdirective.html
referrerdirective.sjs
file_upgrade_insecure.html
@@ -128,6 +127,21 @@ support-files =
file_upgrade_insecure_referrer_server.sjs
file_upgrade_insecure_cors.html
file_upgrade_insecure_cors_server.sjs
file_service_worker.html
file_service_worker.js
file_child-src_iframe.html
file_child-src_inner_frame.html
file_child-src_worker.html
file_child-src_worker_data.html
file_child-src_worker-redirect.html
file_child-src_worker.js
file_child-src_service_worker.html
file_child-src_service_worker.js
file_child-src_shared_worker.html
file_child-src_shared_worker_data.html
file_child-src_shared_worker-redirect.html
file_child-src_shared_worker.js
file_redirect_worker.sjs
[test_base-uri.html]
[test_blob_data_schemes.html]
@@ -181,7 +195,6 @@ skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
[test_null_baseuri.html]
[test_referrerdirective.html]
skip-if = buildapp == 'b2g' #no ssl support
[test_worker_redirect.html]
[test_upgrade_insecure.html]
# no ssl support as well as websocket tests do not work (see test_websocket.html)
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android'
@@ -191,3 +204,10 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolk
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android'
[test_upgrade_insecure_cors.html]
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android'
[test_service_worker.html]
skip-if = buildapp == 'b2g' #no ssl support
[test_child-src_worker.html]
skip-if = buildapp == 'b2g' #investigate in bug 1222904
[test_child-src_worker_data.html]
[test_child-src_worker-redirect.html]
[test_child-src_iframe.html]
+18 -1
View File
@@ -25,6 +25,22 @@ window.tests = {
script_bad: -1,
xhr_good: -1,
xhr_bad: -1,
fetch_good: -1,
fetch_bad: -1,
beacon_good: -1,
beacon_bad: -1,
worker_xhr_same_good: -1,
worker_xhr_cross_good: -1,
worker_fetch_same_good: -1,
worker_fetch_cross_good: -1,
worker_script_same_good: -1,
worker_script_cross_good: -1,
worker_inherited_xhr_good: -1,
worker_inherited_xhr_bad: -1,
worker_inherited_fetch_good: -1,
worker_inherited_fetch_bad: -1,
worker_inherited_script_good: -1,
worker_inherited_script_bad: -1,
media_good: -1,
media_bad: -1,
font_good: -1,
@@ -81,10 +97,11 @@ examiner.prototype = {
window.examiner = new examiner();
window.testResult = function(testname, result, msg) {
//test already complete.... forget it... remember the first result.
// test already complete.... forget it... remember the first result.
if (window.tests[testname] != -1)
return;
ok(testname in window.tests, "It's a real test");
window.tests[testname] = result;
is(result, true, testname + ' test: ' + msg);
@@ -0,0 +1,114 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="visibility: hidden">
</div>
<script class="testbody" type="text/javascript">
/*
* Description of the test:
* We load a page with a given CSP and verify that child frames and workers are correctly
* evaluated through the "child-src" directive.
*/
SimpleTest.waitForExplicitFinish();
var IFRAME_SRC="file_child-src_iframe.html"
var tests = {
'same-src': {
id: "same-src",
file: IFRAME_SRC,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
},
'star-src': {
id: "star-src",
file: IFRAME_SRC,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
},
'other-src': {
id: "other-src",
file: IFRAME_SRC,
result : "blocked",
policy : "default-src http://mochi.test:8888; script-src 'unsafe-inline'; child-src http://www.example.com"
},
'same-src-by-frame-src': {
id: "same-src-by-frame-src",
file: IFRAME_SRC,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'none'; frame-src http://mochi.test:8888"
},
'star-src-by-frame-src': {
id: "star-src-by-frame-src",
file: IFRAME_SRC,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'none'; frame-src *"
},
'other-src-by-frame-src': {
id: "other-src-by-frame-src",
file: IFRAME_SRC,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888; frame-src http://www.example.com"
},
'none-src-by-frame-src': {
id: "none-src-by-frame-src",
file: "file_child-src_iframe.html",
file: IFRAME_SRC,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888; frame-src 'none'"
}
};
finished = {};
function checkFinished() {
if (Object.keys(finished).length == Object.keys(tests).length) {
window.removeEventListener('message', recvMessage);
SimpleTest.finish();
}
}
function recvMessage(ev) {
is(ev.data.message, tests[ev.data.id].result, "CSP child-src test " + ev.data.id);
finished[ev.data.id] = ev.data.message;
checkFinished();
}
window.addEventListener('message', recvMessage, false);
function loadNextTest() {
for (item in tests) {
test = tests[item];
var src = "file_testserver.sjs";
// append the file that should be served
src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
// append the CSP that should be used to serve the file
src += "&csp=" + escape(test.policy);
// add our identifier
src += "#" + escape(test.id);
content = document.getElementById('content');
testframe = document.createElement("iframe");
testframe.setAttribute('id', test.id);
content.appendChild(testframe);
testframe.src = src;
}
}
// start running the tests
loadNextTest();
</script>
</body>
</html>
@@ -0,0 +1,125 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="visibility: hidden">
</div>
<script class="testbody" type="text/javascript">
/*
* Description of the test:
* We load a page with a given CSP and verify that child frames and workers are correctly
* evaluated through the "child-src" directive.
*/
SimpleTest.waitForExplicitFinish();
var WORKER_REDIRECT_TEST_FILE = "file_child-src_worker-redirect.html";
var SHARED_WORKER_REDIRECT_TEST_FILE = "file_child-src_shared_worker-redirect.html";
var tests = {
'same-src-worker_redir-same': {
id: "same-src-worker_redir-same",
file: WORKER_REDIRECT_TEST_FILE,
result : "allowed",
redir: "same",
policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
},
'same-src-worker_redir-other': {
id: "same-src-worker_redir-other",
file: WORKER_REDIRECT_TEST_FILE,
result : "blocked",
redir: "other",
policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
},
'star-src-worker_redir-same': {
id: "star-src-worker_redir-same",
file: WORKER_REDIRECT_TEST_FILE,
redir: "same",
result : "allowed",
policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src *"
},
'other-src-worker_redir-same': {
id: "other-src-worker_redir-same",
file: WORKER_REDIRECT_TEST_FILE,
redir: "same",
result : "blocked",
policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src https://www.example.org"
},
/* shared workers */
'same-src-shared_worker_redir-same': {
id: "same-src-shared_worker_redir-same",
file: SHARED_WORKER_REDIRECT_TEST_FILE,
result : "allowed",
redir: "same",
policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
},
'same-src-shared_worker_redir-other': {
id: "same-src-shared_worker_redir-other",
file: SHARED_WORKER_REDIRECT_TEST_FILE,
result : "blocked",
redir: "other",
policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
},
'star-src-shared_worker_redir-same': {
id: "star-src-shared_worker_redir-same",
file: SHARED_WORKER_REDIRECT_TEST_FILE,
redir: "same",
result : "allowed",
policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src *"
},
'other-src-shared_worker_redir-same': {
id: "other-src-shared_worker_redir-same",
file: SHARED_WORKER_REDIRECT_TEST_FILE,
redir: "same",
result : "blocked",
policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src https://www.example.org"
},
};
finished = {};
function recvMessage(ev) {
is(ev.data.message, tests[ev.data.id].result, "CSP child-src worker test " + ev.data.id);
finished[ev.data.id] = ev.data.message;
if (Object.keys(finished).length == Object.keys(tests).length) {
window.removeEventListener('message', recvMessage);
SimpleTest.finish();
}
}
window.addEventListener('message', recvMessage, false);
function loadNextTest() {
for (item in tests) {
test = tests[item];
var src = "file_testserver.sjs";
// append the file that should be served
src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
// append the CSP that should be used to serve the file
src += "&csp=" + escape(test.policy);
// add whether redirect is to same or different
src += "&redir=" + escape(test.policy);
// add our identifier
src += "#" + escape(test.id);
content = document.getElementById('content');
testframe = document.createElement("iframe");
testframe.setAttribute('id', test.id);
content.appendChild(testframe);
testframe.src = src;
}
}
// start running the tests
loadNextTest();
</script>
</body>
</html>
@@ -0,0 +1,131 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="visibility: hidden">
</div>
<script class="testbody" type="text/javascript">
/*
* Description of the test:
* We load a page with a given CSP and verify that child frames and workers are correctly
* evaluated through the "child-src" directive.
*/
SimpleTest.waitForExplicitFinish();
var WORKER_TEST_FILE = "file_child-src_worker.html";
var SERVICE_WORKER_TEST_FILE = "file_child-src_service_worker.html";
var SHARED_WORKER_TEST_FILE = "file_child-src_shared_worker.html";
var tests = {
'same-src-worker': {
id: "same-src-worker",
file: WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
},
'same-src-service_worker': {
id: "same-src-service_worker",
file: SERVICE_WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
},
'same-src-shared_worker': {
id: "same-src-shared_worker",
file: SHARED_WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
},
'star-src-worker': {
id: "star-src-worker",
file: WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
},
'star-src-service_worker': {
id: "star-src-service_worker",
file: SERVICE_WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
},
'star-src-shared_worker': {
id: "star-src-shared_worker",
file: SHARED_WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
},
'other-src-worker': {
id: "other-src-worker",
file: WORKER_TEST_FILE,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
},
'other-src-service_worker': {
id: "other-src-service_worker",
file: SERVICE_WORKER_TEST_FILE,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
},
'other-src-shared_worker': {
id: "other-src-shared_worker",
file: SHARED_WORKER_TEST_FILE,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
},
};
finished = {};
function recvMessage(ev) {
is(ev.data.message, tests[ev.data.id].result, "CSP child-src worker test " + ev.data.id);
finished[ev.data.id] = ev.data.message;
if (Object.keys(finished).length == Object.keys(tests).length) {
window.removeEventListener('message', recvMessage);
SimpleTest.finish();
}
}
window.addEventListener('message', recvMessage, false);
function loadNextTest() {
for (item in tests) {
test = tests[item];
var src = "file_testserver.sjs";
// append the file that should be served
src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
// append the CSP that should be used to serve the file
src += "&csp=" + escape(test.policy);
// add our identifier
src += "#" + escape(test.id);
content = document.getElementById('content');
testframe = document.createElement("iframe");
testframe.setAttribute('id', test.id);
content.appendChild(testframe);
testframe.src = src;
}
}
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.interception.enabled", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.caches.enabled", true]
]}, loadNextTest);
};
// start running the tests
//loadNextTest();
</script>
</body>
</html>
@@ -0,0 +1,126 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1045891</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="visibility: hidden">
</div>
<script class="testbody" type="text/javascript">
/*
* Description of the test:
* We load a page with a given CSP and verify that child frames and workers are correctly
* evaluated through the "child-src" directive.
*/
SimpleTest.waitForExplicitFinish();
var WORKER_TEST_FILE = "file_child-src_worker_data.html";
var SHARED_WORKER_TEST_FILE = "file_child-src_shared_worker_data.html";
var tests = {
'same-src-worker-no-data': {
id: "same-src-worker-no-data",
file: WORKER_TEST_FILE,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self'"
},
'same-src-worker': {
id: "same-src-worker",
file: WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self' data:"
},
'same-src-shared_worker-no-data': {
id: "same-src-shared_worker-no-data",
file: SHARED_WORKER_TEST_FILE,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self'"
},
'same-src-shared_worker': {
id: "same-src-shared_worker",
file: SHARED_WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self' data:"
},
'star-src-worker': {
id: "star-src-worker",
file: WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src * data:"
},
'star-src-worker-no-data': {
id: "star-src-worker-no-data",
file: WORKER_TEST_FILE,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
},
'star-src-shared_worker-no-data': {
id: "star-src-shared_worker-no-data",
file: SHARED_WORKER_TEST_FILE,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
},
'star-src-shared_worker': {
id: "star-src-shared_worker",
file: SHARED_WORKER_TEST_FILE,
result : "allowed",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src * data:"
},
'other-src-worker-no-data': {
id: "other-src-worker-no-data",
file: WORKER_TEST_FILE,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
},
'other-src-shared_worker-no-data': {
id: "other-src-shared_worker-no-data",
file: SHARED_WORKER_TEST_FILE,
result : "blocked",
policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
},
};
finished = {};
function recvMessage(ev) {
is(ev.data.message, tests[ev.data.id].result, "CSP child-src worker test " + ev.data.id);
finished[ev.data.id] = ev.data.message;
if (Object.keys(finished).length == Object.keys(tests).length) {
window.removeEventListener('message', recvMessage);
SimpleTest.finish();
}
}
window.addEventListener('message', recvMessage, false);
function loadNextTest() {
for (item in tests) {
test = tests[item];
var src = "file_testserver.sjs";
// append the file that should be served
src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
// append the CSP that should be used to serve the file
src += "&csp=" + escape(test.policy);
// add our identifier
src += "#" + escape(test.id);
content = document.getElementById('content');
testframe = document.createElement("iframe");
testframe.setAttribute('id', test.id);
content.appendChild(testframe);
testframe.src = src;
}
}
// start running the tests
loadNextTest();
</script>
</body>
</html>
+10 -4
View File
@@ -86,10 +86,16 @@ var testExpectedResults = { "font-src": true,
"worker-redir": false,
"xhr-src": true,
"xhr-src-redir": false,
"script-src-from-worker": true, /* test runs */
"script-src-redir-from-worker": false, /* redir is blocked */
"img-src-from-css": true, /* test runs */
"img-src-redir-from-css": false, /* redir is blocked */
"from-worker": true,
"script-src-redir-from-worker": true, /* redir is allowed since policy isn't inherited */
"xhr-src-redir-from-worker": true, /* redir is allowed since policy isn't inherited */
"fetch-src-redir-from-worker": true, /* redir is allowed since policy isn't inherited */
"from-blob-worker": true,
"script-src-redir-from-blob-worker": false,
"xhr-src-redir-from-blob-worker": false,
"fetch-src-redir-from-blob-worker": false,
"img-src-from-css": true,
"img-src-redir-from-css": false,
};
// takes the name of the test, the URL that was tested, and whether the
@@ -0,0 +1,62 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1208559 - ServiceWorker registration not governed by CSP</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe style="width:100%;" id="testframe"></iframe>
<script class="testbody" type="text/javascript">
/* Description of the test:
* Spawning a worker from https://example.com but script-src is 'test1.example.com'
* CSP is not consulted
*/
SimpleTest.waitForExplicitFinish();
var tests = [
{
policy: "default-src 'self'; script-src 'unsafe-inline'; child-src test1.example.com;",
expected: "blocked"
},
];
var counter = 0;
var curTest;
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
is(event.data.result, curTest.expected, "Should be (" + curTest.expected + ") in Test " + counter + "!");
loadNextTest();
}
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.interception.enabled", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.caches.enabled", true]
]}, loadNextTest);
}
function loadNextTest() {
if (counter == tests.length) {
SimpleTest.finish();
return;
}
curTest = tests[counter++];
var src = "https://example.com/tests/dom/security/test/csp/file_testserver.sjs";
// append the file that should be served
src += "?file=" + escape("tests/dom/security/test/csp/file_service_worker.html");
// append the CSP that should be used to serve the file
src += "&csp=" + escape(curTest.policy);
document.getElementById("testframe").src = src;
}
</script>
</body>
</html>
@@ -1,76 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 949706 - CSP: Correct handling of web workers importing scripts that get redirected</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id="content" style="visibility: hidden">
<iframe style="width:100%;" id="testframe"></iframe>
</div>
<script class="testbody" type="text/javascript">
/* Description of the test:
* We load a page that loads a script which then instantiates a web worker,
* where that web worker then imports a script which gets redirected.
* We verify that the CSP applies correctly after the imported script of
* the worker gets redirected. More specifically, the test works as follows:
*
* test_worker_redirect.html
* -> loads file_worker_redirect.html file into iframe
* -> loads worker file_worker_redirect.sjs?stage_0_script_loads_worker
* -> creates script file_worker_redirect.sjs?stage_1_worker_import_scripts
* -> redirects script file_worker_redirect.sjs?stage_2_redirect_imported_script
* -> loads target script file_worker_redirect.sjs?stage_3_target_script
*
* Please note that we have to use 'unsafe-eval' in the policy
* so that workers are actually permitted by the CSP.
*
* The main test is loaded using:
* http://mochi.test:8888
* where the imported script gets redirected to:
* http://test1.example.com
*/
var tests = [
{
policy: "default-src 'self'; script-src 'self' 'unsafe-eval' http://test1.example.com;",
expected: "allowed"
},
{
policy: "default-src 'self'; script-src 'self' 'unsafe-eval';",
expected: "blocked",
},
];
var counter = 0;
var curTest;
function checkResult(aResult) {
is(aResult, curTest.expected, "Should be (" + curTest.expected + ") in Test " + counter + "!");
loadNextTest();
}
function loadNextTest() {
if (counter == tests.length) {
SimpleTest.finish();
return;
}
curTest = tests[counter++];
var src = "file_testserver.sjs";
// append the file that should be served
src += "?file=" + escape("tests/dom/security/test/csp/file_worker_redirect.html");
// append the CSP that should be used to serve the file
src += "&csp=" + escape(curTest.policy);
document.getElementById("testframe").src = src;
}
SimpleTest.waitForExplicitFinish();
loadNextTest();
</script>
</body>
</html>
@@ -4,7 +4,7 @@
<title>frame for storage prevented test</title>
<script type="text/javascript" src="https://example.com/tests/dom/tests/mochitest/general/storagePermissionsUtils.js"></script>
<script type="text/javascript">
<script type="text/javascript;version=1.7">
task(function* () {
// We shouldn't be able to access storage
@@ -13,12 +13,24 @@
// This hash of the URI is set to #nullprincipal by the test if the current page has a null principal,
// and thus attempting to create a dedicated worker will throw
if (location.hash == "#nullprincipal") {
try {
new Worker("workerStoragePrevented.js");
ok(false, "Running workers should not have been allowed");
} catch (e) {
ok(true, "Running workers was prevented");
function createWorker() {
return new Promise((resolve, reject) => {
var w;
try {
w = new Worker("workerStoragePrevented.js");
} catch (e) {
ok(true, "Running workers was prevented");
resolve();
}
w.onerror = function() {
ok(true, "Running workers was prevented");
resolve();
}
});
}
yield createWorker();
return;
}
+2 -1
View File
@@ -10,7 +10,8 @@
* liability, trademark and document use rules apply.
*/
[Constructor]
[Constructor,
Exposed=(Window,System)]
interface FileReader : EventTarget {
// async read methods
[Throws]
+5 -1
View File
@@ -12,13 +12,17 @@ typedef (File or USVString) FormDataEntryValue;
[Constructor(optional HTMLFormElement form),
Exposed=(Window,Worker)]
interface FormData {
[Throws]
void append(USVString name, Blob value, optional USVString filename);
[Throws]
void append(USVString name, USVString value);
void delete(USVString name);
FormDataEntryValue? get(USVString name);
sequence<FormDataEntryValue> getAll(USVString name);
boolean has(USVString name);
[Throws]
void set(USVString name, Blob value, optional USVString filename);
[Throws]
void set(USVString name, USVString value);
// iterable<USVString, FormDataEntryValue>; - Bug 1127703
iterable<USVString, FormDataEntryValue>;
};
+7 -2
View File
@@ -68,8 +68,13 @@ void
Performance::InsertUserEntry(PerformanceEntry* aEntry)
{
if (mWorkerPrivate->PerformanceLoggingEnabled()) {
PerformanceBase::LogEntry(aEntry,
NS_ConvertUTF16toUTF8(mWorkerPrivate->ScriptURL()));
nsAutoCString uri;
nsCOMPtr<nsIURI> scriptURI = mWorkerPrivate->GetResolvedScriptURI();
if (!scriptURI || NS_FAILED(scriptURI->GetHost(uri))) {
// If we have no URI, just put in "none".
uri.AssignLiteral("none");
}
PerformanceBase::LogEntry(aEntry, uri);
}
PerformanceBase::InsertUserEntry(aEntry);
}
+43 -38
View File
@@ -1588,7 +1588,6 @@ RuntimeService::RemoveSharedWorker(WorkerDomainInfo* aDomainInfo,
SharedWorkerInfo* data = iter.UserData();
if (data->mWorkerPrivate == aWorkerPrivate) {
#ifdef DEBUG
fprintf(stderr, "njn: RemoveSharedWorker\n");
nsAutoCString key;
GenerateSharedWorkerKey(data->mScriptSpec, data->mName,
aWorkerPrivate->IsInPrivateBrowsing(), key);
@@ -1780,7 +1779,7 @@ RuntimeService::ShutdownIdleThreads(nsITimer* aTimer, void* /* aClosure */)
NS_ASSERTION(aTimer == runtime->mIdleThreadTimer, "Wrong timer!");
// Cheat a little and grab all threads that expire within one second of now.
TimeStamp now = TimeStamp::Now() + TimeDuration::FromSeconds(1);
TimeStamp now = TimeStamp::NowLoRes() + TimeDuration::FromSeconds(1);
TimeStamp nextExpiration;
@@ -1805,27 +1804,23 @@ RuntimeService::ShutdownIdleThreads(nsITimer* aTimer, void* /* aClosure */)
}
}
NS_ASSERTION(nextExpiration.IsNull() || !expiredThreads.IsEmpty(),
"Should have a new time or there should be some threads to shut "
"down");
if (!nextExpiration.IsNull()) {
TimeDuration delta = nextExpiration - TimeStamp::NowLoRes();
uint32_t delay(delta > TimeDuration(0) ? delta.ToMilliseconds() : 0);
// Reschedule the timer.
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
aTimer->InitWithFuncCallback(ShutdownIdleThreads,
nullptr,
delay,
nsITimer::TYPE_ONE_SHOT)));
}
for (uint32_t index = 0; index < expiredThreads.Length(); index++) {
if (NS_FAILED(expiredThreads[index]->Shutdown())) {
NS_WARNING("Failed to shutdown thread!");
}
}
if (!nextExpiration.IsNull()) {
TimeDuration delta = nextExpiration - TimeStamp::Now();
uint32_t delay(delta > TimeDuration(0) ? delta.ToMilliseconds() : 0);
// Reschedule the timer.
if (NS_FAILED(aTimer->InitWithFuncCallback(ShutdownIdleThreads, nullptr,
delay,
nsITimer::TYPE_ONE_SHOT))) {
NS_ERROR("Can't schedule timer!");
}
}
}
nsresult
@@ -2429,40 +2424,43 @@ RuntimeService::NoteIdleThread(WorkerThread* aThread)
AssertIsOnMainThread();
MOZ_ASSERT(aThread);
static TimeDuration timeout =
TimeDuration::FromSeconds(IDLE_THREAD_TIMEOUT_SEC);
bool shutdownThread = mShuttingDown;
bool scheduleTimer = false;
TimeStamp expirationTime = TimeStamp::Now() + timeout;
if (!shutdownThread) {
static TimeDuration timeout =
TimeDuration::FromSeconds(IDLE_THREAD_TIMEOUT_SEC);
TimeStamp expirationTime = TimeStamp::NowLoRes() + timeout;
bool shutdown;
if (mShuttingDown) {
shutdown = true;
}
else {
MutexAutoLock lock(mMutex);
if (mIdleThreadArray.Length() < MAX_IDLE_THREADS) {
uint32_t previousIdleCount = mIdleThreadArray.Length();
if (previousIdleCount < MAX_IDLE_THREADS) {
IdleThreadInfo* info = mIdleThreadArray.AppendElement();
info->mThread = aThread;
info->mExpirationTime = expirationTime;
shutdown = false;
}
else {
shutdown = true;
scheduleTimer = previousIdleCount == 0;
} else {
shutdownThread = true;
}
}
MOZ_ASSERT_IF(shutdownThread, !scheduleTimer);
MOZ_ASSERT_IF(scheduleTimer, !shutdownThread);
// Too many idle threads, just shut this one down.
if (shutdown) {
if (shutdownThread) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aThread->Shutdown()));
return;
} else if (scheduleTimer) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
mIdleThreadTimer->InitWithFuncCallback(ShutdownIdleThreads,
nullptr,
IDLE_THREAD_TIMEOUT_SEC * 1000,
nsITimer::TYPE_ONE_SHOT)));
}
// Schedule timer.
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mIdleThreadTimer->InitWithFuncCallback(
ShutdownIdleThreads, nullptr,
IDLE_THREAD_TIMEOUT_SEC * 1000,
nsITimer::TYPE_ONE_SHOT)));
}
void
@@ -2709,6 +2707,13 @@ WorkerThreadPrimaryRunnable::Run()
}
{
#ifdef MOZ_ENABLE_PROFILER_SPS
PseudoStack* stack = mozilla_get_pseudo_stack();
if (stack) {
stack->sampleRuntime(rt);
}
#endif
{
JSAutoRequest ar(cx);
+162 -113
View File
@@ -22,6 +22,7 @@
#include "nsIURI.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "nsError.h"
#include "nsContentPolicyUtils.h"
#include "nsContentUtils.h"
@@ -121,54 +122,51 @@ ChannelFromScriptURL(nsIPrincipal* principal,
return NS_ERROR_DOM_SYNTAX_ERR;
}
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(aContentPolicyType, uri,
principal, parentDoc,
NS_LITERAL_CSTRING("text/javascript"),
nullptr, &shouldLoad,
nsContentUtils::GetContentPolicy(),
secMan);
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
return rv = NS_ERROR_CONTENT_BLOCKED;
}
return rv = NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
}
if (aWorkerScriptType == DebuggerScript) {
bool isChrome = false;
NS_ENSURE_SUCCESS(uri->SchemeIs("chrome", &isChrome),
NS_ERROR_DOM_SECURITY_ERR);
bool isResource = false;
NS_ENSURE_SUCCESS(uri->SchemeIs("resource", &isResource),
NS_ERROR_DOM_SECURITY_ERR);
if (!isChrome && !isResource) {
return NS_ERROR_DOM_SECURITY_ERR;
}
} else if (aIsMainScript) {
// We pass true as the 3rd argument to checkMayLoad here.
// This allows workers in sandboxed documents to load data URLs
// (and other URLs that inherit their principal from their
// creator.)
rv = principal->CheckMayLoad(uri, false, true);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR);
}
else {
rv = secMan->CheckLoadURIWithPrincipal(principal, uri, 0);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR);
// If we have the document, use it. Unfortunately, for dedicated workers
// 'parentDoc' ends up being the parent document, which is not the document
// that we want to use. So make sure to avoid using 'parentDoc' in that
// situation.
if (parentDoc && parentDoc->NodePrincipal() != principal) {
parentDoc = nullptr;
}
aLoadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
uint32_t secFlags = aIsMainScript ? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
if (aWorkerScriptType == DebuggerScript) {
// A DebuggerScript needs to be a local resource like chrome: or resource:
bool isUIResource = false;
rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE,
&isUIResource);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!isUIResource) {
return NS_ERROR_DOM_SECURITY_ERR;
}
secFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
}
// Note: this is for backwards compatibility and goes against spec.
// We should find a better solution.
bool isData = false;
if (aIsMainScript && NS_SUCCEEDED(uri->SchemeIs("data", &isData)) && isData) {
secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
}
nsCOMPtr<nsIChannel> channel;
// If we have the document, use it
if (parentDoc) {
// If we have the document, use it. Unfortunately, for dedicated workers
// 'parentDoc' ends up being the parent document, which is not the document
// that we want to use. So make sure to avoid using 'parentDoc' in that
// situation.
if (parentDoc && parentDoc->NodePrincipal() == principal) {
rv = NS_NewChannel(getter_AddRefs(channel),
uri,
parentDoc,
nsILoadInfo::SEC_NORMAL,
secFlags,
aContentPolicyType,
loadGroup,
nullptr, // aCallbacks
@@ -183,7 +181,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
rv = NS_NewChannel(getter_AddRefs(channel),
uri,
principal,
nsILoadInfo::SEC_NORMAL,
secFlags,
aContentPolicyType,
loadGroup,
nullptr, // aCallbacks
@@ -318,6 +316,9 @@ private:
WorkerPrivate* aWorkerPrivate,
bool aResult,
bool aMutedError);
void LogExceptionToConsole(JSContext* aCx,
WorkerPrivate* WorkerPrivate);
};
class CacheScriptLoader;
@@ -482,14 +483,51 @@ private:
NS_IMPL_ISUPPORTS0(CachePromiseHandler)
class ScriptLoaderRunnable final : public WorkerFeature,
public nsIRunnable,
public nsIStreamLoaderObserver,
public nsIRequestObserver
class LoaderListener final : public nsIStreamLoaderObserver
, public nsIRequestObserver
{
public:
NS_DECL_ISUPPORTS
LoaderListener(ScriptLoaderRunnable* aRunnable, uint32_t aIndex)
: mRunnable(aRunnable)
, mIndex(aIndex)
{
MOZ_ASSERT(mRunnable);
}
NS_IMETHOD
OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
nsresult aStatus, uint32_t aStringLen,
const uint8_t* aString) override;
NS_IMETHOD
OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) override;
NS_IMETHOD
OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
nsresult aStatusCode) override
{
// Nothing to do here!
return NS_OK;
}
private:
~LoaderListener() {}
RefPtr<ScriptLoaderRunnable> mRunnable;
uint32_t mIndex;
};
NS_IMPL_ISUPPORTS(LoaderListener, nsIStreamLoaderObserver, nsIRequestObserver)
class ScriptLoaderRunnable final : public WorkerFeature
, public nsIRunnable
{
friend class ScriptExecutorRunnable;
friend class CachePromiseHandler;
friend class CacheScriptLoader;
friend class LoaderListener;
WorkerPrivate* mWorkerPrivate;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
@@ -567,45 +605,27 @@ private:
}
}
NS_IMETHOD
OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
nsresult
OnStreamComplete(nsIStreamLoader* aLoader, uint32_t aIndex,
nsresult aStatus, uint32_t aStringLen,
const uint8_t* aString) override
const uint8_t* aString)
{
AssertIsOnMainThread();
MOZ_ASSERT(aIndex < mLoadInfos.Length());
nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext));
NS_ASSERTION(indexSupports, "This should never fail!");
uint32_t index = UINT32_MAX;
if (NS_FAILED(indexSupports->GetData(&index)) ||
index >= mLoadInfos.Length()) {
NS_ERROR("Bad index!");
}
ScriptLoadInfo& loadInfo = mLoadInfos[index];
nsresult rv = OnStreamCompleteInternal(aLoader, aContext, aStatus,
aStringLen, aString, loadInfo);
LoadingFinished(index, rv);
nsresult rv = OnStreamCompleteInternal(aLoader, aStatus, aStringLen,
aString, mLoadInfos[aIndex]);
LoadingFinished(aIndex, rv);
return NS_OK;
}
NS_IMETHOD
OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) override
nsresult
OnStartRequest(nsIRequest* aRequest, uint32_t aIndex)
{
AssertIsOnMainThread();
MOZ_ASSERT(aIndex < mLoadInfos.Length());
nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext));
MOZ_ASSERT(indexSupports, "This should never fail!");
uint32_t index = UINT32_MAX;
if (NS_FAILED(indexSupports->GetData(&index)) ||
index >= mLoadInfos.Length()) {
MOZ_CRASH("Bad index!");
}
ScriptLoadInfo& loadInfo = mLoadInfos[index];
ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
MOZ_ASSERT(channel == loadInfo.mChannel);
@@ -659,7 +679,7 @@ private:
}
RefPtr<CachePromiseHandler> promiseHandler =
new CachePromiseHandler(this, loadInfo, index);
new CachePromiseHandler(this, loadInfo, aIndex);
cachePromise->AppendNativeHandler(promiseHandler);
loadInfo.mCachePromise.swap(cachePromise);
@@ -668,14 +688,6 @@ private:
return NS_OK;
}
NS_IMETHOD
OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
nsresult aStatusCode) override
{
// Nothing to do here!
return NS_OK;
}
virtual bool
Notify(JSContext* aCx, Status aStatus) override
{
@@ -778,6 +790,7 @@ private:
++index) {
nsresult rv = LoadScript(index);
if (NS_WARN_IF(NS_FAILED(rv))) {
LoadingFinished(index, rv);
return rv;
}
}
@@ -875,27 +888,18 @@ private:
// We need to know which index we're on in OnStreamComplete so we know
// where to put the result.
nsCOMPtr<nsISupportsPRUint32> indexSupports =
do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = indexSupports->SetData(aIndex);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
RefPtr<LoaderListener> listener = new LoaderListener(this, aIndex);
// We don't care about progress so just use the simple stream loader for
// OnStreamComplete notification only.
nsCOMPtr<nsIStreamLoader> loader;
rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
rv = NS_NewStreamLoader(getter_AddRefs(loader), listener);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (loadInfo.mCacheStatus != ScriptLoadInfo::ToBeCached) {
rv = channel->AsyncOpen(loader, indexSupports);
rv = channel->AsyncOpen2(loader);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -914,12 +918,12 @@ private:
nsCOMPtr<nsIStreamListenerTee> tee =
do_CreateInstance(NS_STREAMLISTENERTEE_CONTRACTID);
rv = tee->Init(loader, writer, this);
rv = tee->Init(loader, writer, listener);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsresult rv = channel->AsyncOpen(tee, indexSupports);
nsresult rv = channel->AsyncOpen2(tee);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -931,9 +935,9 @@ private:
}
nsresult
OnStreamCompleteInternal(nsIStreamLoader* aLoader, nsISupports* aContext,
nsresult aStatus, uint32_t aStringLen,
const uint8_t* aString, ScriptLoadInfo& aLoadInfo)
OnStreamCompleteInternal(nsIStreamLoader* aLoader, nsresult aStatus,
uint32_t aStringLen, const uint8_t* aString,
ScriptLoadInfo& aLoadInfo)
{
AssertIsOnMainThread();
@@ -972,6 +976,14 @@ private:
principal = parentWorker->GetPrincipal();
}
// We don't mute the main worker script becase we've already done
// same-origin checks on them so we should be able to see their errors.
// Note that for data: url, where we allow it through the same-origin check
// but then give it a different origin.
aLoadInfo.mMutedErrorFlag.emplace(IsMainWorkerScript()
? false
: !principal->Subsumes(channelPrincipal));
// Make sure we're not seeing the result of a 404 or something by checking
// the 'requestSucceeded' attribute on the http channel.
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
@@ -1082,13 +1094,6 @@ private:
}
}
}
else {
// We exempt data urls and other URI's that inherit their
// principal again.
if (NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, false, true))) {
return NS_ERROR_DOM_BAD_URI;
}
}
// The principal can change, but it should still match the original
// load group's appId and browser element flag.
@@ -1232,9 +1237,21 @@ private:
}
};
NS_IMPL_ISUPPORTS(ScriptLoaderRunnable, nsIRunnable,
nsIStreamLoaderObserver,
nsIRequestObserver)
NS_IMPL_ISUPPORTS(ScriptLoaderRunnable, nsIRunnable)
NS_IMETHODIMP
LoaderListener::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
nsresult aStatus, uint32_t aStringLen,
const uint8_t* aString)
{
return mRunnable->OnStreamComplete(aLoader, mIndex, aStatus, aStringLen, aString);
}
NS_IMETHODIMP
LoaderListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
{
return mRunnable->OnStartRequest(aRequest, mIndex);
}
void
CachePromiseHandler::ResolvedCallback(JSContext* aCx,
@@ -1496,9 +1513,14 @@ CacheScriptLoader::ResolvedCallback(JSContext* aCx,
MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::Uncached);
nsresult rv;
if (aValue.isUndefined()) {
mLoadInfo.mCacheStatus = ScriptLoadInfo::ToBeCached;
mRunnable->LoadScript(mIndex);
rv = mRunnable->LoadScript(mIndex);
if (NS_WARN_IF(NS_FAILED(rv))) {
Fail(rv);
}
return;
}
@@ -1506,7 +1528,7 @@ CacheScriptLoader::ResolvedCallback(JSContext* aCx,
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
mozilla::dom::Response* response = nullptr;
nsresult rv = UNWRAP_OBJECT(Response, obj, response);
rv = UNWRAP_OBJECT(Response, obj, response);
if (NS_WARN_IF(NS_FAILED(rv))) {
Fail(rv);
return;
@@ -1809,7 +1831,7 @@ ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx,
// If this error has to be muted, we have to clear the pending exception,
// if any, and use the ErrorResult object to throw a new exception.
if (aMutedError && JS_IsExceptionPending(aCx)) {
JS_ClearPendingException(aCx);
LogExceptionToConsole(aCx, aWorkerPrivate);
mScriptLoader.mRv.Throw(NS_ERROR_FAILURE);
} else {
mScriptLoader.mRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
@@ -1820,6 +1842,33 @@ ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx,
aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, aResult);
}
void
ScriptExecutorRunnable::LogExceptionToConsole(JSContext* aCx,
WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->AssertIsOnWorkerThread();
JS::Rooted<JS::Value> exn(aCx);
if (!JS_GetPendingException(aCx, &exn)) {
return;
}
JS_ClearPendingException(aCx);
js::ErrorReport report(aCx);
if (!report.init(aCx, exn)) {
JS_ClearPendingException(aCx);
return;
}
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
xpcReport->Init(report.report(), report.message(),
aWorkerPrivate->IsChromeWorker(), aWorkerPrivate->WindowID());
RefPtr<AsyncErrorReporter> r = new AsyncErrorReporter(xpcReport);
NS_DispatchToMainThread(r);
}
void
LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsMainScript,

Some files were not shown because too many files have changed in this diff Show More