diff options
Diffstat (limited to 'src/html/xmlhttprequest.nim')
-rw-r--r-- | src/html/xmlhttprequest.nim | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/html/xmlhttprequest.nim b/src/html/xmlhttprequest.nim new file mode 100644 index 00000000..e9905760 --- /dev/null +++ b/src/html/xmlhttprequest.nim @@ -0,0 +1,118 @@ +import std/options +import std/strutils + +import bindings/quickjs +import html/dom +import html/event +import js/domexception +import js/fromjs +import js/javascript +import loader/headers +import loader/request +import loader/response +import types/url + +type + XMLHttpRequestResponseType = enum + TYPE_UNKNOWN = "" + TYPE_ARRAYBUFFER = "arraybuffer" + TYPE_BLOB = "blob" + TYPE_DOCUMENT = "document" + TYPE_JSON = "json" + TYPE_TEXT = "text" + + XMLHttpRequestState = enum + UNSENT = 0u16 + OPENED = 1u16 + HEADERS_RECEIVED = 2u16 + LOADING = 3u16 + DONE = 4u16 + + XMLHttpRequestFlag = enum + SEND_FLAG, UPLOAD_LISTENER_FLAG, SYNC_FLAG + + XMLHttpRequestEventTarget = ref object of EventTarget + onloadstart {.jsgetset.}: EventHandler + onprogress {.jsgetset.}: EventHandler + onabort {.jsgetset.}: EventHandler + onerror {.jsgetset.}: EventHandler + onload {.jsgetset.}: EventHandler + ontimeout {.jsgetset.}: EventHandler + onloadend {.jsgetset.}: EventHandler + + XMLHttpRequestUpload = ref object of XMLHttpRequestEventTarget + + XMLHttpRequest = ref object of XMLHttpRequestEventTarget + onreadystatechange {.jsgetset.}: EventHandler + readyState: XMLHttpRequestState + upload {.jsget.}: XMLHttpRequestUpload + flags: set[XMLHttpRequestFlag] + requestMethod: HttpMethod + requestURL: URL + authorRequestHeaders: Headers + response: Response + responseType {.jsgetset.}: XMLHttpRequestResponseType + +jsDestructor(XMLHttpRequestEventTarget) +jsDestructor(XMLHttpRequestUpload) +jsDestructor(XMLHttpRequest) + +func newXMLHttpRequest(): XMLHttpRequest {.jsctor.} = + let upload = XMLHttpRequestUpload() + return XMLHttpRequest( + upload: upload, + authorRequestHeaders: newHeaders() + ) + +func readyState(this: XMLHttpRequest): uint16 {.jsfget.} = + return uint16(this.readyState) + +proc parseMethod(s: string): DOMResult[HttpMethod] = + return case s.toLowerAscii() + of "get": ok(HTTP_GET) + of "delete": ok(HTTP_DELETE) + of "head": ok(HTTP_HEAD) + of "options": ok(HTTP_OPTIONS) + of "patch": ok(HTTP_PATCH) + of "post": ok(HTTP_POST) + of "put": ok(HTTP_PUT) + of "connect", "trace", "track": + errDOMException("Forbidden method", "SecurityError") + else: + errDOMException("Invalid method", "SyntaxError") + +proc open(ctx: JSContext, this: XMLHttpRequest, httpMethod, url: string): + Err[DOMException] {.jsfunc.} = + let httpMethod = ?parseMethod(httpMethod) + let global = JS_GetGlobalObject(ctx) + let window = fromJS[Window](ctx, global) + JS_FreeValue(ctx, global) + let x = if window.isSome: + parseURL(url, some(window.get.document.baseURL)) + else: + parseURL(url) + if x.isNone: + return errDOMException("Invalid URL", "SyntaxError") + let parsedURL = x.get + #TODO async, username, password arguments + let async = true + #TODO if async is false... probably just throw. + #TODO terminate fetch controller + this.flags.excl(SEND_FLAG) + this.flags.excl(UPLOAD_LISTENER_FLAG) + if async: + this.flags.excl(SYNC_FLAG) + else: + this.flags.incl(SYNC_FLAG) + this.requestMethod = httpMethod + this.authorRequestHeaders = newHeaders() + this.response = makeNetworkError() + this.requestURL = parsedURL + return ok() + +proc addXMLHttpRequestModule*(ctx: JSContext) = + let eventTargetCID = ctx.getClass("EventTarget") + let xhretCID = ctx.registerType(XMLHttpRequestEventTarget, eventTargetCID) + ctx.registerType(XMLHttpRequestUpload, xhretCID) + let xhrCID = ctx.registerType(XMLHttpRequest, xhretCID) + ctx.defineConsts(xhrCID, XMLHttpRequestState, uint16) |