blob: 897ad9773d5500c7f9cbd3926d04e5a3a504b220 [file] [log] [blame]
<import src="/mojo/public/sky/core.sky" as="core" />
<import src="/mojo/public/sky/unicode.sky" as="unicode" />
<import src="/mojo/services/network/public/interfaces/network_service.mojom.sky" as="net" />
<import src="/mojo/services/network/public/interfaces/url_loader.mojom.sky" as="loader" />
<import src="/sky/framework/shell.sky" as="shell" />
<script>
// XHR keeps itself alive.
var outstandingRequests = new Set();
const kPrivate = Symbol("XMLHttpRequestPrivate");
class Private {
constructor() {
this.networkService = shell.connectToService(
"mojo:network_service", net.NetworkService);
this.request = null;
this.loader = null;
this.headers = new Map();
this.responseArrayBuffer = null;
this.responseText = null; // Cached to avoid re-decoding each access.
}
}
// https://xhr.spec.whatwg.org
class XMLHttpRequest {
constructor() {
this[kPrivate] = new Private;
this.responseType = ''; // Only text and arraybuffer support for now.
}
onload() {
}
onerror(error) {
}
get responseText() {
if (this.responseType !== '' && this.responseType !== 'text')
throw 'Non-text responseType ' + this.responseType;
if (this[kPrivate].responseArrayBuffer === null)
return null;
if (this[kPrivate].responseText === null) {
var intArray = new Uint8Array(this[kPrivate].responseArrayBuffer);
this[kPrivate].responseText = unicode.decodeUtf8String(intArray);
}
return this[kPrivate].responseText;
}
get response() {
if (this.responseType === 'text' || this.responseType == '')
return this.responseText;
else if (this.responseType === 'arraybuffer')
return this[kPrivate].responseArrayBuffer;
throw 'Unknown responseType ' + this.responseType;
}
open(method, url) {
var request = new loader.URLRequest();
request.url = new URL(url, document.URL);
request.method = method;
request.auto_follow_redirects = true;
var priv = this[kPrivate];
priv.request = request;
priv.headers.clear();
}
setRequestHeader(header, value) {
this[kPrivate].headers.set(header, value);
}
send() {
var priv = this[kPrivate];
var requestHeaders = [];
priv.headers.forEach(function(value, key) {
requestHeaders.push(key + ': ' + value);
});
priv.request.headers = requestHeaders;
// FIXME: Factor this into the JS bindings.
var pipe = new core.createMessagePipe();
priv.networkService.createURLLoader(pipe.handle1);
priv.loader = shell.wrapHandle(pipe.handle0, loader.URLLoader);
var self = this;
outstandingRequests.add(this);
priv.loader.start(priv.request).then(function(result) {
return core.drainData(result.response.body).then(function(result) {
outstandingRequests.delete(self);
priv.responseArrayBuffer = result.buffer;
// FIXME: Catch exceptions during onload so they don't trip onerror.
self.onload();
});
}).catch(function(error) {
outstandingRequests.delete(self);
self.onerror(error);
});
}
}
module.exports = XMLHttpRequest;
</script>