ultraviolet/src/client/requests/xhr.js
2022-11-18 20:00:58 -05:00

151 lines
4.6 KiB
JavaScript

import EventEmitter from '../events.js';
import HookEvent from '../hook.js';
class Xhr extends EventEmitter {
constructor(ctx) {
super();
this.ctx = ctx;
this.window = ctx.window;
this.XMLHttpRequest = this.window.XMLHttpRequest;
this.xhrProto = this.window.XMLHttpRequest
? this.window.XMLHttpRequest.prototype
: {};
this.open = this.xhrProto.open;
this.abort = this.xhrProto.abort;
this.send = this.xhrProto.send;
this.overrideMimeType = this.xhrProto.overrideMimeType;
this.getAllResponseHeaders = this.xhrProto.getAllResponseHeaders;
this.getResponseHeader = this.xhrProto.getResponseHeader;
this.setRequestHeader = this.xhrProto.setRequestHeader;
this.responseURL = ctx.nativeMethods.getOwnPropertyDescriptor(
this.xhrProto,
'responseURL'
);
this.responseText = ctx.nativeMethods.getOwnPropertyDescriptor(
this.xhrProto,
'responseText'
);
}
override() {
this.overrideOpen();
this.overrideSend();
this.overrideMimeType();
this.overrideGetResHeader();
this.overrideGetResHeaders();
this.overrideSetReqHeader();
}
overrideOpen() {
this.ctx.override(this.xhrProto, 'open', (target, that, args) => {
if (2 > args.length) return target.apply(that, args);
let [method, input, async = true, user = null, password = null] =
args;
const event = new HookEvent(
{ method, input, async, user, password },
target,
that
);
this.emit('open', event);
if (event.intercepted) return event.returnValue;
return event.target.call(
event.that,
event.data.method,
event.data.input,
event.data.async,
event.data.user,
event.data.password
);
});
}
overrideResponseUrl() {
this.ctx.overrideDescriptor(this.xhrProto, 'responseURL', {
get: (target, that) => {
const event = new HookEvent(
{ value: target.call(that) },
target,
that
);
this.emit('responseUrl', event);
if (event.intercepted) return event.returnValue;
return event.data.value;
},
});
}
overrideSend() {
this.ctx.override(
this.xhrProto,
'send',
(target, that, [body = null]) => {
const event = new HookEvent({ body }, target, that);
this.emit('send', event);
if (event.intercepted) return event.returnValue;
return event.target.call(event.that, event.data.body);
}
);
}
overrideSetReqHeader() {
this.ctx.override(
this.xhrProto,
'setRequestHeader',
(target, that, args) => {
if (2 > args.length) return target.apply(that, args);
let [name, value] = args;
const event = new HookEvent({ name, value }, target, that);
this.emit('setReqHeader', event);
if (event.intercepted) return event.returnValue;
return event.target.call(
event.that,
event.data.name,
event.data.value
);
}
);
}
overrideGetResHeaders() {
this.ctx.override(
this.xhrProto,
'getAllResponseHeaders',
(target, that) => {
const event = new HookEvent(
{ value: target.call(that) },
target,
that
);
this.emit('getAllResponseHeaders', event);
if (event.intercepted) return event.returnValue;
return event.data.value;
}
);
}
overrideGetResHeader() {
this.ctx.override(
this.xhrProto,
'getResponseHeader',
(target, that, args) => {
if (!args.length) return target.apply(that, args);
let [name] = args;
const event = new HookEvent(
{ name, value: target.call(that, name) },
target,
that
);
if (event.intercepted) return event.returnValue;
return event.data.value;
}
);
}
}
export default Xhr;