Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
fix: Make the check for ZoneAwarePromise more stringent (#495)
Browse files Browse the repository at this point in the history
`resolvePromise` assumes that if a value is an `instanceof` ZoneAwarePromise
then it has the properties "__zone_symbol__state" and "__zone_symbol__value"
and it _is_ a true ZoneAwarePromise; however, a user can construct a value that
breaks this assumption by inheriting from ZoneAwarePromise without actually
having those properties or being a true ZoneAwarePromise (for example, by
attempting to subclass Promise).

We can fix this by adding checks for "__zone_symbol__state" and
"__zone_symbol__value" to `resolvePromise`.
  • Loading branch information
markandrus authored and mhevery committed Nov 16, 2016
1 parent d8c15eb commit c69df25
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
5 changes: 4 additions & 1 deletion lib/zone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,10 @@ const Zone: ZoneType = (function(global: any) {
function resolvePromise(
promise: ZoneAwarePromise<any>, state: boolean, value: any): ZoneAwarePromise<any> {
if (promise[symbolState] === UNRESOLVED) {
if (value instanceof ZoneAwarePromise && value[symbolState] !== UNRESOLVED) {
if (value instanceof ZoneAwarePromise &&
value.hasOwnProperty(symbolState) &&
value.hasOwnProperty(symbolValue) &&
value[symbolState] !== UNRESOLVED) {
clearRejectedNoCatch(<Promise<any>>value);
resolvePromise(promise, value[symbolState], value[symbolValue]);
} else if (isThenable(value)) {
Expand Down
47 changes: 47 additions & 0 deletions test/common/Promise.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,53 @@ describe(
});
});

describe('Promise subclasses', function() {
function MyPromise(init) {
this._promise = new Promise(init);
}

MyPromise.prototype.catch = function _catch() {
return this._promise.catch.apply(this._promise, arguments);
};

MyPromise.prototype.then = function then() {
return this._promise.then.apply(this._promise, arguments);
};

var setPrototypeOf = (Object as any).setPrototypeOf || function(obj, proto) {
obj.__proto__ = proto;
return obj;
}

setPrototypeOf(MyPromise.prototype, Promise.prototype);

it('should reject if the Promise subclass rejects', function() {
var myPromise = new MyPromise(function(resolve, reject) {
reject('foo');
});

return Promise.resolve().then(function() {
return myPromise;
}).then(function() {
throw new Error('Unexpected resolution');
}, function(result) {
expect(result).toBe('foo');
});
});

it('should resolve if the Promise subclass resolves', function() {
var myPromise = new MyPromise(function(resolve, reject) {
resolve('foo');
});

return Promise.resolve().then(function() {
return myPromise;
}).then(function(result) {
expect(result).toBe('foo');
});
});
});

describe('fetch', ifEnvSupports('fetch', function() {
it('should work for text response', function(done) {
testZone.run(function() {
Expand Down

0 comments on commit c69df25

Please sign in to comment.