diff options
author | bptato <nincsnevem662@gmail.com> | 2024-09-28 17:56:45 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-09-28 17:56:45 +0200 |
commit | 1dea3e9fbe4a902db6325195df0d7a465f82cfc5 (patch) | |
tree | d400bcaa2fdf4c71a81919a45c0a58a345bbc8fc /adapter/protocol/gopher.nim | |
parent | 6a0e957e1f2c9f5bea0882efbf2e0494cd5074fa (diff) | |
download | chawan-1dea3e9fbe4a902db6325195df0d7a465f82cfc5.tar.gz |
gopher: do not depend on libcurl
I'm thinking of making libcurl entirely optional; let's start with the easiest part. I've added a SOCKS5 client for ALL_PROXY support; I know curl supported others too, but whatever.
Diffstat (limited to 'adapter/protocol/gopher.nim')
-rw-r--r-- | adapter/protocol/gopher.nim | 127 |
1 files changed, 53 insertions, 74 deletions
diff --git a/adapter/protocol/gopher.nim b/adapter/protocol/gopher.nim index 13ade18c..b97ced2b 100644 --- a/adapter/protocol/gopher.nim +++ b/adapter/protocol/gopher.nim @@ -1,33 +1,13 @@ -when NimMajor >= 2: - import std/envvars -else: - import std/os - -import curl -import curlerrors -import curlwrap +import std/options +import std/os +import std/posix +import std/strutils import ../gophertypes +import lcgi -import utils/twtstr - -type GopherHandle = ref object - curl: CURL - t: GopherType - statusline: bool - -proc onStatusLine(op: GopherHandle) = - let s = case op.t - of gtDirectory, gtSearch: "Content-Type: text/gopher\n" - of gtHTML: "Content-Type: text/html\n" - of gtGif: "Content-Type: image/gif\n" - of gtPng: "Content-Type: image/png\n" - of gtTextFile, gtError: "Content-Type: text/plain\n" - else: "" - stdout.write(s & "\n") - -proc loadSearch(op: GopherHandle; surl: string) = - stdout.write(""" +proc loadSearch(os: PosixStream; t: GopherType; surl: string) = + os.sendDataLoop(""" Content-Type: text/html <!DOCTYPE HTML> @@ -44,58 +24,57 @@ Content-Type: text/html </HTML> """) -# From the documentation: size is always 1. -proc curlWriteBody(p: cstring; size, nmemb: csize_t; userdata: pointer): - csize_t {.cdecl.} = - let op = cast[GopherHandle](userdata) - if not op.statusline: - op.statusline = true - op.onStatusLine() - return csize_t(stdout.writeBuffer(p, int(nmemb))) +proc loadRegular(os: PosixStream; t: GopherType; path: var string; + host, port, query: string) = + let ps = os.connectSocket(host, port) + if query != "": + path &= '\t' + path &= query + path &= '\n' + ps.sendDataLoop(percentDecode(path)) + let s = case t + of gtDirectory, gtSearch: "Content-Type: text/gopher\n" + of gtHTML: "Content-Type: text/html\n" + of gtGif: "Content-Type: image/gif\n" + of gtPng: "Content-Type: image/png\n" + of gtTextFile, gtError: "Content-Type: text/plain\n" + else: "" + os.sendDataLoop(s & '\n') + var buffer: array[4096, uint8] + while true: + let n = ps.recvData(buffer) + if n == 0: + break + os.sendDataLoop(addr buffer[0], n) + ps.sclose() proc main() = - let curl = curl_easy_init() - doAssert curl != nil + let os = newPosixStream(STDOUT_FILENO) if getEnv("REQUEST_METHOD") != "GET": - stdout.write("Cha-Control: ConnectionError InvalidMethod") - return + os.die("InvalidMethod") + let scheme = getEnv("MAPPED_URI_SCHEME") + var host = getEnv("MAPPED_URI_HOST") + if host == "": + os.die("InvalidURL missing hostname") + if host[0] == '[' and host[^1] == ']': + host.delete(0..0) + host.setLen(host.high) + let port = $parseInt32(getEnv("MAPPED_URI_PORT")).get(70) + let query = getEnv("MAPPED_URI_QUERY").after('=') var path = getEnv("MAPPED_URI_PATH") - if path.len < 1: - path &= '/' - if path.len < 2: - path &= '1' - let url = curl_url() - const flags = cuint(CURLU_PATH_AS_IS) - url.set(CURLUPART_SCHEME, getEnv("MAPPED_URI_SCHEME"), flags) - url.set(CURLUPART_HOST, getEnv("MAPPED_URI_HOST"), flags) - let port = getEnv("MAPPED_URI_PORT") - if port != "": - url.set(CURLUPART_PORT, port, flags) - url.set(CURLUPART_PATH, path, flags) - let query = getEnv("MAPPED_URI_QUERY") - if query != "": - url.set(CURLUPART_QUERY, query.after('='), flags) - let op = GopherHandle( - curl: curl, - t: gopherType(path[1]) - ) - if op.t == gtSearch and query == "": - const flags = cuint(CURLU_PUNY2IDN) - let surl = url.get(CURLUPART_URL, flags) - if surl == nil: - stdout.write("Cha-Control: ConnectionError InvalidURL") + var i = 0 + while i < path.len and path[i] == '/': + inc i + var t = gtDirectory + if i < path.len: + t = gopherType(path[i]) + if t != gtUnknown: + path.delete(0 .. i) else: - op.loadSearch($surl) + t = gtDirectory + if t == gtSearch and query == "": + os.loadSearch(t, scheme & "://" & host & ":" & port & '/') else: - curl.setopt(CURLOPT_CURLU, url) - curl.setopt(CURLOPT_WRITEDATA, op) - curl.setopt(CURLOPT_WRITEFUNCTION, curlWriteBody) - let proxy = getEnv("ALL_PROXY") - if proxy != "": - curl.setopt(CURLOPT_PROXY, proxy) - let res = curl_easy_perform(curl) - if res != CURLE_OK and not op.statusline: - stdout.write(getCurlConnectionError(res)) - curl_easy_cleanup(curl) + os.loadRegular(t, path, host, port, query) main() |