about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/buffer/buffer.nim31
-rw-r--r--src/html/dom.nim6
-rw-r--r--src/io/loader.nim6
-rw-r--r--src/io/response.nim25
-rw-r--r--src/js/exception.nim5
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,