about summary refs log tree commit diff stats
path: root/src/io/loader.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/io/loader.nim')
-rw-r--r--src/io/loader.nim99
1 files changed, 76 insertions, 23 deletions
diff --git a/src/io/loader.nim b/src/io/loader.nim
index bced0298..7c55b2bc 100644
--- a/src/io/loader.nim
+++ b/src/io/loader.nim
@@ -26,6 +26,7 @@ import io/http
 import io/promise
 import io/request
 import io/urlfilter
+import js/javascript
 import ips/serialize
 import ips/serversocket
 import ips/socketstream
@@ -36,8 +37,17 @@ import types/url
 import utils/twtstr
 
 type
-  FileLoader* = object
+  FileLoader* = ref object
     process*: Pid
+    connecting*: Table[int, ConnectData]
+    ongoing*: Table[int, Response]
+    registerFun*: proc(fd: int)
+    unregisterFun*: proc(fd: int)
+
+  ConnectData = object
+    promise: Promise[Response]
+    stream: Stream
+    request: Request
 
   LoaderCommand = enum
     LOAD, QUIT
@@ -192,9 +202,72 @@ proc runFileLoader*(fd: cint, config: LoaderConfig) =
         ctx.handleList.del(idx)
   ctx.exitLoader()
 
-#TODO async requests...
+proc applyHeaders(request: Request, response: Response) =
+  if "Content-Type" in response.headers.table:
+    response.contenttype = response.headers.table["Content-Type"][0].until(';')
+  else:
+    response.contenttype = guessContentType($response.url.path)
+  if "Location" in response.headers.table:
+    if response.status in 301..303 or response.status in 307..308:
+      let location = response.headers.table["Location"][0]
+      let url = parseUrl(location, option(request.url))
+      if url.isSome:
+        if (response.status == 303 and
+            request.httpmethod notin {HTTP_GET, HTTP_HEAD}) or
+            (response.status == 301 or response.status == 302 and
+            request.httpmethod == HTTP_POST):
+          response.redirect = newRequest(url.get, HTTP_GET,
+            mode = request.mode, credentialsMode = request.credentialsMode,
+            destination = request.destination)
+        else:
+          response.redirect = newRequest(url.get, request.httpmethod,
+            body = request.body, multipart = request.multipart,
+            mode = request.mode, credentialsMode = request.credentialsMode,
+            destination = request.destination)
+
+#TODO: add init
+proc fetch*(loader: FileLoader, input: Request): Promise[Response] =
+  let stream = connectSocketStream(loader.process, false, blocking = true)
+  stream.swrite(LOAD)
+  stream.swrite(input)
+  stream.flush()
+  let fd = int(stream.source.getFd())
+  loader.registerFun(fd)
+  let promise = Promise[Response]()
+  loader.connecting[fd] = ConnectData(promise: promise, request: input)
+
+proc newResponse(res: int, request: Request, stream: Stream = nil): Response =
+  return Response(
+    res: res,
+    url: request.url,
+    body: stream
+  )
+
+proc onConnected*(loader: FileLoader, fd: int) =
+  let connectData = loader.connecting[fd]
+  let stream = connectData.stream
+  let promise = connectData.promise
+  let request = connectData.request
+  var res: int
+  stream.sread(res)
+  if res == 0:
+    let response = newResponse(res, request, stream)
+    response.unregisterFun = proc() = loader.unregisterFun(fd)
+    stream.sread(response.status)
+    stream.sread(response.headers)
+    applyHeaders(request, response)
+    response.body = stream
+    loader.ongoing[fd] = response
+    promise.resolve(response)
+  else:
+    #TODO: reject promise instead.
+    let response = newResponse(res, request)
+    promise.resolve(response)
+  loader.connecting.del(fd)
+
 proc doRequest*(loader: FileLoader, request: Request, blocking = true): Response =
   new(result)
+  result.url = request.url
   let stream = connectSocketStream(loader.process, false, blocking = true)
   stream.swrite(LOAD)
   stream.swrite(request)
@@ -203,27 +276,7 @@ proc doRequest*(loader: FileLoader, request: Request, blocking = true): Response
   if result.res == 0:
     stream.sread(result.status)
     stream.sread(result.headers)
-    if "Content-Type" in result.headers.table:
-      result.contenttype = result.headers.table["Content-Type"][0].until(';')
-    else:
-      result.contenttype = guessContentType($request.url.path)
-    if "Location" in result.headers.table:
-      if result.status in 301..303 or result.status in 307..308:
-        let location = result.headers.table["Location"][0]
-        let url = parseUrl(location, some(request.url))
-        if url.isSome:
-          if (result.status == 303 and
-              request.httpmethod notin {HTTP_GET, HTTP_HEAD}) or
-              (result.status == 301 or result.status == 302 and
-              request.httpmethod == HTTP_POST):
-            result.redirect = newRequest(url.get, HTTP_GET,
-              mode = request.mode, credentialsMode = request.credentialsMode,
-              destination = request.destination)
-          else:
-            result.redirect = newRequest(url.get, request.httpmethod,
-              body = request.body, multipart = request.multipart,
-              mode = request.mode, credentialsMode = request.credentialsMode,
-              destination = request.destination)
+    applyHeaders(request, result)
     # Only a stream of the response body may arrive after this point.
     result.body = stream
     if not blocking: