mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:43:44 +00:00
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:
@@ -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));
|
||||
};
|
||||
|
||||
@@ -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
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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',
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
%}
|
||||
@@ -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");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
@@ -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]
|
||||
|
||||
@@ -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 :
|
||||
|
||||
@@ -513,7 +513,6 @@ DOMInterfaces = {
|
||||
},
|
||||
|
||||
'FileReader': {
|
||||
'nativeType': 'nsDOMFileReader',
|
||||
'implicitJSContext': [ 'readAsArrayBuffer' ],
|
||||
},
|
||||
|
||||
|
||||
+56
-2
@@ -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):
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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*
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIAsyncShutdown.h"
|
||||
#include "base/task.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Constructor]
|
||||
[Constructor,
|
||||
Exposed=(Window,System)]
|
||||
interface FileReader : EventTarget {
|
||||
// async read methods
|
||||
[Throws]
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user