about summary refs log tree commit diff stats
path: root/src/io
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-06-02 00:36:54 +0200
committerbptato <nincsnevem662@gmail.com>2023-06-05 03:58:21 +0200
commit8027e52cb221c432bed64517015ebf3182e6166d (patch)
tree18991f9e74c8dcfc0ed7439f3bc78a0cfec9b2d6 /src/io
parentb3b97465805b7367df461a4b7b830fabaccf3a89 (diff)
downloadchawan-8027e52cb221c432bed64517015ebf3182e6166d.tar.gz
Add support for canvas and multipart
Quite incomplete canvas implementation. Crucially, the layout engine
can't do much with whatever is drawn because it doesn't support images
yet.

I've re-introduced multipart as well, with the FormData API. For the
append function I've also introduced a hack to the JS binding generator
that allows requesting the JSContext pointer in nim procs. Really I
should just fix the union generator thing and add support for overloading.

In conclusion, for now the only thing canvas can be used for is exporting
it as PNG and uploading it somewhere. Also, we now have PNG encoding and
decoding too. (Now if only we had sixels as well...)
Diffstat (limited to 'src/io')
-rw-r--r--src/io/http.nim18
-rw-r--r--src/io/request.nim53
2 files changed, 32 insertions, 39 deletions
diff --git a/src/io/http.nim b/src/io/http.nim
index 984cae7c..f9023f5f 100644
--- a/src/io/http.nim
+++ b/src/io/http.nim
@@ -5,6 +5,8 @@ import strutils
 import bindings/curl
 import io/request
 import ips/serialize
+import types/blob
+import types/formdata
 import types/url
 import utils/twtstr
 
@@ -89,7 +91,7 @@ proc applyPostBody(curl: CURL, request: Request, handleData: HandleData) =
       handleData.ostream.swrite(-1)
       handleData.ostream.flush()
       return
-    for entry in request.multipart.get.content:
+    for entry in request.multipart.get:
       let part = curl_mime_addpart(handleData.mime)
       if part == nil:
         # fail (TODO: raise?)
@@ -97,16 +99,16 @@ proc applyPostBody(curl: CURL, request: Request, handleData: HandleData) =
         handleData.ostream.flush()
         return
       curl_mime_name(part, cstring(entry.name))
-      if entry.isFile:
-        if entry.isStream:
-          curl_mime_filedata(part, cstring(entry.filename))
+      if entry.isstr:
+        curl_mime_data(part, cstring(entry.svalue), csize_t(entry.svalue.len))
+      else:
+        let blob = entry.value
+        if blob.isfile: #TODO ?
+          curl_mime_filedata(part, cstring(WebFile(blob).path))
         else:
-          let fd = readFile(entry.filename)
-          curl_mime_data(part, cstring(fd), csize_t(fd.len))
+          curl_mime_data(part, blob.buffer, csize_t(blob.size))
         # may be overridden by curl_mime_filedata, so set it here
         curl_mime_filename(part, cstring(entry.filename))
-      else:
-        curl_mime_data(part, cstring(entry.content), csize_t(entry.content.len))
     curl.setopt(CURLOPT_MIMEPOST, handleData.mime)
   elif request.body.issome:
     curl.setopt(CURLOPT_POSTFIELDS, cstring(request.body.get))
diff --git a/src/io/request.nim b/src/io/request.nim
index 531a2fc3..76fd9fc4 100644
--- a/src/io/request.nim
+++ b/src/io/request.nim
@@ -4,6 +4,7 @@ import strutils
 import tables
 
 import bindings/quickjs
+import types/formdata
 import types/url
 import js/javascript
 import utils/twtstr
@@ -66,7 +67,7 @@ type
     url*: Url
     headers* {.jsget.}: Headers
     body*: Option[string]
-    multipart*: Option[MimeData]
+    multipart*: Option[FormData]
     referer*: URL
     mode* {.jsget.}: RequestMode
     destination* {.jsget.}: RequestDestination
@@ -92,19 +93,6 @@ type
   Headers* = ref object
     table* {.jsget.}: Table[string, seq[string]]
 
-# Originally from the stdlib
-  MimePart* = object
-    name*, content*: string
-    case isFile*: bool
-    of true:
-      filename*, contentType*: string
-      fileSize*: int64
-      isStream*: bool
-    else: discard
-
-  MimeData* = object
-    content*: seq[MimePart]
-
 proc Request_url(ctx: JSContext, this: JSValue, magic: cint): JSValue {.cdecl.} =
   let op = getOpaque0(this)
   if unlikely(not ctx.isInstanceOf(this, "Request") or op == nil):
@@ -213,31 +201,30 @@ func newHeaders*(table: Table[string, string]): Headers =
       result.table[k] = @[v]
 
 func newRequest*(url: URL, httpmethod = HTTP_GET, headers = newHeaders(),
-                 body = none(string), # multipart = none(MimeData),
-                 mode = RequestMode.NO_CORS,
-                 credentialsMode = CredentialsMode.SAME_ORIGIN,
-                 destination = RequestDestination.NO_DESTINATION,
-                 proxy: URL = nil): Request =
+    body = none(string), multipart = none(FormData), mode = RequestMode.NO_CORS,
+    credentialsMode = CredentialsMode.SAME_ORIGIN,
+    destination = RequestDestination.NO_DESTINATION, proxy: URL = nil): Request =
   return Request(
     url: url,
     httpmethod: httpmethod,
     headers: headers,
     body: body,
-    #multipart: multipart,
+    multipart: multipart,
     mode: mode,
     credentialsMode: credentialsMode,
     destination: destination,
     proxy: proxy
   )
 
-func newRequest*(url: URL, httpmethod = HTTP_GET, headers: seq[(string, string)] = @[],
-                 body = none(string), # multipart = none(MimeData), TODO TODO TODO multipart
-                 mode = RequestMode.NO_CORS, proxy: URL = nil): Request =
+func newRequest*(url: URL, httpmethod = HTTP_GET,
+    headers: seq[(string, string)] = @[], body = none(string),
+    multipart = none(FormData), mode = RequestMode.NO_CORS, proxy: URL = nil):
+    Request =
   let hl = newHeaders()
   for pair in headers:
     let (k, v) = pair
     hl.table[k] = @[v]
-  return newRequest(url, httpmethod, hl, body, mode, proxy = proxy)
+  return newRequest(url, httpmethod, hl, body, multipart, mode, proxy = proxy)
 
 func createPotentialCORSRequest*(url: URL, destination: RequestDestination, cors: CORSAttribute, fallbackFlag = false): Request =
   var mode = if cors == NO_CORS:
@@ -257,16 +244,23 @@ func createPotentialCORSRequest*(url: URL, destination: RequestDestination, cors
 func newRequest*(resource: string, init: JSObject): Request {.jserr, jsctor.} =
   let x = parseURL(resource)
   if x.isNone:
-    JS_ERR JS_TypeError, resource & " is not a valid URL"
+    JS_ERR JS_TypeError, resource & " is not a valid URL."
   if x.get.username != "" or x.get.password != "":
-    JS_ERR JS_TypeError, resource & " is not a valid URL"
+    JS_ERR JS_TypeError, resource & " is not a valid URL."
   let url = x.get
   let ctx = init.ctx
   let fallbackMode = some(RequestMode.CORS) #TODO none if resource is request
   #TODO fallback mode, origin, window, request mode, ...
   let httpMethod = fromJS[HttpMethod](ctx,
     JS_GetPropertyStr(ctx, init.val, "method")).get(HTTP_GET)
-  let body = fromJS[string](ctx, JS_GetPropertyStr(ctx, init.val, "body"))
+  let bodyProp = JS_GetPropertyStr(ctx, init.val, "body")
+  let multipart = fromJS[FormData](ctx, bodyProp)
+  var body: Option[string]
+  if multipart.isNone:
+    body = fromJS[string](ctx, bodyProp)
+  #TODO inputbody
+  if (multipart.isSome or body.isSome) and httpMethod in {HTTP_GET, HTTP_HEAD}:
+    JS_ERR JS_TypeError, "HEAD or GET Request cannot have a body."
   let jheaders = JS_GetPropertyStr(ctx, init.val, "headers")
   let hl = newHeaders()
   hl.fill(ctx, jheaders)
@@ -276,10 +270,7 @@ func newRequest*(resource: string, init: JSObject): Request {.jserr, jsctor.} =
     .get(fallbackMode.get(RequestMode.NO_CORS))
   #TODO find a standard compatible way to implement this
   let proxyUrl = fromJS[URL](ctx, JS_GetPropertyStr(ctx, init.val, "proxyUrl"))
-  return newRequest(url, httpMethod, hl, body, mode, credentials, proxy = proxyUrl.get(nil))
-
-proc `[]=`*(multipart: var MimeData, k, v: string) =
-  multipart.content.add(MimePart(name: k, content: v))
+  return newRequest(url, httpMethod, hl, body, multipart, mode, credentials, proxy = proxyUrl.get(nil))
 
 proc add*(headers: var Headers, k, v: string) =
   let k = k.toHeaderCase()