diff options
author | bptato <nincsnevem662@gmail.com> | 2023-12-12 22:06:46 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-12-12 22:07:07 +0100 |
commit | bf761bcb6dcc5288a86aa5e8c2b67df3f0df056b (patch) | |
tree | a2f4c0d47ed484bcca4daaaa11b4d862243019fe /adapter | |
parent | 1df10adfe7eb20bc460eeb0e5a8e242970642c58 (diff) | |
download | chawan-bf761bcb6dcc5288a86aa5e8c2b67df3f0df056b.tar.gz |
Move gopher to adapter/
Also, move default urimethodmap config to res.
Diffstat (limited to 'adapter')
-rw-r--r-- | adapter/format/gopher2html.nim | 16 | ||||
-rw-r--r-- | adapter/gophertypes.nim | 15 | ||||
-rw-r--r-- | adapter/protocol/gopher.nim | 113 |
3 files changed, 129 insertions, 15 deletions
diff --git a/adapter/format/gopher2html.nim b/adapter/format/gopher2html.nim index cfdeab1e..33cd564a 100644 --- a/adapter/format/gopher2html.nim +++ b/adapter/format/gopher2html.nim @@ -7,21 +7,7 @@ import std/strutils import utils/twtstr -type GopherType = enum - UNKNOWN = "unsupported" - TEXT_FILE = "text file" - ERROR = "error" - DIRECTORY = "directory" - DOS_BINARY = "DOS binary" - SEARCH = "search" - MESSAGE = "message" - SOUND = "sound" - GIF = "gif" - HTML = "HTML" - INFO = "" - IMAGE = "image" - BINARY = "binary" - PNG = "png" +include ../gophertypes func gopherType(c: char): GopherType = return case c diff --git a/adapter/gophertypes.nim b/adapter/gophertypes.nim new file mode 100644 index 00000000..dbc8d64d --- /dev/null +++ b/adapter/gophertypes.nim @@ -0,0 +1,15 @@ +type GopherType = enum + UNKNOWN = "unsupported" + TEXT_FILE = "text file" + ERROR = "error" + DIRECTORY = "directory" + DOS_BINARY = "DOS binary" + SEARCH = "search" + MESSAGE = "message" + SOUND = "sound" + GIF = "gif" + HTML = "HTML" + INFO = "" + IMAGE = "image" + BINARY = "binary" + PNG = "png" diff --git a/adapter/protocol/gopher.nim b/adapter/protocol/gopher.nim new file mode 100644 index 00000000..cf3038f7 --- /dev/null +++ b/adapter/protocol/gopher.nim @@ -0,0 +1,113 @@ +import std/envvars +import std/options + +import bindings/curl +import loader/connecterror +import loader/curlwrap +import loader/request +import types/opt +import types/url +import utils/twtstr + +include ../gophertypes + +type GopherHandle = ref object + curl: CURL + t: GopherType + statusline: bool + +func gopherType(c: char): GopherType = + return case c + of '0': TEXT_FILE + of '1': DIRECTORY + of '3': ERROR + of '5': DOS_BINARY + of '7': SEARCH + of 'm': MESSAGE + of 's': SOUND + of 'g': GIF + of 'h': HTML + of 'i': INFO + of 'I': IMAGE + of '9': BINARY + of 'p': PNG + else: UNKNOWN + +proc onStatusLine(op: GopherHandle) = + var status: clong + op.curl.getinfo(CURLINFO_RESPONSE_CODE, addr status) + stdout.write("Status: " & $status & "\n") + let s = case op.t + of DIRECTORY, SEARCH: "Content-Type: text/gopher\n" + of HTML: "Content-Type: text/html\n" + of GIF: "Content-Type: image/gif\n" + of PNG: "Content-Type: image/png\n" + of TEXT_FILE, ERROR: "Content-Type: text/plain\n" + else: "" + stdout.write(s & "\n") + +proc loadSearch(op: GopherHandle, surl: string) = + stdout.write(""" +Content-Type: text/html + +<!DOCTYPE HTML> +<HTML> +<HEAD> +<BASE HREF="""" & surl & """"> +</HEAD> +<BODY> +<H1>Search """ & htmlEscape(surl) & """</H1> +<FORM> +<INPUT TYPE=SEARCH NAME="NAME"> +</FORM> +</BODY> +</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 main() = + let curl = curl_easy_init() + doAssert curl != nil + if getEnv("REQUEST_METHOD") != "GET": + stdout.write("Cha-Control: ConnectionError " & $int(ERROR_INVALID_METHOD)) + return + var url = newURL(getEnv("QUERY_STRING")).get + var path = url.pathname + if path.len < 1: + path &= '/' + if path.len < 2: + path &= '1' + url = newURL(url) + url.setPathname(path) + let op = GopherHandle( + curl: curl, + t: gopherType(path[1]) + ) + if op.t == SEARCH: + if url.query.isNone: + op.loadSearch(url.serialize()) + return + else: + url.query = some(url.query.get.after('=')) + let surl = url.serialize() + #TODO avoid re-parsing + curl.setopt(CURLOPT_URL, surl) + 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("Cha-Control: ConnectionError " & $int(res) & "\n") + curl_easy_cleanup(curl) + +main() |