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

- Bug 1212114 - Stop using dom::Promise::MaybeRejectBrokenly() in various FileSystemTaskBase subclasses. r=baku (9f6ea5db27)
- Bug 1253534 - Suspicious code with probably reversed parms in call to IsSingleLineTextControl, r=mounir (1a5ee1fd1e)
- Bug 769117 - Mochitests for youtube flash -> html5 rewriting; r=bz r=hsivonen (6324471dd9)
- Bug 1250148 - FormData should treat empty input type=file as empty string in FormData and as unnamed Blob in HTML submission, r=smaug (7043113247)
- Bug 1173320 - patch 1/8 - Implement Directory object as string and not as BlobImpl, r=smaug (eca4bec6ea)
- Bug 1173320 - patch 2/8 - Proper naming for the FileSystem path serialization, r=smaug (e1604ff2b1)
- Bug 1173320 - patch 3/8 - Improve the Windows path management, r=smaug (f8da8541b5)
- Bug 1252347 - Provide missing implementations of nsIBaseWindow::SetPositionDesktopPix. r=emk (97f9b92465)
- Bug 1235066 - SVG elements should not display title attributes as tooltips. r=enndeakin (a77e809688)
- Bug 1251809 - Add input[type=file] tooltip support for e10s. r=ehsan (9f72cf3cd2)
- Bug 1173320 - patch 4/8 - Directory in FileList, r=smaug (c09d445043)
- Bug 1246244 - Regression test. r=jaws,Margaret (8de084f9db)
- Bug 1224105 - Allow windowless chrome docshells containing content docshells (r=smaug) (3343a2a966)
- Bug 1230267 - Inconsistent display of SVG title as tooltip when multi-process is enabled. r=jst (b3fc298b7f)
- Bug 1173320 - patch 5/8 - Cleanup manual string path management, r=smaug (8f6f0c4e44)
- Bug 1250403 - Part 1. Define ARCH_CPU_ARM64 instead of ARCH_CPU_AARCH64. r=billm (d93a0b54da)
- Bug 1250403 - Part 2. Import crbug #354405 for aarch64. r=billm (9dca949bcc)
- Bug 1246501 - Add ppc specific atomic operations to ipc/chromium. r=Waldo (8054b612be)
- Bug 1257305 - Avoid VS2015 about casting int to void*. r=dvander (6234acf6fc)
- Bug 1207401 - Send B2G sandbox logging to both stderr and logcat. r=kang (ae404aa5ca)
- Bug 1173320 - patch 6/8 - Make FileList clonable to workers if it doesn't contain Directories, r=smaug (ea6ba42f31)
- Bug 1173320 - patch 7/8 - Tests for FileList and Directories, r=smaug (3f11503300)
- Bug 1222522, part 1 - Make most dom/devicestorage/ tests work with e10s. r=dhylands (3cc7e339a5)
- Bug 1173320 - patch 8/8 - Fix e10s tests for DeviceStorage API, r=smaug (949454bae7)
- Bug 1222522, part 2 - Inline devicestorage_cleanup() in dom/devicestorage/ tests. r=dhylands (bcdee11385)
- Bug 1258137 - OSFileSystem should not be kept alive by more than 1 Directory, r=smaug (225775f48d)
- Bug 1255867. Remove some unnecessary AutoJSAPI uses. r=bholley (618cf018e8)
- Bug 1237173 - Part2: Change type of duration to Maybe<StickyTimeDuration>. r=birtles (6b83473e05)
- Bug 1238469 - Part 1: Refactor b2g emulator tests to remove the usage of custom mozharness configs; r=ahal (a128c8a8bb)
- Bug 1238469 - Part 2: Refactor b2g mulet tests to remove the usage of custom mozharness configs; r=ahal (6c7ced3419)
- Bug 1238469 - Part 3: Use b2g_emulator_unittest.py for b2g marionette tests; r=ahal (5fdb88b0e1)
- Bug 1237173 - Part3: Throw TypeError if duration is NaN, negative value or not 'auto' string. r=birtles, r=smaug (d60b0318d2)
- Bug 1136567 - Marionette test for selection carets' positions after changing orientation of device. r=Automatedtester (e7b25b1e4f)
- Bug 1138839 - Part1 - Marionette test for selecting text inside an iframe. r=automatedtester (45db397a94)
- Bug 1138839 - Part2 - Fix naming issue in marionette test for selection carets. r=automatedtester (c54850d9d3)
- Bug 1198542: Update Marionette element IDs to be valid UUID. r=ato This allows WebDriver compatibility to create valid URI. (1b3de245de)
- Bug 1204496: When searching by link text start from the startNode and not the rootNode; r=ato (0dfa3b8830)
- Bug 1157725 - Rewrite test_mouse_action.py to be more robust. r=ato (40273abca2)
- Bug 1141519: added test that puts marionette into a position that can cause hangs when in content scope; r=jgriffin (c99d8cf325)
- Bug 1246407 - Rename parent directories for Marionette client and test harness; r=automatedtester (79d4e521fd)
- Bug 1253989 Part 3 - Use @parameterized to rewrite selection mode tests. r=mtseng (baf189f1d5)
- Bug 1253989 Part 4 - Rename AccessibleCaret test files. r=mtseng (d562edc8f4)
- Bug 1251519 Part 3 - Add regression tests for caret dragging. r=mats (048dd5f103)
- Bug 1253989 Part 5 - Remove touch caret and selection carets naming. r=mtseng (9929425b6d)
- Bug 1253989 Part 6 - Refactor open_test_html(). r=mtseng (25a2424ca1)
- Bug 1251519 Part 4 - Add tests for dragging caret to content boundary. r=mats (489b47269b)
- Bug 1251519 Part 5 - Use union rect of child frames for clamping. r=mats (5520416749)
- Bug 1216924 - Don't align to tiles (either real or virtual) if displayport suppression is enabled. r=BenWa (d470d188e4)
- Bug 1254273 - Align the displayport to a max of 256 pixels even if the layer is larger. r=BenWa (0cf8cc0b6c)
- Bug 1257938 part 3: Remove support for the "layout.css.sticky.enabled" pref (so we'll unconditionally support "position: sticky"). r=corey (fe12efd18f)
- Bug 1257938 part 1: Adjust automated tests to assume position:sticky is unconditionally supported. r=corey (e749ac579e)
- Bug 1257938 part 2: Remove separation between test_position_sticky.html & its helper-file, now that it doesn't need to tweak a pref. r=corey (631edab31a)
- Bug 1257491 - Ensure that if the peek-messages code modifies the displayport, we schedule a repaint. r=BenWa (d6fb6ff96c)
- Bug 1255006 - Ensure the displayport rect takes priority over a suppressed-margins displayport. r=kats (aa6cbc0250)
- Bug 1259235 - Add IsScrollFrameWithSnapping to speed up event regions. r=mstange (2a744c311e)
- Bug 1185140 - [css-grid][flexbox] Make grid/flex item blockification happen before creating table pseudos, per the latest specs. r=dholbert (dddb8b17ef)
- Bug 1224424 - Replace mask-mode:auto keyword by mask-mode:match-source; r=dbaron (5a51b3b301)
- Bug 1252039 - corrected MOZ_ASSERT expression in SeparatorRequiredBetweenTokens. r=dbaron (08790aa514)
- Bug 1243734 - Part 1. Use MOZ_ENABLE_MASK_AS_SHORTHAND to define the type of mask property; r=dbaron (d8cd3a1c4a)
- Bug 1243734 - Part 2. Set up gCSSProperties depends on mask-as-shorth and; r=dbaron (aa6b0259d8)
- Bug 1243734 - Part 3. Set mask-mode reftest as failure before enable mask-as-shorthand; r=dbaron (6a326fbaf2)
- Bug 1243734 - Part 5. Add MOZ_ENABLE_MASK_AS_SHORTHAND compile flag; r=ted r=dbaron (fcc1344ac8)
- Bug 1142531: Check more bits in nsStyleContext::MoveTo assertion. r=heycam (8b62b139df)
- Bug 1258147 - Pierce through display:contents style context ancestors when looking for CB context to compare our writing-mode to. r=jfkthame (956d8c25e5)
- Bug 823483 patch 1 - Check for percentage max-width in addition to percentage width when deciding to ignore intrinsic min-width of replaced elements. r=dholbert (f88cb5f6a8)
- Bug 823483 patch 3 - Limit effect of percentage width and max-width on intrinsic size to elements with replaced element sizing. r=dholbert (2573c3cfff)
- Bug 823483 patch 4 - Make a percentage max-width override a fixed width for replaced element intrinsic size computation. r=dholbert (dda859f06c)
- Bug 823483 patch 5 - Make (again) percentage width on text inputs make intrinsic minimum width be 0. r=dholbert (d46ada73ef)
- Bug 1247929 patch 2 - Hard-code the Web-compatible set of form controls whose intrinsic minimum inline-size shrinks to 0 when inline-size (width) is specified as a percentage. r=dholbert (e4f0c80fcb)
- Bug 1254968 - Add support for running JS builtins' constructors over Xray wrappers without unwrapping the newTarget. r=bholley,f=bz (56213ae395)
- Bug 1249123 - Add telemetry for __defineGetter__/__defineSetter__ |this| values. data-review=bsmedberg r=till (52c5fd3488)
- Bug 1232639 - Implement Object.{values,entries} in C++ to avoid native call overhead in tight loop. r=jorendorff (7262497283)
- Bug 1254966 - Disambiguate JS Telemetry macro names. r=evilpie (781d0916c4)
- Bug 1254384: Use generic shell switch syntax in js/src/jit-test tests. r=nbp (6f5975cc55)
- Bug 1253016 - Remove legacy __defineGetter__/__defineSetter__ this behavior. r=till (cf1b7ad28c)
- Bug 1253016 - Implement and test the new spec for legacy functions. r=till (1ff7762e3e)
This commit is contained in:
2024-02-28 12:10:08 +08:00
parent baacd3ba62
commit cf2d7d1ae9
566 changed files with 7128 additions and 5646 deletions
@@ -0,0 +1,59 @@
<svg width="640px" height="480px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>This is a root SVG element's title</title>
<foreignObject>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<svg xmlns="http://www.w3.org/2000/svg" id="svg1">
<title>This is a non-root SVG element title</title>
</svg>
</body>
</html>
</foreignObject>
<text id="text1" x="10px" y="32px" font-size="24px">
This contains only &lt;title&gt;
<title>
This is a title
</title>
</text>
<text id="text2" x="10px" y="96px" font-size="24px">
This contains only &lt;desc&gt;
<desc>This is a desc</desc>
</text>
<text id="text3" x="10px" y="128px" font-size="24px" title="ignored for SVG">
This contains nothing.
</text>
<a id="link1" xlink:href="#">
This link contains &lt;title&gt;
<title>
This is a title
</title>
<text id="text4" x="10px" y="192px" font-size="24px">
</text>
</a>
<a id="link2" xlink:href="#">
<text x="10px" y="192px" font-size="24px">
This text contains &lt;title&gt;
<title>
This is a title
</title>
</text>
</a>
<a id="link3" xlink:href="#" xlink:title="This is an xlink:title attribute">
<text x="10px" y="224px" font-size="24px">
This link contains &lt;title&gt; &amp; xlink:title attr.
<title>This is a title</title>
</text>
</a>
<a id="link4" xlink:href="#" xlink:title="This is an xlink:title attribute">
<text x="10px" y="256px" font-size="24px">
This link contains xlink:title attr.
</text>
</a>
<text id="text5" x="10px" y="160px" font-size="24px"
xlink:title="This is an xlink:title attribute but it isn't on a link" >
This contains nothing.
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+2 -2
View File
@@ -50,9 +50,9 @@ SEARCH_PATHS = [
'testing/firefox-ui/harness',
'testing/firefox-ui/tests',
'testing/luciddream',
'testing/marionette/harness',
'testing/marionette/harness/marionette/runner/mixins/browsermob-proxy-py',
'testing/marionette/client',
'testing/marionette/client/marionette/runner/mixins/browsermob-proxy-py',
'testing/marionette/driver',
'testing/mozbase/mozcrash',
'testing/mozbase/mozdebug',
'testing/mozbase/mozdevice',
+3
View File
@@ -258,3 +258,6 @@ https://sha256ee.example.com:443 privileged,cer
https://ssl3.example.com:443 privileged,ssl3
https://rc4.example.com:443 privileged,rc4
https://ssl3rc4.example.com:443 privileged,ssl3,rc4
# Hosts for youtube rewrite tests
https://mochitest.youtube.com:443
+3 -3
View File
@@ -1,7 +1,7 @@
marionette_driver.pth:testing/marionette/driver
browsermobproxy.pth:testing/marionette/client/marionette/runner/mixins/browsermob-proxy-py
marionette_driver.pth:testing/marionette/client
browsermobproxy.pth:testing/marionette/harness/marionette/runner/mixins/browsermob-proxy-py
wptserve.pth:testing/web-platform/tests/tools/wptserve
marionette.pth:testing/marionette/client
marionette.pth:testing/marionette/harness
blessings.pth:python/blessings
configobj.pth:python/configobj
jsmin.pth:python/jsmin
+10
View File
@@ -8839,6 +8839,16 @@ fi
MOZ_CONFIG_ICU()
dnl ========================================================
dnl mask as short hand property
dnl ========================================================
dnl Uncommenting the next line would enable mask-as-shorthand feature.
dnl MOZ_ENABLE_MASK_AS_SHORTHAND=1
if test "$MOZ_ENABLE_MASK_AS_SHORTHAND"; then
AC_DEFINE(MOZ_ENABLE_MASK_AS_SHORTHAND)
fi
AC_SUBST(MOZ_ENABLE_MASK_AS_SHORTHAND)
if test -z "$JS_SHARED_LIBRARY"; then
AC_DEFINE(MOZ_STATIC_JS)
fi
+8 -4
View File
@@ -5783,10 +5783,14 @@ nsDocShell::SetPosition(int32_t aX, int32_t aY)
NS_IMETHODIMP
nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY)
{
// Added to nsIBaseWindow in bug 1247335;
// implement if a use-case is found.
NS_ASSERTION(false, "implement me!");
return NS_ERROR_NOT_IMPLEMENTED;
nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
if (ownerWindow) {
return ownerWindow->SetPositionDesktopPix(aX, aY);
}
double scale = 1.0;
GetDevicePixelsPerDesktopPixel(&scale);
return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
}
NS_IMETHODIMP
+8 -13
View File
@@ -8,6 +8,7 @@
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/AnimationEffectTimingBinding.h"
#include "mozilla/TimingParams.h"
namespace mozilla {
namespace dom {
@@ -39,26 +40,20 @@ AnimationEffectTiming::SetEndDelay(double aEndDelay)
}
void
AnimationEffectTiming::SetDuration(const UnrestrictedDoubleOrString& aDuration)
AnimationEffectTiming::SetDuration(const UnrestrictedDoubleOrString& aDuration,
ErrorResult& aRv)
{
if (mTiming.mDuration.IsUnrestrictedDouble() &&
aDuration.IsUnrestrictedDouble() &&
mTiming.mDuration.GetAsUnrestrictedDouble() ==
aDuration.GetAsUnrestrictedDouble()) {
Maybe<StickyTimeDuration> newDuration =
TimingParams::ParseDuration(aDuration, aRv);
if (aRv.Failed()) {
return;
}
if (mTiming.mDuration.IsString() && aDuration.IsString() &&
mTiming.mDuration.GetAsString() == aDuration.GetAsString()) {
if (mTiming.mDuration == newDuration) {
return;
}
if (aDuration.IsUnrestrictedDouble()) {
mTiming.mDuration.SetAsUnrestrictedDouble() =
aDuration.GetAsUnrestrictedDouble();
} else {
mTiming.mDuration.SetAsString() = aDuration.GetAsString();
}
mTiming.mDuration = newDuration;
NotifyTimingUpdate();
}
+2 -1
View File
@@ -25,7 +25,8 @@ public:
void Unlink() override { mEffect = nullptr; }
void SetEndDelay(double aEndDelay);
void SetDuration(const UnrestrictedDoubleOrString& aDuration);
void SetDuration(const UnrestrictedDoubleOrString& aDuration,
ErrorResult& aRv);
private:
void NotifyTimingUpdate();
@@ -26,6 +26,17 @@ AnimationEffectTimingReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*>
return AnimationEffectTimingReadOnlyBinding::Wrap(aCx, this, aGivenProto);
}
void
AnimationEffectTimingReadOnly::GetDuration(
OwningUnrestrictedDoubleOrString& aRetVal) const
{
if (mTiming.mDuration) {
aRetVal.SetAsUnrestrictedDouble() = mTiming.mDuration->ToMilliseconds();
} else {
aRetVal.SetAsString().AssignLiteral("auto");
}
}
void
AnimationEffectTimingReadOnly::GetEasing(nsString& aRetVal) const
{
@@ -41,10 +41,7 @@ public:
FillMode Fill() const { return mTiming.mFill; }
double IterationStart() const { return mTiming.mIterationStart; }
double Iterations() const { return mTiming.mIterations; }
void GetDuration(OwningUnrestrictedDoubleOrString& aRetVal) const
{
aRetVal = mTiming.mDuration;
}
void GetDuration(OwningUnrestrictedDoubleOrString& aRetVal) const;
PlaybackDirection Direction() const { return mTiming.mDirection; }
void GetEasing(nsString& aRetVal) const;
+5 -5
View File
@@ -238,12 +238,12 @@ KeyframeEffectReadOnly::GetComputedTimingAt(
// Always return the same object to benefit from return-value optimization.
ComputedTiming result;
if (aTiming.mDuration.IsUnrestrictedDouble()) {
double durationMs = aTiming.mDuration.GetAsUnrestrictedDouble();
if (!IsNaN(durationMs) && durationMs >= 0.0f) {
result.mDuration = StickyTimeDuration::FromMilliseconds(durationMs);
}
if (aTiming.mDuration) {
MOZ_ASSERT(aTiming.mDuration.ref() >= zeroDuration,
"Iteration duration should be positive");
result.mDuration = aTiming.mDuration.ref();
}
result.mIterations = IsNaN(aTiming.mIterations) || aTiming.mIterations < 0.0f ?
1.0f :
aTiming.mIterations;
+12 -4
View File
@@ -204,9 +204,13 @@ public:
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
ErrorResult& aRv)
{
TimingParams timingParams =
TimingParams::FromOptionsUnion(aOptions, aTarget, aRv);
if (aRv.Failed()) {
return nullptr;
}
return ConstructKeyframeEffect<KeyframeEffectReadOnly>(
aGlobal, aTarget, aFrames,
TimingParams::FromOptionsUnion(aOptions, aTarget), aRv);
aGlobal, aTarget, aFrames, timingParams, aRv);
}
void GetTarget(Nullable<OwningElementOrCSSPseudoElement>& aRv) const;
@@ -431,9 +435,13 @@ public:
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
ErrorResult& aRv)
{
TimingParams timingParams =
TimingParams::FromOptionsUnion(aOptions, aTarget, aRv);
if (aRv.Failed()) {
return nullptr;
}
return ConstructKeyframeEffect<KeyframeEffect>(
aGlobal, aTarget, aFrames,
TimingParams::FromOptionsUnion(aOptions, aTarget), aRv);
aGlobal, aTarget, aFrames, timingParams, aRv);
}
// More generalized version for Animatable.animate.
+34 -37
View File
@@ -8,24 +8,6 @@
namespace mozilla {
TimingParams::TimingParams(const dom::AnimationEffectTimingProperties& aRhs,
const dom::Element* aTarget)
: mDuration(aRhs.mDuration)
, mDelay(TimeDuration::FromMilliseconds(aRhs.mDelay))
, mEndDelay(TimeDuration::FromMilliseconds(aRhs.mEndDelay))
, mIterations(aRhs.mIterations)
, mIterationStart(aRhs.mIterationStart)
, mDirection(aRhs.mDirection)
, mFill(aRhs.mFill)
{
mFunction = AnimationUtils::ParseEasing(aTarget, aRhs.mEasing);
}
TimingParams::TimingParams(double aDuration)
{
mDuration.SetAsUnrestrictedDouble() = aDuration;
}
template <class OptionsType>
static const dom::AnimationEffectTimingProperties&
GetTimingProperties(const OptionsType& aOptions);
@@ -52,10 +34,18 @@ template <class OptionsType>
static TimingParams
TimingParamsFromOptionsUnion(
const OptionsType& aOptions,
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget)
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget,
ErrorResult& aRv)
{
TimingParams result;
if (aOptions.IsUnrestrictedDouble()) {
return TimingParams(aOptions.GetAsUnrestrictedDouble());
double durationInMs = aOptions.GetAsUnrestrictedDouble();
if (durationInMs >= 0) {
result.mDuration.emplace(
StickyTimeDuration::FromMilliseconds(durationInMs));
} else {
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
}
} else {
// If aTarget is a pseudo element, we pass its parent element because
// TimingParams only needs its owner doc to parse easing and both pseudo
@@ -72,41 +62,48 @@ TimingParamsFromOptionsUnion(
targetElement = target.GetAsCSSPseudoElement().ParentElement();
}
}
return TimingParams(GetTimingProperties(aOptions), targetElement);
const dom::AnimationEffectTimingProperties& timing =
GetTimingProperties(aOptions);
Maybe<StickyTimeDuration> duration =
TimingParams::ParseDuration(timing.mDuration, aRv);
if (aRv.Failed()) {
return result;
}
result.mDuration = duration;
result.mDelay = TimeDuration::FromMilliseconds(timing.mDelay);
result.mEndDelay = TimeDuration::FromMilliseconds(timing.mEndDelay);
result.mIterations = timing.mIterations;
result.mIterationStart = timing.mIterationStart;
result.mDirection = timing.mDirection;
result.mFill = timing.mFill;
result.mFunction =
AnimationUtils::ParseEasing(targetElement, timing.mEasing);
}
return result;
}
/* static */ TimingParams
TimingParams::FromOptionsUnion(
const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget)
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget,
ErrorResult& aRv)
{
return TimingParamsFromOptionsUnion(aOptions, aTarget);
return TimingParamsFromOptionsUnion(aOptions, aTarget, aRv);
}
/* static */ TimingParams
TimingParams::FromOptionsUnion(
const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget)
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget,
ErrorResult& aRv)
{
return TimingParamsFromOptionsUnion(aOptions, aTarget);
return TimingParamsFromOptionsUnion(aOptions, aTarget, aRv);
}
bool
TimingParams::operator==(const TimingParams& aOther) const
{
bool durationEqual;
if (mDuration.IsUnrestrictedDouble()) {
durationEqual = aOther.mDuration.IsUnrestrictedDouble() &&
(mDuration.GetAsUnrestrictedDouble() ==
aOther.mDuration.GetAsUnrestrictedDouble());
} else {
// We consider all string values and uninitialized values as meaning "auto".
// Since mDuration is either a string or uninitialized, we consider it equal
// if aOther.mDuration is also either a string or uninitialized.
durationEqual = !aOther.mDuration.IsUnrestrictedDouble();
}
return durationEqual &&
return mDuration == aOther.mDuration &&
mDelay == aOther.mDelay &&
mIterations == aOther.mIterations &&
mIterationStart == aOther.mIterationStart &&
+27 -8
View File
@@ -33,20 +33,39 @@ class ElementOrCSSPseudoElement;
struct TimingParams
{
TimingParams() = default;
TimingParams(const dom::AnimationEffectTimingProperties& aTimingProperties,
const dom::Element* aTarget);
explicit TimingParams(double aDuration);
static TimingParams FromOptionsUnion(
const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget);
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget,
ErrorResult& aRv);
static TimingParams FromOptionsUnion(
const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget);
const Nullable<dom::ElementOrCSSPseudoElement>& aTarget,
ErrorResult& aRv);
// The unitialized state of mDuration represents "auto".
// Bug 1237173: We will replace this with Maybe<TimeDuration>.
dom::OwningUnrestrictedDoubleOrString mDuration;
// Range-checks and validates an UnrestrictedDoubleOrString or
// OwningUnrestrictedDoubleOrString object and converts to a
// StickyTimeDuration value or Nothing() if aDuration is "auto".
// Caller must check aRv.Failed().
template <class DoubleOrString>
static Maybe<StickyTimeDuration> ParseDuration(DoubleOrString& aDuration,
ErrorResult& aRv) {
Maybe<StickyTimeDuration> result;
if (aDuration.IsUnrestrictedDouble()) {
double durationInMs = aDuration.GetAsUnrestrictedDouble();
if (durationInMs >= 0) {
result.emplace(StickyTimeDuration::FromMilliseconds(durationInMs));
return result;
}
} else if (aDuration.GetAsString().EqualsLiteral("auto")) {
return result;
}
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return result;
}
// mDuration.isNothing() represents the "auto" value
Maybe<StickyTimeDuration> mDuration;
TimeDuration mDelay; // Initializes to zero
TimeDuration mEndDelay;
double mIterations = 1.0; // Can be NaN, negative, +/-Infinity
+7 -2
View File
@@ -3425,9 +3425,14 @@ Element::Animate(const Nullable<ElementOrCSSPseudoElement>& aTarget,
}
}
TimingParams timingParams =
TimingParams::FromOptionsUnion(aOptions, aTarget, aError);
if (aError.Failed()) {
return nullptr;
}
RefPtr<KeyframeEffect> effect =
KeyframeEffect::Constructor(global, aTarget, frames,
TimingParams::FromOptionsUnion(aOptions, aTarget), aError);
KeyframeEffect::Constructor(global, aTarget, frames, timingParams, aError);
if (aError.Failed()) {
return nullptr;
}
+2 -20
View File
@@ -227,12 +227,6 @@ Blob::IsFile() const
return mImpl->IsFile();
}
bool
Blob::IsDirectory() const
{
return mImpl->IsDirectory();
}
const nsTArray<RefPtr<BlobImpl>>*
Blob::GetSubBlobImpls() const
{
@@ -420,11 +414,10 @@ File::Create(nsISupports* aParent, BlobImpl* aImpl)
/* static */ already_AddRefed<File>
File::Create(nsISupports* aParent, const nsAString& aName,
const nsAString& aContentType, uint64_t aLength,
int64_t aLastModifiedDate, BlobDirState aDirState)
int64_t aLastModifiedDate)
{
RefPtr<File> file = new File(aParent,
new BlobImplBase(aName, aContentType, aLength, aLastModifiedDate,
aDirState));
new BlobImplBase(aName, aContentType, aLength, aLastModifiedDate));
return file.forget();
}
@@ -946,17 +939,6 @@ BlobImplFile::SetPath(const nsAString& aPath)
mPath = aPath;
}
void
BlobImplFile::LookupAndCacheIsDirectory()
{
MOZ_ASSERT(mIsFile,
"This should only be called when this object has been created "
"from an nsIFile to note that the nsIFile is a directory");
bool isDir;
mFile->IsDirectory(&isDir);
mDirState = isDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir;
}
////////////////////////////////////////////////////////////////////////////
// EmptyBlobImpl implementation
+3 -85
View File
@@ -44,18 +44,6 @@ class BlobImpl;
class File;
class OwningArrayBufferOrArrayBufferViewOrBlobOrString;
/**
* Used to indicate when a Blob/BlobImpl that was created from an nsIFile
* (when IsFile() will return true) was from an nsIFile for which
* nsIFile::IsDirectory() returned true. This is a tri-state to enable us to
* assert that the state is always set when callers request it.
*/
enum BlobDirState : uint32_t {
eIsDir,
eIsNotDir,
eUnknownIfDir
};
class Blob : public nsIDOMBlob
, public nsIXHRSendable
, public nsIMutable
@@ -101,12 +89,6 @@ public:
bool IsFile() const;
/**
* This may return true if the Blob was created from an nsIFile that is a
* directory.
*/
bool IsDirectory() const;
const nsTArray<RefPtr<BlobImpl>>* GetSubBlobImpls() const;
// This method returns null if this Blob is not a File; it returns
@@ -114,9 +96,6 @@ public:
// otherwise it returns a new File object with the same BlobImpl.
already_AddRefed<File> ToFile();
// XXXjwatt Consider having a ToDirectory() method. The need for a FileSystem
// object complicates that though.
// This method creates a new File object with the given name and the same
// BlobImpl.
already_AddRefed<File> ToFile(const nsAString& aName,
@@ -194,7 +173,7 @@ public:
static already_AddRefed<File>
Create(nsISupports* aParent, const nsAString& aName,
const nsAString& aContentType, uint64_t aLength,
int64_t aLastModifiedDate, BlobDirState aDirState);
int64_t aLastModifiedDate);
// The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
// freed by moz_free so it must be allocated by moz_malloc or something
@@ -339,28 +318,6 @@ public:
virtual bool IsFile() const = 0;
/**
* Called when this BlobImpl was created from an nsIFile in order to call
* nsIFile::IsDirectory() and cache the result so that when the BlobImpl is
* copied to another process that informaton is available.
* nsIFile::IsDirectory() does synchronous I/O, and BlobImpl objects may be
* created on the main thread or in a non-chrome process (where I/O is not
* allowed). Do not call this on a non-chrome process, and preferably do not
* call it on the main thread.
*
* Not all creators of BlobImplFile will call this method, in which case
* calling IsDirectory will MOZ_ASSERT.
*/
virtual void LookupAndCacheIsDirectory() = 0;
virtual void SetIsDirectory(bool aIsDir) = 0;
virtual bool IsDirectory() const = 0;
/**
* Prefer IsDirectory(). This exists to help consumer code pass on state from
* one BlobImpl when creating another.
*/
virtual BlobDirState GetDirState() const = 0;
// True if this implementation can be sent to other threads.
virtual bool MayBeClonedToOtherThreads() const
{
@@ -377,11 +334,9 @@ class BlobImplBase : public BlobImpl
{
public:
BlobImplBase(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength, int64_t aLastModifiedDate,
BlobDirState aDirState = BlobDirState::eUnknownIfDir)
uint64_t aLength, int64_t aLastModifiedDate)
: mIsFile(true)
, mImmutable(false)
, mDirState(aDirState)
, mContentType(aContentType)
, mName(aName)
, mStart(0)
@@ -397,7 +352,6 @@ public:
uint64_t aLength)
: mIsFile(true)
, mImmutable(false)
, mDirState(BlobDirState::eUnknownIfDir)
, mContentType(aContentType)
, mName(aName)
, mStart(0)
@@ -412,7 +366,6 @@ public:
BlobImplBase(const nsAString& aContentType, uint64_t aLength)
: mIsFile(false)
, mImmutable(false)
, mDirState(BlobDirState::eUnknownIfDir)
, mContentType(aContentType)
, mStart(0)
, mLength(aLength)
@@ -427,7 +380,6 @@ public:
uint64_t aLength)
: mIsFile(false)
, mImmutable(false)
, mDirState(BlobDirState::eUnknownIfDir)
, mContentType(aContentType)
, mStart(aStart)
, mLength(aLength)
@@ -518,36 +470,6 @@ public:
return mIsFile;
}
virtual void LookupAndCacheIsDirectory() override
{
MOZ_ASSERT(false, "Why is this being called on a non-BlobImplFile?");
}
virtual void SetIsDirectory(bool aIsDir) override
{
MOZ_ASSERT(mIsFile,
"This should only be called when this object has been created "
"from an nsIFile to note that the nsIFile is a directory");
mDirState = aIsDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir;
}
/**
* Returns true if the nsIFile that this object wraps is a directory.
*/
virtual bool IsDirectory() const override
{
MOZ_ASSERT(mDirState != BlobDirState::eUnknownIfDir,
"Must only be used by callers for whom the code paths are "
"know to call LookupAndCacheIsDirectory() or "
"SetIsDirectory()");
return mDirState == BlobDirState::eIsDir;
}
virtual BlobDirState GetDirState() const override
{
return mDirState;
}
virtual bool IsSizeUnknown() const override
{
return mLength == UINT64_MAX;
@@ -565,7 +487,6 @@ protected:
bool mIsFile;
bool mImmutable;
BlobDirState mDirState;
nsString mContentType;
nsString mName;
@@ -590,8 +511,7 @@ public:
BlobImplMemory(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
const nsAString& aContentType, int64_t aLastModifiedDate)
: BlobImplBase(aName, aContentType, aLength, aLastModifiedDate,
BlobDirState::eIsNotDir)
: BlobImplBase(aName, aContentType, aLength, aLastModifiedDate)
, mDataOwner(new DataOwner(aMemoryBuffer, aLength))
{
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
@@ -792,8 +712,6 @@ public:
void SetPath(const nsAString& aFullPath);
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; }
+83 -4
View File
@@ -4,6 +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 "mozilla/dom/Directory.h"
#include "mozilla/dom/FileList.h"
#include "mozilla/dom/FileListBinding.h"
#include "mozilla/dom/File.h"
@@ -11,7 +12,7 @@
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFiles, mParent)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFilesOrDirectories, mParent)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@@ -28,6 +29,20 @@ FileList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return mozilla::dom::FileListBinding::Wrap(aCx, this, aGivenProto);
}
void
FileList::Append(File* aFile)
{
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
element->SetAsFile() = aFile;
}
void
FileList::Append(Directory* aDirectory)
{
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
element->SetAsDirectory() = aDirectory;
}
NS_IMETHODIMP
FileList::GetLength(uint32_t* aLength)
{
@@ -37,12 +52,76 @@ FileList::GetLength(uint32_t* aLength)
}
NS_IMETHODIMP
FileList::Item(uint32_t aIndex, nsISupports** aFile)
FileList::Item(uint32_t aIndex, nsISupports** aValue)
{
nsCOMPtr<nsIDOMBlob> file = Item(aIndex);
file.forget(aFile);
if (aIndex >= mFilesOrDirectories.Length()) {
return NS_ERROR_FAILURE;
}
if (mFilesOrDirectories[aIndex].IsFile()) {
nsCOMPtr<nsIDOMBlob> file = mFilesOrDirectories[aIndex].GetAsFile();
file.forget(aValue);
return NS_OK;
}
MOZ_ASSERT(mFilesOrDirectories[aIndex].IsDirectory());
RefPtr<Directory> directory = mFilesOrDirectories[aIndex].GetAsDirectory();
directory.forget(aValue);
return NS_OK;
}
void
FileList::Item(uint32_t aIndex, Nullable<OwningFileOrDirectory>& aValue,
ErrorResult& aRv) const
{
if (aIndex >= mFilesOrDirectories.Length()) {
aValue.SetNull();
return;
}
aValue.SetValue(mFilesOrDirectories[aIndex]);
}
void
FileList::IndexedGetter(uint32_t aIndex, bool& aFound,
Nullable<OwningFileOrDirectory>& aFileOrDirectory,
ErrorResult& aRv) const
{
aFound = aIndex < mFilesOrDirectories.Length();
Item(aIndex, aFileOrDirectory, aRv);
}
void
FileList::ToSequence(Sequence<OwningFileOrDirectory>& aSequence,
ErrorResult& aRv) const
{
MOZ_ASSERT(aSequence.IsEmpty());
if (mFilesOrDirectories.IsEmpty()) {
return;
}
if (!aSequence.SetLength(mFilesOrDirectories.Length(),
mozilla::fallible_t())) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
aSequence[i] = mFilesOrDirectories[i];
}
}
bool
FileList::ClonableToDifferentThreadOrProcess() const
{
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
if (mFilesOrDirectories[i].IsDirectory()) {
return false;
}
}
return true;
}
} // namespace dom
} // namespace mozilla
+24 -20
View File
@@ -8,6 +8,7 @@
#define mozilla_dom_FileList_h
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/UnionTypes.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDOMFileList.h"
#include "nsWrapperCache.h"
@@ -39,15 +40,13 @@ public:
return mParent;
}
bool Append(File* aFile)
{
return mFiles.AppendElement(aFile);
}
void Append(File* aFile);
void Append(Directory* aDirectory);
bool Remove(uint32_t aIndex)
{
if (aIndex < mFiles.Length()) {
mFiles.RemoveElementAt(aIndex);
if (aIndex < mFilesOrDirectories.Length()) {
mFilesOrDirectories.RemoveElementAt(aIndex);
return true;
}
@@ -56,7 +55,7 @@ public:
void Clear()
{
return mFiles.Clear();
return mFilesOrDirectories.Clear();
}
static FileList* FromSupports(nsISupports* aSupports)
@@ -76,29 +75,34 @@ public:
return static_cast<FileList*>(aSupports);
}
File* Item(uint32_t aIndex)
const OwningFileOrDirectory& UnsafeItem(uint32_t aIndex) const
{
return mFiles.SafeElementAt(aIndex);
MOZ_ASSERT(aIndex < Length());
return mFilesOrDirectories[aIndex];
}
File* IndexedGetter(uint32_t aIndex, bool& aFound)
void Item(uint32_t aIndex,
Nullable<OwningFileOrDirectory>& aFileOrDirectory,
ErrorResult& aRv) const;
void IndexedGetter(uint32_t aIndex, bool& aFound,
Nullable<OwningFileOrDirectory>& aFileOrDirectory,
ErrorResult& aRv) const;
uint32_t Length() const
{
aFound = aIndex < mFiles.Length();
if (!aFound) {
return nullptr;
}
return mFiles.ElementAt(aIndex);
return mFilesOrDirectories.Length();
}
uint32_t Length()
{
return mFiles.Length();
}
void ToSequence(Sequence<OwningFileOrDirectory>& aSequence,
ErrorResult& aRv) const;
bool ClonableToDifferentThreadOrProcess() const;
private:
~FileList() {}
nsTArray<RefPtr<File>> mFiles;
nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
nsCOMPtr<nsISupports> mParent;
};
+20 -8
View File
@@ -125,7 +125,7 @@ FormData::Append(const nsAString& aName, Blob& aBlob,
return;
}
AddNameBlobPair(aName, file);
AddNameBlobOrNullPair(aName, file);
}
void
@@ -179,12 +179,18 @@ FormData::Has(const nsAString& aName)
}
nsresult
FormData::AddNameBlobPair(const nsAString& aName, Blob* aBlob)
FormData::AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob)
{
MOZ_ASSERT(aBlob);
RefPtr<File> file;
if (!aBlob) {
FormDataTuple* data = mFormData.AppendElement();
SetNameValuePair(data, aName, EmptyString(), true /* aWasNullBlob */);
return NS_OK;
}
ErrorResult rv;
RefPtr<File> file = GetOrCreateFileCalledBlob(*aBlob, rv);
file = GetOrCreateFileCalledBlob(*aBlob, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
@@ -269,10 +275,12 @@ FormData::GetValueAtIndex(uint32_t aIndex) const
void
FormData::SetNameValuePair(FormDataTuple* aData,
const nsAString& aName,
const nsAString& aValue)
const nsAString& aValue,
bool aWasNullBlob)
{
MOZ_ASSERT(aData);
aData->name = aName;
aData->wasNullBlob = aWasNullBlob;
aData->value.SetAsUSVString() = aValue;
}
@@ -285,6 +293,7 @@ FormData::SetNameFilePair(FormDataTuple* aData,
MOZ_ASSERT(aFile);
aData->name = aName;
aData->wasNullBlob = false;
aData->value.SetAsBlob() = aFile;
}
@@ -366,13 +375,16 @@ FormData::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].value.IsBlob()) {
fs.AddNameBlobPair(mFormData[i].name, mFormData[i].value.GetAsBlob());
if (mFormData[i].wasNullBlob) {
MOZ_ASSERT(mFormData[i].value.IsUSVString());
fs.AddNameBlobOrNullPair(mFormData[i].name, nullptr);
} else if (mFormData[i].value.IsUSVString()) {
fs.AddNameValuePair(mFormData[i].name,
mFormData[i].value.GetAsUSVString());
} else {
MOZ_CRASH("This should no be possible.");
MOZ_ASSERT(mFormData[i].value.IsBlob());
fs.AddNameBlobOrNullPair(mFormData[i].name,
mFormData[i].value.GetAsBlob());
}
}
+5 -3
View File
@@ -35,6 +35,7 @@ private:
struct FormDataTuple
{
nsString name;
bool wasNullBlob;
OwningBlobOrUSVString value;
};
@@ -45,7 +46,8 @@ private:
void SetNameValuePair(FormDataTuple* aData,
const nsAString& aName,
const nsAString& aValue);
const nsAString& aValue,
bool aWasNullBlob = false);
void SetNameFilePair(FormDataTuple* aData,
const nsAString& aName,
@@ -114,8 +116,8 @@ public:
return NS_OK;
}
virtual nsresult AddNameBlobPair(const nsAString& aName,
Blob* aBlob) override;
virtual nsresult AddNameBlobOrNullPair(const nsAString& aName,
Blob* aBlob) override;
typedef bool (*FormDataEntryCallback)(const nsString& aName,
const OwningBlobOrUSVString& aValue,
+87 -39
View File
@@ -10,6 +10,7 @@
#include "mozilla/AutoRestore.h"
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/CryptoKey.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileList.h"
#include "mozilla/dom/FileListBinding.h"
@@ -723,36 +724,59 @@ ReadFileList(JSContext* aCx,
{
RefPtr<FileList> fileList = new FileList(aHolder->ParentDuringRead());
uint32_t tag, offset;
// Offset is the index of the blobImpl from which we can find the blobImpl
// for this FileList.
if (!JS_ReadUint32Pair(aReader, &tag, &offset)) {
return nullptr;
}
MOZ_ASSERT(tag == 0);
// |aCount| is the number of BlobImpls to use from the |offset|.
// |aCount| is the number of Files or Directory for this FileList.
for (uint32_t i = 0; i < aCount; ++i) {
uint32_t index = offset + i;
MOZ_ASSERT(index < aHolder->BlobImpls().Length());
RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[index];
MOZ_ASSERT(blobImpl->IsFile());
ErrorResult rv;
blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
uint32_t tagOrDirectoryType, indexOrLengthOfString;
if (!JS_ReadUint32Pair(aReader, &tagOrDirectoryType,
&indexOrLengthOfString)) {
return nullptr;
}
MOZ_ASSERT(blobImpl);
MOZ_ASSERT(tagOrDirectoryType == SCTAG_DOM_BLOB ||
tagOrDirectoryType == Directory::eDOMRootDirectory ||
tagOrDirectoryType == Directory::eNotDOMRootDirectory);
RefPtr<File> file = File::Create(aHolder->ParentDuringRead(), blobImpl);
if (!fileList->Append(file)) {
if (tagOrDirectoryType == SCTAG_DOM_BLOB) {
MOZ_ASSERT(indexOrLengthOfString < aHolder->BlobImpls().Length());
RefPtr<BlobImpl> blobImpl =
aHolder->BlobImpls()[indexOrLengthOfString];
MOZ_ASSERT(blobImpl->IsFile());
ErrorResult rv;
blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return nullptr;
}
RefPtr<File> file =
File::Create(aHolder->ParentDuringRead(), blobImpl);
MOZ_ASSERT(file);
fileList->Append(file);
continue;
}
nsAutoString path;
path.SetLength(indexOrLengthOfString);
size_t charSize = sizeof(nsString::char_type);
if (!JS_ReadBytes(aReader, (void*) path.BeginWriting(),
indexOrLengthOfString * charSize)) {
return nullptr;
}
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
RefPtr<Directory> directory =
Directory::Create(aHolder->ParentDuringRead(), file,
(Directory::DirectoryType) tagOrDirectoryType);
fileList->Append(directory);
}
if (!ToJSValue(aCx, fileList, &val)) {
@@ -765,7 +789,13 @@ ReadFileList(JSContext* aCx,
// The format of the FileList serialization is:
// - pair of ints: SCTAG_DOM_FILELIST, Length of the FileList
// - pair of ints: 0, The offset of the BlobImpl array
// - for each element of the FileList:
// - if it's a blob:
// - pair of ints: SCTAG_DOM_BLOB, index of the BlobImpl in the array
// mBlobImplArray.
// - else:
// - pair of ints: 0/1 is root, string length
// - value string
bool
WriteFileList(JSStructuredCloneWriter* aWriter,
FileList* aFileList,
@@ -775,13 +805,8 @@ WriteFileList(JSStructuredCloneWriter* aWriter,
MOZ_ASSERT(aFileList);
MOZ_ASSERT(aHolder);
// A FileList is serialized writing the X number of elements and the offset
// from mBlobImplArray. The Read will take X elements from mBlobImplArray
// starting from the offset.
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
aFileList->Length()) ||
!JS_WriteUint32Pair(aWriter, 0,
aHolder->BlobImpls().Length())) {
aFileList->Length())) {
return false;
}
@@ -789,18 +814,39 @@ WriteFileList(JSStructuredCloneWriter* aWriter,
nsTArray<RefPtr<BlobImpl>> blobImpls;
for (uint32_t i = 0; i < aFileList->Length(); ++i) {
RefPtr<BlobImpl> blobImpl =
EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl(), nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return false;
const OwningFileOrDirectory& data = aFileList->UnsafeItem(i);
if (data.IsFile()) {
RefPtr<BlobImpl> blobImpl =
EnsureBlobForBackgroundManager(data.GetAsFile()->Impl(), nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return false;
}
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
aHolder->BlobImpls().Length())) {
return false;
}
aHolder->BlobImpls().AppendElement(blobImpl);
continue;
}
MOZ_ASSERT(blobImpl);
blobImpls.AppendElement(blobImpl);
MOZ_ASSERT(data.IsDirectory());
nsAutoString path;
data.GetAsDirectory()->GetFullRealPath(path);
size_t charSize = sizeof(nsString::char_type);
if (!JS_WriteUint32Pair(aWriter,
(uint32_t)data.GetAsDirectory()->Type(),
path.Length()) ||
!JS_WriteBytes(aWriter, path.get(), path.Length() * charSize)) {
return false;
}
}
aHolder->BlobImpls().AppendElements(blobImpls);
return true;
}
@@ -1004,7 +1050,9 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
// See if this is a FileList object.
{
FileList* fileList = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList)) &&
(mSupportedContext == SameProcessSameThread ||
fileList->ClonableToDifferentThreadOrProcess())) {
return WriteFileList(aWriter, fileList, this);
}
}
-1
View File
@@ -7576,7 +7576,6 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
// has this data available to it when passed over:
blobImpl->GetSize(rv);
blobImpl->GetLastModified(rv);
blobImpl->LookupAndCacheIsDirectory();
} else {
if (aInSyncMessage) {
// Can't do anything.
+1 -1
View File
@@ -5,7 +5,7 @@
#include "nsISupports.idl"
[uuid(57128a85-34de-42db-a252-84dd57724a59)]
[builtinclass, uuid(57128a85-34de-42db-a252-84dd57724a59)]
interface nsIDOMFileList : nsISupports
{
readonly attribute unsigned long length;
+60
View File
@@ -0,0 +1,60 @@
const CC = Components.Constructor;
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream");
function utf8decode(s) {
return decodeURIComponent(escape(s));
}
function utf8encode(s) {
return unescape(encodeURIComponent(s));
}
function handleRequest(request, response) {
var bodyStream = new BinaryInputStream(request.bodyInputStream);
var requestBody = "";
while ((bodyAvail = bodyStream.available()) > 0) {
requestBody += bodyStream.readBytes(bodyAvail);
}
var result = [];
if (request.method == "POST") {
var contentTypeParams = {};
request.getHeader("Content-Type").split(/\s*\;\s*/).forEach(function(s) {
if (s.indexOf('=') >= 0) {
let [name, value] = s.split('=');
contentTypeParams[name] = value;
}
else {
contentTypeParams[''] = s;
}
});
if (contentTypeParams[''] == "multipart/form-data" &&
request.queryString == "") {
requestBody.split("--" + contentTypeParams.boundary).slice(1, -1).forEach(function (s) {
let headers = {};
let headerEnd = s.indexOf("\r\n\r\n");
s.substr(2, headerEnd-2).split("\r\n").forEach(function(s) {
// We're assuming UTF8 for now
let [name, value] = s.split(': ');
headers[name] = utf8decode(value);
});
let body = s.substring(headerEnd + 4, s.length - 2);
if (!headers["Content-Type"] || headers["Content-Type"] == "text/plain") {
// We're assuming UTF8 for now
body = utf8decode(body);
}
result.push({ headers: headers, body: body});
});
}
}
response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
response.write(utf8encode(JSON.stringify(result)));
}
+3
View File
@@ -257,6 +257,7 @@ support-files =
referrer_change_server.sjs
file_change_policy_redirect.html
file_bug1198095.js
file_bug1250148.sjs
[test_anonymousContent_api.html]
[test_anonymousContent_append_after_reflow.html]
@@ -848,3 +849,5 @@ skip-if = buildapp == 'b2g' #no ssl support
[test_document.all_iteration.html]
[test_bug1198095.html]
[test_bug1187157.html]
[test_bug769117.html]
[test_bug1250148.html]
+17 -7
View File
@@ -1,15 +1,25 @@
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.importGlobalProperties(["File"]);
let testFile = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIDirectoryService)
.QueryInterface(Ci.nsIProperties)
.get("ProfD", Ci.nsIFile);
testFile.append("prefs.js");
addMessageListener("file.open", function () {
var testFile = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIDirectoryService)
.QueryInterface(Ci.nsIProperties)
.get("ProfD", Ci.nsIFile);
testFile.append("prefs.js");
sendAsyncMessage("file.opened", {
file: new File(testFile)
});
});
addMessageListener("dir.open", function () {
var testFile = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIDirectoryService)
.QueryInterface(Ci.nsIProperties)
.get("ProfD", Ci.nsIFile);
sendAsyncMessage("dir.opened", {
dir: testFile.path
});
});
+1 -7
View File
@@ -15,14 +15,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=789315
<script type="text/javascript">
var obj = new FormData(document.getElementById('a')).get('b');
is(obj, "", "We want an empty string.");
ok(obj instanceof Blob, "This should return an empty Blob");
is(obj.size, 0, "Size should be 0");
is(obj.type, "application/octet-stream", "Type should be application/octet-stream");
var o = obj.slice(10, 100, "foo/bar");
is(o.size, 0, "The new blob has size 0");
is(o.type, "foo/bar", "The new blob has type foo/bar");
</script>
</body>
+52
View File
@@ -0,0 +1,52 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1250148
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1250148 - FormData and HTML submission compatibility</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<form id="form" enctype="multipart/form-data"><input type="file" name="test" /></form>
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
var f = document.getElementById('form');
var fd = new FormData(f);
is(fd.get("test"), "", "We want an empty string.");
var getAll = fd.getAll("test");
ok(Array.isArray(getAll), "We want an array with 1 empty string.");
is(getAll.length, 1, "We want an array with 1 empty string.");
is(getAll[0], "", "We want an array with 1 empty string.");
var xhr = new XMLHttpRequest();
xhr.open("POST", "file_bug1250148.sjs", true);
xhr.onload = function() {
var obj = JSON.parse(xhr.responseText);
ok(Array.isArray(obj), "XHR response is an array.");
is(obj.length, 1, "XHR response array contains 1 result.");
ok("headers" in obj[0], "XHR response has an header value");
ok("Content-Disposition" in obj[0].headers, "XHR response.headers array has a Content-Desposition value");
is(obj[0].headers["Content-Disposition"], "form-data; name=\"test\"; filename=\"\"", "Correct Content-Disposition");
ok("Content-Type" in obj[0].headers, "XHR response.headers array has a Content-Type value");
is(obj[0].headers["Content-Type"], "application/octet-stream", "Correct Content-Type");
ok("body" in obj[0], "XHR response has a body value");
is(obj[0].body, "", "Correct body value");
SimpleTest.finish();
}
xhr.send(fd);
</script>
</body>
</html>
+51
View File
@@ -0,0 +1,51 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=769117
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 769117</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
/** Test for Bug 769117 **/
"use strict";
function onLoad () {
let youtube_url = "https://mochitest.youtube.com/v/Xm5i5kbIXzc";
let youtube_changed_url = "https://mochitest.youtube.com/embed/Xm5i5kbIXzc";
function testEmbed(embed) {
ok (embed, "Embed node exists");
embed = SpecialPowers.wrap(embed);
is (embed.srcURI.spec, youtube_changed_url, "Should have src uri of " + youtube_changed_url);
}
info("Running static embed youtube rewrite test");
testEmbed(document.getElementById("testembed"));
testEmbed(document.getElementById("testobject"));
info("Running dynamic embed youtube rewrite test");
let embed_dynamic = document.createElement("embed");
embed_dynamic.src = "https://mochitest.youtube.com/v/Xm5i5kbIXzc";
embed_dynamic.type = "application/x-shockwave-flash";
document.body.appendChild(embed_dynamic);
SimpleTest.executeSoon(() =>
{
testEmbed(embed_dynamic);
SimpleTest.finish();
});
}
</script>
</head>
<body onload="onLoad()">
<embed id="testembed"
src="https://mochitest.youtube.com/v/Xm5i5kbIXzc"
type="application/x-shockwave-flash"
allowscriptaccess="always"></embed>
<object id="testobject"
data="https://mochitest.youtube.com/v/Xm5i5kbIXzc"></embed>
</body>
</html>
+51 -14
View File
@@ -61,18 +61,18 @@ function compare(a, b) {
}
var clonableObjects = [
'hello world',
123,
null,
true,
new Date(),
[ 1, 'test', true, new Date() ],
{ a: true, b: null, c: new Date(), d: [ true, false, {} ] },
new Blob([123], { type: 'plain/text' }),
new ImageData(2, 2),
{ crossThreads: true, data: 'hello world' },
{ crossThreads: true, data: 123 },
{ crossThreads: true, data: null },
{ crossThreads: true, data: true },
{ crossThreads: true, data: new Date() },
{ crossThreads: true, data: [ 1, 'test', true, new Date() ] },
{ crossThreads: true, data: { a: true, b: null, c: new Date(), d: [ true, false, {} ] } },
{ crossThreads: true, data: new Blob([123], { type: 'plain/text' }) },
{ crossThreads: true, data: new ImageData(2, 2) },
];
function create_fileList() {
function create_fileList_forFile() {
var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
var script = SpecialPowers.loadChromeScript(url);
@@ -84,7 +84,7 @@ function create_fileList() {
var domFile = fileList.files[0];
is(domFile.name, "prefs.js", "fileName should be prefs.js");
clonableObjects.push(fileList.files);
clonableObjects.push({ crossThreads: true, data: fileList.files });
script.destroy();
next();
}
@@ -93,6 +93,27 @@ function create_fileList() {
script.sendAsyncMessage("file.open");
}
function create_fileList_forDir() {
var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
var script = SpecialPowers.loadChromeScript(url);
function onOpened(message) {
var fileList = document.getElementById('fileList');
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
// Just a simple test
is(fileList.files.length, 1, "Filelist has 1 element");
ok(fileList.files[0] instanceof Directory, "We have a directory.");
clonableObjects.push({ crossThreads: false, data: fileList.files });
script.destroy();
next();
}
script.addMessageListener("dir.opened", onOpened);
script.sendAsyncMessage("dir.open");
}
function runTests(obj) {
ok(('clonableObjects' in obj) &&
('transferableObjects' in obj) &&
@@ -113,8 +134,16 @@ function runTests(obj) {
}
var object = clonableObjects[clonableObjectsId++];
obj.send(object, []).then(function(received) {
compare(received.data, object);
// If this test requires a cross-thread structured clone algorithm, maybe
// we have to skip it.
if (!object.crossThread && obj.crossThread) {
runClonableTest();
return;
}
obj.send(object.data, []).then(function(received) {
compare(received.data, object.data);
runClonableTest();
});
}
@@ -203,6 +232,7 @@ function test_windowToWindow() {
runTests({
clonableObjects: true,
transferableObjects: true,
crossThread: false,
send: function(what, ports) {
return new Promise(function(r, rr) {
resolve = r;
@@ -256,6 +286,7 @@ function test_windowToIframeURL(url) {
runTests({
clonableObjects: true,
transferableObjects: true,
crossThread: false,
send: function(what, ports) {
return new Promise(function(r, rr) {
resolve = r;
@@ -303,6 +334,7 @@ function test_workers() {
runTests({
clonableObjects: true,
transferableObjects: true,
crossThread: true,
send: function(what, ports) {
return new Promise(function(r, rr) {
resolve = r;
@@ -346,6 +378,7 @@ function test_broadcastChannel() {
runTests({
clonableObjects: true,
transferableObjects: false,
crossThread: true,
send: function(what, ports) {
return new Promise(function(r, rr) {
if (ports.length) {
@@ -391,6 +424,7 @@ function test_broadcastChannel_inWorkers() {
runTests({
clonableObjects: true,
transferableObjects: false,
crossThread: true,
send: function(what, ports) {
return new Promise(function(r, rr) {
if (ports.length) {
@@ -432,6 +466,7 @@ function test_messagePort() {
runTests({
clonableObjects: true,
transferableObjects: true,
crossThread: true,
send: function(what, ports) {
return new Promise(function(r, rr) {
resolve = r;
@@ -477,6 +512,7 @@ function test_messagePort_inWorkers() {
runTests({
clonableObjects: true,
transferableObjects: true,
crossThread: true,
send: function(what, ports) {
return new Promise(function(r, rr) {
resolve = r;
@@ -498,7 +534,8 @@ function test_messagePort_inWorkers() {
}
var tests = [
create_fileList,
create_fileList_forFile,
create_fileList_forDir,
test_windowToWindow,
test_windowToIframe,
@@ -26,6 +26,7 @@
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsServiceManagerUtils.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
@@ -520,12 +521,7 @@ BrowserElementAudioChannel::NotifyChannel(const nsAString& aEvent,
do_GetService("@mozilla.org/system-message-internal;1");
MOZ_ASSERT(systemMessenger);
AutoJSAPI jsAPI;
if (!jsAPI.Init(GetOwner())) {
return nullptr;
}
JS::Rooted<JS::Value> value(jsAPI.cx());
JS::Rooted<JS::Value> value(nsContentUtils::RootingCxForThread());
value.setInt32((uint32_t)mAudioChannel);
nsCOMPtr<nsIURI> manifestURI;
+3 -3
View File
@@ -101,8 +101,9 @@ public:
// we want to make sure that the names of file can't reach
// outside of the type of storage the user asked for.
bool IsSafePath();
bool IsSafePath(const nsAString& aPath);
bool IsSafePath() const;
bool ValidateAndSplitPath(const nsAString& aPath,
nsTArray<nsString>* aParts = nullptr) const;
void Dump(const char* label);
@@ -137,7 +138,6 @@ public:
private:
~DeviceStorageFile() {}
void Init();
void NormalizeFilePath();
void AppendRelativePath(const nsAString& aPath);
void AccumDirectoryUsage(nsIFile* aFile,
uint64_t* aPicturesSoFar,
+10 -10
View File
@@ -573,7 +573,16 @@ DeviceStorageStatics::ResetOverrideRootDir()
nsCOMPtr<nsIFile> f;
DS_LOG_INFO("");
if (Preferences::GetBool(kPrefTesting, false)) {
// For users running on desktop, it's convenient to be able to override
// all of the directories to point to a single tree, much like what happens
// on a real device.
const nsAdoptingString& overrideRootDir =
mozilla::Preferences::GetString(kPrefOverrideRootDir);
if (overrideRootDir && !overrideRootDir.IsEmpty()) {
NS_NewLocalFile(overrideRootDir, false, getter_AddRefs(f));
}
if (!f && Preferences::GetBool(kPrefTesting, false)) {
DS_LOG_INFO("temp");
nsCOMPtr<nsIProperties> dirService
= do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
@@ -583,15 +592,6 @@ DeviceStorageStatics::ResetOverrideRootDir()
f->AppendRelativeNativePath(
NS_LITERAL_CSTRING("device-storage-testing"));
}
} else {
// For users running on desktop, it's convenient to be able to override
// all of the directories to point to a single tree, much like what happens
// on a real device.
const nsAdoptingString& overrideRootDir =
mozilla::Preferences::GetString(kPrefOverrideRootDir);
if (overrideRootDir && !overrideRootDir.IsEmpty()) {
NS_NewLocalFile(overrideRootDir, false, getter_AddRefs(f));
}
}
if (f) {
-8
View File
@@ -1,8 +0,0 @@
{
"runtests":{
},
"excludetests":{
"dom/devicestorage/test/test_dirs.html":"excluded",
"dom/devicestorage/test/test_storageAreaListener.html":"excluded"
}
}
-8
View File
@@ -1,8 +0,0 @@
[DEFAULT]
skip-if = toolkit == 'android' || e10s #bug 781789 & bug 782275
support-files =
../test/devicestorage_common.js
ipc.json
[test_ipc.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(nested ipc not working) b2g-debug(nested ipc not working) b2g-desktop(nested ipc not working)
-173
View File
@@ -1,173 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for OOP DeviceStorage</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
// The crash observer registration functions are stubbed out here to
// prevent the iframe test runner from breaking later crash-related tests.
function iframeScriptFirst() {
SpecialPowers.prototype.registerProcessCrashObservers = () => {};
SpecialPowers.prototype.unregisterProcessCrashObservers = () => {};
content.wrappedJSObject.RunSet.reloadAndRunAll({
preventDefault: function() { },
__exposedProps__: { preventDefault: 'r' }
});
}
function iframeScriptSecond() {
let TestRunner = content.wrappedJSObject.TestRunner;
let oldComplete = TestRunner.onComplete;
TestRunner.onComplete = function() {
TestRunner.onComplete = oldComplete;
sendAsyncMessage("test:DeviceStorage:ipcTestComplete", {
result: JSON.stringify(TestRunner._failedTests)
});
if (oldComplete) {
oldComplete();
}
};
TestRunner.structuredLogger._dumpMessage = function(msg) {
sendAsyncMessage("test:DeviceStorage:ipcTestMessage", { msg: msg });
}
}
let VALID_ACTIONS = ['suite_start', 'suite_end', 'test_start', 'test_end', 'test_status', 'process_output', 'log'];
function validStructuredMessage(message) {
return message.action !== undefined && VALID_ACTIONS.indexOf(message.action) >= 0;
}
function onTestMessage(data) {
let message = SpecialPowers.wrap(data).data.msg;
if (validStructuredMessage(message)) {
switch (message.action) {
case "test_status":
case "test_end":
let test_tokens = message.test.split("/");
let test_name = test_tokens[test_tokens.length - 1];
if (message.subtest) {
test_name += " | " + message.subtest;
}
ok(message.expected === undefined, test_name, message.message);
break;
case "log":
info(message.message);
break;
default:
// nothing
}
}
}
function onTestComplete() {
let comp = SpecialPowers.wrap(SpecialPowers.Components);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
let spObserver = comp.classes["@mozilla.org/special-powers-observer;1"]
.getService(comp.interfaces.nsIMessageListener);
mm.removeMessageListener("SPPrefService", spObserver);
mm.removeMessageListener("SPProcessCrashService", spObserver);
mm.removeMessageListener("SPPingService", spObserver);
mm.removeMessageListener("SpecialPowers.Quit", spObserver);
mm.removeMessageListener("SPPermissionManager", spObserver);
mm.removeMessageListener("test:DeviceStorage:ipcTestMessage", onTestMessage);
mm.removeMessageListener("test:DeviceStorage:ipcTestComplete", onTestComplete);
SimpleTest.executeSoon(function () { SimpleTest.finish(); });
}
function runTests() {
let iframe = document.createElement("iframe");
SpecialPowers.wrap(iframe).mozbrowser = true;
iframe.id = "iframe";
iframe.style.width = "100%";
iframe.style.height = "1000px";
function iframeLoadSecond() {
ok(true, "Got second iframe load event.");
iframe.removeEventListener("mozbrowserloadend", iframeLoadSecond);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
mm.loadFrameScript("data:,(" + iframeScriptSecond.toString() + ")();",
false);
}
function iframeLoadFirst() {
ok(true, "Got first iframe load event.");
iframe.removeEventListener("mozbrowserloadend", iframeLoadFirst);
iframe.addEventListener("mozbrowserloadend", iframeLoadSecond);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
let comp = SpecialPowers.wrap(SpecialPowers.Components);
let spObserver =
comp.classes["@mozilla.org/special-powers-observer;1"]
.getService(comp.interfaces.nsIMessageListener);
mm.addMessageListener("SPPrefService", spObserver);
mm.addMessageListener("SPProcessCrashService", spObserver);
mm.addMessageListener("SPPingService", spObserver);
mm.addMessageListener("SpecialPowers.Quit", spObserver);
mm.addMessageListener("SPPermissionManager", spObserver);
mm.addMessageListener("test:DeviceStorage:ipcTestMessage", onTestMessage);
mm.addMessageListener("test:DeviceStorage:ipcTestComplete", onTestComplete);
let specialPowersBase = "chrome://specialpowers/content/";
mm.loadFrameScript(specialPowersBase + "MozillaLogger.js", false);
mm.loadFrameScript(specialPowersBase + "specialpowersAPI.js", false);
mm.loadFrameScript(specialPowersBase + "specialpowers.js", false);
mm.loadFrameScript("data:,(" + iframeScriptFirst.toString() + ")();", false);
}
iframe.addEventListener("mozbrowserloadend", iframeLoadFirst);
// Strip this filename and one directory level and then add "/test".
let href = window.location.href;
href = href.substring(0, href.lastIndexOf('/'));
href = href.substring(0, href.lastIndexOf('/'));
let manifest = "tests/dom/devicestorage/ipc/ipc.json";
iframe.src = href + "/test?consoleLevel=INFO&testManifest=" + manifest;
document.body.appendChild(iframe);
}
addEventListener("load", function() {
SpecialPowers.addPermission("browser", true, document);
SpecialPowers.pushPrefEnv({
"set": [
["device.storage.enabled", true],
["device.storage.testing", true],
["device.storage.prompt.testing", true],
// TODO: remove this as part of bug 820712
["network.disable.ipc.security", true],
["dom.ipc.browser_frames.oop_by_default", true],
["dom.mozBrowserFramesEnabled", true],
["browser.pagethumbnails.capturing_disabled", true]
]
}, runTests);
});
</script>
</body>
</html>
-1
View File
@@ -41,7 +41,6 @@ LOCAL_INCLUDES += [
]
MOCHITEST_MANIFESTS += [
'ipc/mochitest.ini',
'test/mochitest.ini',
]
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
+70 -34
View File
@@ -30,6 +30,7 @@
#include "nsArrayUtils.h"
#include "nsAutoPtr.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsGlobalWindow.h"
#include "nsServiceManagerUtils.h"
#include "nsIFile.h"
@@ -76,10 +77,35 @@ using namespace mozilla::dom;
using namespace mozilla::dom::devicestorage;
using namespace mozilla::ipc;
namespace mozilla {
namespace mozilla
{
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, PR_Close);
} // namespace mozilla
namespace {
void
NormalizeFilePath(nsAString& aPath)
{
#if defined(XP_WIN)
char16_t* cur = aPath.BeginWriting();
char16_t* end = aPath.EndWriting();
for (; cur < end; ++cur) {
if (char16_t('\\') == *cur) {
*cur = FILESYSTEM_DOM_PATH_SEPARATOR_CHAR;
}
}
#endif
}
bool
TokenizerIgnoreNothing(char16_t /* aChar */)
{
return false;
}
} // anonymous namespace
StaticAutoPtr<DeviceStorageUsedSpaceCache>
DeviceStorageUsedSpaceCache::sDeviceStorageUsedSpaceCache;
@@ -510,7 +536,8 @@ DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType,
if (!mPath.EqualsLiteral("")) {
AppendRelativePath(mPath);
}
NormalizeFilePath();
NormalizeFilePath(mPath);
}
DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType,
@@ -525,7 +552,7 @@ DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType,
{
Init();
AppendRelativePath(aPath);
NormalizeFilePath();
NormalizeFilePath(mPath);
}
DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType,
@@ -734,7 +761,7 @@ DeviceStorageFile::CreateUnique(const nsAString& aStorageType,
void
DeviceStorageFile::SetPath(const nsAString& aPath) {
mPath.Assign(aPath);
NormalizeFilePath();
NormalizeFilePath(mPath);
}
void
@@ -745,13 +772,14 @@ DeviceStorageFile::SetEditable(bool aEditable) {
// we want to make sure that the names of file can't reach
// outside of the type of storage the user asked for.
bool
DeviceStorageFile::IsSafePath()
DeviceStorageFile::IsSafePath() const
{
return IsSafePath(mRootDir) && IsSafePath(mPath);
return ValidateAndSplitPath(mRootDir) && ValidateAndSplitPath(mPath);
}
bool
DeviceStorageFile::IsSafePath(const nsAString& aPath)
DeviceStorageFile::ValidateAndSplitPath(const nsAString& aPath,
nsTArray<nsString>* aParts) const
{
nsAString::const_iterator start, end;
aPath.BeginReading(start);
@@ -764,33 +792,43 @@ DeviceStorageFile::IsSafePath(const nsAString& aPath)
StringBeginsWith(aPath, tildeSlash)) {
NS_WARNING("Path name starts with tilde!");
return false;
}
// split on /. if any token is "", ., or .., return false.
NS_ConvertUTF16toUTF8 cname(aPath);
char* buffer = cname.BeginWriting();
const char* token;
}
while ((token = nsCRT::strtok(buffer, "/", &buffer))) {
if (PL_strcmp(token, "") == 0 ||
PL_strcmp(token, ".") == 0 ||
PL_strcmp(token, "..") == 0 ) {
NS_NAMED_LITERAL_STRING(kCurrentDir, ".");
NS_NAMED_LITERAL_STRING(kParentDir, "..");
// Split path and check each path component.
nsCharSeparatedTokenizerTemplate<TokenizerIgnoreNothing>
tokenizer(aPath, FILESYSTEM_DOM_PATH_SEPARATOR_CHAR);
while (tokenizer.hasMoreTokens()) {
nsDependentSubstring pathComponent = tokenizer.nextToken();
// The path containing empty components, such as "foo//bar", is invalid.
// We don't allow paths, such as "../foo", "foo/./bar" and "foo/../bar",
// to walk up the directory.
if (pathComponent.IsEmpty() ||
pathComponent.Equals(kCurrentDir) ||
pathComponent.Equals(kParentDir)) {
return false;
}
if (aParts) {
aParts->AppendElement(pathComponent);
}
}
return true;
}
void
DeviceStorageFile::NormalizeFilePath() {
FileSystemUtils::LocalPathToNormalizedPath(mPath, mPath);
}
void
DeviceStorageFile::AppendRelativePath(const nsAString& aPath) {
DeviceStorageFile::AppendRelativePath(const nsAString& aPath)
{
if (!mFile) {
return;
}
if (!IsSafePath(aPath)) {
nsTArray<nsString> parts;
if (!ValidateAndSplitPath(aPath, &parts)) {
// All of the APIs (in the child) do checks to verify that the path is
// valid and return PERMISSION_DENIED if a non-safe path is entered.
// This check is done in the parent and prevents a compromised
@@ -800,9 +838,13 @@ DeviceStorageFile::AppendRelativePath(const nsAString& aPath) {
NS_WARNING(NS_LossyConvertUTF16toASCII(aPath).get());
return;
}
nsString localPath;
FileSystemUtils::NormalizedPathToLocalPath(aPath, localPath);
mFile->AppendRelativePath(localPath);
for (uint32_t i = 0; i < parts.Length(); ++i) {
nsresult rv = mFile->AppendRelativePath(parts[i]);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
}
}
nsresult
@@ -3932,14 +3974,8 @@ DeviceStorageRequestManager::Resolve(uint32_t aId, uint64_t aValue,
return NS_OK;
}
nsIGlobalObject* global = mPending[i].mRequest->GetOwnerGlobal();
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(global))) {
return RejectInternal(i, NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN));
}
JS::RootedValue value(jsapi.cx(), JS_NumberValue((double)aValue));
JS::RootedValue value(nsContentUtils::RootingCxForThread(),
JS_NumberValue((double)aValue));
return ResolveInternal(i, value);
}
+20 -30
View File
@@ -4,7 +4,7 @@
*/
var oldVal = false;
Object.defineProperty(Array.prototype, "remove", {
enumerable: false,
configurable: false,
@@ -17,36 +17,26 @@ Object.defineProperty(Array.prototype, "remove", {
}
});
function devicestorage_setup() {
// ensure that the directory we are writing into is empty
try {
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
var directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
f.remove(true);
} catch(e) {}
function devicestorage_setup(callback) {
SimpleTest.waitForExplicitFinish();
if (SpecialPowers.isMainProcess()) {
try {
oldVal = SpecialPowers.getBoolPref("device.storage.enabled");
} catch(e) {}
SpecialPowers.setBoolPref("device.storage.enabled", true);
SpecialPowers.setBoolPref("device.storage.testing", true);
SpecialPowers.setBoolPref("device.storage.prompt.testing", true);
}
}
function devicestorage_cleanup() {
if (SpecialPowers.isMainProcess()) {
SpecialPowers.setBoolPref("device.storage.enabled", oldVal);
SpecialPowers.setBoolPref("device.storage.testing", false);
SpecialPowers.setBoolPref("device.storage.prompt.testing", false);
}
SimpleTest.finish();
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
var directoryService = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
let script = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('remove_testing_directory.js'));
script.addMessageListener('directory-removed', function listener () {
script.removeMessageListener('directory-removed', listener);
var prefs = [["device.storage.enabled", true],
["device.storage.testing", true],
["device.storage.overrideRootDir", f.path],
["device.storage.prompt.testing", true]];
SpecialPowers.pushPrefEnv({"set": prefs}, callback);
});
}
function getRandomBuffer() {
@@ -75,7 +65,7 @@ function randomFilename(l) {
function reportErrorAndQuit(e) {
ok(false, "handleError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function createTestFiles(storage, paths) {
+3 -1
View File
@@ -1,6 +1,7 @@
[DEFAULT]
skip-if = e10s || (toolkit == 'android' && processor == 'x86') # bug 781789 & bug 782275
skip-if = (toolkit == 'android' && processor == 'x86') # Android: bug 781789 & bug 782275
support-files = devicestorage_common.js
remove_testing_directory.js
[test_823965.html]
# [test_add.html]
@@ -9,6 +10,7 @@ support-files = devicestorage_common.js
[test_available.html]
[test_basic.html]
[test_dirs.html]
skip-if = e10s # Bug 1063569.
# [test_diskSpace.html]
# Possible race between the time we write a file, and the
# time it takes to be reflected by statfs(). Bug # 791287
@@ -0,0 +1,11 @@
// ensure that the directory we are writing into is empty
try {
var Cc = Components.classes;
var Ci = Components.interfaces;
var directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
f.remove(true);
} catch(e) {}
sendAsyncMessage('directory-removed', {});
+7 -6
View File
@@ -22,7 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=823965
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
var gFileName = "devicestorage/" + randomFilename(12) + "/hi.png";
var gData = "My name is Doug Turner (?!?). My IRC nick is DougT. I like Maple cookies."
@@ -43,11 +43,11 @@ function getSuccess(e) {
var dreq = storage2.delete(mreq.result.name);
dreq.onerror = function () {
ok(true, "The bug has been fixed");
devicestorage_cleanup();
SimpleTest.finish();
};
dreq.onsuccess = function () {
ok(false, "The bug has been fixed");
devicestorage_cleanup();
SimpleTest.finish();
};
};
@@ -56,7 +56,7 @@ function getSuccess(e) {
function getError(e) {
ok(false, "getError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@@ -85,7 +85,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
@@ -99,8 +99,9 @@ ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>
+7 -6
View File
@@ -18,13 +18,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=786922
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=786922">Mozilla Bug 786922</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function add(storage, mime) {
dump("adding: " + mime + "\n");
@@ -40,18 +40,18 @@ var tests = [
function fail(e) {
ok(false, "onerror was called");
devicestorage_cleanup();
SimpleTest.finish();
}
function next(e) {
if (e != undefined)
ok(true, "addError was called");
var f = tests.pop();
if (f == undefined) {
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@@ -62,8 +62,9 @@ function next(e) {
next();
});
</script>
</pre>
</body>
</html>
@@ -18,13 +18,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=786922
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=786922">Mozilla Bug 786922</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function addNamed(storage, mime, fileExtension) {
dump("adding: " + mime + " " + fileExtension + "\n");
@@ -45,18 +45,18 @@ function fail(e) {
ok(false, "addSuccess was called");
ok(e.target.error.name == "TypeMismatchError", "Error must be TypeMismatchError");
devicestorage_cleanup();
SimpleTest.finish();
}
function next(e) {
if (e != undefined)
ok(true, "addError was called");
var f = tests.pop();
if (f == undefined) {
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@@ -67,8 +67,9 @@ function next(e) {
next();
});
</script>
</pre>
</body>
</html>
+5 -3
View File
@@ -22,16 +22,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=834595
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function availableSuccess(e) {
isnot(e.target.result, null, "result should not be null");
devicestorage_cleanup();
SimpleTest.finish();
}
function availableError(e) {
ok(false, "availableError was called");
devicestorage_cleanup();
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
@@ -42,6 +42,8 @@ ok(request, "Should have a non-null request");
request.onsuccess = availableSuccess;
request.onerror = availableError;
});
</script>
</pre>
</body>
+9 -8
View File
@@ -17,12 +17,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function() {
var gFileName = "devicestorage/" + randomFilename(12) + "/hi.png";
var gData = "My name is Doug Turner. My IRC nick is DougT. I like Maple cookies."
@@ -31,12 +31,12 @@ var gFileReader = new FileReader();
function getAfterDeleteSuccess(e) {
ok(false, "file was deleted not successfully");
devicestorage_cleanup();
SimpleTest.finish();
}
function getAfterDeleteError(e) {
ok(true, "file was deleted successfully");
devicestorage_cleanup();
SimpleTest.finish();
}
function deleteSuccess(e) {
@@ -53,7 +53,7 @@ function deleteSuccess(e) {
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function getSuccess(e) {
@@ -88,7 +88,7 @@ function readerCallback(e) {
function getError(e) {
ok(false, "getError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@@ -119,7 +119,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
@@ -133,8 +133,9 @@ ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>
+6 -6
View File
@@ -17,13 +17,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
var freeBytes = -1;
var stats = 0;
@@ -39,7 +38,7 @@ function stat(s, file_list_length) {
stats = stats + 1;
if (stats == 2) {
devicestorage_cleanup();
SimpleTest.finish();
}
}
@@ -60,7 +59,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
ok(true, "hi");
@@ -94,8 +93,9 @@ for (var i=0; i < music_files.length; i++) {
request.onerror = addError;
}
});
</script>
</pre>
</body>
</html>
+6 -7
View File
@@ -17,12 +17,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function testingStorage() {
return navigator.getDeviceStorage("pictures");
@@ -40,20 +40,20 @@ var gFileName = "../owned.png";
function fail(e) {
ok(false, "addSuccess was called");
dump(request);
devicestorage_cleanup();
SimpleTest.finish();
}
function next(e) {
if (e != undefined) {
ok(true, "addError was called");
ok(true, "addError was called");
ok(e.target.error.name == "SecurityError", "Error must be SecurityError");
}
var f = tests.pop();
if (f == undefined) {
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@@ -64,10 +64,9 @@ function next(e) {
next();
});
</script>
</pre>
</body>
</html>
+8 -7
View File
@@ -17,22 +17,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function enumerateSuccess(e) {
if (e.target.result == null) {
ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
dump("We still have length = " + files.length + "\n");
devicestorage_cleanup();
SimpleTest.finish();
return;
}
var filename = e.target.result.name;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
@@ -61,7 +61,7 @@ function enumerateSuccess(e) {
function handleError(e) {
ok(false, "handleError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@@ -76,7 +76,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
@@ -96,8 +96,9 @@ for (var i=0; i<files.length; i++) {
request.onerror = addError;
}
});
</script>
</pre>
</body>
</html>
@@ -17,12 +17,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function enumerateSuccess(e) {
}
@@ -39,12 +39,12 @@ try {
}
catch (e) {
ok(true, "Calling continue before enumerateSuccess fires should throw");
devicestorage_cleanup();
SimpleTest.finish();
}
});
</script>
</pre>
</body>
</html>
@@ -35,7 +35,7 @@ function enumerateSuccess(e) {
if (e.target.result == null) {
ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@@ -67,7 +67,7 @@ function enumerateSuccess(e) {
function handleError(e) {
ok(false, "handleError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@@ -82,7 +82,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
@@ -18,12 +18,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup()
devicestorage_setup(function () {
storage = navigator.getDeviceStorage("pictures");
@@ -70,12 +70,11 @@ var cursor = storage.enumerate({"path": "a", "since": new Date(0) });
} catch(e) {throws = true}
ok(!throws, "enumerate object parameter with path");
SimpleTest.finish()
});
devicestorage_cleanup()
</script>
</pre>
</body>
</html>
+6 -5
View File
@@ -22,23 +22,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function freeSpaceSuccess(e) {
ok(e.target.result > 0, "free bytes should exist and be greater than zero");
devicestorage_cleanup();
SimpleTest.finish();
}
function freeSpaceError(e) {
ok(false, "freeSpaceError was called");
devicestorage_cleanup();
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@@ -54,8 +54,9 @@ request = storage.addNamed(createRandomBlob('image/png'), prefix + "/a/b.png");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>
@@ -26,15 +26,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=855952
var file = new Blob(["This is a text file."], {type: "text/plain"});
var appendFile = new Blob([" Another text file."], {type: "text/plain"});
devicestorage_setup();
devicestorage_setup(function () {
function deleteSuccess(e) {
devicestorage_cleanup();
SimpleTest.finish();
}
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function appendSuccess(e) {
@@ -47,7 +47,7 @@ function appendSuccess(e) {
function appendError(e) {
ok(false, "appendError was called.");
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@@ -83,8 +83,9 @@ ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(gStorage, "Should get storage from sdcard");
runtest();
});
</script>
</pre>
</body>
</html>
+6 -4
View File
@@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=910412
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
var gFileName = randomFilename(12);
@@ -46,12 +46,12 @@ function createDirectorySuccess(d) {
function getSuccess(d) {
ok(d.name === gFileName, "Should get directory - " + gFileName + ".");
devicestorage_cleanup();
SimpleTest.finish();
}
function cbError(e) {
ok(false, "Should not arrive here! Error: " + e.name);
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
@@ -63,8 +63,10 @@ var promise = storage.getRoot();
ok(promise, "Should have a non-null promise");
promise.then(getRootSuccess, cbError);
});
</script>
</pre>
</body>
</html>
@@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=910412
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
// The root directory object.
var gRoot;
@@ -34,14 +34,14 @@ function testCreateDirectory(rootDir, path) {
}
function createDirectorySuccess(d) {
ok(d.name === gName, "Failed to create directory: name mismatch.");
is(d.name, gName, "Failed to create directory: name mismatch.");
// Get the new created directory from the root.
gRoot.get(gPath).then(getSuccess, cbError);
}
function getSuccess(d) {
ok(d.name === gName, "Should get directory - " + (gPath || "[root]") + ".");
is(d.name, gName, "Should get directory - " + (gPath || "[root]") + ".");
switch (gTestCount) {
case 0:
gRoot = d;
@@ -59,7 +59,7 @@ function getSuccess(d) {
// Create directory with an existing path.
gRoot.createDirectory(gPath).then(function(what) {
ok(false, "Should not overwrite an existing directory.");
devicestorage_cleanup();
SimpleTest.finish();
}, function(e) {
ok(true, "Creating directory should fail if it already exists.");
@@ -73,10 +73,10 @@ function getSuccess(d) {
// Create the parent directory.
d.createDirectory('..').then(function(what) {
ok(false, "Should not overwrite an existing directory.");
devicestorage_cleanup();
SimpleTest.finish();
}, function(e) {
ok(true, "Accessing parent directory with '..' is not allowed.");
devicestorage_cleanup();
SimpleTest.finish();
});
break;
}
@@ -85,7 +85,7 @@ function getSuccess(d) {
function cbError(e) {
ok(false, e.name + " error should not arrive here!");
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
@@ -98,8 +98,10 @@ ok(promise, "Should have a non-null promise for getRoot.");
gName = storage.storageName;
promise.then(getSuccess, cbError);
});
</script>
</pre>
</body>
</html>
@@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=910412
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
devicestorage_setup();
devicestorage_setup(function () {
let gTestCount = 0;
let gFileReader = new FileReader();
@@ -84,7 +84,7 @@ let gTestCases = [
function next() {
if (gTestCount >= gTestCases.length) {
devicestorage_cleanup();
SimpleTest.finish();
return;
}
let c = gTestCases[gTestCount++];
@@ -122,11 +122,12 @@ storage.getRoot().then(function(dir) {
next();
}, function(e) {
ok(false, e.name + " error should not arrive here!");
devicestorage_cleanup();
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>
+10 -8
View File
@@ -21,7 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=910412
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
SimpleTest.requestCompleteLog();
// The root directory object.
@@ -77,7 +78,7 @@ function getSuccess(r) {
break;
default:
ok(false, "Should not arrive at getSuccess!");
devicestorage_cleanup();
SimpleTest.finish();
break;
}
gTestCount++;
@@ -137,11 +138,11 @@ function getFailure(e) {
testGetFailure(gRoot, "sub1//sub2");
break;
case 17:
devicestorage_cleanup();
SimpleTest.finish();
break;
default:
ok(false, "Should not arrive here!");
devicestorage_cleanup();
SimpleTest.finish();
break;
}
gTestCount++;
@@ -149,12 +150,12 @@ function getFailure(e) {
function cbError(e) {
ok(false, "Should not arrive at cbError! Error: " + e.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function cbSuccess(e) {
ok(false, "Should not arrive at cbSuccess!");
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
@@ -173,7 +174,7 @@ function createTestFile(path, callback) {
req.onerror = function(e) {
ok(false, "Failed to create " + path + ": " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
};
}
@@ -197,8 +198,9 @@ createTestFile("sub1/sub2/test.png", function() {
promise.then(getSuccess, cbError);
});
});
</script>
</pre>
</body>
</html>
@@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=XXX
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
SimpleTest.requestCompleteLog();
// The root directory object.
@@ -62,12 +62,12 @@ function checkContents1(contents) {
function checkContents2(contents) {
is(contents[0].name, "c.png", "'sub2' should contain 'c.png'");
devicestorage_cleanup();
SimpleTest.finish();
}
function handleError(e) {
ok(false, "Should not arrive at handleError! Error: " + e.name);
devicestorage_cleanup();
SimpleTest.finish();
}
var gStorage = navigator.getDeviceStorage("pictures");
@@ -87,11 +87,12 @@ createTestFiles(gStorage, ["sub/a.png", "sub/b.png", "sub/sub2/c.png", "sub/sub3
runTests();
}, function() {
ok(false, "Failed to created test files.");
devicestorage_cleanup();
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>
+7 -6
View File
@@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=934368
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
devicestorage_setup();
devicestorage_setup(function () {
let gStorage = null;
let gTestCount = 0;
@@ -93,7 +93,7 @@ function runNextTests() {
function runTests() {
function cbError(e) {
ok(false, "Should not arrive at cbError! Error: " + e.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function cbSuccess(r) {
@@ -116,7 +116,7 @@ function runNextTests() {
testNextRemove();
}, function() {
ok(false, "Failed to get test files.");
devicestorage_cleanup();
SimpleTest.finish();
});
}, cbError);
};
@@ -124,7 +124,7 @@ function runNextTests() {
runTests();
}, function() {
ok(false, "Failed to created test files.");
devicestorage_cleanup();
SimpleTest.finish();
});
}
@@ -156,7 +156,7 @@ function testNextRemove() {
return;
}
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
@@ -168,8 +168,9 @@ ok(gStorage, "Should have gotten a storage.");
gRemoveDeep = true;
runNextTests();
});
</script>
</pre>
</body>
</html>
@@ -17,13 +17,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.requestFlakyTimeout("untriaged");
devicestorage_setup();
devicestorage_setup(function () {
// We put the old files in 2 levels deep. When you add a file to a directory
// it will modify the parents last modification time, but not the parents
// parents. So we want to make sure that even though x's timestamp is earlier
@@ -44,7 +45,7 @@ function verifyAndDelete(prefix, files, e) {
ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
dump("We still have length = " + files.length + "\n");
dump(files + "\n");
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@@ -86,12 +87,12 @@ function addFile(filename, callback) {
}
getReq.onerror = function(e) {
ok(false, "getError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
};
}
addReq.onerror = function(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
}
@@ -115,7 +116,7 @@ function delFile(filename, callback) {
};
req.onerror = function(e) {
ok(false, "delError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
};
}
@@ -129,7 +130,7 @@ function afterNewFiles() {
};
cursor.onerror = function (e) {
ok(false, "handleError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
};
}
@@ -167,8 +168,9 @@ function addOldFiles() {
addOldFiles();
});
</script>
</pre>
</body>
</html>
+10 -10
View File
@@ -17,12 +17,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
var gFileName = "devicestorage/" + randomFilename(12) + "/hi.png";
var gData = "My name is Doug Turner. My IRC nick is DougT. I like Maple cookies."
@@ -31,12 +31,12 @@ var gFileReader = new FileReader();
function getAfterDeleteSuccess(e) {
ok(false, "file was deleted not successfully");
devicestorage_cleanup();
SimpleTest.finish();
}
function getAfterDeleteError(e) {
ok(true, "file was deleted successfully");
devicestorage_cleanup();
SimpleTest.finish();
}
function deleteSuccess(e) {
@@ -54,7 +54,7 @@ function deleteSuccess(e) {
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function getSuccess(e) {
@@ -92,7 +92,7 @@ function readerCallback(e) {
function getError(e) {
ok(false, "getError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@@ -123,7 +123,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function startTest() {
@@ -149,15 +149,15 @@ try {
// The remove will fail if the directory doesn't exist, which is fine.
f.remove(true);
} catch (e) {}
SpecialPowers.pushPrefEnv({'set': [["device.storage.overrideRootDir", f.path],
["device.storage.testing", false]]},
SpecialPowers.pushPrefEnv({'set': [["device.storage.overrideRootDir", f.path]]},
function() {
startTest();
});
} catch(e) {}
});
</script>
</pre>
</body>
</html>
+7 -6
View File
@@ -18,28 +18,28 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
var filename = "devicestorage/aaaa.png"
devicestorage_setup();
devicestorage_setup(function () {
function deleteSuccess(e) {
devicestorage_cleanup();
SimpleTest.finish();
}
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addOverwritingSuccess(e) {
ok(false, "addOverwritingSuccess was called.");
devicestorage_cleanup();
SimpleTest.finish();
}
function addOverwritingError(e) {
@@ -85,8 +85,9 @@ function runtest() {
runtest();
});
</script>
</pre>
</body>
</html>
+5 -4
View File
@@ -18,12 +18,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup()
devicestorage_setup(function () {
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
@@ -50,10 +50,11 @@ ok(storage, "videos - Should have getDeviceStorage");
var cursor = storage.enumerate();
ok(cursor, "Should have a non-null cursor");
devicestorage_cleanup();
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>
@@ -23,7 +23,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1126694
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup()
devicestorage_setup(function () {
var XPCOMUtils = SpecialPowers.Cu.import("resource://gre/modules/XPCOMUtils.jsm").XPCOMUtils;
var Ci = SpecialPowers.Ci;
@@ -49,7 +49,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1126694
}
else if (e.operation == "removed") {
ok (true, "got removal event");
devicestorage_cleanup();
SimpleTest.finish();
}
});
@@ -58,6 +58,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1126694
volumeService.createFakeVolume(volName, mountPoint);
});
</script>
</pre>
</body>
+6 -4
View File
@@ -22,23 +22,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function usedSpaceSuccess(e) {
ok(e.target.result > 0, "total bytes should exist and be greater than zero");
devicestorage_cleanup();
SimpleTest.finish();
}
function usedSpaceError(e) {
ok(false, "usedSpaceError was called");
devicestorage_cleanup();
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@@ -54,6 +54,8 @@ request = storage.addNamed(createRandomBlob('image/png'), prefix + "/a/b.png");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
+5 -3
View File
@@ -22,7 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
var gFileName = randomFilename(20) + ".png"
@@ -31,7 +31,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function onChange(e) {
@@ -51,7 +51,7 @@ function onChange(e) {
if (filename == gFileName) {
ok(true, "we saw the file get created");
storage.removeEventListener("change", onChange);
devicestorage_cleanup();
SimpleTest.finish();
}
else {
// we may see other file changes during the test, and
@@ -69,6 +69,8 @@ ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
+5 -3
View File
@@ -22,7 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
var gFileName = randomFilename(20) + ".png"
@@ -31,7 +31,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function onChange(e) {
@@ -51,7 +51,7 @@ function onChange(e) {
if (filename == gFileName) {
ok(true, "we saw the file get created");
storage.removeEventListener("change", onChange);
devicestorage_cleanup();
SimpleTest.finish();
}
else {
// we may see other file changes during the test, and
@@ -78,6 +78,8 @@ ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
+16 -48
View File
@@ -49,7 +49,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mItems)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage)
@@ -57,7 +57,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mItems)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage)
@@ -281,11 +281,12 @@ DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
FileList*
DataTransfer::GetFiles(ErrorResult& aRv)
{
return GetFilesInternal(aRv, nsContentUtils::SubjectPrincipal());
return GetFileListInternal(aRv, nsContentUtils::SubjectPrincipal());
}
FileList*
DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal)
DataTransfer::GetFileListInternal(ErrorResult& aRv,
nsIPrincipal* aSubjectPrincipal)
{
if (mEventMessage != eDrop &&
mEventMessage != eLegacyDragDrop &&
@@ -293,14 +294,15 @@ DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal
return nullptr;
}
if (!mFiles) {
mFiles = new FileList(static_cast<nsIDOMDataTransfer*>(this));
if (!mFileList) {
mFileList = new FileList(static_cast<nsIDOMDataTransfer*>(this));
uint32_t count = mItems.Length();
for (uint32_t i = 0; i < count; i++) {
nsCOMPtr<nsIVariant> variant;
aRv = GetDataAtInternal(NS_ConvertUTF8toUTF16(kFileMime), i, aSubjectPrincipal, getter_AddRefs(variant));
aRv = GetDataAtInternal(NS_ConvertUTF8toUTF16(kFileMime), i,
aSubjectPrincipal, getter_AddRefs(variant));
if (aRv.Failed()) {
return nullptr;
}
@@ -338,21 +340,18 @@ DataTransfer::GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal
MOZ_ASSERT(domFile);
}
if (!mFiles->Append(domFile)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mFileList->Append(domFile);
}
}
return mFiles;
return mFileList;
}
NS_IMETHODIMP
DataTransfer::GetFiles(nsIDOMFileList** aFileList)
{
ErrorResult rv;
NS_IF_ADDREF(*aFileList = GetFilesInternal(rv, nsContentUtils::GetSystemPrincipal()));
NS_IF_ADDREF(*aFileList = GetFileListInternal(rv, nsContentUtils::GetSystemPrincipal()));
return rv.StealNSResult();
}
@@ -874,7 +873,7 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
return nullptr;
}
if (!mFiles) {
if (!mFileList) {
GetFiles(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@@ -882,40 +881,9 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
}
Sequence<OwningFileOrDirectory> filesAndDirsSeq;
if (mFiles && mFiles->Length()) {
if (!filesAndDirsSeq.SetLength(mFiles->Length(), mozilla::fallible_t())) {
p->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
return p.forget();
}
for (uint32_t i = 0; i < mFiles->Length(); ++i) {
if (mFiles->Item(i)->Impl()->IsDirectory()) {
#if defined(ANDROID) || defined(MOZ_B2G)
MOZ_ASSERT(false,
"Directory picking should have been redirected to normal "
"file picking for platforms that don't have a directory "
"picker");
#endif
nsAutoString path;
mFiles->Item(i)->GetMozFullPathInternal(path, aRv);
if (aRv.Failed()) {
return nullptr;
}
int32_t leafSeparatorIndex = path.RFind(FILE_PATH_SEPARATOR);
nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex);
nsDependentSubstring basename = Substring(path, leafSeparatorIndex);
RefPtr<OSFileSystem> fs = new OSFileSystem(dirname);
fs->Init(parentNode->OwnerDoc()->GetInnerWindow());
RefPtr<Directory> directory = new Directory(fs, basename);
directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive"));
filesAndDirsSeq[i].SetAsDirectory() = directory;
} else {
filesAndDirsSeq[i].SetAsFile() = mFiles->Item(i);
}
}
mFileList->ToSequence(filesAndDirsSeq, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
p->MaybeResolve(filesAndDirsSeq);
+4 -3
View File
@@ -252,7 +252,7 @@ protected:
void FillInExternalData(TransferItem& aItem, uint32_t aIndex);
FileList* GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal);
FileList* GetFileListInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal);
nsresult GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
nsIPrincipal* aSubjectPrincipal, nsIVariant** aData);
nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex,
@@ -300,8 +300,9 @@ protected:
// array of items, each containing an array of format->data pairs
nsTArray<nsTArray<TransferItem> > mItems;
// array of files, containing only the files present in the dataTransfer
RefPtr<FileList> mFiles;
// array of files and directories, containing only the files present in the
// dataTransfer
RefPtr<FileList> mFileList;
// the target of the drag. The drag and dragend events will fire at this.
nsCOMPtr<mozilla::dom::Element> mDragTarget;
+1 -2
View File
@@ -318,8 +318,7 @@ ConvertActorToFile(FileHandleBase* aFileHandle,
actor->SetMysteryBlobInfo(mutableFile->Name(),
mutableFile->Type(),
size.get_uint64_t(),
lastModified.get_int64_t(),
BlobDirState::eUnknownIfDir);
lastModified.get_int64_t());
RefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
MOZ_ASSERT(blobImpl);
+96 -36
View File
@@ -6,7 +6,6 @@
#include "CreateDirectoryTask.h"
#include "DOMError.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
@@ -17,33 +16,73 @@
namespace mozilla {
namespace dom {
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
const nsAString& aPath,
ErrorResult& aRv)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aPath)
/* static */ already_AddRefed<CreateDirectoryTask>
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<CreateDirectoryTask> task =
new CreateDirectoryTask(aFileSystem, aTargetPath);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
do_QueryInterface(aFileSystem->GetParentObject());
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mPromise = Promise::Create(globalObject, aRv);
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
CreateDirectoryTask::CreateDirectoryTask(
FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
/* static */ already_AddRefed<CreateDirectoryTask>
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<CreateDirectoryTask> task =
new CreateDirectoryTask(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath)
: FileSystemTaskBase(aFileSystem)
, mTargetPath(aTargetPath)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
mTargetRealPath = aParam.realPath();
}
CreateDirectoryTask::~CreateDirectoryTask()
@@ -60,25 +99,44 @@ CreateDirectoryTask::GetPromise()
}
FileSystemParams
CreateDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
CreateDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemCreateDirectoryParams(aFileSystem, mTargetRealPath);
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemCreateDirectoryParams();
}
return FileSystemCreateDirectoryParams(aSerializedDOMPath, path);
}
FileSystemResponseValue
CreateDirectoryTask::GetSuccessRequestResult() const
CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemDirectoryResponse(mTargetRealPath);
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemDirectoryResponse();
}
return FileSystemDirectoryResponse(path);
}
void
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemDirectoryResponse r = aValue;
mTargetRealPath = r.realPath();
NS_ConvertUTF16toUTF8 path(r.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
NS_WARN_IF(aRv.Failed());
}
nsresult
@@ -92,13 +150,8 @@ CreateDirectoryTask::Work()
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
if (!file) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
bool fileExists;
nsresult rv = file->Exists(&fileExists);
nsresult rv = mTargetPath->Exists(&fileExists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -107,8 +160,12 @@ CreateDirectoryTask::Work()
return NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
}
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0770);
return rv;
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0770);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
void
@@ -121,13 +178,16 @@ CreateDirectoryTask::HandlerCallback()
}
if (HasError()) {
RefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
mErrorValue);
mPromise->MaybeRejectBrokenly(domError);
mPromise->MaybeReject(mErrorValue);
mPromise = nullptr;
return;
}
RefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
mTargetPath,
Directory::eNotDOMRootDirectory,
mFileSystem);
MOZ_ASSERT(dir);
mPromise->MaybeResolve(dir);
mPromise = nullptr;
}
+24 -12
View File
@@ -16,16 +16,19 @@ namespace dom {
class Promise;
class CreateDirectoryTask final
: public FileSystemTaskBase
class CreateDirectoryTask final : public FileSystemTaskBase
{
public:
CreateDirectoryTask(FileSystemBase* aFileSystem,
const nsAString& aPath,
ErrorResult& aRv);
CreateDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<CreateDirectoryTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
ErrorResult& aRv);
static already_AddRefed<CreateDirectoryTask>
Create(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~CreateDirectoryTask();
@@ -38,13 +41,15 @@ public:
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@@ -53,8 +58,15 @@ protected:
HandlerCallback() override;
private:
CreateDirectoryTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath);
CreateDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent);
RefPtr<Promise> mPromise;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
};
} // namespace dom
+116 -68
View File
@@ -8,7 +8,6 @@
#include <algorithm>
#include "DOMError.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h"
@@ -26,34 +25,104 @@ namespace dom {
uint32_t CreateFileTask::sOutputBufferSize = 0;
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
const nsAString& aPath,
Blob* aBlobData,
InfallibleTArray<uint8_t>& aArrayData,
bool replace,
ErrorResult& aRv)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aPath)
, mReplace(replace)
/* static */ already_AddRefed<CreateFileTask>
CreateFileTask::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Blob* aBlobData,
InfallibleTArray<uint8_t>& aArrayData,
bool aReplace,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
GetOutputBufferSize();
RefPtr<CreateFileTask> task =
new CreateFileTask(aFileSystem, aTargetPath, aReplace);
// aTargetPath can be null. In this case SetError will be called.
task->GetOutputBufferSize();
if (aBlobData) {
if (XRE_IsParentProcess()) {
aBlobData->GetInternalStream(getter_AddRefs(mBlobStream), aRv);
NS_WARN_IF(aRv.Failed());
aBlobData->GetInternalStream(getter_AddRefs(task->mBlobStream), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
} else {
mBlobData = aBlobData;
task->mBlobData = aBlobData;
}
}
mArrayData.SwapElements(aArrayData);
task->mArrayData.SwapElements(aArrayData);
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
do_QueryInterface(aFileSystem->GetParentObject());
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mPromise = Promise::Create(globalObject, aRv);
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
/* static */ already_AddRefed<CreateFileTask>
CreateFileTask::Create(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<CreateFileTask> task =
new CreateFileTask(aFileSystem, aParam, aParent);
task->GetOutputBufferSize();
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->mReplace = aParam.replace();
auto& data = aParam.data();
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
task->mArrayData = data;
return task.forget();
}
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
MOZ_ASSERT(blobImpl, "blobData should not be null.");
ErrorResult rv;
blobImpl->GetInternalStream(getter_AddRefs(task->mBlobStream), rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
return task.forget();
}
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
bool aReplace)
: FileSystemTaskBase(aFileSystem)
, mTargetPath(aTargetPath)
, mReplace(aReplace)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
@@ -62,32 +131,9 @@ CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mReplace(false)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
GetOutputBufferSize();
mTargetRealPath = aParam.realPath();
mReplace = aParam.replace();
auto& data = aParam.data();
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
mArrayData = data;
return;
}
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
MOZ_ASSERT(blobImpl, "blobData should not be null.");
ErrorResult rv;
blobImpl->GetInternalStream(getter_AddRefs(mBlobStream), rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
}
CreateFileTask::~CreateFileTask()
@@ -108,16 +154,22 @@ CreateFileTask::GetPromise()
}
FileSystemParams
CreateFileTask::GetRequestParams(const nsString& aFileSystem) const
CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemCreateFileParams param;
param.filesystem() = aFileSystem;
param.realPath() = mTargetRealPath;
param.filesystem() = aSerializedDOMPath;
aRv = mTargetPath->GetPath(param.realPath());
if (NS_WARN_IF(aRv.Failed())) {
return param;
}
param.replace() = mReplace;
if (mBlobData) {
BlobChild* actor
= ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlobData);
BlobChild* actor =
ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlobData);
if (actor) {
param.data() = actor;
}
@@ -128,7 +180,7 @@ CreateFileTask::GetRequestParams(const nsString& aFileSystem) const
}
FileSystemResponseValue
CreateFileTask::GetSuccessRequestResult() const
CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
BlobParent* actor = GetBlobParent(mTargetBlobImpl);
@@ -141,7 +193,8 @@ CreateFileTask::GetSuccessRequestResult() const
}
void
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemFileResponse r = aValue;
@@ -152,7 +205,7 @@ CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
nsresult
CreateFileTask::Work()
{
class AutoClose
class MOZ_RAII AutoClose final
{
public:
explicit AutoClose(nsIOutputStream* aStream)
@@ -165,6 +218,7 @@ CreateFileTask::Work()
{
mStream->Close();
}
private:
nsCOMPtr<nsIOutputStream> mStream;
};
@@ -177,24 +231,19 @@ CreateFileTask::Work()
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
if (!file) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
if (!mFileSystem->IsSafeFile(file)) {
if (!mFileSystem->IsSafeFile(mTargetPath)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
bool exists = false;
nsresult rv = file->Exists(&exists);
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (exists) {
bool isFile = false;
rv = file->IsFile(&isFile);
rv = mTargetPath->IsFile(&isFile);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -208,19 +257,19 @@ CreateFileTask::Work()
}
// Remove the old file before creating.
rv = file->Remove(false);
rv = mTargetPath->Remove(false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
rv = mTargetPath->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIOutputStream> outputStream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mTargetPath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -263,7 +312,7 @@ CreateFileTask::Work()
return NS_ERROR_FAILURE;
}
mTargetBlobImpl = new BlobImplFile(file);
mTargetBlobImpl = new BlobImplFile(mTargetPath);
return NS_OK;
}
@@ -282,7 +331,7 @@ CreateFileTask::Work()
return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
}
mTargetBlobImpl = new BlobImplFile(file);
mTargetBlobImpl = new BlobImplFile(mTargetPath);
return NS_OK;
}
@@ -297,15 +346,14 @@ CreateFileTask::HandlerCallback()
}
if (HasError()) {
RefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
mErrorValue);
mPromise->MaybeRejectBrokenly(domError);
mPromise->MaybeReject(mErrorValue);
mPromise = nullptr;
mBlobData = nullptr;
return;
}
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetBlobImpl);
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetParentObject(),
mTargetBlobImpl);
mPromise->MaybeResolve(blob);
mPromise = nullptr;
mBlobData = nullptr;
+28 -15
View File
@@ -20,19 +20,22 @@ class Blob;
class BlobImpl;
class Promise;
class CreateFileTask final
: public FileSystemTaskBase
class CreateFileTask final : public FileSystemTaskBase
{
public:
CreateFileTask(FileSystemBase* aFileSystem,
const nsAString& aPath,
Blob* aBlobData,
InfallibleTArray<uint8_t>& aArrayData,
bool replace,
ErrorResult& aRv);
CreateFileTask(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<CreateFileTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aFile,
Blob* aBlobData,
InfallibleTArray<uint8_t>& aArrayData,
bool replace,
ErrorResult& aRv);
static already_AddRefed<CreateFileTask>
Create(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~CreateFileTask();
@@ -45,13 +48,15 @@ public:
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@@ -60,12 +65,20 @@ protected:
HandlerCallback() override;
private:
CreateFileTask(FileSystemBase* aFileSystem,
nsIFile* aFile,
bool aReplace);
CreateFileTask(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent);
void
GetOutputBufferSize() const;
static uint32_t sOutputBufferSize;
RefPtr<Promise> mPromise;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
// Not thread-safe and should be released on main thread.
RefPtr<Blob> mBlobData;
+52 -26
View File
@@ -21,9 +21,8 @@
namespace mozilla {
namespace dom {
DeviceStorageFileSystem::DeviceStorageFileSystem(
const nsAString& aStorageType,
const nsAString& aStorageName)
DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
const nsAString& aStorageName)
: mWindowId(0)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -31,12 +30,6 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(
mStorageType = aStorageType;
mStorageName = aStorageName;
// Generate the string representation of the file system.
mString.AppendLiteral("devicestorage-");
mString.Append(mStorageType);
mString.Append('-');
mString.Append(mStorageName);
mRequiresPermissionChecks =
!mozilla::Preferences::GetBool("device.storage.prompt.testing", false);
@@ -46,19 +39,16 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(
NS_WARN_IF(NS_FAILED(rv));
// Get the local path of the file system root.
// Since the child process is not allowed to access the file system, we only
// do this from the parent process.
if (!XRE_IsParentProcess()) {
return;
}
nsCOMPtr<nsIFile> rootFile;
DeviceStorageFile::GetRootDirectoryForType(aStorageType,
aStorageName,
getter_AddRefs(rootFile));
NS_WARN_IF(!rootFile || NS_FAILED(rootFile->GetPath(mLocalRootPath)));
FileSystemUtils::LocalPathToNormalizedPath(mLocalRootPath,
mNormalizedLocalRootPath);
if (!XRE_IsParentProcess()) {
return;
}
// DeviceStorageTypeChecker is a singleton object and must be initialized on
// the main thread. We initialize it here so that we can use it on the worker
@@ -72,6 +62,17 @@ DeviceStorageFileSystem::~DeviceStorageFileSystem()
{
}
already_AddRefed<FileSystemBase>
DeviceStorageFileSystem::Clone()
{
RefPtr<DeviceStorageFileSystem> fs =
new DeviceStorageFileSystem(mStorageType, mStorageName);
fs->mWindowId = mWindowId;
return fs.forget();
}
void
DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage)
{
@@ -89,13 +90,13 @@ DeviceStorageFileSystem::Shutdown()
mShutdown = true;
}
nsPIDOMWindow*
DeviceStorageFileSystem::GetWindow() const
nsISupports*
DeviceStorageFileSystem::GetParentObject() const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
MOZ_ASSERT_IF(!mShutdown, window);
return window;
return ToSupports(window);
}
void
@@ -111,12 +112,15 @@ DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
"Should be on parent process!");
MOZ_ASSERT(aFile);
// Check if this file belongs to this storage.
nsAutoString path;
if (NS_FAILED(aFile->GetPath(path))) {
nsCOMPtr<nsIFile> rootPath;
nsresult rv = NS_NewLocalFile(GetLocalRootPath(), false,
getter_AddRefs(rootPath));
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (!LocalPathToRealPath(path, path)) {
// Check if this file belongs to this storage.
if (NS_WARN_IF(!FileSystemUtils::IsDescendantPath(rootPath, aFile))) {
return false;
}
@@ -132,10 +136,32 @@ DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aDir);
RefPtr<FileSystemBase> fs = aDir->GetFileSystem();
MOZ_ASSERT(fs);
ErrorResult rv;
RefPtr<FileSystemBase> fs = aDir->GetFileSystem(rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return false;
}
nsAutoString fsSerialization;
fs->SerializeDOMPath(fsSerialization);
nsAutoString thisSerialization;
SerializeDOMPath(thisSerialization);
// Check if the given directory is from this storage.
return fs->ToString() == mString;
return fsSerialization == thisSerialization;
}
void
DeviceStorageFileSystem::SerializeDOMPath(nsAString& aString) const
{
// Generate the string representation of the file system.
aString.AssignLiteral("devicestorage-");
aString.Append(mStorageType);
aString.Append('-');
aString.Append(mStorageName);
}
} // namespace dom
+9 -2
View File
@@ -27,11 +27,14 @@ public:
// Overrides FileSystemBase
virtual already_AddRefed<FileSystemBase>
Clone() override;
virtual void
Shutdown() override;
virtual nsPIDOMWindow*
GetWindow() const override;
virtual nsISupports*
GetParentObject() const override;
virtual void
GetRootName(nsAString& aRetval) const override;
@@ -41,6 +44,10 @@ public:
virtual bool
IsSafeDirectory(Directory* aDir) const override;
virtual void
SerializeDOMPath(nsAString& aSerializedString) const override;
private:
virtual
~DeviceStorageFileSystem();
+233 -103
View File
@@ -18,6 +18,7 @@
#include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/OSFileSystem.h"
// Resolve the name collision of Microsoft's API name with macros defined in
// Windows header files. Undefine the macro of CreateDirectory to avoid
@@ -34,15 +35,70 @@
namespace mozilla {
namespace dom {
namespace {
bool
TokenizerIgnoreNothing(char16_t /* aChar */)
{
return false;
}
bool
IsValidRelativeDOMPath(const nsString& aPath, nsTArray<nsString>& aParts)
{
// We don't allow empty relative path to access the root.
if (aPath.IsEmpty()) {
return false;
}
// Leading and trailing "/" are not allowed.
if (aPath.First() == FILESYSTEM_DOM_PATH_SEPARATOR_CHAR ||
aPath.Last() == FILESYSTEM_DOM_PATH_SEPARATOR_CHAR) {
return false;
}
NS_NAMED_LITERAL_STRING(kCurrentDir, ".");
NS_NAMED_LITERAL_STRING(kParentDir, "..");
// Split path and check each path component.
nsCharSeparatedTokenizerTemplate<TokenizerIgnoreNothing>
tokenizer(aPath, FILESYSTEM_DOM_PATH_SEPARATOR_CHAR);
while (tokenizer.hasMoreTokens()) {
nsDependentSubstring pathComponent = tokenizer.nextToken();
// The path containing empty components, such as "foo//bar", is invalid.
// We don't allow paths, such as "../foo", "foo/./bar" and "foo/../bar",
// to walk up the directory.
if (pathComponent.IsEmpty() ||
pathComponent.Equals(kCurrentDir) ||
pathComponent.Equals(kParentDir)) {
return false;
}
aParts.AppendElement(pathComponent);
}
return true;
}
} // anonymous namespace
NS_IMPL_CYCLE_COLLECTION_CLASS(Directory)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Directory)
tmp->mFileSystem->Unlink();
if (tmp->mFileSystem) {
tmp->mFileSystem->Unlink();
tmp->mFileSystem = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Directory)
tmp->mFileSystem->Traverse(cb);
if (tmp->mFileSystem) {
tmp->mFileSystem->Traverse(cb);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -59,33 +115,73 @@ NS_INTERFACE_MAP_END
already_AddRefed<Promise>
Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
{
RefPtr<GetFileOrDirectoryTask> task = new GetFileOrDirectoryTask(
aFileSystem, EmptyString(), true, aRv);
if (aRv.Failed()) {
MOZ_ASSERT(aFileSystem);
nsCOMPtr<nsIFile> path;
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aFileSystem->GetLocalRootPath()),
true, getter_AddRefs(path));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<GetFileOrDirectoryTask> task =
GetFileOrDirectoryTask::Create(aFileSystem, path, eDOMRootDirectory, true, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
}
Directory::Directory(FileSystemBase* aFileSystem,
const nsAString& aPath)
: mFileSystem(aFileSystem)
, mPath(aPath)
/* static */ already_AddRefed<Directory>
Directory::Create(nsISupports* aParent, nsIFile* aFile,
DirectoryType aType, FileSystemBase* aFileSystem)
{
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
// Remove the trailing "/".
mPath.Trim(FILESYSTEM_DOM_PATH_SEPARATOR, false, true);
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aParent);
MOZ_ASSERT(aFile);
#ifdef DEBUG
bool isDir;
nsresult rv = aFile->IsDirectory(&isDir);
MOZ_ASSERT(NS_SUCCEEDED(rv) && isDir);
#endif
RefPtr<Directory> directory =
new Directory(aParent, aFile, aType, aFileSystem);
return directory.forget();
}
Directory::Directory(nsISupports* aParent,
nsIFile* aFile,
DirectoryType aType,
FileSystemBase* aFileSystem)
: mParent(aParent)
, mFile(aFile)
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aFile);
// aFileSystem can be null. In this case we create a OSFileSystem when needed.
if (aFileSystem) {
// More likely, this is a OSFileSystem. This object keeps a reference of
// mParent but it's not cycle collectable and to avoid manual
// addref/release, it's better to have 1 object per directory. For this
// reason we clone it here.
mFileSystem = aFileSystem->Clone();
}
}
Directory::~Directory()
{
}
nsPIDOMWindow*
nsISupports*
Directory::GetParentObject() const
{
return mFileSystem->GetWindow();
return mParent;
}
JSObject*
@@ -95,25 +191,28 @@ Directory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
}
void
Directory::GetName(nsAString& aRetval) const
Directory::GetName(nsAString& aRetval, ErrorResult& aRv)
{
aRetval.Truncate();
if (mPath.IsEmpty()) {
mFileSystem->GetRootName(aRetval);
if (mType == eDOMRootDirectory) {
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
fs->GetRootName(aRetval);
return;
}
aRetval = Substring(mPath,
mPath.RFindChar(FileSystemUtils::kSeparatorChar) + 1);
aRv = mFile->GetLeafName(aRetval);
NS_WARN_IF(aRv.Failed());
}
already_AddRefed<Promise>
Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
ErrorResult& aRv)
{
nsresult error = NS_OK;
nsAutoString realPath;
RefPtr<Blob> blobData;
InfallibleTArray<uint8_t> arrayData;
bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace);
@@ -138,15 +237,20 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
}
}
if (!DOMPathToRealPath(aPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
nsCOMPtr<nsIFile> realPath;
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<CreateFileTask> task =
new CreateFileTask(mFileSystem, realPath, blobData, arrayData, replace, aRv);
if (aRv.Failed()) {
CreateFileTask::Create(fs, realPath, blobData, arrayData, replace, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->SetError(error);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
@@ -155,16 +259,20 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
already_AddRefed<Promise>
Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
{
nsresult error = NS_OK;
nsAutoString realPath;
if (!DOMPathToRealPath(aPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
RefPtr<CreateDirectoryTask> task = new CreateDirectoryTask(
mFileSystem, realPath, aRv);
if (aRv.Failed()) {
nsCOMPtr<nsIFile> realPath;
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<CreateDirectoryTask> task =
CreateDirectoryTask::Create(fs, realPath, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->SetError(error);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
@@ -173,16 +281,21 @@ Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
already_AddRefed<Promise>
Directory::Get(const nsAString& aPath, ErrorResult& aRv)
{
nsresult error = NS_OK;
nsAutoString realPath;
if (!DOMPathToRealPath(aPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
RefPtr<GetFileOrDirectoryTask> task = new GetFileOrDirectoryTask(
mFileSystem, realPath, false, aRv);
if (aRv.Failed()) {
nsCOMPtr<nsIFile> realPath;
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<GetFileOrDirectoryTask> task =
GetFileOrDirectoryTask::Create(fs, realPath, eNotDOMRootDirectory, false,
aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->SetError(error);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
@@ -205,30 +318,33 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
ErrorResult& aRv)
{
nsresult error = NS_OK;
nsAutoString realPath;
nsCOMPtr<nsIFile> realPath;
RefPtr<BlobImpl> blob;
// Check and get the target path.
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (aPath.IsFile()) {
blob = aPath.GetAsFile().Impl();
} else if (aPath.IsString()) {
if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
} else if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) {
error = DOMPathToRealPath(aPath.GetAsString(), getter_AddRefs(realPath));
} else if (!fs->IsSafeDirectory(&aPath.GetAsDirectory())) {
error = NS_ERROR_DOM_SECURITY_ERR;
} else {
realPath = aPath.GetAsDirectory().mPath;
realPath = aPath.GetAsDirectory().mFile;
// The target must be a descendant of this directory.
if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) {
if (!FileSystemUtils::IsDescendantPath(mFile, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
}
}
RefPtr<RemoveTask> task = new RemoveTask(mFileSystem, mPath, blob, realPath,
aRecursive, aRv);
if (aRv.Failed()) {
RefPtr<RemoveTask> task =
RemoveTask::Create(fs, mFile, blob, realPath, aRecursive, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->SetError(error);
@@ -237,23 +353,38 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
}
void
Directory::GetPath(nsAString& aRetval) const
Directory::GetPath(nsAString& aRetval, ErrorResult& aRv)
{
if (mPath.IsEmpty()) {
// The Directory ctor removes any trailing '/'; this is the root directory.
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
if (mType == eDOMRootDirectory) {
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
} else {
aRetval = mPath;
// TODO: this should be a bit different...
GetName(aRetval, aRv);
}
}
already_AddRefed<Promise>
Directory::GetFilesAndDirectories()
nsresult
Directory::GetFullRealPath(nsAString& aPath)
{
ErrorResult rv;
nsresult rv = mFile->GetPath(aPath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
already_AddRefed<Promise>
Directory::GetFilesAndDirectories(ErrorResult& aRv)
{
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<GetDirectoryListingTask> task =
new GetDirectoryListingTask(mFileSystem, mPath, mFilters, rv);
if (NS_WARN_IF(rv.Failed())) {
GetDirectoryListingTask::Create(fs, mFile, mType, mFilters, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@@ -268,16 +399,38 @@ Directory::SetContentFilters(const nsAString& aFilters)
}
FileSystemBase*
Directory::GetFileSystem() const
Directory::GetFileSystem(ErrorResult& aRv)
{
return mFileSystem.get();
if (!mFileSystem) {
nsCOMPtr<nsIFile> parent;
aRv = mFile->GetParent(getter_AddRefs(parent));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// Parent can be null if mFile is pointing to the top directory.
if (!parent) {
parent = mFile;
}
nsAutoString path;
aRv = parent->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<OSFileSystem> fs = new OSFileSystem(path);
fs->Init(mParent);
mFileSystem = fs;
}
return mFileSystem;
}
bool
Directory::DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const
nsresult
Directory::DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const
{
aRealPath.Truncate();
nsString relativePath;
relativePath = aPath;
@@ -285,49 +438,26 @@ Directory::DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const
static const char kWhitespace[] = "\b\t\r\n ";
relativePath.Trim(kWhitespace);
if (!IsValidRelativePath(relativePath)) {
return false;
nsTArray<nsString> parts;
if (!IsValidRelativeDOMPath(relativePath, parts)) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
aRealPath = mPath + NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR) +
relativePath;
return true;
}
// static
bool
Directory::IsValidRelativePath(const nsString& aPath)
{
// We don't allow empty relative path to access the root.
if (aPath.IsEmpty()) {
return false;
nsCOMPtr<nsIFile> file;
nsresult rv = mFile->Clone(getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Leading and trailing "/" are not allowed.
if (aPath.First() == FileSystemUtils::kSeparatorChar ||
aPath.Last() == FileSystemUtils::kSeparatorChar) {
return false;
}
NS_NAMED_LITERAL_STRING(kCurrentDir, ".");
NS_NAMED_LITERAL_STRING(kParentDir, "..");
// Split path and check each path component.
nsCharSeparatedTokenizer tokenizer(aPath, FileSystemUtils::kSeparatorChar);
while (tokenizer.hasMoreTokens()) {
nsDependentSubstring pathComponent = tokenizer.nextToken();
// The path containing empty components, such as "foo//bar", is invalid.
// We don't allow paths, such as "../foo", "foo/./bar" and "foo/../bar",
// to walk up the directory.
if (pathComponent.IsEmpty() ||
pathComponent.Equals(kCurrentDir) ||
pathComponent.Equals(kParentDir)) {
return false;
for (uint32_t i = 0; i < parts.Length(); ++i) {
rv = file->AppendRelativePath(parts[i]);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return true;
file.forget(aFile);
return NS_OK;
}
} // namespace dom
+49 -16
View File
@@ -13,7 +13,6 @@
#include "mozilla/dom/File.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsPIDOMWindow.h"
#include "nsWrapperCache.h"
// Resolve the name collision of Microsoft's API name with macros defined in
@@ -41,25 +40,48 @@ class Directory final
, public nsWrapperCache
{
public:
struct BlobImplOrDirectoryPath
{
RefPtr<BlobImpl> mBlobImpl;
nsString mDirectoryPath;
enum {
eBlobImpl,
eDirectoryPath
} mType;
};
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
public:
static already_AddRefed<Promise>
GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
Directory(FileSystemBase* aFileSystem, const nsAString& aPath);
enum DirectoryType {
// When a directory is selected using a HTMLInputElement, that will be the
// DOM root directory and its name will be '/'. All the sub directory will
// be called with they real name. We use this enum to mark what we must
// consider the '/' of this DOM filesystem.
eDOMRootDirectory,
// All the sub directories of the '/' will be marked using this other value.
eNotDOMRootDirectory
};
static already_AddRefed<Directory>
Create(nsISupports* aParent, nsIFile* aDirectory,
DirectoryType aType, FileSystemBase* aFileSystem = 0);
// ========= Begin WebIDL bindings. ===========
nsPIDOMWindow*
nsISupports*
GetParentObject() const;
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void
GetName(nsAString& aRetval) const;
GetName(nsAString& aRetval, ErrorResult& aRv);
already_AddRefed<Promise>
CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
@@ -80,10 +102,13 @@ public:
// From https://microsoftedge.github.io/directory-upload/proposal.html#directory-interface :
void
GetPath(nsAString& aRetval) const;
GetPath(nsAString& aRetval, ErrorResult& aRv);
nsresult
GetFullRealPath(nsAString& aPath);
already_AddRefed<Promise>
GetFilesAndDirectories();
GetFilesAndDirectories(ErrorResult& aRv);
// =========== End WebIDL bindings.============
@@ -113,26 +138,34 @@ public:
SetContentFilters(const nsAString& aFilters);
FileSystemBase*
GetFileSystem() const;
private:
~Directory();
GetFileSystem(ErrorResult& aRv);
static bool
IsValidRelativePath(const nsString& aPath);
DirectoryType Type() const
{
return mType;
}
private:
Directory(nsISupports* aParent,
nsIFile* aFile, DirectoryType aType,
FileSystemBase* aFileSystem = nullptr);
~Directory();
/*
* Convert relative DOM path to the absolute real path.
* @return true if succeed. false if the DOM path is invalid.
*/
bool
DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const;
nsresult
DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const;
already_AddRefed<Promise>
RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
ErrorResult& aRv);
nsCOMPtr<nsISupports> mParent;
RefPtr<FileSystemBase> mFileSystem;
nsString mPath;
nsCOMPtr<nsIFile> mFile;
DirectoryType mType;
nsString mFilters;
};
+12 -37
View File
@@ -15,7 +15,7 @@ namespace dom {
// static
already_AddRefed<FileSystemBase>
FileSystemBase::FromString(const nsAString& aString)
FileSystemBase::DeserializeDOMPath(const nsAString& aString)
{
if (StringBeginsWith(aString, NS_LITERAL_STRING("devicestorage-"))) {
// The string representation of devicestorage file system is of the format:
@@ -38,6 +38,7 @@ FileSystemBase::FromString(const nsAString& aString)
new DeviceStorageFileSystem(storageType, storageName);
return f.forget();
}
return RefPtr<OSFileSystem>(new OSFileSystem(aString)).forget();
}
@@ -57,37 +58,19 @@ FileSystemBase::Shutdown()
mShutdown = true;
}
nsPIDOMWindow*
FileSystemBase::GetWindow() const
nsISupports*
FileSystemBase::GetParentObject() const
{
return nullptr;
}
already_AddRefed<nsIFile>
FileSystemBase::GetLocalFile(const nsAString& aRealPath) const
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Should be on parent process!");
nsAutoString localPath;
FileSystemUtils::NormalizedPathToLocalPath(aRealPath, localPath);
localPath = mLocalRootPath + localPath;
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewLocalFile(localPath, false, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return file.forget();
}
bool
FileSystemBase::GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const
FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Should be on parent process!");
MOZ_ASSERT(aFile, "aFile Should not be null.");
aRealPath.Truncate();
nsAutoString filePath;
ErrorResult rv;
aFile->GetMozFullPathInternal(filePath, rv);
@@ -95,7 +78,13 @@ FileSystemBase::GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const
return false;
}
return LocalPathToRealPath(filePath, aRealPath);
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(filePath),
true, aPath);
if (NS_WARN_IF(rv.Failed())) {
return false;
}
return true;
}
bool
@@ -110,19 +99,5 @@ FileSystemBase::IsSafeDirectory(Directory* aDir) const
return false;
}
bool
FileSystemBase::LocalPathToRealPath(const nsAString& aLocalPath,
nsAString& aRealPath) const
{
nsAutoString path;
FileSystemUtils::LocalPathToNormalizedPath(aLocalPath, path);
if (!FileSystemUtils::IsDescendantPath(mNormalizedLocalRootPath, path)) {
aRealPath.Truncate();
return false;
}
aRealPath = Substring(path, mNormalizedLocalRootPath.Length());
return true;
}
} // namespace dom
} // namespace mozilla
+9 -31
View File
@@ -10,8 +10,6 @@
#include "nsAutoPtr.h"
#include "nsString.h"
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
@@ -25,28 +23,22 @@ public:
// Create file system object from its string representation.
static already_AddRefed<FileSystemBase>
FromString(const nsAString& aString);
DeserializeDOMPath(const nsAString& aString);
FileSystemBase();
virtual void
Shutdown();
// Get the string representation of the file system.
const nsString&
ToString() const
{
return mString;
}
// SerializeDOMPath the FileSystem to string.
virtual void
SerializeDOMPath(nsAString& aOutput) const = 0;
virtual nsPIDOMWindow*
GetWindow() const;
virtual already_AddRefed<FileSystemBase>
Clone() = 0;
/**
* Create nsIFile object from the given real path (absolute DOM path).
*/
already_AddRefed<nsIFile>
GetLocalFile(const nsAString& aRealPath) const;
virtual nsISupports*
GetParentObject() const;
/*
* Get the virtual name of the root directory. This name will be exposed to
@@ -73,13 +65,8 @@ public:
virtual bool
IsSafeDirectory(Directory* aDir) const;
/*
* Get the real path (absolute DOM path) of the DOM file in the file system.
* If succeeded, returns true. Otherwise, returns false and set aRealPath to
* empty string.
*/
bool
GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const;
GetRealPath(BlobImpl* aFile, nsIFile** aPath) const;
/*
* Get the permission name required to access this file system.
@@ -103,21 +90,12 @@ public:
protected:
virtual ~FileSystemBase();
bool
LocalPathToRealPath(const nsAString& aLocalPath, nsAString& aRealPath) const;
// The local path of the root (i.e. the OS path, with OS path separators, of
// the OS directory that acts as the root of this OSFileSystem).
// Only available in the parent process.
// In the child process, we don't use it and its value should be empty.
nsString mLocalRootPath;
// The same, but with path separators normalized to "/".
nsString mNormalizedLocalRootPath;
// The string representation of the file system.
nsString mString;
bool mShutdown;
// The permission name required to access the file system.
@@ -15,7 +15,8 @@
namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS(FileSystemPermissionRequest, nsIRunnable, nsIContentPermissionRequest)
NS_IMPL_ISUPPORTS(FileSystemPermissionRequest, nsIRunnable,
nsIContentPermissionRequest)
// static
void
@@ -28,8 +29,7 @@ FileSystemPermissionRequest::RequestForTask(FileSystemTaskBase* aTask)
NS_DispatchToCurrentThread(request);
}
FileSystemPermissionRequest::FileSystemPermissionRequest(
FileSystemTaskBase* aTask)
FileSystemPermissionRequest::FileSystemPermissionRequest(FileSystemTaskBase* aTask)
: mTask(aTask)
{
MOZ_ASSERT(mTask, "aTask should not be null!");
@@ -44,8 +44,8 @@ FileSystemPermissionRequest::FileSystemPermissionRequest(
mPermissionType = filesystem->GetPermission();
mWindow = filesystem->GetWindow();
if (!mWindow) {
mWindow = do_QueryInterface(filesystem->GetParentObject());
if (NS_WARN_IF(!mWindow)) {
return;
}
+7 -2
View File
@@ -28,8 +28,11 @@ FileSystemRequestParent::~FileSystemRequestParent()
#define FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(name) \
case FileSystemParams::TFileSystem##name##Params: { \
const FileSystem##name##Params& p = aParams; \
mFileSystem = FileSystemBase::FromString(p.filesystem()); \
task = new name##Task(mFileSystem, p, this); \
mFileSystem = FileSystemBase::DeserializeDOMPath(p.filesystem()); \
task = name##Task::Create(mFileSystem, p, this, rv); \
if (NS_WARN_IF(rv.Failed())) { \
return false; \
} \
break; \
}
@@ -39,6 +42,8 @@ FileSystemRequestParent::Dispatch(ContentParent* aParent,
{
MOZ_ASSERT(aParent, "aParent should not be null.");
RefPtr<FileSystemTaskBase> task;
ErrorResult rv;
switch (aParams.type()) {
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(CreateDirectory)
+25 -7
View File
@@ -23,7 +23,7 @@ namespace dom {
namespace {
class FileSystemReleaseRunnable : public nsRunnable
class FileSystemReleaseRunnable final : public nsRunnable
{
public:
explicit FileSystemReleaseRunnable(RefPtr<FileSystemBase>& aDoomed)
@@ -106,12 +106,22 @@ FileSystemTaskBase::Start()
return;
}
nsAutoString serialization;
mFileSystem->SerializeDOMPath(serialization);
ErrorResult rv;
FileSystemParams params = GetRequestParams(serialization, rv);
if (NS_WARN_IF(rv.Failed())) {
return;
}
// Retain a reference so the task object isn't deleted without IPDL's
// knowledge. The reference will be released by
// mozilla::dom::ContentChild::DeallocPFileSystemRequestChild.
NS_ADDREF_THIS();
ContentChild::GetSingleton()->SendPFileSystemRequestConstructor(this,
GetRequestParams(mFileSystem->ToString()));
params);
}
NS_IMETHODIMP
@@ -154,11 +164,17 @@ FileSystemTaskBase::GetRequestResult() const
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (HasError()) {
return FileSystemErrorResponse(mErrorValue);
} else {
return GetSuccessRequestResult();
if (!HasError()) {
ErrorResult rv;
FileSystemResponseValue value = GetSuccessRequestResult(rv);
if (NS_WARN_IF(rv.Failed())) {
return FileSystemErrorResponse(rv.StealNSResult());
}
return value;
}
return FileSystemErrorResponse(mErrorValue);
}
void
@@ -171,7 +187,9 @@ FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
FileSystemErrorResponse r = aValue;
mErrorValue = r.error();
} else {
SetSuccessRequestResult(aValue);
ErrorResult rv;
SetSuccessRequestResult(aValue, rv);
mErrorValue = rv.StealNSResult();
}
}
+5 -3
View File
@@ -176,7 +176,8 @@ protected:
* @param filesystem The string representation of the file system.
*/
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const = 0;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const = 0;
/*
* Wrap the task success result to FileSystemResponseValue for sending it
@@ -185,7 +186,7 @@ protected:
* send the task success result back to the child process.
*/
virtual FileSystemResponseValue
GetSuccessRequestResult() const = 0;
GetSuccessRequestResult(ErrorResult& aRv) const = 0;
/*
* Unwrap the IPC message to get the task success result.
@@ -194,7 +195,8 @@ protected:
* success result.
*/
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) = 0;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) = 0;
bool
HasError() const { return mErrorValue != NS_OK; }
+13 -44
View File
@@ -6,59 +6,28 @@
#include "mozilla/dom/FileSystemUtils.h"
#include "nsXULAppAPI.h"
namespace mozilla {
namespace dom {
// static
void
FileSystemUtils::LocalPathToNormalizedPath(const nsAString& aLocal,
nsAString& aNorm)
/* static */ bool
FileSystemUtils::IsDescendantPath(nsIFile* aFile,
nsIFile* aDescendantFile)
{
nsString result;
result = aLocal;
#if defined(XP_WIN)
char16_t* cur = result.BeginWriting();
char16_t* end = result.EndWriting();
for (; cur < end; ++cur) {
if (char16_t('\\') == *cur)
*cur = char16_t('/');
nsAutoString path;
nsresult rv = aFile->GetPath(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
#endif
aNorm = result;
}
// static
void
FileSystemUtils::NormalizedPathToLocalPath(const nsAString& aNorm,
nsAString& aLocal)
{
nsString result;
result = aNorm;
#if defined(XP_WIN)
char16_t* cur = result.BeginWriting();
char16_t* end = result.EndWriting();
for (; cur < end; ++cur) {
if (char16_t('/') == *cur)
*cur = char16_t('\\');
nsAutoString descendantPath;
rv = aDescendantFile->GetPath(descendantPath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
#endif
aLocal = result;
}
// static
bool
FileSystemUtils::IsDescendantPath(const nsAString& aPath,
const nsAString& aDescendantPath)
{
// The descendant path should begin with its ancestor path.
nsAutoString prefix;
prefix = aPath + NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR);
// Check the sub-directory path to see if it has the parent path as prefix.
if (aDescendantPath.Length() < prefix.Length() ||
!StringBeginsWith(aDescendantPath, prefix)) {
if (descendantPath.Length() <= path.Length() ||
!StringBeginsWith(descendantPath, path)) {
return false;
}
+5 -20
View File
@@ -7,12 +7,13 @@
#ifndef mozilla_dom_FileSystemUtils_h
#define mozilla_dom_FileSystemUtils_h
#include "nsString.h"
class nsIFile;
namespace mozilla {
namespace dom {
#define FILESYSTEM_DOM_PATH_SEPARATOR "/"
#define FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL "/"
#define FILESYSTEM_DOM_PATH_SEPARATOR_CHAR '/'
/*
* This class is for error handling.
@@ -22,26 +23,10 @@ class FileSystemUtils
{
public:
/*
* Convert the path separator to "/".
*/
static void
LocalPathToNormalizedPath(const nsAString& aLocal, nsAString& aNorm);
/*
* Convert the normalized path separator "/" to the system dependent path
* separator, which is "/" on Mac and Linux, and "\" on Windows.
*/
static void
NormalizedPathToLocalPath(const nsAString& aNorm, nsAString& aLocal);
/*
* Return true if aDescendantPath is a descendant of aPath. Both aPath and
* aDescendantPath are absolute DOM path.
* Return true if aDescendantPath is a descendant of aPath.
*/
static bool
IsDescendantPath(const nsAString& aPath, const nsAString& aDescendantPath);
static const char16_t kSeparatorChar = char16_t('/');
IsDescendantPath(nsIFile* aPath, nsIFile* aDescendantPath);
};
} // namespace dom
+165 -60
View File
@@ -8,7 +8,6 @@
#include "HTMLSplitOnSpacesTokenizer.h"
#include "js/Value.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
@@ -21,33 +20,80 @@
namespace mozilla {
namespace dom {
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
const nsAString& aFilters,
ErrorResult& aRv)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aTargetPath)
, mFilters(aFilters)
/* static */ already_AddRefed<GetDirectoryListingTask>
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetDirectoryListingTask> task =
new GetDirectoryListingTask(aFileSystem, aTargetPath, aType, aFilters);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
do_QueryInterface(aFileSystem->GetParentObject());
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mPromise = Promise::Create(globalObject, aRv);
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
/* static */ already_AddRefed<GetDirectoryListingTask>
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetDirectoryListingTask> task =
new GetDirectoryListingTask(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->mType = aParam.isRoot()
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
return task.forget();
}
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters)
: FileSystemTaskBase(aFileSystem)
, mTargetPath(aTargetPath)
, mFilters(aFilters)
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mTargetRealPath(aParam.realPath())
, mFilters(aParam.filters())
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
@@ -66,43 +112,79 @@ GetDirectoryListingTask::GetPromise()
}
FileSystemParams
GetDirectoryListingTask::GetRequestParams(const nsString& aFileSystem) const
GetDirectoryListingTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemGetDirectoryListingParams(aFileSystem, mTargetRealPath,
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemGetDirectoryListingParams();
}
return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
mType == Directory::eDOMRootDirectory,
mFilters);
}
FileSystemResponseValue
GetDirectoryListingTask::GetSuccessRequestResult() const
GetDirectoryListingTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
InfallibleTArray<PBlobParent*> blobs;
for (unsigned i = 0; i < mTargetBlobImpls.Length(); i++) {
BlobParent* blobParent = GetBlobParent(mTargetBlobImpls[i]);
if (blobParent) {
blobs.AppendElement(blobParent);
nsTArray<FileSystemDirectoryListingResponseData> inputs;
for (unsigned i = 0; i < mTargetData.Length(); i++) {
if (mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl) {
BlobParent* blobParent = GetBlobParent(mTargetData[i].mBlobImpl);
if (!blobParent) {
continue;
}
FileSystemDirectoryListingResponseBlob blobData;
blobData.blobParent() = blobParent;
inputs.AppendElement(blobData);
} else {
MOZ_ASSERT(mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath);
FileSystemDirectoryListingResponseDirectory directoryData;
directoryData.directoryRealPath() = mTargetData[i].mDirectoryPath;
inputs.AppendElement(directoryData);
}
}
FileSystemDirectoryListingResponse response;
response.blobsParent().SwapElements(blobs);
response.data().SwapElements(inputs);
return response;
}
void
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aValue.type() ==
FileSystemResponseValue::TFileSystemDirectoryListingResponse);
FileSystemDirectoryListingResponse r = aValue;
nsTArray<PBlobChild*>& blobs = r.blobsChild();
for (uint32_t i = 0; i < r.data().Length(); ++i) {
const FileSystemDirectoryListingResponseData& data = r.data()[i];
for (unsigned i = 0; i < blobs.Length(); i++) {
mTargetBlobImpls.AppendElement(static_cast<BlobChild*>(blobs[i])->GetBlobImpl());
if (data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseBlob) {
PBlobChild* blob = data.get_FileSystemDirectoryListingResponseBlob().blobChild();
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
element->mType = Directory::BlobImplOrDirectoryPath::eBlobImpl;
element->mBlobImpl = static_cast<BlobChild*>(blob)->GetBlobImpl();
} else {
MOZ_ASSERT(data.type() == FileSystemDirectoryListingResponseData::TFileSystemDirectoryListingResponseDirectory);
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
element->mType = Directory::BlobImplOrDirectoryPath::eDirectoryPath;
element->mDirectoryPath = data.get_FileSystemDirectoryListingResponseDirectory().directoryRealPath();
}
}
}
@@ -117,27 +199,19 @@ GetDirectoryListingTask::Work()
return NS_ERROR_FAILURE;
}
// Whether we want to get the root directory.
bool getRoot = mTargetRealPath.IsEmpty();
nsCOMPtr<nsIFile> dir = mFileSystem->GetLocalFile(mTargetRealPath);
if (!dir) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
bool exists;
nsresult rv = dir->Exists(&exists);
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!exists) {
if (!getRoot) {
if (mType == Directory::eNotDOMRootDirectory) {
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
}
// If the root directory doesn't exit, create it.
rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0777);
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -145,7 +219,7 @@ GetDirectoryListingTask::Work()
// Get isDirectory.
bool isDir;
rv = dir->IsDirectory(&isDir);
rv = mTargetPath->IsDirectory(&isDir);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -155,7 +229,7 @@ GetDirectoryListingTask::Work()
}
nsCOMPtr<nsISimpleEnumerator> entries;
rv = dir->GetDirectoryEntries(getter_AddRefs(entries));
rv = mTargetPath->GetDirectoryEntries(getter_AddRefs(entries));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -186,7 +260,7 @@ GetDirectoryListingTask::Work()
nsCOMPtr<nsIFile> currFile = do_QueryInterface(supp);
MOZ_ASSERT(currFile);
bool isLink, isSpecial, isFile;
if (NS_WARN_IF(NS_FAILED(currFile->IsSymlink(&isLink)) ||
NS_FAILED(currFile->IsSpecial(&isSpecial))) ||
@@ -213,9 +287,22 @@ GetDirectoryListingTask::Work()
}
}
BlobImplFile* impl = new BlobImplFile(currFile);
impl->LookupAndCacheIsDirectory();
mTargetBlobImpls.AppendElement(impl);
if (isDir) {
nsAutoString path;
if (NS_WARN_IF(NS_FAILED(currFile->GetPath(path)))) {
continue;
}
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
element->mType = Directory::BlobImplOrDirectoryPath::eDirectoryPath;
element->mDirectoryPath = path;
} else {
BlobImplFile* impl = new BlobImplFile(currFile);
Directory::BlobImplOrDirectoryPath* element = mTargetData.AppendElement();
element->mType = Directory::BlobImplOrDirectoryPath::eBlobImpl;
element->mBlobImpl = impl;
}
}
return NS_OK;
}
@@ -235,37 +322,55 @@ GetDirectoryListingTask::HandlerCallback()
return;
}
size_t count = mTargetBlobImpls.Length();
size_t count = mTargetData.Length();
Sequence<OwningFileOrDirectory> listing;
if (!listing.SetLength(count, mozilla::fallible_t())) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
mPromise = nullptr;
return;
}
for (unsigned i = 0; i < count; i++) {
if (mTargetBlobImpls[i]->IsDirectory()) {
nsAutoString name;
mTargetBlobImpls[i]->GetName(name);
nsAutoString path(mTargetRealPath);
path.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR);
path.Append(name);
#ifdef DEBUG
if (XRE_IsParentProcess()) {
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(path);
bool exist;
file->Exists(&exist);
MOZ_ASSERT(exist);
if (mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath) {
nsCOMPtr<nsIFile> directoryPath;
NS_ConvertUTF16toUTF8 path(mTargetData[i].mDirectoryPath);
nsresult rv = NS_NewNativeLocalFile(path, true,
getter_AddRefs(directoryPath));
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(rv);
mPromise = nullptr;
return;
}
#ifdef DEBUG
nsCOMPtr<nsIFile> rootPath;
rv = NS_NewLocalFile(mFileSystem->GetLocalRootPath(), false,
getter_AddRefs(rootPath));
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(rv);
mPromise = nullptr;
return;
}
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, directoryPath));
#endif
RefPtr<Directory> directory = new Directory(mFileSystem, path);
RefPtr<Directory> directory =
Directory::Create(mFileSystem->GetParentObject(),
directoryPath,
Directory::eNotDOMRootDirectory,
mFileSystem);
MOZ_ASSERT(directory);
// Propogate mFilter onto sub-Directory object:
directory->SetContentFilters(mFilters);
listing[i].SetAsDirectory() = directory;
} else {
listing[i].SetAsFile() = File::Create(mFileSystem->GetWindow(), mTargetBlobImpls[i]);
MOZ_ASSERT(mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl);
listing[i].SetAsFile() =
File::Create(mFileSystem->GetParentObject(), mTargetData[i].mBlobImpl);
}
}
+34 -17
View File
@@ -7,6 +7,7 @@
#ifndef mozilla_dom_GetDirectoryListing_h
#define mozilla_dom_GetDirectoryListing_h
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemTaskBase.h"
#include "mozilla/ErrorResult.h"
#include "nsAutoPtr.h"
@@ -16,18 +17,21 @@ namespace dom {
class BlobImpl;
class GetDirectoryListingTask final
: public FileSystemTaskBase
class GetDirectoryListingTask final : public FileSystemTaskBase
{
public:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetDirectoryListingTask(FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
const nsAString& aFilters,
ErrorResult& aRv);
GetDirectoryListingTask(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<GetDirectoryListingTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters,
ErrorResult& aRv);
static already_AddRefed<GetDirectoryListingTask>
Create(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~GetDirectoryListingTask();
@@ -37,15 +41,28 @@ public:
virtual void
GetPermissionAccessType(nsCString& aAccess) const override;
protected:
private:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetDirectoryListingTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters);
GetDirectoryListingTask(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent);
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@@ -53,14 +70,14 @@ protected:
virtual void
HandlerCallback() override;
private:
RefPtr<Promise> mPromise;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
nsString mFilters;
Directory::DirectoryType mType;
// We cannot store File or Directory objects bacause this object is created
// on a different thread and File and Directory are not thread-safe.
nsTArray<RefPtr<BlobImpl>> mTargetBlobImpls;
nsTArray<Directory::BlobImplOrDirectoryPath> mTargetData;
};
} // namespace dom
+109 -47
View File
@@ -7,8 +7,6 @@
#include "GetFileOrDirectoryTask.h"
#include "js/Value.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
@@ -21,37 +19,82 @@
namespace mozilla {
namespace dom {
GetFileOrDirectoryTask::GetFileOrDirectoryTask(
FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
bool aDirectoryOnly,
ErrorResult& aRv)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aTargetPath)
, mIsDirectory(aDirectoryOnly)
/* static */ already_AddRefed<GetFileOrDirectoryTask>
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetFileOrDirectoryTask> task =
new GetFileOrDirectoryTask(aFileSystem, aTargetPath, aType, aDirectoryOnly);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
do_QueryInterface(aFileSystem->GetParentObject());
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mPromise = Promise::Create(globalObject, aRv);
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
GetFileOrDirectoryTask::GetFileOrDirectoryTask(
FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent)
/* static */ already_AddRefed<GetFileOrDirectoryTask>
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetFileOrDirectoryTask> task =
new GetFileOrDirectoryTask(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->mType = aParam.isRoot()
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
return task.forget();
}
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly)
: FileSystemTaskBase(aFileSystem)
, mTargetPath(aTargetPath)
, mIsDirectory(aDirectoryOnly)
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mIsDirectory(false)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
mTargetRealPath = aParam.realPath();
}
GetFileOrDirectoryTask::~GetFileOrDirectoryTask()
@@ -68,18 +111,33 @@ GetFileOrDirectoryTask::GetPromise()
}
FileSystemParams
GetFileOrDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
GetFileOrDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemGetFileOrDirectoryParams(aFileSystem, mTargetRealPath);
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemGetFileOrDirectoryParams();
}
return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path,
mType == Directory::eDOMRootDirectory);
}
FileSystemResponseValue
GetFileOrDirectoryTask::GetSuccessRequestResult() const
GetFileOrDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (mIsDirectory) {
return FileSystemDirectoryResponse(mTargetRealPath);
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemDirectoryResponse();
}
return FileSystemDirectoryResponse(path);
}
BlobParent* actor = GetBlobParent(mTargetBlobImpl);
@@ -92,7 +150,8 @@ GetFileOrDirectoryTask::GetSuccessRequestResult() const
}
void
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
switch (aValue.type()) {
@@ -105,7 +164,13 @@ GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& a
}
case FileSystemResponseValue::TFileSystemDirectoryResponse: {
FileSystemDirectoryResponse r = aValue;
mTargetRealPath = r.realPath();
NS_ConvertUTF16toUTF8 path(r.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
mIsDirectory = true;
break;
}
@@ -128,33 +193,26 @@ GetFileOrDirectoryTask::Work()
}
// Whether we want to get the root directory.
bool getRoot = mTargetRealPath.IsEmpty();
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
if (!file) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
bool exists;
nsresult rv = file->Exists(&exists);
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!exists) {
if (!getRoot) {
if (mType == Directory::eNotDOMRootDirectory) {
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
}
// If the root directory doesn't exit, create it.
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777);
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// Get isDirectory.
rv = file->IsDirectory(&mIsDirectory);
rv = mTargetPath->IsDirectory(&mIsDirectory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -164,13 +222,13 @@ GetFileOrDirectoryTask::Work()
}
// Check if the root is a directory.
if (getRoot) {
if (mType == Directory::eDOMRootDirectory) {
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
}
bool isFile;
// Get isFile
rv = file->IsFile(&isFile);
rv = mTargetPath->IsFile(&isFile);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -180,11 +238,11 @@ GetFileOrDirectoryTask::Work()
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
}
if (!mFileSystem->IsSafeFile(file)) {
if (!mFileSystem->IsSafeFile(mTargetPath)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
mTargetBlobImpl = new BlobImplFile(file);
mTargetBlobImpl = new BlobImplFile(mTargetPath);
return NS_OK;
}
@@ -199,21 +257,25 @@ GetFileOrDirectoryTask::HandlerCallback()
}
if (HasError()) {
RefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
mErrorValue);
mPromise->MaybeRejectBrokenly(domError);
mPromise->MaybeReject(mErrorValue);
mPromise = nullptr;
return;
}
if (mIsDirectory) {
RefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
mTargetPath,
mType,
mFileSystem);
MOZ_ASSERT(dir);
mPromise->MaybeResolve(dir);
mPromise = nullptr;
return;
}
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetBlobImpl);
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetParentObject(),
mTargetBlobImpl);
mPromise->MaybeResolve(blob);
mPromise = nullptr;
}
+32 -14
View File
@@ -7,6 +7,7 @@
#ifndef mozilla_dom_GetFileOrDirectory_h
#define mozilla_dom_GetFileOrDirectory_h
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemTaskBase.h"
#include "nsAutoPtr.h"
#include "mozilla/ErrorResult.h"
@@ -16,18 +17,21 @@ namespace dom {
class BlobImpl;
class GetFileOrDirectoryTask final
: public FileSystemTaskBase
class GetFileOrDirectoryTask final : public FileSystemTaskBase
{
public:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
bool aDirectoryOnly,
ErrorResult& aRv);
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<GetFileOrDirectoryTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly,
ErrorResult& aRv);
static already_AddRefed<GetFileOrDirectoryTask>
Create(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~GetFileOrDirectoryTask();
@@ -39,13 +43,15 @@ public:
GetPermissionAccessType(nsCString& aAccess) const override;
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@@ -54,10 +60,22 @@ protected:
HandlerCallback() override;
private:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly);
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent);
RefPtr<Promise> mPromise;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
// Whether we get a directory.
bool mIsDirectory;
Directory::DirectoryType mType;
// This cannot be a File bacause this object is created on a different
// thread and File is not thread-safe. Let's use the BlobImpl instead.
+35 -17
View File
@@ -9,10 +9,10 @@
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "nsIGlobalObject.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "nsIFile.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
@@ -20,40 +20,52 @@ namespace dom {
OSFileSystem::OSFileSystem(const nsAString& aRootDir)
{
mLocalRootPath = aRootDir;
FileSystemUtils::LocalPathToNormalizedPath(mLocalRootPath,
mNormalizedLocalRootPath);
// Non-mobile devices don't have the concept of separate permissions to
// access different parts of devices storage like Pictures, or Videos, etc.
mRequiresPermissionChecks = false;
mString = mLocalRootPath;
#ifdef DEBUG
mPermission.AssignLiteral("never-used");
#endif
}
void
OSFileSystem::Init(nsPIDOMWindow* aWindow)
already_AddRefed<FileSystemBase>
OSFileSystem::Clone()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(!mWindow, "No duple Init() calls");
MOZ_ASSERT(aWindow);
mWindow = aWindow;
RefPtr<OSFileSystem> fs = new OSFileSystem(mLocalRootPath);
if (mParent) {
fs->Init(mParent);
}
return fs.forget();
}
nsPIDOMWindow*
OSFileSystem::GetWindow() const
void
OSFileSystem::Init(nsISupports* aParent)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return mWindow;
MOZ_ASSERT(!mParent, "No duple Init() calls");
MOZ_ASSERT(aParent);
mParent = aParent;
#ifdef DEBUG
nsCOMPtr<nsIGlobalObject> obj = do_QueryInterface(aParent);
MOZ_ASSERT(obj);
#endif
}
nsISupports*
OSFileSystem::GetParentObject() const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return mParent;
}
void
OSFileSystem::GetRootName(nsAString& aRetval) const
{
return aRetval.AssignLiteral("/");
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
}
bool
@@ -79,14 +91,20 @@ OSFileSystem::IsSafeDirectory(Directory* aDir) const
void
OSFileSystem::Unlink()
{
mWindow = nullptr;
mParent = nullptr;
}
void
OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb)
{
OSFileSystem* tmp = this;
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent);
}
void
OSFileSystem::SerializeDOMPath(nsAString& aOutput) const
{
aOutput = mLocalRootPath;
}
} // namespace dom
+10 -4
View File
@@ -18,12 +18,15 @@ public:
explicit OSFileSystem(const nsAString& aRootDir);
void
Init(nsPIDOMWindow* aWindow);
Init(nsISupports* aParent);
// Overrides FileSystemBase
virtual nsPIDOMWindow*
GetWindow() const override;
virtual already_AddRefed<FileSystemBase>
Clone() override;
virtual nsISupports*
GetParentObject() const override;
virtual void
GetRootName(nsAString& aRetval) const override;
@@ -34,6 +37,9 @@ public:
virtual bool
IsSafeDirectory(Directory* aDir) const override;
virtual void
SerializeDOMPath(nsAString& aOutput) const override;
// CC methods
virtual void Unlink() override;
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) override;
@@ -41,7 +47,7 @@ public:
private:
virtual ~OSFileSystem() {}
nsCOMPtr<nsPIDOMWindow> mWindow;
nsCOMPtr<nsISupports> mParent;
};
} // namespace dom
+18 -1
View File
@@ -20,9 +20,26 @@ struct FileSystemDirectoryResponse
nsString realPath;
};
struct FileSystemDirectoryListingResponseBlob
{
PBlob blob;
};
struct FileSystemDirectoryListingResponseDirectory
{
// This is the full real path for the directory that we are sending via IPC.
nsString directoryRealPath;
};
union FileSystemDirectoryListingResponseData
{
FileSystemDirectoryListingResponseBlob;
FileSystemDirectoryListingResponseDirectory;
};
struct FileSystemDirectoryListingResponse
{
PBlob[] blobs;
FileSystemDirectoryListingResponseData[] data;
};
struct FileSystemErrorResponse
+110 -53
View File
@@ -6,7 +6,6 @@
#include "RemoveTask.h"
#include "DOMError.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
@@ -19,27 +18,94 @@
namespace mozilla {
namespace dom {
/* static */ already_AddRefed<RemoveTask>
RemoveTask::Create(FileSystemBase* aFileSystem,
nsIFile* aDirPath,
BlobImpl* aTargetBlob,
nsIFile* aTargetPath,
bool aRecursive,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
MOZ_ASSERT(aDirPath);
RefPtr<RemoveTask> task =
new RemoveTask(aFileSystem, aDirPath, aTargetBlob, aTargetPath, aRecursive);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetParentObject());
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
/* static */ already_AddRefed<RemoveTask>
RemoveTask::Create(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<RemoveTask> task =
new RemoveTask(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 directoryPath(aParam.directory());
aRv = NS_NewNativeLocalFile(directoryPath, true,
getter_AddRefs(task->mDirPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->mRecursive = aParam.recursive();
const FileSystemPathOrFileValue& target = aParam.target();
if (target.type() == FileSystemPathOrFileValue::TnsString) {
NS_ConvertUTF16toUTF8 path(target);
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
task->mTargetBlobImpl = bp->GetBlobImpl();
MOZ_ASSERT(task->mTargetBlobImpl);
return task.forget();
}
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
const nsAString& aDirPath,
nsIFile* aDirPath,
BlobImpl* aTargetBlob,
const nsAString& aTargetPath,
bool aRecursive,
ErrorResult& aRv)
nsIFile* aTargetPath,
bool aRecursive)
: FileSystemTaskBase(aFileSystem)
, mDirRealPath(aDirPath)
, mDirPath(aDirPath)
, mTargetBlobImpl(aTargetBlob)
, mTargetRealPath(aTargetPath)
, mTargetPath(aTargetPath)
, mRecursive(aRecursive)
, mReturnValue(false)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
}
mPromise = Promise::Create(globalObject, aRv);
MOZ_ASSERT(aDirPath);
}
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
@@ -49,25 +115,9 @@ RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
, mRecursive(false)
, mReturnValue(false)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
mDirRealPath = aParam.directory();
mRecursive = aParam.recursive();
const FileSystemPathOrFileValue& target = aParam.target();
if (target.type() == FileSystemPathOrFileValue::TnsString) {
mTargetRealPath = target;
return;
}
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
mTargetBlobImpl = bp->GetBlobImpl();
MOZ_ASSERT(mTargetBlobImpl);
}
RemoveTask::~RemoveTask()
@@ -84,36 +134,49 @@ RemoveTask::GetPromise()
}
FileSystemParams
RemoveTask::GetRequestParams(const nsString& aFileSystem) const
RemoveTask::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemRemoveParams param;
param.filesystem() = aFileSystem;
param.directory() = mDirRealPath;
param.filesystem() = aSerializedDOMPath;
aRv = mDirPath->GetPath(param.directory());
if (NS_WARN_IF(aRv.Failed())) {
return param;
}
param.recursive() = mRecursive;
if (mTargetBlobImpl) {
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(),
mTargetBlobImpl);
RefPtr<Blob> blob = Blob::Create(mFileSystem->GetParentObject(),
mTargetBlobImpl);
BlobChild* actor
= ContentChild::GetSingleton()->GetOrCreateActorForBlob(blob);
if (actor) {
param.target() = actor;
}
} else {
param.target() = mTargetRealPath;
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return param;
}
param.target() = path;
}
return param;
}
FileSystemResponseValue
RemoveTask::GetSuccessRequestResult() const
RemoveTask::GetSuccessRequestResult(ErrorResult& aRv) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemBooleanResponse(mReturnValue);
}
void
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemBooleanResponse r = aValue;
@@ -131,23 +194,19 @@ RemoveTask::Work()
return NS_ERROR_FAILURE;
}
// Get the DOM path if a File is passed as the target.
// Get the path if a File is passed as the target.
if (mTargetBlobImpl) {
if (!mFileSystem->GetRealPath(mTargetBlobImpl, mTargetRealPath)) {
if (!mFileSystem->GetRealPath(mTargetBlobImpl,
getter_AddRefs(mTargetPath))) {
return NS_ERROR_DOM_SECURITY_ERR;
}
if (!FileSystemUtils::IsDescendantPath(mDirRealPath, mTargetRealPath)) {
if (!FileSystemUtils::IsDescendantPath(mDirPath, mTargetPath)) {
return NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
}
}
nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
if (!file) {
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
bool exists = false;
nsresult rv = file->Exists(&exists);
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -158,16 +217,16 @@ RemoveTask::Work()
}
bool isFile = false;
rv = file->IsFile(&isFile);
rv = mTargetPath->IsFile(&isFile);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (isFile && !mFileSystem->IsSafeFile(file)) {
if (isFile && !mFileSystem->IsSafeFile(mTargetPath)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
rv = file->Remove(mRecursive);
rv = mTargetPath->Remove(mRecursive);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -187,9 +246,7 @@ RemoveTask::HandlerCallback()
}
if (HasError()) {
RefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
mErrorValue);
mPromise->MaybeRejectBrokenly(domError);
mPromise->MaybeReject(mErrorValue);
mPromise = nullptr;
return;
}
+32 -16
View File
@@ -17,19 +17,22 @@ namespace dom {
class BlobImpl;
class Promise;
class RemoveTask final
: public FileSystemTaskBase
class RemoveTask final : public FileSystemTaskBase
{
public:
RemoveTask(FileSystemBase* aFileSystem,
const nsAString& aDirPath,
BlobImpl* aTargetBlob,
const nsAString& aTargetPath,
bool aRecursive,
ErrorResult& aRv);
RemoveTask(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent);
static already_AddRefed<RemoveTask>
Create(FileSystemBase* aFileSystem,
nsIFile* aDirPath,
BlobImpl* aTargetBlob,
nsIFile* aTargetPath,
bool aRecursive,
ErrorResult& aRv);
static already_AddRefed<RemoveTask>
Create(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual
~RemoveTask();
@@ -42,13 +45,15 @@ public:
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const override;
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult() const override;
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) override;
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual nsresult
Work() override;
@@ -57,12 +62,23 @@ protected:
HandlerCallback() override;
private:
RemoveTask(FileSystemBase* aFileSystem,
nsIFile* aDirPath,
BlobImpl* aTargetBlob,
nsIFile* aTargetPath,
bool aRecursive);
RemoveTask(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent);
RefPtr<Promise> mPromise;
nsString mDirRealPath;
nsCOMPtr<nsIFile> mDirPath;
// This cannot be a File because this object will be used on a different
// thread and File is not thread-safe. Let's use the BlobImpl instead.
RefPtr<BlobImpl> mTargetBlobImpl;
nsString mTargetRealPath;
nsCOMPtr<nsIFile> mTargetPath;
bool mRecursive;
bool mReturnValue;
};
+2
View File
@@ -4,6 +4,8 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
TEST_DIRS += ['tests']
EXPORTS.mozilla.dom += [
'DeviceStorageFileSystem.h',
'Directory.h',
+5
View File
@@ -0,0 +1,5 @@
[DEFAULT]
support-files =
script_fileList.js
[test_basic.html]
+7
View File
@@ -0,0 +1,7 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MOCHITEST_MANIFESTS += ['mochitest.ini']

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