Uncaught TypeError when assigning null to xhr.onreadystatechange/onprogress (breaks hls.js abort)
Description
Libraries like hls.js clear XHR event callbacks before aborting in-flight requests (see XhrLoader.abortInternal in hls.js):
xhr.onreadystatechange = null;
xhr.onprogress = null;
xhr.abort();With vConsole enabled, this throws an uncaught TypeError, because the XHR proxy wraps whatever value is assigned to onreadystatechange / onabort / ontimeout without a null check — the wrapper later calls value.apply(...) on null.
src/network/xhr.proxy.ts (still present on current master):
protected setOnReadyStateChange(target: T, key: string, value) {
...
Reflect.set(target, key, function () {
...
value.apply(target, args); // value may be null
});
}
// setOnAbort / setOnTimeout have the same problemAssigning null to these callbacks is a legitimate, spec-compliant way to remove them, so the proxy should pass null through instead of wrapping it.
Steps to reproduce
<script src="https://unpkg.com/[email protected]/dist/vconsole.min.js"></script>
<script>
new VConsole();
var xhr = new XMLHttpRequest();
xhr.open('GET', '/'); // any URL
xhr.onreadystatechange = function () {};
xhr.send();
xhr.onreadystatechange = null; // how hls.js abortInternal cleans up
xhr.onprogress = null;
xhr.abort(); // → Uncaught TypeError: Cannot read properties of null (reading 'apply')
</script>Running the exact same code without vConsole produces no error (verified side by side).
Real-world impact
Any page playing HLS video via hls.js throws this on every stream switch / stop / destroy:
Uncaught TypeError: Cannot read property 'apply' of null
at XMLHttpRequest.<anonymous> (vconsole.js)
at t.r.abortInternal (hls.min.js)
at t.abort (hls.min.js)
at e.t.abort (hls.min.js)
at t.r.stopLoad (hls.min.js)
...Environment
- vConsole version: 3.15.1 (latest release; null check also missing on current master)
- Browser: any (reproduced in Chrome)
Suggested fix
Pass null/undefined through instead of wrapping it, in all three setters:
protected setOnReadyStateChange(target: T, key: string, value) {
if (!value) return Reflect.set(target, key, value);
...
}Source: Tencent/vConsole