结构化克隆算法拒绝的类别

时间:2017-02-11 00:31:51

标签: javascript clone indexeddb postmessage

我正在寻求忠实地为IndexedDB polyfill(包括Node)实现结构化克隆算法。虽然算法的某些类型的明确白名单大部分是明确的,但我更理解它的全面黑名单(以及如何检测这种黑名单类型)。

结构化克隆算法states

  

默认情况下,平台对象不是可复制对象。

...“平台对象”是defined in WebIDL

  

在一组IDL片段的给定实现中,对象可以被描述为平台对象,用户对象或两者都不是。有两种对象被认为是平台对象:

     
      
  • 实现非回调接口的对象;
  •   
  • 表示IDL DOMExceptions的对象。
  •   

对于另一类(可能)不可克隆的对象,SCA在将某些类型列入白名单后mentions

  
      
  1. 否则,如果输入有[[Prototype]]或[[Extensible]]以外的任何内部插槽,则抛出“DataCloneError”DOMException。
  2.         

    例如,[[PromiseState]]或[[WeakMapData]]内部插槽。

         
        
    1. 否则,如果input是异物,则抛出“DataCloneError”DOMException。
    2.   

“异国情调的对象”在ECMAScript 2017中定义为:

  

对象没有一个或多个基本内部方法的默认行为   注意   任何不是普通对象的对象都是异国情调的对象。

由于SCA抛出IsCallable检查[[Call]](和“所有ECMAScript函数对象都有[[Call]]内部方法定义在这里”),我已经排除了“基本内部方法”对于函数,导致以下内容:

  • [[GetPrototypeOf]],[[SetPrototypeOf]],[[IsExtensible]],[[PreventExtensions]],[[GetOwnProperty]],[[DefineOwnProperty]],[[HasProperty]],[[获取]] ,[[设置]],[[删除]],[[OwnPropertyKeys]]

因此,关于拒绝的条件出现了一些问题:

  1. 如何检测默认黑名单的平台对象,以及如何检测/找到那些具有[[Clone]]内部方法且因此可以列入白名单的平台对象
  2. 对于拒绝(非白名单,即阵列)未在ECMAScript本身中定义的外来对象,如何找到哪些其他规范不为其对象中的“基本内部方法”提供默认行为(除非HTML spec声明“JavaScript规范中定义的对象由StructuredClone抽象操作直接处理。”表示没有非ECMAScript定义的对象将应用此算法。
  3. 除ECMAScript之外的其他规范是否为其对象定义了自己的内部插槽(这可能是拒绝的另一个标准)
  4. 到目前为止我的实施是:

    function throwUponDataCloneError (val) {
        // Should also throw with:
        // 1. `IsDetachedBuffer` (a process not called within the ECMAScript spec)
        // 2. We are not dealing with `Blob`/`File` at this point as the
        //     IndexedDB spec requires synchronous rejection and we'd apparently
        //     have to use deprecated sync XHR (or `readFileSync` in Node) to get this
        // 'Proxy' should be rejected but no apparent way to introspect on it
        const stringTag = ({}.toString.call(val).slice(8, -1));
        if (typeof val === 'symbol' || // Symbol's `toStringTag` is only "Symbol" for its initial value, so safer to check `typeof`
            [
                'Function', // All functions including bound function exotic objects; rejected per `IsCallable` check (could also be covered by `typeof === 'function'`)
                'Arguments', // A non-array exotic object
                'Error', // `Error` and other errors have the [[ErrorData]] internal slot and give "Error"
                // The following checks are only based on the default expected `toStringTag` values
                'Module', // A non-array exotic object
                'Promise', // Promise instances have an extra slot ([[PromiseState]]) but not throwing in Chrome `postMessage`
                'WeakMap', // WeakMap instances have an extra slot ([[WeakMapData]]) but not throwing in Chrome `postMessage`
                'WeakSet' // WeakSet instances have an extra slot ([[WeakSetData]]) but not throwing in Chrome `postMessage`
            ].includes(stringTag) ||
            val === Object.prototype || // A non-array exotic object but not throwing in Chrome `postMessage`
        ) {
            throw new DOMException('The object cannot be cloned.', 'DataCloneError');
        }
    }
    

    作为检测平台对象的一种方法,WebIDL声明:

      

    实现一个或多个接口的平台对象的类字符串必须是平台对象主接口的标识符。

    ...“类字符串”为defined as

      

    要包含在从Object.prototype.toString返回的字符串中的字符串。如果对象具有类字符串,则该对象在创建时必须具有名称为@@toStringTag符号且其值为指定字符串的属性。

    事实上,我可以找到一个SCA的JS实现,CycloneJS采用这种方法来抛弃任何未被识别的@@toStringTag

    然而,我担心:

    1. 特别是因为@@toStringTag不是内部插槽,因此具有不同内容的对象不是自动取消限定符,我会担心拒绝任何具有这种不同标记的对象会过于禁止。但也许这些案例太少而无法引起关注。
    2. 然而,我仍然离开了一个问题,即是否需要为“基本内部方法”的非默认行为搜索规范以拒绝这些行为。同样,如果ECMAScript之外的其他规范定义了自己的内部插槽(这可能是拒绝的另一个标准)。我想知道对于这两种情况是否安全,但是大多数(如果不是全部)确实会有自己独特的@@toStringTag,因此可能会因为关注方法#1而被拒绝。
    3. 基本上,我想知道Object.prototype.toString白名单方法是否应该足以避免误报或漏报,以及任何其他检测技术是否可以提供更细粒度的控制。

0 个答案:

没有答案