mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-09 01:08:39 +09:00
Fix stream transfer over message ports
This commit is contained in:
parent
7d8bf841ed
commit
a6b18bcd14
3 changed files with 255 additions and 32 deletions
|
|
@ -152,11 +152,6 @@ struct SameThreadStreamTransferData
|
|||
JS::PersistentRootedObject mRecord;
|
||||
};
|
||||
|
||||
struct MessagePortStreamTransferData
|
||||
{
|
||||
MessagePortIdentifier mIdentifier;
|
||||
};
|
||||
|
||||
bool
|
||||
CallStreamTransferHelper(JSContext* aCx,
|
||||
const char* aHelperName,
|
||||
|
|
@ -235,6 +230,7 @@ TryWriteSameThreadStreamTransfer(JSContext* aCx,
|
|||
bool
|
||||
TryWriteReadableStreamPortTransfer(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aObj,
|
||||
nsTArray<MessagePortIdentifier>& aPortIdentifiers,
|
||||
uint32_t* aTag,
|
||||
JS::TransferableOwnership* aOwnership,
|
||||
void** aContent,
|
||||
|
|
@ -265,13 +261,13 @@ TryWriteReadableStreamPortTransfer(JSContext* aCx,
|
|||
return false;
|
||||
}
|
||||
|
||||
MessagePortStreamTransferData* data = new MessagePortStreamTransferData();
|
||||
port->CloneAndDisentangle(data->mIdentifier);
|
||||
*aExtraData = aPortIdentifiers.Length();
|
||||
MessagePortIdentifier* identifier = aPortIdentifiers.AppendElement();
|
||||
port->CloneAndDisentangle(*identifier);
|
||||
|
||||
*aTag = SCTAG_DOM_TRANSFERRED_READABLESTREAM;
|
||||
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||
*aContent = data;
|
||||
*aExtraData = 0;
|
||||
*aContent = nullptr;
|
||||
*aHandled = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -304,18 +300,19 @@ ReadSameThreadStreamTransfer(JSContext* aCx,
|
|||
bool
|
||||
ReadReadableStreamPortTransfer(JSContext* aCx,
|
||||
nsISupports* aParent,
|
||||
void* aContent,
|
||||
nsTArray<MessagePortIdentifier>& aPortIdentifiers,
|
||||
uint64_t aExtraData,
|
||||
JS::MutableHandleObject aReturnObject)
|
||||
{
|
||||
MOZ_ASSERT(aContent);
|
||||
MessagePortStreamTransferData* data =
|
||||
static_cast<MessagePortStreamTransferData*>(aContent);
|
||||
if (aExtraData >= aPortIdentifiers.Length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
|
||||
|
||||
ErrorResult rv;
|
||||
RefPtr<MessagePort> port =
|
||||
MessagePort::Create(global, data->mIdentifier, rv);
|
||||
MessagePort::Create(global, aPortIdentifiers[aExtraData], rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
|
|
@ -339,7 +336,6 @@ ReadReadableStreamPortTransfer(JSContext* aCx,
|
|||
}
|
||||
|
||||
aReturnObject.set(&result.toObject());
|
||||
delete data;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1592,11 +1588,20 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx,
|
|||
"__uxpReceiveReadableStreamTransfer",
|
||||
aReturnObject);
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM) {
|
||||
return ReadSameThreadStreamTransfer(aCx, aContent,
|
||||
"__uxpReceiveTransformStreamTransfer",
|
||||
aReturnObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread &&
|
||||
if ((mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread ||
|
||||
mStructuredCloneScope == StructuredCloneScope::DifferentProcess) &&
|
||||
aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM) {
|
||||
return ReadReadableStreamPortTransfer(aCx, mParent, aContent,
|
||||
MOZ_ASSERT(!aContent);
|
||||
return ReadReadableStreamPortTransfer(aCx, mParent, mPortIdentifiers,
|
||||
aExtraData,
|
||||
aReturnObject);
|
||||
}
|
||||
|
||||
|
|
@ -1691,12 +1696,25 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
|
|||
if (handled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!TryWriteSameThreadStreamTransfer(aCx, obj,
|
||||
"__uxpTransferTransformStream",
|
||||
SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM,
|
||||
aTag, aOwnership, aContent,
|
||||
aExtraData, &handled)) {
|
||||
return false;
|
||||
}
|
||||
if (handled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
|
||||
if (mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread ||
|
||||
mStructuredCloneScope == StructuredCloneScope::DifferentProcess) {
|
||||
bool handled = false;
|
||||
if (!TryWriteReadableStreamPortTransfer(aCx, obj, aTag, aOwnership,
|
||||
aContent, aExtraData, &handled)) {
|
||||
if (!TryWriteReadableStreamPortTransfer(aCx, obj, mPortIdentifiers,
|
||||
aTag, aOwnership, aContent,
|
||||
aExtraData, &handled)) {
|
||||
return false;
|
||||
}
|
||||
if (handled) {
|
||||
|
|
@ -1743,7 +1761,8 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
|
|||
}
|
||||
|
||||
if ((aTag == SCTAG_DOM_TRANSFERRED_WRITABLESTREAM ||
|
||||
aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM) &&
|
||||
aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM ||
|
||||
aTag == SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM) &&
|
||||
mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) {
|
||||
MOZ_ASSERT(aContent);
|
||||
SameThreadStreamTransferData* data =
|
||||
|
|
@ -1753,12 +1772,11 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
|
|||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM &&
|
||||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
|
||||
MOZ_ASSERT(aContent);
|
||||
MessagePortStreamTransferData* data =
|
||||
static_cast<MessagePortStreamTransferData*>(aContent);
|
||||
MessagePort::ForceClose(data->mIdentifier);
|
||||
delete data;
|
||||
(mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread ||
|
||||
mStructuredCloneScope == StructuredCloneScope::DifferentProcess)) {
|
||||
MOZ_ASSERT(!aContent);
|
||||
MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
|
||||
MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ enum StructuredCloneTags {
|
|||
// Same-thread transferable stream records. These are not supported by IDB.
|
||||
SCTAG_DOM_TRANSFERRED_READABLESTREAM,
|
||||
SCTAG_DOM_TRANSFERRED_WRITABLESTREAM,
|
||||
SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM,
|
||||
|
||||
// When adding a new tag for IDB, please don't add it to the end of the list!
|
||||
// Tags that are supported by IDB must not ever change. See the static assert
|
||||
|
|
|
|||
|
|
@ -6735,6 +6735,163 @@ js::InitStreamExtras(JSContext* cx, HandleObject global)
|
|||
return makeDOMException("The object could not be cloned.", "DataCloneError");
|
||||
}
|
||||
|
||||
function cloneTransferReasonError(value) {
|
||||
var constructors = [
|
||||
global.EvalError,
|
||||
global.RangeError,
|
||||
global.ReferenceError,
|
||||
global.SyntaxError,
|
||||
global.TypeError,
|
||||
global.URIError,
|
||||
global.Error
|
||||
];
|
||||
|
||||
for (var i = 0; i < constructors.length; ++i) {
|
||||
var C = constructors[i];
|
||||
if (typeof C !== "function")
|
||||
continue;
|
||||
try {
|
||||
if (!(value instanceof C))
|
||||
continue;
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var message = "";
|
||||
var descriptor;
|
||||
try {
|
||||
descriptor = Object.getOwnPropertyDescriptor(value, "message");
|
||||
} catch (e) {
|
||||
descriptor = undefined;
|
||||
}
|
||||
if (descriptor && hasOwn.call(descriptor, "value"))
|
||||
message = String(descriptor.value);
|
||||
return new C(message);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function cloneTransferReasonValue(value, memory) {
|
||||
if (typeof value === "function" || typeof value === "symbol")
|
||||
throw makeDataCloneError();
|
||||
if (!isObject(value))
|
||||
return value;
|
||||
if (isUncloneableStreamChunk(value))
|
||||
throw makeDataCloneError();
|
||||
|
||||
memory = memory || new WeakMap();
|
||||
if (memory.has(value))
|
||||
return memory.get(value);
|
||||
|
||||
if (typeof global.DOMException === "function") {
|
||||
try {
|
||||
if (value instanceof global.DOMException) {
|
||||
return new global.DOMException(String(value.message),
|
||||
String(value.name));
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
var errorClone = cloneTransferReasonError(value);
|
||||
if (errorClone !== undefined)
|
||||
return errorClone;
|
||||
|
||||
if (typeof global.ArrayBuffer === "function") {
|
||||
try {
|
||||
if (value instanceof global.ArrayBuffer) {
|
||||
var bufferClone = value.slice(0);
|
||||
memory.set(value, bufferClone);
|
||||
return bufferClone;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (global.ArrayBuffer && global.ArrayBuffer.isView &&
|
||||
global.ArrayBuffer.isView(value)) {
|
||||
var clonedBuffer = cloneTransferReasonValue(value.buffer, memory);
|
||||
var viewClone;
|
||||
if (objectToString.call(value) === "[object DataView]") {
|
||||
viewClone = new global.DataView(clonedBuffer, value.byteOffset,
|
||||
value.byteLength);
|
||||
} else {
|
||||
viewClone = new value.constructor(clonedBuffer, value.byteOffset,
|
||||
value.length);
|
||||
}
|
||||
memory.set(value, viewClone);
|
||||
return viewClone;
|
||||
}
|
||||
|
||||
if (typeof global.Date === "function") {
|
||||
try {
|
||||
if (value instanceof global.Date) {
|
||||
var dateClone = new global.Date(value.getTime());
|
||||
memory.set(value, dateClone);
|
||||
return dateClone;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (typeof global.RegExp === "function") {
|
||||
try {
|
||||
if (value instanceof global.RegExp) {
|
||||
var flags = "";
|
||||
flags += value.global ? "g" : "";
|
||||
flags += value.ignoreCase ? "i" : "";
|
||||
flags += value.multiline ? "m" : "";
|
||||
flags += value.unicode ? "u" : "";
|
||||
flags += value.sticky ? "y" : "";
|
||||
var regexpClone = new global.RegExp(value.source, flags);
|
||||
regexpClone.lastIndex = value.lastIndex;
|
||||
memory.set(value, regexpClone);
|
||||
return regexpClone;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (typeof global.Map === "function") {
|
||||
try {
|
||||
if (value instanceof global.Map) {
|
||||
var mapClone = new global.Map();
|
||||
memory.set(value, mapClone);
|
||||
value.forEach(function(v, k) {
|
||||
mapClone.set(cloneTransferReasonValue(k, memory),
|
||||
cloneTransferReasonValue(v, memory));
|
||||
});
|
||||
return mapClone;
|
||||
}
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof global.Set === "function") {
|
||||
try {
|
||||
if (value instanceof global.Set) {
|
||||
var setClone = new global.Set();
|
||||
memory.set(value, setClone);
|
||||
value.forEach(function(v) {
|
||||
setClone.add(cloneTransferReasonValue(v, memory));
|
||||
});
|
||||
return setClone;
|
||||
}
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
var clone = Array.isArray(value) ? [] : {};
|
||||
memory.set(value, clone);
|
||||
|
||||
var keys = Object.keys(value);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
clone[key] = cloneTransferReasonValue(value[key], memory);
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
function abortTransferredWritable(record, reason) {
|
||||
try {
|
||||
return record.writer.abort(reason);
|
||||
|
|
@ -6908,12 +7065,16 @@ js::InitStreamExtras(JSContext* cx, HandleObject global)
|
|||
|
||||
function cancelReadableTransfer(record, reason) {
|
||||
record.canceled = true;
|
||||
Promise.resolve().then(function() {
|
||||
var cancelPromise = Promise.resolve().then(function() {
|
||||
var clonedReason = cloneTransferReasonValue(reason);
|
||||
try {
|
||||
silenceRejection(record.reader.cancel(reason));
|
||||
} catch (e) {}
|
||||
return record.reader.cancel(clonedReason);
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
silenceRejection(cancelPromise);
|
||||
return cancelPromise;
|
||||
}
|
||||
|
||||
function closeReadableTransferPort(port) {
|
||||
|
|
@ -7139,13 +7300,50 @@ js::InitStreamExtras(JSContext* cx, HandleObject global)
|
|||
},
|
||||
cancel: function(reason) {
|
||||
state.canceled = true;
|
||||
tryPostReadableTransferPort(port, { type: "cancel", reason: reason });
|
||||
try {
|
||||
port.postMessage({ type: "cancel", reason: reason });
|
||||
} catch (e) {
|
||||
closeReadableTransferPort(port);
|
||||
return Promise.reject(e);
|
||||
}
|
||||
closeReadableTransferPort(port);
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function __uxpTransferTransformStream(stream) {
|
||||
if (!isObject(stream) || !transformState.has(stream))
|
||||
return undefined;
|
||||
|
||||
var state = transformState.get(stream);
|
||||
if (state.readable.locked || state.writable.locked)
|
||||
return null;
|
||||
|
||||
var readableRecord = __uxpTransferReadableStream(state.readable);
|
||||
if (!readableRecord)
|
||||
return null;
|
||||
|
||||
var writableRecord = __uxpTransferWritableStream(state.writable);
|
||||
if (!writableRecord)
|
||||
return null;
|
||||
|
||||
return {
|
||||
readable: readableRecord,
|
||||
writable: writableRecord
|
||||
};
|
||||
}
|
||||
|
||||
function __uxpReceiveTransformStreamTransfer(record) {
|
||||
var stream = Object.create(global.TransformStream.prototype);
|
||||
transformState.set(stream, {
|
||||
readable: __uxpReceiveReadableStreamTransfer(record.readable),
|
||||
writable: __uxpReceiveWritableStreamTransfer(record.writable),
|
||||
controller: undefined
|
||||
});
|
||||
return stream;
|
||||
}
|
||||
|
||||
function __uxpReceiveReadableStreamTransfer(record) {
|
||||
return new ReadableStream({
|
||||
start: function(controller) {
|
||||
|
|
@ -7323,6 +7521,12 @@ js::InitStreamExtras(JSContext* cx, HandleObject global)
|
|||
Object.defineProperty(global, "__uxpReceiveReadableStreamTransferFromPort",
|
||||
{ value: __uxpReceiveReadableStreamTransferFromPort,
|
||||
configurable: true });
|
||||
Object.defineProperty(global, "__uxpTransferTransformStream",
|
||||
{ value: __uxpTransferTransformStream,
|
||||
configurable: true });
|
||||
Object.defineProperty(global, "__uxpReceiveTransformStreamTransfer",
|
||||
{ value: __uxpReceiveTransformStreamTransfer,
|
||||
configurable: true });
|
||||
|
||||
if (global.ReadableStream && !global.ReadableStream.from) {
|
||||
Object.defineProperty(global.ReadableStream, "from", {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue