feat: add support for Blob's going over the ctx bridge (#29247)

This commit is contained in:
Samuel Attard 2021-05-26 10:34:29 -07:00 committed by GitHub
parent d0b9a931cc
commit f01e35f4ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 2 deletions

View file

@ -107,6 +107,7 @@ has been included below for completeness:
| `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. | | `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. |
| [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types | | [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types |
| `Element` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending custom elements will not work. | | `Element` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending custom elements will not work. |
| `Blob` | Complex | ✅ | ✅ | N/A |
| `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped | | `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped |
If the type you care about is not in the above table, it is probably not supported. If the type you care about is not in the above table, it is probably not supported.

View file

@ -24,6 +24,7 @@
#include "shell/common/gin_helper/promise.h" #include "shell/common/gin_helper/promise.h"
#include "shell/common/node_includes.h" #include "shell/common/node_includes.h"
#include "shell/common/world_ids.h" #include "shell/common/world_ids.h"
#include "third_party/blink/public/web/web_blob.h"
#include "third_party/blink/public/web/web_element.h" #include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_local_frame.h" #include "third_party/blink/public/web/web_local_frame.h"
@ -346,6 +347,14 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
destination_context->Global(), destination_context->GetIsolate())); destination_context->Global(), destination_context->GetIsolate()));
} }
// Custom logic to "clone" Blob references
blink::WebBlob blob = blink::WebBlob::FromV8Value(value);
if (!blob.IsNull()) {
v8::Context::Scope destination_context_scope(destination_context);
return v8::MaybeLocal<v8::Value>(blob.ToV8Value(
destination_context->Global(), destination_context->GetIsolate()));
}
// Proxy all objects // Proxy all objects
if (IsPlainObject(value)) { if (IsPlainObject(value)) {
auto object_value = value.As<v8::Object>(); auto object_value = value.As<v8::Object>();

View file

@ -584,6 +584,33 @@ describe('contextBridge', () => {
expect(result).to.deep.equal(['BODY', 'HTMLBodyElement', 'function']); expect(result).to.deep.equal(['BODY', 'HTMLBodyElement', 'function']);
}); });
it('should handle Blobs', async () => {
await makeBindingWindow(() => {
contextBridge.exposeInMainWorld('example', {
getBlob: () => new Blob(['ab', 'cd'])
});
});
const result = await callWithBindings(async (root: any) => {
return [await root.example.getBlob().text()];
});
expect(result).to.deep.equal(['abcd']);
});
it('should handle Blobs going backwards over the bridge', async () => {
await makeBindingWindow(() => {
contextBridge.exposeInMainWorld('example', {
getBlobText: async (fn: Function) => {
const blob = fn();
return [await blob.text()];
}
});
});
const result = await callWithBindings((root: any) => {
return root.example.getBlobText(() => new Blob(['12', '45']));
});
expect(result).to.deep.equal(['1245']);
});
// Can only run tests which use the GCRunner in non-sandboxed environments // Can only run tests which use the GCRunner in non-sandboxed environments
if (!useSandbox) { if (!useSandbox) {
it('should release the global hold on methods sent across contexts', async () => { it('should release the global hold on methods sent across contexts', async () => {
@ -789,7 +816,8 @@ describe('contextBridge', () => {
symbolKeyed: { symbolKeyed: {
[Symbol('foo')]: 123 [Symbol('foo')]: 123
}, },
getBody: () => document.body getBody: () => document.body,
getBlob: () => new Blob(['ab', 'cd'])
}); });
}); });
const result = await callWithBindings(async (root: any) => { const result = await callWithBindings(async (root: any) => {
@ -862,7 +890,8 @@ describe('contextBridge', () => {
[(await example.object.getPromise()).arr[3][0], String], [(await example.object.getPromise()).arr[3][0], String],
[arg, Object], [arg, Object],
[arg.key, String], [arg.key, String],
[example.getBody(), HTMLBodyElement] [example.getBody(), HTMLBodyElement],
[example.getBlob(), Blob]
]; ];
return { return {
protoMatches: protoChecks.map(([a, Constructor]) => Object.getPrototypeOf(a) === Constructor.prototype) protoMatches: protoChecks.map(([a, Constructor]) => Object.getPrototypeOf(a) === Constructor.prototype)