diff options
author | bptato <nincsnevem662@gmail.com> | 2022-08-18 17:09:52 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-08-18 17:09:52 +0200 |
commit | a78c26198e747d4de887e1f582d29f14fb59391b (patch) | |
tree | dbea97fe93618e146dd0e3901d54328e86d54fd1 /src/io/loader.nim | |
parent | e2203257e07aada157be9d0a948273cb9d683072 (diff) | |
download | chawan-a78c26198e747d4de887e1f582d29f14fb59391b.tar.gz |
Use a separate process for file loading
Not very useful for now, since we still have to load the entire page before parsing it.
Diffstat (limited to 'src/io/loader.nim')
-rw-r--r-- | src/io/loader.nim | 125 |
1 files changed, 107 insertions, 18 deletions
diff --git a/src/io/loader.nim b/src/io/loader.nim index f7ac06e6..74a692fe 100644 --- a/src/io/loader.nim +++ b/src/io/loader.nim @@ -4,12 +4,14 @@ import tables when defined(posix): import posix +import bindings/curl import io/http -import io/loadertypes +import io/request +import io/serialize import types/mime import types/url -export loadertypes +export request const DefaultHeaders = { "User-Agent": "chawan", @@ -32,26 +34,113 @@ proc doFork(): Pid = quit(0) return 0 +proc loadFile(url: Url, ostream: Stream) = + when defined(windows) or defined(OS2) or defined(DOS): + let path = url.path.serialize_unicode_dos() + else: + let path = url.path.serialize_unicode() + let istream = newFileStream(path, fmRead) + ostream.swrite(if istream != nil: + 200 # ok + else: + 404 # file not found + ) + ostream.swrite(guessContentType(path)) + ostream.swrite(none(Url)) + while not istream.atEnd: + const bufferSize = 4096 + var buffer {.noinit.}: array[bufferSize, char] + while true: + let n = readData(istream, addr buffer[0], bufferSize) + if n == 0: + break + ostream.swrite(n) + ostream.writeData(addr buffer[0], n) + ostream.flush() + if n < bufferSize: + break + ostream.swrite("") + ostream.flush() + +proc loadResource(loader: FileLoader, request: Request, ostream: Stream) = + case request.url.scheme + of "file": + loadFile(request.url, ostream) + of "http", "https": + loadHttp(request, ostream) + +proc runFileLoader(loader: FileLoader) = + if curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK: + eprint "Failed to initialize libcurl." + quit(1) + let istream = newFileStream(stdin) + let ostream = newFileStream(stdout) + while true: + try: + let request = istream.readRequest() + loader.loadResource(request, ostream) + except IOError: + # End-of-file, quit. + # TODO this should be EOFError + break + istream.close() + ostream.close() + curl_global_cleanup() + quit(0) + +proc doRequest*(loader: FileLoader, request: Request): LoadResult = + if loader.istream != nil: + loader.istream.swrite(request) + loader.istream.flush() + loader.ostream.sread(result.status) + loader.ostream.sread(result.contenttype) + loader.ostream.sread(result.redirect) + result.s = loader.ostream + else: + eprint "Error: no loader process" + quit(1) + proc newFileLoader*(defaultHeaders: HeaderList): FileLoader = new(result) result.defaultHeaders = defaultHeaders + when defined(posix): + var pipefd_a: array[0..1, cint] + var pipefd_b: array[0..1, cint] + if pipe(pipefd_a) == -1: + eprint "Failed to open pipe." + quit(1) + if pipe(pipefd_b) == -1: + eprint "Failed to open pipe." + quit(1) + let pid = doFork() + if pid == 0: + # child process + let readfd = pipefd_a[0] # get read a + discard close(pipefd_a[1]) # close write a + let writefd = pipefd_b[1] # get write b + discard close(pipefd_b[0]) # close read b + discard dup2(readfd, stdin.getFileHandle()) + discard dup2(writefd, stdout.getFileHandle()) + result.runFileLoader() + else: + result.process = pid + let writefd = pipefd_a[1] # get write a + discard close(pipefd_a[0]) # close read a + let readfd = pipefd_b[0] # get read b + discard close(pipefd_b[1]) # close write b + var readf: File + var writef: File + if not open(readf, FileHandle(readfd), fmRead): + eprint "Failed to open output handle." + quit(1) + if not open(writef, FileHandle(writefd), fmWrite): + eprint "Failed to open input handle." + quit(1) + result.ostream = newFileStream(readf) + result.istream = newFileStream(writef) proc newFileLoader*(): FileLoader = newFileLoader(DefaultHeaders) -proc getPage*(loader: FileLoader, url: Url, smethod: HttpMethod = HTTP_GET, mimetype = "", body = none(string), multipart = none(MimeData)): LoadResult = - case url.scheme - of "file": - when defined(windows) or defined(OS2) or defined(DOS): - let path = url.path.serialize_unicode_dos() - else: - let path = url.path.serialize_unicode() - result.contenttype = guessContentType(path) - result.s = newFileStream(path, fmRead) - if result.s != nil: - result.status = 200 # ok - else: - result.status = 404 # file not found - of "http", "https": - let request = loader.newRequest(url, smethod, {"Content-Type": mimetype}, body, multipart) - return getPageHttp(request) +proc getPage*(loader: FileLoader, request: Request): LoadResult = + loader.doRequest(request) |