diff options
-rw-r--r-- | src/buffer/buffer.nim | 31 | ||||
-rw-r--r-- | src/html/dom.nim | 6 | ||||
-rw-r--r-- | src/io/loader.nim | 6 | ||||
-rw-r--r-- | src/io/response.nim | 25 | ||||
-rw-r--r-- | src/js/exception.nim | 5 |
5 files changed, 50 insertions, 23 deletions
diff --git a/src/buffer/buffer.nim b/src/buffer/buffer.nim index e8f8eaaa..90505c34 100644 --- a/src/buffer/buffer.nim +++ b/src/buffer/buffer.nim @@ -3,14 +3,12 @@ import nativesockets import net import options import os +import posix import selectors import streams import tables import unicode -when defined(posix): - import posix - import buffer/cell import config/config import css/cascade @@ -34,6 +32,7 @@ import io/window import ips/serialize import ips/serversocket import ips/socketstream +import js/exception import js/javascript import js/regex import js/timeout @@ -562,15 +561,15 @@ proc loadResource(buffer: Buffer, elem: HTMLLinkElement): EmptyPromise = let media = parseMediaQueryList(cvals) if not media.applies(document.window): return return buffer.loader.fetch(newRequest(url)) - .then(proc(res: Result[Response, JSError]): Opt[Promise[string]] = + .then(proc(res: Result[Response, JSError]): Promise[JSResult[string]] = if res.isOk: let res = res.get #TODO we should use ReadableStreams for this (which would allow us to # parse CSS asynchronously) if res.contenttype == "text/css": - return ok(res.text()) + return res.text() res.unregisterFun() - ).then(proc(s: Opt[string]) = + ).then(proc(s: JSResult[string]) = if s.isOk: #TODO this is extremely inefficient, and text() should return # utf8 anyways @@ -588,14 +587,18 @@ proc loadResource(buffer: Buffer, elem: HTMLImageElement): EmptyPromise = if url.isSome: let url = url.get return buffer.loader.fetch(newRequest(url)) - .then(proc(res: Result[Response, JSError]): Promise[string] = - if res.isOk: - let res = res.get - if res.contenttype == "image/png": - #TODO using text() for PNG is wrong - return res.text() - ).then(proc(pngData: string) = - elem.bitmap = fromPNG(toOpenArrayByte(pngData, 0, pngData.high))) + .then(proc(res: Result[Response, JSError]): Promise[JSResult[string]] = + if res.isErr: + return + let res = res.get + if res.contenttype == "image/png": + #TODO using text() for PNG is wrong + return res.text() + ).then(proc(pngData: JSResult[string]) = + if pngData.isErr: + return + let pngData = pngData.get + elem.bitmap = fromPNG(toOpenArrayByte(pngData, 0, pngData.high))) proc loadResources(buffer: Buffer): EmptyPromise = let document = buffer.document diff --git a/src/html/dom.nim b/src/html/dom.nim index 3bf67b05..0445aa83 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -2403,8 +2403,10 @@ proc fetchClassicScript(element: HTMLScriptElement, url: URL, #TODO use charset from content-type #TODO text() should decode return r.get.text() - ).then(proc(s: string) = - let ss = newStringStream(s) #TODO unnecessary copy + ).then(proc(s: JSResult[string]) = + if s.isErr: + return + let ss = newStringStream(s.get) #TODO unnecessary copy let cs = if cs == CHARSET_UNKNOWN: CHARSET_UTF_8 else: cs let source = newDecoderStream(ss, cs = cs).readAll() #TODO use response url diff --git a/src/io/loader.nim b/src/io/loader.nim index acc432ec..0ce19c38 100644 --- a/src/io/loader.nim +++ b/src/io/loader.nim @@ -60,6 +60,7 @@ type buf: string readbufsize: int response: Response + bodyRead: Promise[string] ConnectErrorCode* = enum ERROR_SOURCE_NOT_FOUND = (-4, "clone source could not be found"), @@ -295,6 +296,7 @@ proc onConnected*(loader: FileLoader, fd: int) = loader.ongoing[fd] = OngoingData( response: response, readbufsize: BufferSize, + bodyRead: response.bodyRead ) SocketStream(stream).source.getFd().setBlocking(false) promise.resolve(Result[Response, JSError].ok(response)) @@ -319,7 +321,9 @@ proc onRead*(loader: FileLoader, fd: int) = buffer[].readbufsize = min(BufferSize, buffer[].readbufsize * 2) buffer[].buf.setLen(olen + n) if response.body.atEnd(): - response.bodyRead.resolve(buffer[].buf) + buffer[].bodyRead.resolve(buffer[].buf) + buffer[].bodyRead = nil + buffer[].buf = "" response.unregisterFun() break except ErrorAgain, ErrorWouldBlock: diff --git a/src/io/response.nim b/src/io/response.nim index 2c336a8c..fbe5339e 100644 --- a/src/io/response.nim +++ b/src/io/response.nim @@ -3,6 +3,7 @@ import streams import bindings/quickjs import io/promise import io/request +import js/exception import js/javascript import types/url @@ -44,13 +45,25 @@ proc close*(response: Response) {.jsfunc.} = if response.body != nil: response.body.close() -proc text*(response: Response): Promise[string] {.jsfunc.} = - return response.bodyRead +proc text*(response: Response): Promise[Result[string, JSError]] {.jsfunc.} = + if response.bodyRead == nil: + let p = Promise[Result[string, JSError]]() + let err = Result[string, JSError] + .err(newTypeError("Body has already been consumed")) + p.resolve(err) + return p + let bodyRead = response.bodyRead + response.bodyRead = nil + return bodyRead.then(proc(s: string): Result[string, JSError] = + ok(s)) -proc json(ctx: JSContext, this: Response): Promise[JSValue] {.jsfunc.} = - return this.text().then(proc(s: string): JSValue = - return JS_ParseJSON(ctx, cstring(s), cast[csize_t](s.len), - cstring"<input>")) +proc json(ctx: JSContext, this: Response): Promise[Result[JSValue, JSError]] + {.jsfunc.} = + return this.text().then(proc(s: Result[string, JSError]): + Result[JSValue, JSError] = + let s = ?s + return ok(JS_ParseJSON(ctx, cstring(s), cast[csize_t](s.len), + cstring"<input>"))) proc addResponseModule*(ctx: JSContext) = ctx.registerType(Response) diff --git a/src/js/exception.nim b/src/js/exception.nim index 1550d431..f30c4898 100644 --- a/src/js/exception.nim +++ b/src/js/exception.nim @@ -31,6 +31,11 @@ const NamesTable = { type DOMException* = ref object of JSError name* {.jsget.}: string +type + JSResult*[T] = Result[T, JSError] + + DOMResult*[T] = Result[T, DOMException] + proc newDOMException*(message = "", name = "Error"): DOMException {.jsctor.} = return DOMException( e: JS_DOM_EXCEPTION, |