about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-12-08 17:45:27 +0100
committerbptato <nincsnevem662@gmail.com>2024-12-08 18:10:28 +0100
commit8974f7deaaecd84b5f95e40bf935f735253521f3 (patch)
tree2ed5a61ba633dbae71596a85734f7ffe31576d3c /src
parentf6f340bfaa65657e78f93adb1fa715261c466fbc (diff)
downloadchawan-8974f7deaaecd84b5f95e40bf935f735253521f3.tar.gz
response: simplify text()
It gets copied once anyway, so just use a blob.

I guess I could skip the copy with some effort, but the 4 lines
implementation is too attractive :P
This is still an improvement, as it doesn't needlessly zero-fill the
buffer on realloc.

(I've also removed the final realloc from blob, as it seemed quite
pointless.  Using Content-Length could help... except it doesn't,
because it refers to the encoded length. Ugh.)
Diffstat (limited to 'src')
-rw-r--r--src/server/response.nim49
-rw-r--r--src/types/blob.nim7
2 files changed, 14 insertions, 42 deletions
diff --git a/src/server/response.nim b/src/server/response.nim
index 37ff2434..1f68932a 100644
--- a/src/server/response.nim
+++ b/src/server/response.nim
@@ -124,49 +124,8 @@ proc resume*(response: Response) =
   response.resumeFun(response.outputId)
   response.resumeFun = nil
 
-type TextOpaque = ref object of RootObj
-  buf: string
-  bodyRead: Promise[JSResult[string]]
-
 const BufferSize = 4096
 
-proc onReadText(response: Response) =
-  let opaque = TextOpaque(response.opaque)
-  while true:
-    let olen = opaque.buf.len
-    try:
-      opaque.buf.setLen(olen + BufferSize)
-      let n = response.body.recvData(addr opaque.buf[olen], BufferSize)
-      opaque.buf.setLen(olen + n)
-      if n == 0:
-        break
-    except ErrorAgain:
-      opaque.buf.setLen(olen)
-      break
-
-proc onFinishText(response: Response; success: bool) =
-  let opaque = TextOpaque(response.opaque)
-  let bodyRead = opaque.bodyRead
-  if success:
-    let charset = response.getCharset(CHARSET_UTF_8)
-    bodyRead.resolve(JSResult[string].ok(opaque.buf.decodeAll(charset)))
-  else:
-    bodyRead.resolve(JSResult[string].err(newFetchTypeError()))
-
-proc text*(response: Response): Promise[JSResult[string]] {.jsfunc.} =
-  if response.body == nil:
-    return newResolvedPromise(JSResult[string].ok(""))
-  if response.bodyUsed:
-    let err = newTypeError("Body has already been consumed")
-    return newResolvedPromise(JSResult[string].err(err))
-  let opaque = TextOpaque(bodyRead: Promise[JSResult[string]]())
-  response.opaque = opaque
-  response.onRead = onReadText
-  response.onFinish = onFinishText
-  response.bodyUsed = true
-  response.resume()
-  return opaque.bodyRead
-
 type BlobOpaque = ref object of RootObj
   p: pointer
   len: int
@@ -194,7 +153,7 @@ proc onFinishBlob(response: Response; success: bool) =
   let opaque = BlobOpaque(response.opaque)
   let bodyRead = opaque.bodyRead
   if success:
-    let p = realloc(opaque.p, opaque.len)
+    let p = opaque.p
     opaque.p = nil
     let blob = if p == nil:
       newBlob(nil, 0, opaque.contentType, nil)
@@ -225,6 +184,12 @@ proc blob*(response: Response): Promise[JSResult[Blob]] {.jsfunc.} =
   response.resume()
   return opaque.bodyRead
 
+proc text*(response: Response): Promise[JSResult[string]] {.jsfunc.} =
+  return response.blob().then(proc(res: JSResult[Blob]): JSResult[string] =
+    let blob = ?res
+    return ok(blob.toOpenArray().toValidUTF8())
+  )
+
 proc json(ctx: JSContext; this: Response): Promise[JSValue] {.jsfunc.} =
   return this.text().then(proc(s: JSResult[string]): JSValue =
     if s.isNone:
diff --git a/src/types/blob.nim b/src/types/blob.nim
index f21d0954..689883a8 100644
--- a/src/types/blob.nim
+++ b/src/types/blob.nim
@@ -77,6 +77,13 @@ proc deallocBlob*(opaque, p: pointer) =
   if p != nil:
     dealloc(p)
 
+template toOpenArray*(blob: Blob): openArray[char] =
+  let p = cast[ptr UncheckedArray[char]](blob.buffer)
+  if p != nil:
+    p.toOpenArray(0, blob.size - 1)
+  else:
+    []
+
 proc finalize(blob: Blob) {.jsfin.} =
   if blob.fd.isSome:
     discard close(blob.fd.get)