about summary refs log tree commit diff stats
path: root/adapter/protocol/file.nim
blob: bd2c34a2d467c8b9b5ff3babd21fe41cee8bfca1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import std/algorithm
import std/os
import std/times

import dirlist

import loader/connecterror
import utils/twtstr

proc loadDir(path, opath: string) =
  var path = path
  if path[^1] != '/': #TODO dos/windows
    path &= '/'
  var base = "file://" & opath
  if base[^1] != '/': #TODO dos/windows
    base &= '/'
  stdout.write("Content-Type: text/html\n\n")
  stdout.write("""
<HTML>
<HEAD>
<BASE HREF="""" & base & """">
<TITLE>Directory list of """ & path & """</TITLE>
</HEAD>
<BODY>
<H1>Directory list of """ & path & """</H1>
<PRE>
""")
  var fs: seq[(PathComponent, string)]
  for pc, file in walkDir(path, relative = true):
    fs.add((pc, file))
  fs.sort(cmp = proc(a, b: (PathComponent, string)): int = cmp(a[1], b[1]))
  var items: seq[DirlistItem]
  for (pc, file) in fs:
    let fullpath = path / file
    var info: FileInfo
    try:
      info = getFileInfo(fullpath, followSymlink = false)
    except OSError:
      continue
    let modified = $info.lastWriteTime.local().format("MMM/dd/yyyy HH:MM")
    case pc
    of pcDir:
      items.add(DirlistItem(
        t: ditDir,
        name: file,
        modified: modified
      ))
    of pcFile:
      items.add(DirlistItem(
        t: ditFile,
        name: file,
        modified: modified,
        nsize: int(info.size)
      ))
    of pcLinkToDir, pcLinkToFile:
      var target = expandSymlink(fullpath)
      if pc == pcLinkToDir:
        target &= '/'
      items.add(DirlistItem(
        t: ditLink,
        name: file,
        modified: modified,
        linkto: target
      ))
  stdout.write(makeDirlist(items))
  stdout.write("\n</PRE>\n</BODY>\n</HTML>\n")

proc loadFile(f: File) =
  # No headers, we'll let the browser figure out the file type.
  stdout.write("\n")
  const BufferSize = 16384
  var buffer {.noinit.}: array[BufferSize, char]
  while true:
    let n = f.readBuffer(addr buffer[0], BufferSize)
    if n == 0:
      break
    let n2 = stdout.writeBuffer(addr buffer[0], n)
    if n2 < n or n < BufferSize:
      break

proc main() =
  if getEnv("MAPPED_URI_HOST") != "":
    let code = int(ERROR_INVALID_URL)
    stdout.write("Cha-Control: ConnectionError " & $code &
      " cannot use host in file")
    return
  let opath = getEnv("MAPPED_URI_PATH")
  let path = percentDecode(opath)
  var f: File
  if f.open(path, fmRead):
    loadFile(f)
  elif dirExists(path):
    loadDir(path, opath)
  else:
    let code = int(ERROR_FILE_NOT_FOUND)
    stdout.write("Cha-Control: ConnectionError " & $code)

main()