about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config/config.nim3
-rw-r--r--src/loader/cgi.nim23
-rw-r--r--src/loader/ftp.nim204
-rw-r--r--src/loader/loader.nim5
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: