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

Javascript 结构化克隆算法拒绝的类别,javascript,clone,indexeddb,postmessage,Javascript,Clone,Indexeddb,Postmessage,我正在寻求为IndexedDB polyfill(包括节点)忠实地实现结构化克隆算法。虽然该算法对某些类型的显式白名单基本上是清楚的,但我更不了解它的总体黑名单(以及如何检测此类黑名单类型) 结构化克隆算法: 默认情况下,平台对象不是可克隆对象 …其中“平台对象”是: 在一组IDL片段的给定实现中,可以将对象描述为平台对象、用户对象或两者都不是。有两种对象被视为平台对象: 实现非回调接口的对象 表示IDL异常的对象 至于另一类(可能)不可克隆对象,SCA在将某些类型列入白名单后: 否则,如果

我正在寻求为IndexedDB polyfill(包括节点)忠实地实现结构化克隆算法。虽然该算法对某些类型的显式白名单基本上是清楚的,但我更不了解它的总体黑名单(以及如何检测此类黑名单类型)

结构化克隆算法:

默认情况下,平台对象不是可克隆对象

…其中“平台对象”是:

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

  • 实现非回调接口的对象
  • 表示IDL异常的对象
至于另一类(可能)不可克隆对象,SCA在将某些类型列入白名单后:

  • 否则,如果输入有[[Prototype]]或[[Extensible]]以外的任何内部插槽,则抛出“DataCloneError”DomeException
  • 例如,[[PromiseState]]或[[WeakMapData]]内部插槽

  • 否则,如果输入是外来对象,则抛出“DataCloneError”DomeException
  • “外来对象”在中定义为:

    对象,该对象不具有一个或多个基本内部方法的默认行为 注 任何不是普通对象的对象都是外来对象

    由于SCA抛出用于检查
    [[Call]]
    (以及“所有ECMAScript函数对象都有此处定义的[[Call]]内部方法”)的
    IsCallable
    ,因此我排除了函数的“基本内部方法”,导致以下情况:

    • [[GetPrototypeOf]、[[SetPrototypeOf]、[[IsExtensible]、[[PreventExtensions]、[[GetOwnProperty]、[[DefineOwnProperty]、[[HasProperty]、[[Get]、[[Set]、[[Delete]、[[OwnPropertyKeys]]
    因此,出现了一些关于拒收条件的问题:

  • 如何检测默认黑名单中的平台对象,以及如何检测/查找那些具有
    [[Clone]]
    内部方法并因此可以被白名单的平台对象
  • 对于拒绝ECMAScript本身中未定义的外来对象(非白名单,即数组),如何查找哪些其他规范不提供上述对象中“基本内部方法”的默认行为(除非“JavaScript规范中定义的对象由StructuredClone抽象操作直接处理。”表示没有非ECMAScript定义的对象将应用此算法)
  • ECMAScript之外的其他规范是否为其对象定义了自己的内部插槽(这可能是拒绝的另一个标准)
  • 到目前为止,我的执行情况是:

    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声明:

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

    …其中“类字符串”是:

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

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

    然而,我感到关切的是:

  • 特别是由于
    @@toStringTag
    不是一个内部插槽,因此具有不同标签的对象不是自动取消资格的对象,我担心拒绝任何具有这种不同标签的对象会过于禁止。但这些情况可能太少而不值得关注
  • 然而,我仍然有一个问题:是否有必要在规范中搜索“基本内部方法”的非默认行为,以拒绝这些行为。同样,如果ECMAScript之外的其他规范定义了自己的内部槽(这可能是拒绝的另一个标准).我想知道是否可以安全地假设,对于这两种情况,大多数(如果不是所有的话)都会有自己独特的
    @@toStringTag
    ,因此可能会根据相关方法被拒绝1

  • 因此,本质上,我想知道
    Object.prototype.toString
    白名单方法是否足以避免误报或漏报,以及其他检测技术是否可以提供更精确的控制。

    这是Web平台包含“魔法”的不幸地方之一,即无法使用平台的其他部分(ECMAScript、浏览器API等)实现的行为。由于您没有访问这些内部插槽的权限,因此无法实现与本机实现相同的测试。一般来说,我们希望从平台上消除魔法,但是。。。有很多,而且很少是最优先的工作。。。我还没有(到目前为止?)花足够的时间研究你的算法来判断它是否“基本上足够”,所以我不会把它列为一个答案。顺便说一句,FWIW,@JoshuaBell,关于Chrome中错误的不违背承诺、WeakMap和WeakSet(SCA的第18步),我报告(但它被归类为垃圾邮件)。我刚才在评论中提到了
    对象的非故障。prototype
    作为一个(非数组)外来对象,它似乎也应该故障。感谢ping。我将尝试反垃圾邮件的问题(我至少报告为假阳性)可能的重复