about summary refs log tree commit diff stats
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
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.)
-rw-r--r--src/loader/loader.nim56
-rw-r--r--src/loader/response.nim6
-rw-r--r--src/local/pager.nim9
3 files changed, 41 insertions, 30 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".} =
diff --git a/src/local/pager.nim b/src/local/pager.nim
index de990767..c77d724b 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -1970,13 +1970,8 @@ proc handleConnectingContainer*(pager: Pager; i: int) =
     inc item.state
     # continue
   of ccsBeforeHeaders:
-    let response = Response(
-      res: item.res,
-      outputId: item.outputId,
-      status: item.status,
-      url: container.request.url,
-      body: stream
-    )
+    let response = newResponse(item.res, container.request, stream,
+      item.outputId, item.status)
     var r = stream.initPacketReader()
     r.sread(response.headers)
     # done