diff options
author | bptato <nincsnevem662@gmail.com> | 2023-09-01 21:49:19 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-09-01 21:49:19 +0200 |
commit | b57be7b89d656d1eda13f464b41373c2535e106f (patch) | |
tree | b01685e5eb364b105f70119d3a1f152846d6c0e1 /src/io | |
parent | 5be61f0ab87d4ca7877815b09a38f1fcffa4d7fa (diff) | |
download | chawan-b57be7b89d656d1eda13f464b41373c2535e106f.tar.gz |
loader: add data URLs
Diffstat (limited to 'src/io')
-rw-r--r-- | src/io/connecterror.nim | 1 | ||||
-rw-r--r-- | src/io/data.nim | 45 | ||||
-rw-r--r-- | src/io/loader.nim | 6 | ||||
-rw-r--r-- | src/io/urlfilter.nim | 19 |
4 files changed, 66 insertions, 5 deletions
diff --git a/src/io/connecterror.nim b/src/io/connecterror.nim index 563a4291..d2af5762 100644 --- a/src/io/connecterror.nim +++ b/src/io/connecterror.nim @@ -1,6 +1,7 @@ import bindings/curl type ConnectErrorCode* = enum + ERROR_INVALID_DATA_URL = (-7, "invalid data URL") ERROR_ABOUT_PAGE_NOT_FOUND = (-6, "about page not found") ERROR_FILE_NOT_FOUND = (-5, "file not found") ERROR_SOURCE_NOT_FOUND = (-4, "clone source could not be found"), diff --git a/src/io/data.nim b/src/io/data.nim new file mode 100644 index 00000000..012cba05 --- /dev/null +++ b/src/io/data.nim @@ -0,0 +1,45 @@ +import base64 +import strutils +import tables + +import io/connecterror +import io/headers +import io/loaderhandle +import io/request +import types/url + +proc loadData*(handle: LoaderHandle, request: Request) = + template t(body: untyped) = + if not body: + return + let str = $request.url + let si = "data:".len # start index + var ct = "" + eprint "load data", str + for i in si ..< str.len: + if str[i] == ',': + break + ct &= str[i] + let sd = si + ct.len + 1 # data start + if ct.endsWith(";base64"): + try: + let d = base64.decode(str[sd .. ^1]) # decode from ct end + 1 + t handle.sendResult(0) + t handle.sendStatus(200) + ct.setLen(ct.len - ";base64".len) # remove base64 indicator + t handle.sendHeaders(newHeaders({ + "Content-Type": ct + }.toTable())) + if d.len > 0: + t handle.sendData(d) + except ValueError: + discard handle.sendResult(ERROR_INVALID_DATA_URL) + else: + t handle.sendResult(0) + t handle.sendStatus(200) + t handle.sendHeaders(newHeaders({ + "Content-Type": ct + }.toTable())) + if ct.len + 1 < str.len: + eprint "send data", str[sd .. ^1], sd, str.len - sd + t handle.sendData(addr str[sd], str.len - sd) diff --git a/src/io/loader.nim b/src/io/loader.nim index c497b1dd..45e19357 100644 --- a/src/io/loader.nim +++ b/src/io/loader.nim @@ -22,6 +22,7 @@ import tables import bindings/curl import io/about import io/connecterror +import io/data import io/file import io/headers import io/http @@ -109,6 +110,9 @@ proc loadResource(ctx: LoaderContext, request: Request, handle: LoaderHandle) = of "about": handle.loadAbout(request) handle.close() + of "data": + handle.loadData(request) + handle.close() else: discard handle.sendResult(ERROR_UNKNOWN_SCHEME) handle.close() @@ -116,7 +120,9 @@ proc loadResource(ctx: LoaderContext, request: Request, handle: LoaderHandle) = proc onLoad(ctx: LoaderContext, stream: Stream) = var request: Request stream.sread(request) + eprint "FETCH ONLOAD", $request.url if not ctx.config.filter.match(request.url): + eprint "disallowed" stream.swrite(ERROR_DISALLOWED_URL) stream.close() else: diff --git a/src/io/urlfilter.nim b/src/io/urlfilter.nim index 9541a699..c0832b17 100644 --- a/src/io/urlfilter.nim +++ b/src/io/urlfilter.nim @@ -6,26 +6,35 @@ import types/url #TODO add denyhost/s for blocklists type URLFilter* = object scheme: Option[string] + allowschemes: seq[string] allowhost*: Option[string] allowhosts: seq[Regex] default: bool -proc newURLFilter*(scheme = none(string), allowhost = none(string), - allowhosts: seq[Regex] = @[], default = false): URLFilter = +proc newURLFilter*(scheme = none(string), allowschemes: seq[string] = @[], + allowhost = none(string), allowhosts: seq[Regex] = @[], + default = false): URLFilter = + doAssert scheme.isSome or allowschemes.len == 0, + "allowschemes without scheme is not supported" return URLFilter( scheme: scheme, + allowschemes: allowschemes, allowhost: allowhost, allowhosts: allowhosts, default: default ) # Filters as follows: -# If scheme is given, only URLs with the same scheme are matched. +# If scheme/s are given, only URLs with the same scheme are matched. # Then, allowhost and allowhosts are checked; if none of these match the host, # the function returns the value of `default'. proc match*(filter: URLFilter, url: URL): bool = - if filter.scheme.isSome and filter.scheme.get != url.scheme: - return false + block check_scheme: + if filter.scheme.isSome and filter.scheme.get != url.scheme: + for scheme in filter.allowschemes: + if scheme == url.scheme: + break check_scheme + return false let host = url.host if filter.allowhost.isSome and filter.allowhost.get == host: return true |