diff --git a/packages/ddp-client/client/client_convenience.js b/packages/ddp-client/client/client_convenience.js index 029ad16445..f243fadec0 100644 --- a/packages/ddp-client/client/client_convenience.js +++ b/packages/ddp-client/client/client_convenience.js @@ -31,7 +31,9 @@ var retry = new Retry(); function onDDPVersionNegotiationFailure(description) { Meteor._debug(description); if (Package.reload) { - var migrationData = Package.reload.Reload._migrationData('livedata') || {}; + var migrationData = + Package.reload.Reload._migrationData('livedata') || + Object.create(null); var failures = migrationData.DDPVersionNegotiationFailures || 0; ++failures; Package.reload.Reload._onMigrate('livedata', () => { diff --git a/packages/ddp-client/common/livedata_connection.js b/packages/ddp-client/common/livedata_connection.js index a1f7b147e9..47d9c7477e 100644 --- a/packages/ddp-client/common/livedata_connection.js +++ b/packages/ddp-client/common/livedata_connection.js @@ -52,7 +52,7 @@ export class Connection { }, heartbeatInterval: 17500, heartbeatTimeout: 15000, - npmFayeOptions: {}, + npmFayeOptions: Object.create(null), // These options are only for testing. reloadWithOutstanding: false, supportedDDPVersions: DDPCommon.SUPPORTED_DDP_VERSIONS, @@ -95,8 +95,8 @@ export class Connection { self._lastSessionId = null; self._versionSuggestion = null; // The last proposed DDP version. self._version = null; // The DDP version agreed on by client and server. - self._stores = {}; // name -> object with methods - self._methodHandlers = {}; // name -> func + self._stores = Object.create(null); // name -> object with methods + self._methodHandlers = Object.create(null); // name -> func self._nextMethodId = 1; self._supportedDDPVersions = options.supportedDDPVersions; @@ -107,7 +107,7 @@ export class Connection { // called their user callback (ie, they are waiting on their result or for all // of their writes to be written to the local cache). Map from method ID to // MethodInvoker object. - self._methodInvokers = {}; + self._methodInvokers = Object.create(null); // Tracks methods which the user has called but whose result messages have not // arrived yet. @@ -151,7 +151,7 @@ export class Connection { // documents written by a given method's stub. keys are associated with // methods whose stub wrote at least one document, and whose data-done message // has not yet been received. - self._documentsWrittenByStub = {}; + self._documentsWrittenByStub = Object.create(null); // collection -> IdMap of "server document" object. A "server document" has: // - "document": the version of the document according the // server (ie, the snapshot before a stub wrote it, amended by any changes @@ -159,7 +159,7 @@ export class Connection { // It is undefined if we think the document does not exist // - "writtenByStubs": a set of method IDs whose stubs wrote to the document // whose "data done" messages have not yet been processed - self._serverDocuments = {}; + self._serverDocuments = Object.create(null); // Array of callbacks to be called after the next update of the local // cache. Used for: @@ -188,16 +188,16 @@ export class Connection { // Map from method ID -> true. Methods are removed from this when their // "data done" message is received, and we will not quiesce until it is // empty. - self._methodsBlockingQuiescence = {}; + self._methodsBlockingQuiescence = Object.create(null); // map from sub ID -> true for subs that were ready (ie, called the sub // ready callback) before reconnect but haven't become ready again yet - self._subsBeingRevived = {}; // map from sub._id -> true + self._subsBeingRevived = Object.create(null); // map from sub._id -> true // if true, the next data update should reset all stores. (set during // reconnect.) self._resetStores = false; // name -> array of updates for (yet to be created) collections - self._updatesForUnknownStores = {}; + self._updatesForUnknownStores = Object.create(null); // if we're blocking a migration, the retry func self._retryMigrate = null; @@ -207,7 +207,7 @@ export class Connection { self ); // Collection name -> array of messages. - self._bufferedWrites = {}; + self._bufferedWrites = Object.create(null); // When current buffer of updates must be flushed at, in ms timestamp. self._bufferedWritesFlushAt = null; // Timeout handle for the next processing of all pending writes @@ -227,7 +227,7 @@ export class Connection { // an error, XXX COMPAT WITH 1.0.3.1) // - stopCallback (an optional callback to call when the sub terminates // for any reason, with an error argument if an error triggered the stop) - self._subscriptions = {}; + self._subscriptions = Object.create(null); // Reactive userId. self._userId = null; @@ -287,7 +287,7 @@ export class Connection { // Wrap the input object in an object which makes any store method not // implemented by 'store' into a no-op. - var store = {}; + var store = Object.create(null); _.each( [ 'update', @@ -341,7 +341,7 @@ export class Connection { var self = this; var params = Array.prototype.slice.call(arguments, 1); - var callbacks = {}; + var callbacks = Object.create(null); if (params.length) { var lastParam = params[params.length - 1]; if (typeof lastParam === 'function') { @@ -584,9 +584,9 @@ export class Connection { // or (name, args, callback) if (!callback && typeof options === 'function') { callback = options; - options = {}; + options = Object.create(null); } - options = options || {}; + options = options || Object.create(null); if (callback) { // XXX would it be better form to do the binding in stream.on, @@ -816,7 +816,10 @@ export class Connection { docsWritten.push({ collection: collection, id: id }); if (!_.has(self._serverDocuments, collection)) self._serverDocuments[collection] = new MongoIDMap(); - var serverDoc = self._serverDocuments[collection].setDefault(id, {}); + var serverDoc = self._serverDocuments[collection].setDefault( + id, + Object.create(null) + ); if (serverDoc.writtenByStubs) { // We're not the first stub to write this doc. Just add our method ID // to the record. @@ -825,7 +828,7 @@ export class Connection { // First stub! Save the original value and our method ID. serverDoc.document = doc; serverDoc.flushCallbacks = []; - serverDoc.writtenByStubs = {}; + serverDoc.writtenByStubs = Object.create(null); serverDoc.writtenByStubs[methodId] = true; } }); @@ -971,13 +974,13 @@ export class Connection { // Forget about messages we were buffering for unknown collections. They'll // be resent if still relevant. - self._updatesForUnknownStores = {}; + self._updatesForUnknownStores = Object.create(null); if (self._resetStores) { // Forget about the effects of stubs. We'll be resetting all collections // anyway. - self._documentsWrittenByStub = {}; - self._serverDocuments = {}; + self._documentsWrittenByStub = Object.create(null); + self._serverDocuments = Object.create(null); } // Clear _afterUpdateCallbacks. @@ -987,7 +990,7 @@ export class Connection { // ready callback) as needing to be revived. // XXX We should also block reconnect quiescence until unnamed subscriptions // (eg, autopublish) are done re-publishing to avoid flicker! - self._subsBeingRevived = {}; + self._subsBeingRevived = Object.create(null); _.each(self._subscriptions, (sub, id) => { if (sub.ready) self._subsBeingRevived[id] = true; }); @@ -999,7 +1002,7 @@ export class Connection { // Start by clearing _methodsBlockingQuiescence: methods sent before // reconnect don't matter, and any "wait" methods sent on the new connection // that we drop here will be restored by the loop below. - self._methodsBlockingQuiescence = {}; + self._methodsBlockingQuiescence = Object.create(null); if (self._resetStores) { _.each(self._methodInvokers, invoker => { if (invoker.gotResult()) { @@ -1126,7 +1129,7 @@ export class Connection { // performWrites. As there's no guarantee that it // will exit cleanly. var writes = self._bufferedWrites; - self._bufferedWrites = {}; + self._bufferedWrites = Object.create(null); self._performWrites(writes); } @@ -1208,7 +1211,7 @@ export class Connection { // Some outstanding stub wrote here. var isExisting = serverDoc.document !== undefined; - serverDoc.document = msg.fields || {}; + serverDoc.document = msg.fields || Object.create(null); serverDoc.document._id = id; if (self._resetStores) { diff --git a/packages/ddp-client/common/stream_client_common.js b/packages/ddp-client/common/stream_client_common.js index 02badeb538..8d3ac32f44 100644 --- a/packages/ddp-client/common/stream_client_common.js +++ b/packages/ddp-client/common/stream_client_common.js @@ -24,7 +24,7 @@ export default class StreamClientCommon { } _initCommon(options) { - options = options || {}; + options = options || Object.create(null); //// Constants @@ -32,7 +32,7 @@ export default class StreamClientCommon { // failed. this.CONNECT_TIMEOUT = options.connectTimeoutMs || 10000; - this.eventCallbacks = {}; // name -> [callback] + this.eventCallbacks = Object.create(null); // name -> [callback] this._forcedToDisconnect = false; @@ -57,7 +57,7 @@ export default class StreamClientCommon { // Trigger a reconnect. reconnect(options) { - options = options || {}; + options = options || Object.create(null); if (options.url) { this._changeUrl(options.url); @@ -87,7 +87,7 @@ export default class StreamClientCommon { } disconnect(options) { - options = options || {}; + options = options || Object.create(null); // Failed is permanent. If we're failed, don't let people go back // online by calling 'disconnect' then 'reconnect'. diff --git a/packages/ddp-client/server/stream_client_nodejs.js b/packages/ddp-client/server/stream_client_nodejs.js index 719ff77911..f8c103084d 100644 --- a/packages/ddp-client/server/stream_client_nodejs.js +++ b/packages/ddp-client/server/stream_client_nodejs.js @@ -20,7 +20,7 @@ export default class ClientStream extends StreamClientCommon { constructor(endpoint, options) { super(); - options = options || {}; + options = options || Object.create(null); this.options = Object.assign( { @@ -32,8 +32,8 @@ export default class ClientStream extends StreamClientCommon { this.client = null; // created in _launchConnection this.endpoint = endpoint; - this.headers = this.options.headers || {}; - this.npmFayeOptions = this.options.npmFayeOptions || {}; + this.headers = this.options.headers || Object.create(null); + this.npmFayeOptions = this.options.npmFayeOptions || Object.create(null); this._initCommon(this.options); diff --git a/packages/ddp-client/test/livedata_test_service.js b/packages/ddp-client/test/livedata_test_service.js index 200b4b43a4..28cce2d660 100644 --- a/packages/ddp-client/test/livedata_test_service.js +++ b/packages/ddp-client/test/livedata_test_service.js @@ -19,7 +19,7 @@ Meteor.methods({ throwThroughFuture: Match.Optional(Boolean) }) ); - options = options || {}; + options = options || Object.create(null); var shouldThrow = (Meteor.isServer && where === 'server') || (Meteor.isClient && where === 'client') || @@ -57,7 +57,7 @@ Meteor.methods({ if (Meteor.isServer) { // Keys are random tokens, used to isolate multiple test invocations from each // other. - var waiters = {}; + var waiters = Object.create(null); var Future = Npm.require('fibers/future'); @@ -179,7 +179,7 @@ if (Meteor.isServer) { }); (function() { - var userIdWhenStopped = {}; + var userIdWhenStopped = Object.create(null); Meteor.publish('recordUserIdOnStop', function(key) { check(key, String); var self = this; @@ -363,7 +363,7 @@ if (Meteor.isServer) { } /// Helper for "livedata - result by value" -var resultByValueArrays = {}; +var resultByValueArrays = Object.create(null); Meteor.methods({ getArray: function(testId) { if (!_.has(resultByValueArrays, testId)) resultByValueArrays[testId] = []; diff --git a/packages/ddp-client/test/stub_stream.js b/packages/ddp-client/test/stub_stream.js index 2bfb4da0cd..c922affd12 100644 --- a/packages/ddp-client/test/stub_stream.js +++ b/packages/ddp-client/test/stub_stream.js @@ -2,7 +2,7 @@ StubStream = function() { var self = this; self.sent = []; - self.callbacks = {}; + self.callbacks = Object.create(null); }; _.extend(StubStream.prototype, {