mirror of
https://github.com/titaniumnetwork-dev/Ultraviolet.git
synced 2025-05-16 21:10:02 -04:00
V3 support, WebSocketApi
brought back the old WebSocket hook API and added hooks for send() and readyState
This commit is contained in:
parent
56bf6fc6b8
commit
a8c84e8926
6 changed files with 179 additions and 224 deletions
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -9,7 +9,7 @@
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tomphttp/bare-client": "^1.1.2-beta.3",
|
"@tomphttp/bare-client": "^2.0.0-beta",
|
||||||
"css-tree": "^2.0.4",
|
"css-tree": "^2.0.4",
|
||||||
"esotope-hammerhead": "^0.6.1",
|
"esotope-hammerhead": "^0.6.1",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
|
@ -190,9 +190,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tomphttp/bare-client": {
|
"node_modules/@tomphttp/bare-client": {
|
||||||
"version": "1.1.2-beta.3",
|
"version": "2.0.0-beta",
|
||||||
"resolved": "https://registry.npmjs.org/@tomphttp/bare-client/-/bare-client-1.1.2-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tomphttp/bare-client/-/bare-client-2.0.0-beta.tgz",
|
||||||
"integrity": "sha512-WyIVnSAqzfrLejmOhh/l/LtDOeK+SHnBGi/z+QyliVP1T1JxoNE5eecwxlV+osM9J6FTAYVGNHr8/5bubaIj6Q=="
|
"integrity": "sha512-M2ap0V4DwIdc+gtiiAN8GFqiXDi81iOc+fu4JZGQTIa4Y4gIQVN9bFybFm0hz23QjfqSiFYfHO9o/BhQOo5bSQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/eslint": {
|
"node_modules/@types/eslint": {
|
||||||
"version": "8.4.6",
|
"version": "8.4.6",
|
||||||
|
@ -2964,9 +2964,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tomphttp/bare-client": {
|
"@tomphttp/bare-client": {
|
||||||
"version": "1.1.2-beta.3",
|
"version": "2.0.0-beta",
|
||||||
"resolved": "https://registry.npmjs.org/@tomphttp/bare-client/-/bare-client-1.1.2-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tomphttp/bare-client/-/bare-client-2.0.0-beta.tgz",
|
||||||
"integrity": "sha512-WyIVnSAqzfrLejmOhh/l/LtDOeK+SHnBGi/z+QyliVP1T1JxoNE5eecwxlV+osM9J6FTAYVGNHr8/5bubaIj6Q=="
|
"integrity": "sha512-M2ap0V4DwIdc+gtiiAN8GFqiXDi81iOc+fu4JZGQTIa4Y4gIQVN9bFybFm0hz23QjfqSiFYfHO9o/BhQOo5bSQ=="
|
||||||
},
|
},
|
||||||
"@types/eslint": {
|
"@types/eslint": {
|
||||||
"version": "8.4.6",
|
"version": "8.4.6",
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"watch": "cross-env NODE_ENV=development webpack-cli --watch"
|
"watch": "cross-env NODE_ENV=development webpack-cli --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tomphttp/bare-client": "^1.1.2-beta.3",
|
"@tomphttp/bare-client": "^2.0.0-beta",
|
||||||
"css-tree": "^2.0.4",
|
"css-tree": "^2.0.4",
|
||||||
"esotope-hammerhead": "^0.6.1",
|
"esotope-hammerhead": "^0.6.1",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
|
|
|
@ -17,12 +17,19 @@ import EventEmitter from 'events';
|
||||||
import StorageApi from './storage.js';
|
import StorageApi from './storage.js';
|
||||||
import StyleApi from './dom/style.js';
|
import StyleApi from './dom/style.js';
|
||||||
import IDBApi from './idb.js';
|
import IDBApi from './idb.js';
|
||||||
|
import WebSocketApi from './requests/websocket.js';
|
||||||
|
|
||||||
class UVClient extends EventEmitter {
|
class UVClient extends EventEmitter {
|
||||||
constructor(window = self, worker = !window.window) {
|
/**
|
||||||
|
*
|
||||||
|
* @param {typeof globalThis} window
|
||||||
|
* @param {import('@tomphttp/bare-client').BareClient} bareClient
|
||||||
|
* @param {boolean} worker
|
||||||
|
*/
|
||||||
|
constructor(window = self, bareClient, worker = !window.window) {
|
||||||
super();
|
super();
|
||||||
/**
|
/**
|
||||||
* @type {typeof self}
|
* @type {typeof globalThis}
|
||||||
*/
|
*/
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.nativeMethods = {
|
this.nativeMethods = {
|
||||||
|
@ -42,6 +49,7 @@ class UVClient extends EventEmitter {
|
||||||
Proxy: this.window.Proxy,
|
Proxy: this.window.Proxy,
|
||||||
};
|
};
|
||||||
this.worker = worker;
|
this.worker = worker;
|
||||||
|
this.bareClient = bareClient;
|
||||||
this.fetch = new Fetch(this);
|
this.fetch = new Fetch(this);
|
||||||
this.xhr = new Xhr(this);
|
this.xhr = new Xhr(this);
|
||||||
this.idb = new IDBApi(this);
|
this.idb = new IDBApi(this);
|
||||||
|
@ -51,6 +59,7 @@ class UVClient extends EventEmitter {
|
||||||
this.document = new DocumentHook(this);
|
this.document = new DocumentHook(this);
|
||||||
this.function = new FunctionHook(this);
|
this.function = new FunctionHook(this);
|
||||||
this.object = new ObjectHook(this);
|
this.object = new ObjectHook(this);
|
||||||
|
this.websocket = new WebSocketApi(this);
|
||||||
this.message = new MessageApi(this);
|
this.message = new MessageApi(this);
|
||||||
this.navigator = new NavigatorApi(this);
|
this.navigator = new NavigatorApi(this);
|
||||||
this.eventSource = new EventSourceApi(this);
|
this.eventSource = new EventSourceApi(this);
|
||||||
|
|
108
src/client/requests/websocket.js
Normal file
108
src/client/requests/websocket.js
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import EventEmitter from 'events';
|
||||||
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../index').default} UVClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
class WebSocketApi extends EventEmitter {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {UVClient} ctx
|
||||||
|
*/
|
||||||
|
constructor(ctx) {
|
||||||
|
super();
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.window = ctx.window;
|
||||||
|
this.WebSocket = this.window.WebSocket || {};
|
||||||
|
this.wsProto = this.WebSocket.prototype || {};
|
||||||
|
this.url = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.wsProto,
|
||||||
|
'url'
|
||||||
|
);
|
||||||
|
this.protocol = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.wsProto,
|
||||||
|
'protocol'
|
||||||
|
);
|
||||||
|
this.readyState = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.wsProto,
|
||||||
|
'readyState'
|
||||||
|
);
|
||||||
|
this.send = this.wsProto.send;
|
||||||
|
this.CONNECTING = WebSocket.CONNECTING;
|
||||||
|
this.OPEN = WebSocket.OPEN;
|
||||||
|
this.CLOSING = WebSocket.CLOSING;
|
||||||
|
this.CLOSED = WebSocket.CLOSED;
|
||||||
|
}
|
||||||
|
overrideWebSocket() {
|
||||||
|
this.ctx.override(
|
||||||
|
this.window,
|
||||||
|
'WebSocket',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return new target(...args);
|
||||||
|
// just give the listeners direct access to the arguments
|
||||||
|
// an error occurs with too little arguments, listeners should be able to catch that
|
||||||
|
const event = new HookEvent({ args }, target, that);
|
||||||
|
this.emit('websocket', event);
|
||||||
|
|
||||||
|
if (event.intercepted) return event.returnValue;
|
||||||
|
return new event.target(event.data.url, event.data.protocols);
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
this.window.WebSocket.CONNECTING = this.CONNECTING;
|
||||||
|
this.window.WebSocket.OPEN = this.OPEN;
|
||||||
|
this.window.WebSocket.CLOSING = this.CLOSING;
|
||||||
|
this.window.WebSocket.CLOSED = this.CLOSED;
|
||||||
|
}
|
||||||
|
overrideURL() {
|
||||||
|
this.ctx.overrideDescriptor(this.wsProto, 'url', {
|
||||||
|
get: (target, that) => {
|
||||||
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('url', event);
|
||||||
|
return event.data.value;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
overrideProtocol() {
|
||||||
|
this.ctx.overrideDescriptor(this.wsProto, 'protocol', {
|
||||||
|
get: (target, that) => {
|
||||||
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('protocol', event);
|
||||||
|
return event.data.value;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
overrideReadyState() {
|
||||||
|
this.ctx.overrideDescriptor(this.wsProto, 'readyState', {
|
||||||
|
get: (target, that) => {
|
||||||
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('readyState', event);
|
||||||
|
return event.data.value;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
overrideSend() {
|
||||||
|
this.ctx.override(this.wsProto, 'send', (target, that, args) => {
|
||||||
|
const event = new HookEvent({ args }, target, that);
|
||||||
|
this.emit('send', event);
|
||||||
|
if (event.intercepted) return event.returnValue;
|
||||||
|
return event.target.call(event.that, event.data.args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WebSocketApi;
|
|
@ -34,7 +34,7 @@ import {
|
||||||
wrapEval,
|
wrapEval,
|
||||||
} from './rewrite.script.js';
|
} from './rewrite.script.js';
|
||||||
import { openDB } from 'idb';
|
import { openDB } from 'idb';
|
||||||
import BareClient from '@tomphttp/bare-client';
|
import { BareClient } from '@tomphttp/bare-client';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -62,7 +62,10 @@ function __uvHook(window) {
|
||||||
config.construct(__uv, worker ? 'worker' : 'window');
|
config.construct(__uv, worker ? 'worker' : 'window');
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
const client = new UVClient(window);
|
// websockets
|
||||||
|
const bareClient = new Ultraviolet.BareClient(__uv$bareURL, __uv$bareData);
|
||||||
|
|
||||||
|
const client = new UVClient(window, bareClient, worker);
|
||||||
const {
|
const {
|
||||||
HTMLMediaElement,
|
HTMLMediaElement,
|
||||||
HTMLScriptElement,
|
HTMLScriptElement,
|
||||||
|
@ -108,11 +111,6 @@ function __uvHook(window) {
|
||||||
__uv.localStorageObj = {};
|
__uv.localStorageObj = {};
|
||||||
__uv.sessionStorageObj = {};
|
__uv.sessionStorageObj = {};
|
||||||
|
|
||||||
// websockets
|
|
||||||
const bareClient = new Ultraviolet.BareClient(__uv$bareURL, __uv$bareData);
|
|
||||||
|
|
||||||
__uv.bareClient = bareClient;
|
|
||||||
|
|
||||||
if (__uv.location.href === 'about:srcdoc') {
|
if (__uv.location.href === 'about:srcdoc') {
|
||||||
__uv.meta = window.parent.__uv.meta;
|
__uv.meta = window.parent.__uv.meta;
|
||||||
}
|
}
|
||||||
|
@ -1017,223 +1015,57 @@ function __uvHook(window) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function eventTarget(target, event) {
|
client.websocket.on('websocket', async (event) => {
|
||||||
const property = `on${event}`;
|
const requestHeaders = Object.create(null);
|
||||||
const listeners = new WeakMap();
|
requestHeaders['Origin'] = __uv.meta.url.origin;
|
||||||
|
requestHeaders['User-Agent'] = navigator.userAgent;
|
||||||
|
|
||||||
Reflect.defineProperty(target, property, {
|
if (cookieStr !== '') requestHeaders['Cookie'] = cookieStr.toString();
|
||||||
enumerable: true,
|
|
||||||
configurable: true,
|
|
||||||
get() {
|
|
||||||
if (listeners.has(this)) {
|
|
||||||
return listeners.get(this);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
if (typeof value == 'function') {
|
|
||||||
if (listeners.has(this)) {
|
|
||||||
this.removeEventListener(event, listeners.get(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
listeners.set(this, value);
|
const socket = bareClient.createWebSocket(
|
||||||
this.addEventListener(event, value);
|
event.data.args[0],
|
||||||
}
|
event.data.args[1],
|
||||||
|
requestHeaders,
|
||||||
|
(socket, getReadyState) => {
|
||||||
|
socket.__uv$getReadyState = getReadyState;
|
||||||
},
|
},
|
||||||
|
(socket, getSendError) => {
|
||||||
|
socket.__uv$getSendError = getSendError;
|
||||||
|
},
|
||||||
|
event.target
|
||||||
|
);
|
||||||
|
|
||||||
|
socket.addEventListener('meta', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
// prevent event from being exposed to clients
|
||||||
|
event.stopPropagation();
|
||||||
|
socket.__uv$socketMeta = event.meta;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const wsProtocols = ['ws:', 'wss:'];
|
event.respondWith(socket);
|
||||||
|
});
|
||||||
|
|
||||||
class MockWebSocket extends EventTarget {
|
client.websocket.on('url', (event) => {
|
||||||
/**
|
if ('__uv$socketMeta' in event.that)
|
||||||
* @type {import("@tomphttp/bare-client").BareWebSocket}
|
event.data.value = event.that.__uv$socketMeta.url;
|
||||||
*/
|
});
|
||||||
#socket;
|
|
||||||
#ready;
|
|
||||||
#binaryType = 'blob';
|
|
||||||
#protocol = '';
|
|
||||||
#extensions = '';
|
|
||||||
#url = '';
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {URL} remote
|
|
||||||
* @param {any} protocol
|
|
||||||
*/
|
|
||||||
async #open(url, protocol) {
|
|
||||||
const requestHeaders = {};
|
|
||||||
Reflect.setPrototypeOf(requestHeaders, null);
|
|
||||||
|
|
||||||
requestHeaders['Origin'] = __uv.meta.url.origin;
|
client.websocket.on('protocol', (event) => {
|
||||||
requestHeaders['User-Agent'] = navigator.userAgent;
|
if ('__uv$socketMeta' in event.that)
|
||||||
|
event.data.value = event.that.__uv$socketMeta.protocol;
|
||||||
|
});
|
||||||
|
|
||||||
if (cookieStr !== '')
|
client.websocket.on('readyState', (event) => {
|
||||||
requestHeaders['Cookie'] = cookieStr.toString();
|
if ('__uv$getReadyState' in event.that)
|
||||||
|
event.data.value = event.that.__uv$getReadyState();
|
||||||
|
});
|
||||||
|
|
||||||
this.#socket = await bareClient.createWebSocket(
|
client.websocket.on('send', (event) => {
|
||||||
url,
|
if ('__uv$getSendError' in event.that) {
|
||||||
requestHeaders,
|
const error = event.that.__uv$getSendError();
|
||||||
protocol
|
if (error) throw error;
|
||||||
);
|
|
||||||
|
|
||||||
this.#socket.binaryType = this.#binaryType;
|
|
||||||
|
|
||||||
this.#socket.addEventListener('message', (event) => {
|
|
||||||
this.dispatchEvent(new MessageEvent('message', event));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.#socket.addEventListener('open', async (event) => {
|
|
||||||
this.dispatchEvent(new Event('open', event));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.#socket.addEventListener('error', (event) => {
|
|
||||||
this.dispatchEvent(new ErrorEvent('error', event));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.#socket.addEventListener('close', (event) => {
|
|
||||||
this.dispatchEvent(new Event('close', event));
|
|
||||||
});
|
|
||||||
|
|
||||||
const meta = await this.#socket.meta;
|
|
||||||
|
|
||||||
if (meta.headers.has('sec-websocket-protocol'))
|
|
||||||
this.#protocol = meta.headers.get('sec-websocket-protocol');
|
|
||||||
|
|
||||||
if (meta.headers.has('sec-websocket-extensions'))
|
|
||||||
this.#extensions = meta.headers.get('sec-websocket-extensions');
|
|
||||||
|
|
||||||
let setCookie = meta.rawHeaders['set-cookie'] || [];
|
|
||||||
if (!Array.isArray(setCookie)) setCookie = [];
|
|
||||||
// trip the hook
|
|
||||||
for (const cookie of setCookie) document.cookie = cookie;
|
|
||||||
}
|
}
|
||||||
get url() {
|
});
|
||||||
return this.#url;
|
|
||||||
}
|
|
||||||
constructor(...args) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (!args.length)
|
|
||||||
throw new DOMException(
|
|
||||||
`Failed to construct 'WebSocket': 1 argument required, but only 0 present.`
|
|
||||||
);
|
|
||||||
|
|
||||||
const [url, protocol] = args;
|
|
||||||
|
|
||||||
let parsed;
|
|
||||||
|
|
||||||
try {
|
|
||||||
parsed = new URL(url);
|
|
||||||
} catch (err) {
|
|
||||||
throw new DOMException(
|
|
||||||
`Faiiled to construct 'WebSocket': The URL '${url}' is invalid.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!wsProtocols.includes(parsed.protocol)) {
|
|
||||||
throw new DOMException(
|
|
||||||
`Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss'. '${parsed.protocol}' is not allowed.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.#ready = this.#open(parsed, protocol);
|
|
||||||
}
|
|
||||||
get protocol() {
|
|
||||||
return this.#protocol;
|
|
||||||
}
|
|
||||||
get extensions() {
|
|
||||||
return this.#extensions;
|
|
||||||
}
|
|
||||||
get readyState() {
|
|
||||||
if (this.#socket) {
|
|
||||||
return this.#socket.readyState;
|
|
||||||
} else {
|
|
||||||
return MockWebSocket.CONNECTING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get binaryType() {
|
|
||||||
return this.#binaryType;
|
|
||||||
}
|
|
||||||
set binaryType(value) {
|
|
||||||
this.#binaryType = value;
|
|
||||||
|
|
||||||
if (this.#socket) {
|
|
||||||
this.#socket.binaryType = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
send(data) {
|
|
||||||
if (!this.#socket) {
|
|
||||||
throw new DOMException(
|
|
||||||
`Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.#socket.send(data);
|
|
||||||
}
|
|
||||||
close(code, reason) {
|
|
||||||
if (typeof code !== 'undefined') {
|
|
||||||
if (typeof code !== 'number') {
|
|
||||||
code = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (code !== 1000 && (code < 3000 || code > 4999)) {
|
|
||||||
throw new DOMException(
|
|
||||||
`Failed to execute 'close' on 'WebSocket': The code must be either 1000, or between 3000 and 4999. ${code} is neither.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.#ready.then(() => this.#socket.close(code, reason));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eventTarget(MockWebSocket.prototype, 'close');
|
|
||||||
eventTarget(MockWebSocket.prototype, 'open');
|
|
||||||
eventTarget(MockWebSocket.prototype, 'message');
|
|
||||||
eventTarget(MockWebSocket.prototype, 'error');
|
|
||||||
|
|
||||||
for (const hook of [
|
|
||||||
'url',
|
|
||||||
'protocol',
|
|
||||||
'extensions',
|
|
||||||
'readyState',
|
|
||||||
'binaryType',
|
|
||||||
]) {
|
|
||||||
const officialDesc = Object.getOwnPropertyDescriptor(
|
|
||||||
window.WebSocket.prototype,
|
|
||||||
hook
|
|
||||||
);
|
|
||||||
const customDesc = Object.getOwnPropertyDescriptor(
|
|
||||||
MockWebSocket.prototype,
|
|
||||||
hook
|
|
||||||
);
|
|
||||||
|
|
||||||
if (customDesc?.get && officialDesc?.get)
|
|
||||||
client.emit('wrap', customDesc.get, officialDesc.get);
|
|
||||||
|
|
||||||
if (customDesc?.set && officialDesc?.set)
|
|
||||||
client.emit('wrap', customDesc.get, officialDesc.get);
|
|
||||||
}
|
|
||||||
|
|
||||||
client.emit(
|
|
||||||
'wrap',
|
|
||||||
window.WebSocket.prototype.send,
|
|
||||||
MockWebSocket.prototype.send
|
|
||||||
);
|
|
||||||
client.emit(
|
|
||||||
'wrap',
|
|
||||||
window.WebSocket.prototype.close,
|
|
||||||
MockWebSocket.prototype.close
|
|
||||||
);
|
|
||||||
|
|
||||||
client.override(
|
|
||||||
window,
|
|
||||||
'WebSocket',
|
|
||||||
(target, that, args) => new MockWebSocket(...args),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
MockWebSocket.prototype.constructor = window.WebSocket;
|
|
||||||
|
|
||||||
client.function.on('function', (event) => {
|
client.function.on('function', (event) => {
|
||||||
event.data.script = __uv.rewriteJS(event.data.script);
|
event.data.script = __uv.rewriteJS(event.data.script);
|
||||||
|
@ -1425,6 +1257,12 @@ function __uvHook(window) {
|
||||||
client.history.overrideReplaceState();
|
client.history.overrideReplaceState();
|
||||||
client.eventSource.overrideConstruct();
|
client.eventSource.overrideConstruct();
|
||||||
client.eventSource.overrideUrl();
|
client.eventSource.overrideUrl();
|
||||||
|
client.websocket.overrideWebSocket();
|
||||||
|
client.websocket.overrideProtocol();
|
||||||
|
client.websocket.overrideURL();
|
||||||
|
client.websocket.overrideReadyState();
|
||||||
|
client.websocket.overrideProtocol();
|
||||||
|
client.websocket.overrideSend();
|
||||||
client.url.overrideObjectURL();
|
client.url.overrideObjectURL();
|
||||||
client.document.overrideCookie();
|
client.document.overrideCookie();
|
||||||
client.message.overridePostMessage();
|
client.message.overridePostMessage();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue