about summary refs log tree commit diff stats
path: root/src/loader
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-07-19 18:12:44 +0200
committerbptato <nincsnevem662@gmail.com>2024-07-19 18:16:12 +0200
commit0d08ee8959d126d652fc42e9af63dbc8cc1d93ba (patch)
tree1b597924989f1eb3e4b96714c69e385af97d7186 /src/loader
parentf94b84bde340739647ffe7dd92cfcefb6686eca2 (diff)
downloadchawan-0d08ee8959d126d652fc42e9af63dbc8cc1d93ba.tar.gz
loader: async status/headers for fetch
The status code & headers are no longer guaranteed to be sent right
after res/outputId, so read them asynchronously instead.

(This is pretty much the same code as the buffer connection handler in
pager. Hopefully we can merge the two at some point.)
Diffstat (limited to 'src/loader')
-rw-r--r--src/loader/loader.nim56
-rw-r--r--src/loader/response.nim6
2 files changed, 39 insertions, 23 deletions
diff --git a/src/loader/loader.nim b/src/loader/loader.nim
index 29913031..f773936f 100644
--- a/src/loader/loader.nim
+++ b/src/loader/loader.nim
@@ -72,7 +72,14 @@ type
     # (FreeBSD only) fd for the socket directory so we can connectat() on it
     sockDirFd*: int
 
-  ConnectData = object
+  ConnectDataState = enum
+    cdsBeforeResult, cdsBeforeStatus, cdsBeforeHeaders
+
+  ConnectData = ref object
+    state: ConnectDataState
+    status: uint16
+    res: int
+    outputId: int
     promise: Promise[JSResult[Response]]
     stream*: SocketStream
     request: Request
@@ -1018,17 +1025,32 @@ proc onConnected*(loader: FileLoader; fd: int) =
   let stream = connectData.stream
   let promise = connectData.promise
   let request = connectData.request
-  # delete before resolving the promise
-  loader.connecting.del(fd)
   var r = stream.initPacketReader()
-  var res: int
-  r.sread(res) # packet 1
-  if res == 0:
-    let response = newResponse(res, request, stream)
-    r.sread(response.outputId) # packet 1
-    r = stream.initPacketReader()
-    r.sread(response.status) # packet 2
-    r = stream.initPacketReader()
+  case connectData.state
+  of cdsBeforeResult:
+    var res: int
+    r.sread(res) # packet 1
+    if res == 0:
+      r.sread(connectData.outputId) # packet 1
+      inc connectData.state
+    else:
+      var msg: string
+      # msg is discarded.
+      #TODO maybe print if called from trusted code (i.e. global == client)?
+      r.sread(msg) # packet 1
+      loader.unregisterFun(fd)
+      loader.unregistered.add(fd)
+      stream.sclose()
+      # delete before resolving the promise
+      loader.connecting.del(fd)
+      let err = newTypeError("NetworkError when attempting to fetch resource")
+      promise.resolve(JSResult[Response].err(err))
+  of cdsBeforeStatus:
+    r.sread(connectData.status) # packet 2
+    inc connectData.state
+  of cdsBeforeHeaders:
+    let response = newResponse(connectData.res, request, stream,
+      connectData.outputId, connectData.status)
     r.sread(response.headers) # packet 3
     # Only a stream of the response body may arrive after this point.
     response.body = stream
@@ -1041,17 +1063,9 @@ proc onConnected*(loader: FileLoader; fd: int) =
       loader.resume(outputId)
     loader.ongoing[fd] = response
     stream.setBlocking(false)
+    # delete before resolving the promise
+    loader.connecting.del(fd)
     promise.resolve(JSResult[Response].ok(response))
-  else:
-    var msg: string
-    # msg is discarded.
-    #TODO maybe print if called from trusted code (i.e. global == client)?
-    r.sread(msg) # packet 1
-    loader.unregisterFun(fd)
-    loader.unregistered.add(fd)
-    stream.sclose()
-    let err = newTypeError("NetworkError when attempting to fetch resource")
-    promise.resolve(JSResult[Response].err(err))
 
 proc onRead*(loader: FileLoader; fd: int) =
   let response = loader.ongoing.getOrDefault(fd)
diff --git a/src/loader/response.nim b/src/loader/response.nim
index 8b33621e..5531da9d 100644
--- a/src/loader/response.nim
+++ b/src/loader/response.nim
@@ -59,13 +59,15 @@ type
 
 jsDestructor(Response)
 
-proc newResponse*(res: int; request: Request; stream: SocketStream): Response =
+proc newResponse*(res: int; request: Request; stream: SocketStream;
+    outputId: int; status: uint16): Response =
   return Response(
     res: res,
     url: request.url,
     body: stream,
     bodyRead: EmptyPromise(),
-    outputId: -1
+    outputId: outputId,
+    status: status
   )
 
 func makeNetworkError*(): Response {.jsstfunc: "Response.error".} =