diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config/config.nim | 3 | ||||
-rw-r--r-- | src/loader/cgi.nim | 23 | ||||
-rw-r--r-- | src/loader/ftp.nim | 204 | ||||
-rw-r--r-- | src/loader/loader.nim | 5 |
4 files changed, 18 insertions, 217 deletions
diff --git a/src/config/config.nim b/src/config/config.nim index 269c37d5..79561c3a 100644 --- a/src/config/config.nim +++ b/src/config/config.nim @@ -413,6 +413,9 @@ gemini: cgi-bin:gmifetch?%s about: cgi-bin:about data: cgi-bin:data file: cgi-bin:file?%s +ftp: cgi-bin:ftp?%s +sftp: cgi-bin:sftp?%s +ftps: cgi-bin:ftps?%s """) proc getURIMethodMap*(config: Config): URIMethodMap = diff --git a/src/loader/cgi.nim b/src/loader/cgi.nim index dbdce99c..89361a7c 100644 --- a/src/loader/cgi.nim +++ b/src/loader/cgi.nim @@ -70,6 +70,7 @@ proc handleFirstLine(handle: LoaderHandle, line: string, headers: Headers, return RESULT_ERROR let v = line.substr(k.len + 1).strip() if k.equalsIgnoreCase("Status"): + discard handle.sendResult(0) # success status = parseInt32(v).get(0) return RESULT_CONTROL_CONTINUE if k.equalsIgnoreCase("Cha-Control"): @@ -77,18 +78,19 @@ proc handleFirstLine(handle: LoaderHandle, line: string, headers: Headers, discard handle.sendResult(0) # success return RESULT_CONTROL_CONTINUE elif v.startsWithIgnoreCase("ConnectionError"): - let errs = v.substr("ConnectionError".len + 1).split(' ') - if errs.len == 0: + let errs = v.split(' ') + if errs.len <= 1: discard handle.sendResult(ERROR_CGI_INVALID_CHA_CONTROL) else: let fb = int32(ERROR_CGI_INVALID_CHA_CONTROL) - let code = int(parseInt32(errs[0]).get(fb)) + let code = int(parseInt32(errs[1]).get(fb)) discard handle.sendResult(code) return RESULT_ERROR elif v.startsWithIgnoreCase("ControlDone"): return RESULT_CONTROL_DONE discard handle.sendResult(ERROR_CGI_INVALID_CHA_CONTROL) return RESULT_ERROR + discard handle.sendResult(0) # success headers.add(k, v) return RESULT_CONTROL_DONE @@ -230,16 +232,21 @@ proc loadCGI*(handle: LoaderHandle, request: Request, cgiDir: seq[string], var res = handle.handleFirstLine(line, headers, status) if res == RESULT_ERROR: return + var crlfFound = false while not ps.atEnd and res == RESULT_CONTROL_CONTINUE: let line = ps.readLine() + if line == "": + crlfFound = true + break res = handle.handleControlLine(line, headers, status) if res == RESULT_ERROR: return - while not ps.atEnd: - let line = ps.readLine() - if line == "": #\r\n - break - handle.handleLine(line, headers) + if not crlfFound: + while not ps.atEnd: + let line = ps.readLine() + if line == "": #\r\n + break + handle.handleLine(line, headers) t handle.sendStatus(status) t handle.sendHeaders(headers) var buffer: array[4096, uint8] diff --git a/src/loader/ftp.nim b/src/loader/ftp.nim deleted file mode 100644 index bf69afff..00000000 --- a/src/loader/ftp.nim +++ /dev/null @@ -1,204 +0,0 @@ -import strutils - -import bindings/curl -import loader/connecterror -import loader/curlhandle -import loader/curlwrap -import loader/dirlist -import loader/headers -import loader/loaderhandle -import loader/request -import types/opt -import types/url -import utils/twtstr - -type FtpHandle = ref object of CurlHandle - buffer: string - dirmode: bool - base: string - path: string - -func newFtpHandle(curl: CURL, request: Request, handle: LoaderHandle, - dirmode: bool): FtpHandle = - return FtpHandle( - headers: newHeaders(), - curl: curl, - handle: handle, - request: request, - dirmode: dirmode - ) - -proc curlWriteHeader(p: cstring, size: csize_t, nitems: csize_t, - userdata: pointer): csize_t {.cdecl.} = - var line = newString(nitems) - if nitems > 0: - prepareMutation(line) - copyMem(addr line[0], p, nitems) - - let op = cast[FtpHandle](userdata) - - if not op.statusline: - if line.startsWith("150") or line.startsWith("125"): - op.statusline = true - if not op.handle.sendResult(int(CURLE_OK)): - return 0 - var status: clong - op.curl.getinfo(CURLINFO_RESPONSE_CODE, addr status) - if not op.handle.sendStatus(cast[int](status)): - return 0 - if op.dirmode: - op.headers.add("Content-Type", "text/html") - if not op.handle.sendHeaders(op.headers): - return 0 - if op.dirmode: - if not op.handle.sendData(""" -<HTML> -<HEAD> -<BASE HREF=""" & op.base & """> -<TITLE>""" & op.path & """</TITLE> -</HEAD> -<BODY> -<H1>Index of """ & htmlEscape(op.path) & """</H1> -<PRE> -"""): - return 0 - return nitems - elif line.startsWith("530"): # login incorrect - op.statusline = true - if not op.handle.sendResult(int(CURLE_OK)): - return 0 - var status: clong - op.curl.getinfo(CURLINFO_RESPONSE_CODE, addr status) - discard op.handle.sendStatus(401) # unauthorized (shim http) - op.headers.add("Content-Type", "text/html") - discard op.handle.sendHeaders(op.headers) - discard op.handle.sendData(""" -<HTML> -<HEAD> -<TITLE>Unauthorized</TITLE> -</HEAD> -<BODY> -<PRE> -""" & htmlEscape(line)) - return 0 - return nitems - -# From the documentation: size is always 1. -proc curlWriteBody(p: cstring, size: csize_t, nmemb: csize_t, - userdata: pointer): csize_t {.cdecl.} = - let op = cast[FtpHandle](userdata) - - if nmemb > 0: - if op.dirmode: - let i = op.buffer.len - op.buffer.setLen(op.buffer.len + int(nmemb)) - prepareMutation(op.buffer) - copyMem(addr op.buffer[i], p, nmemb) - else: - if not op.handle.sendData(p, int(nmemb)): - return 0 - return nmemb - -proc finish(op: CurlHandle) = - let op = cast[FtpHandle](op) - var items: seq[DirlistItem] - for line in op.buffer.split('\n'): - if line.len == 0: continue - var i = 10 # permission - template skip_till_space = - while i < line.len and line[i] != ' ': - inc i - # link count - i = line.skipBlanks(i) - while i < line.len and line[i] in AsciiDigit: - inc i - # owner - i = line.skipBlanks(i) - skip_till_space - # group - i = line.skipBlanks(i) - while i < line.len and line[i] != ' ': - inc i - # size - i = line.skipBlanks(i) - var sizes = "" - while i < line.len and line[i] in AsciiDigit: - sizes &= line[i] - inc i - let nsize = parseInt64(sizes).get(-1) - # date - i = line.skipBlanks(i) - let datestarti = i - skip_till_space # m - i = line.skipBlanks(i) - skip_till_space # d - i = line.skipBlanks(i) - skip_till_space # y - let dates = line.substr(datestarti, i) - inc i - let name = line.substr(i) - if name == "." or name == "..": continue - case line[0] - of 'l': # link - let x = " -> " - let linki = name.find(x) - let linkfrom = name.substr(0, linki - 1) - let linkto = name.substr(linki + 4) # you? - items.add(DirlistItem( - t: ITEM_LINK, - name: linkfrom, - modified: dates, - linkto: linkto - )) - of 'd': # directory - items.add(DirlistItem( - t: ITEM_DIR, - name: name, - modified: dates - )) - else: # file - items.add(DirlistItem( - t: ITEM_FILE, - name: name, - modified: dates, - nsize: int(nsize) - )) - discard op.handle.sendData(makeDirlist(items)) - discard op.handle.sendData("\n</PRE>\n</BODY>\n</HTML>\n") - -proc loadFtp*(handle: LoaderHandle, curlm: CURLM, - request: Request): CurlHandle = - let curl = curl_easy_init() - doAssert curl != nil - let surl = request.url.serialize() - let path = request.url.path.serialize_unicode() - # By default, cURL CWD's into relative paths, and an extra slash is - # necessary to specify absolute paths. - # This is incredibly confusing, and probably not what the user wanted. - # So we work around it by adding the extra slash ourselves. - let hackurl = newURL(request.url) - hackurl.setPathname('/' & request.url.pathname) - let csurl = hackurl.serialize() - curl.setopt(CURLOPT_URL, csurl) - let dirmode = path.len > 0 and path[^1] == '/' - let handleData = curl.newFtpHandle(request, handle, dirmode) - curl.setopt(CURLOPT_HEADERDATA, handleData) - curl.setopt(CURLOPT_HEADERFUNCTION, curlWriteHeader) - curl.setopt(CURLOPT_WRITEDATA, handleData) - curl.setopt(CURLOPT_WRITEFUNCTION, curlWriteBody) - curl.setopt(CURLOPT_FTP_FILEMETHOD, CURLFTPMETHOD_SINGLECWD) - if dirmode: - handleData.finish = finish - handleData.base = surl - handleData.path = path - if request.proxy != nil: - let purl = request.proxy.serialize() - curl.setopt(CURLOPT_PROXY, purl) - if request.httpmethod != HTTP_GET: - discard handle.sendResult(int(ERROR_INVALID_METHOD)) - return nil - let res = curl_multi_add_handle(curlm, curl) - if res != CURLM_OK: - discard handle.sendResult(int(res)) - return nil - return handleData diff --git a/src/loader/loader.nim b/src/loader/loader.nim index 28029160..13684301 100644 --- a/src/loader/loader.nim +++ b/src/loader/loader.nim @@ -31,7 +31,6 @@ import js/javascript import loader/cgi import loader/connecterror import loader/curlhandle -import loader/ftp import loader/gopher import loader/headers import loader/http @@ -141,10 +140,6 @@ proc loadResource(ctx: LoaderContext, request: Request, handle: LoaderHandle) = let handleData = handle.loadHttp(ctx.curlm, request) if handleData != nil: ctx.handleList.add(handleData) - of "ftp", "ftps", "sftp": - let handleData = handle.loadFtp(ctx.curlm, request) - if handleData != nil: - ctx.handleList.add(handleData) of "gopher", "gophers": let handleData = handle.loadGopher(ctx.curlm, request) if handleData != nil: |