diff options
author | bptato <nincsnevem662@gmail.com> | 2023-09-09 12:18:45 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-09-09 12:18:45 +0200 |
commit | ecaf2a633425bd6f02f7857e68410594ae0547a0 (patch) | |
tree | 46aeb17b7e0f55f90f2e10b69e7b63a9a2b5a928 /src | |
parent | 07245ef4826298fffc3e34e34a74fdf77c7a4fac (diff) | |
download | chawan-ecaf2a633425bd6f02f7857e68410594ae0547a0.tar.gz |
fetch: use JSDict
Diffstat (limited to 'src')
-rw-r--r-- | src/display/client.nim | 4 | ||||
-rw-r--r-- | src/html/env.nim | 2 | ||||
-rw-r--r-- | src/io/headers.nim | 72 | ||||
-rw-r--r-- | src/io/request.nim | 107 |
4 files changed, 139 insertions, 46 deletions
diff --git a/src/display/client.nim b/src/display/client.nim index c8a4ab1f..c621580a 100644 --- a/src/display/client.nim +++ b/src/display/client.nim @@ -109,8 +109,8 @@ proc finalize(client: Client) {.jsfin.} = proc doRequest(client: Client, req: Request): Response {.jsfunc.} = return client.loader.doRequest(req) -proc fetch[T: Request|string](client: Client, req: T, init = none(JSValue)): - JSResult[FetchPromise] {.jsfunc.} = +proc fetch[T: Request|string](client: Client, req: T, + init = none(RequestInit)): JSResult[FetchPromise] {.jsfunc.} = let req = ?newRequest(client.jsctx, req, init) return ok(client.loader.fetch(req)) diff --git a/src/html/env.nim b/src/html/env.nim index 144a6a05..94bef626 100644 --- a/src/html/env.nim +++ b/src/html/env.nim @@ -66,7 +66,7 @@ proc addNavigatorModule(ctx: JSContext) = ctx.registerType(PluginArray) ctx.registerType(MimeTypeArray) -proc fetch[T: Request|string](window: Window, req: T, init = none(JSValue)): +proc fetch[T: Request|string](window: Window, req: T, init = none(RequestInit)): JSResult[FetchPromise] {.jsfunc.} = if window.loader.isSome: let req = ?newRequest(window.jsctx, req, init) diff --git a/src/io/headers.nim b/src/io/headers.nim index e0dacf33..b02f30df 100644 --- a/src/io/headers.nim +++ b/src/io/headers.nim @@ -1,48 +1,78 @@ import tables +import bindings/quickjs +import js/error import js/fromjs import js/javascript import utils/twtstr -type Headers* = ref object - table* {.jsget.}: Table[string, seq[string]] +type + Headers* = ref object + table* {.jsget.}: Table[string, seq[string]] + + HeadersInitType = enum + HEADERS_INIT_SEQUENCE, HEADERS_INIT_TABLE + + HeadersInit* = object + case t: HeadersInitType + of HEADERS_INIT_SEQUENCE: + s: seq[(string, string)] + of HEADERS_INIT_TABLE: + tab: Table[string, string] jsDestructor(Headers) -proc fill*(headers: Headers, ctx: JSContext, val: JSValue) = +proc fromJS2*(ctx: JSContext, val: JSValue, res: var JSResult[HeadersInit]) = + if JS_IsUndefined(val) or JS_IsNull(val): + res.err(nil) + return if isSequence(ctx, val): let x = fromJS[seq[(string, string)]](ctx, val) if x.isSome: - for (k, v) in x.get: - if k in headers.table: - headers.table[k].add(v) - else: - headers.table[k] = @[v] + res.ok(HeadersInit(t: HEADERS_INIT_SEQUENCE, s: x.get)) else: let x = fromJS[Table[string, string]](ctx, val) if x.isSome: - for k, v in x.get: - if k in headers.table: - headers.table[k].add(v) - else: - headers.table[k] = @[v] + res.ok(HeadersInit(t: HEADERS_INIT_TABLE, tab: x.get)) + +proc fill*(headers: Headers, s: seq[(string, string)]) = + for (k, v) in s: + if k in headers.table: + headers.table[k].add(v) + else: + headers.table[k] = @[v] + +proc fill*(headers: Headers, tab: Table[string, string]) = + for k, v in tab: + if k in headers.table: + headers.table[k].add(v) + else: + headers.table[k] = @[v] + +proc fill*(headers: Headers, init: HeadersInit) = + if init.t == HEADERS_INIT_SEQUENCE: + headers.fill(init.s) + else: # table + headers.fill(init.tab) func newHeaders*(): Headers = - new(result) + return Headers() -func newHeaders*(ctx: JSContext, obj = none(JSValue)): Headers {.jsctor.} = - new(result) +func newHeaders(obj = none(HeadersInit)): Headers {.jsctor.} = + let headers = Headers() if obj.isSome: - result.fill(ctx, obj.get) + headers.fill(obj.get) + return headers func newHeaders*(table: Table[string, string]): Headers = - new(result) + let headers = Headers() for k, v in table: let k = k.toHeaderCase() - if k in result.table: - result.table[k].add(v) + if k in headers.table: + headers.table[k].add(v) else: - result.table[k] = @[v] + headers.table[k] = @[v] + return headers func clone*(headers: Headers): Headers = return Headers( diff --git a/src/io/request.nim b/src/io/request.nim index 211246f1..8e1df806 100644 --- a/src/io/request.nim +++ b/src/io/request.nim @@ -5,17 +5,20 @@ import tables import bindings/quickjs import io/headers +import js/dict import js/error import js/fromjs import js/javascript +import types/blob import types/formdata +import types/referer import types/url type HttpMethod* = enum + HTTP_GET = "GET" HTTP_CONNECT = "CONNECT" HTTP_DELETE = "DELETE" - HTTP_GET = "GET" HTTP_HEAD = "HEAD" HTTP_OPTIONS = "OPTIONS" HTTP_PATCH = "PATCH" @@ -194,9 +197,66 @@ func createPotentialCORSRequest*(url: URL, destination: RequestDestination, cors else: CredentialsMode.INCLUDE return newRequest(url, destination = destination, mode = mode, credentialsMode = credentialsMode) +type + BodyInitType = enum + BODY_INIT_BLOB, BODY_INIT_FORM_DATA, BODY_INIT_URL_SEARCH_PARAMS, + BODY_INIT_STRING + + BodyInit = object + #TODO ReadableStream, BufferSource + case t: BodyInitType + of BODY_INIT_BLOB: + blob: Blob + of BODY_INIT_FORM_DATA: + formData: FormData + of BODY_INIT_URL_SEARCH_PARAMS: + searchParams: URLSearchParams + of BODY_INIT_STRING: + str: string + + RequestInit* = object of JSDict + #TODO aliasing in dicts + `method`: HttpMethod # default: GET + headers: Opt[HeadersInit] + body: Opt[BodyInit] + referrer: Opt[string] + referrerPolicy: Opt[ReferrerPolicy] + credentials: Opt[CredentialsMode] + proxyUrl: URL + mode: Opt[RequestMode] + +proc fromJS2*(ctx: JSContext, val: JSValue, res: var JSResult[BodyInit]) = + if JS_IsUndefined(val) or JS_IsNull(val): + res.err(nil) + return + if not JS_IsObject(val): + res.err(newTypeError("Not an object")) + return + block formData: + let x = fromJS[FormData](ctx, val) + if x.isSome: + res.ok(BodyInit(t: BODY_INIT_FORM_DATA, formData: x.get)) + return + block blob: + let x = fromJS[Blob](ctx, val) + if x.isSome: + res.ok(BodyInit(t: BODY_INIT_BLOB, blob: x.get)) + return + block searchParams: + let x = fromJS[URLSearchParams](ctx, val) + if x.isSome: + res.ok(BodyInit(t: BODY_INIT_URL_SEARCH_PARAMS, searchParams: x.get)) + return + block str: + let x = fromJS[string](ctx, val) + if x.isSome: + res.ok(BodyInit(t: BODY_INIT_STRING, str: x.get)) + return + res.err(newTypeError("Invalid body init type")) + #TODO init as an actual dictionary func newRequest*[T: string|Request](ctx: JSContext, resource: T, - init = none(JSValue)): JSResult[Request] {.jsctor.} = + init = none(RequestInit)): JSResult[Request] {.jsctor.} = when T is string: let url = ?newURL(resource) if url.username != "" or url.password != "": @@ -224,28 +284,31 @@ func newRequest*[T: string|Request](ctx: JSContext, resource: T, let destination = NO_DESTINATION #TODO origin, window if init.isSome: + if mode == RequestMode.NAVIGATE: + mode = RequestMode.SAME_ORIGIN + #TODO flags? + #TODO referrer let init = init.get - httpMethod = fromJS[HttpMethod](ctx, - JS_GetPropertyStr(ctx, init, "method")).get(HTTP_GET) - let bodyProp = JS_GetPropertyStr(ctx, init, "body") - if not JS_IsNull(bodyProp) and not JS_IsUndefined(bodyProp): - # ???? - multipart = opt(fromJS[FormData](ctx, bodyProp)) - if multipart.isNone: - body = opt(fromJS[string](ctx, bodyProp)) - #TODO inputbody - if (multipart.isSome or body.isSome) and - httpMethod in {HTTP_GET, HTTP_HEAD}: - return err(newTypeError("HEAD or GET Request cannot have a body.")) - let jheaders = JS_GetPropertyStr(ctx, init, "headers") - headers.fill(ctx, jheaders) - credentials = fromJS[CredentialsMode](ctx, JS_GetPropertyStr(ctx, init, - "credentials")).get(credentials) - mode = fromJS[RequestMode](ctx, JS_GetPropertyStr(ctx, init, "mode")) - .get(mode) + httpMethod = init.`method` + if init.body.isSome: + let ibody = init.body.get + case ibody.t + of BODY_INIT_FORM_DATA: + multipart = opt(ibody.formData) + of BODY_INIT_STRING: + body = opt(ibody.str) + else: + discard #TODO + if httpMethod in {HTTP_GET, HTTP_HEAD}: + return err(newTypeError("HEAD or GET Request cannot have a body.")) + if init.headers.isSome: + headers.fill(init.headers.get) + if init.credentials.isSome: + credentials = init.credentials.get + if init.mode.isSome: + mode = init.mode.get #TODO find a standard compatible way to implement this - let proxyUrlProp = JS_GetPropertyStr(ctx, init, "proxyUrl") - proxyUrl = fromJS[URL](ctx, proxyUrlProp).get(nil) + proxyUrl = init.proxyUrl return ok(Request( url: url, httpmethod: httpmethod, |