* Auto generate directory indexes.
authorUrban Wallasch <urban.wallasch@freenet.de>
Wed, 3 Apr 2019 23:42:41 +0000 (01:42 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Wed, 3 Apr 2019 23:42:41 +0000 (01:42 +0200)
* Use io.Copy to send file contents.
* Refactored and reformatted source.
* Removed stage 1 test files.

dummy.txt [deleted file]
gogopherd.go
index.gox [deleted file]

diff --git a/dummy.txt b/dummy.txt
deleted file mode 100644 (file)
index e2da9dc..0000000
--- a/dummy.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Hello, world!
-Delirium Solarium Besenstiel
index c1aadd7e969e6c26e5c5ea970ee8d7f108ba5992..70caffe3d0d82135268c5d9b996f8530bb911856 100644 (file)
@@ -18,10 +18,12 @@ import (
        "bufio"
        "flag"
        "fmt"
+       "io"
        "io/ioutil"
        "log"
        "net"
        "os"
+       "strconv"
        "strings"
 )
 
@@ -32,26 +34,26 @@ var (
 )
 
 var cfg = struct {
-       bindIface   string
-       bindPortTcp string
-       fqdn        string
-       docRoot     string
-       indexFile   string
-       verbose     bool
+       iface   string
+       port    string
+       fqdn    string
+       docRoot string
+       header  string
+       verbose bool
 }{
-       bindIface:   "localhost",
-       bindPortTcp: "7070",
-       fqdn:        "localhost",
-       docRoot:     ".",
-       indexFile:   "index.gox",
-       verbose:     false,
+       iface:   "localhost",
+       port:    "7070",
+       fqdn:    "localhost",
+       docRoot: ".",
+       header: "igogopherd on localhost                        \r\n",
+       verbose: false,
 }
 
 func initialize() {
-       flag.StringVar(&cfg.bindIface, "i", cfg.bindIface, "interface to bind to")
-       flag.StringVar(&cfg.bindPortTcp, "p", cfg.bindPortTcp, "TCP port to listen on")
+       flag.StringVar(&cfg.iface, "i", cfg.iface, "interface to bind to")
+       flag.StringVar(&cfg.port, "p", cfg.port, "TCP port to listen on")
        flag.StringVar(&cfg.docRoot, "d", cfg.docRoot, "document root directory")
-       flag.StringVar(&cfg.indexFile, "x", cfg.indexFile, "index file")
+       flag.StringVar(&cfg.header, "H", cfg.header, "index header")
        flag.BoolVar(&cfg.verbose, "v", cfg.verbose, "produce verbose output")
        flag.Parse()
        if 0 != len(flag.Args()) {
@@ -67,11 +69,11 @@ func initialize() {
                tracer = log.New(ioutil.Discard, "", 0)
        }
 
-       tracer.Print("interface:  ", cfg.bindIface)
-       tracer.Print("TCP port:   ", cfg.bindPortTcp)
-       tracer.Print("doc root:   ", cfg.docRoot)
-       tracer.Print("index file: ", cfg.indexFile)
-       tracer.Print("verbose:    ", cfg.verbose)
+       tracer.Print("interface: ", cfg.iface)
+       tracer.Print("TCP port:  ", cfg.port)
+       tracer.Print("doc root:  ", cfg.docRoot)
+       tracer.Print("header:    ", cfg.header)
+       tracer.Print("verbose:   ", cfg.verbose)
 }
 
 func checkFatal(err error, msg string) {
@@ -81,20 +83,14 @@ func checkFatal(err error, msg string) {
        }
 }
 
-func check(err error, msg string)(error) {
+func check(err error, msg string) error {
        if err != nil {
                tracer.Print(msg, ": ", err.Error())
        }
        return err
 }
 
-func getErrorString(code string) (string) {
-       // TODO flesh this out
-       res := "Error: " + code + " Resource not found. "
-       return res;
-}
-
-func sanitizeSelector(selector string) (string) {
+func sanitizeSelector(selector string) string {
        selector = strings.Replace(selector, "\r", "", -1)
        selector = strings.Replace(selector, "\n", "", -1)
        selector = strings.Replace(selector, "../", "/", -1)
@@ -103,30 +99,71 @@ func sanitizeSelector(selector string) (string) {
        return selector
 }
 
-func getResource(selector string) ([]byte, error) {
-       if ( selector == "" || selector == "/" ) {
-               selector = cfg.indexFile
+func makeIndex(selector string) (string, error) {
+       dirname := cfg.docRoot + selector
+       d, err := os.Open(dirname)
+       defer d.Close()
+       if check(err, "Open "+dirname) != nil {
+               return "", err
+       }
+       fi, err := d.Readdir(-1)
+       if check(err, "Readdir "+dirname) != nil {
+               return "", err
+       }
+       list := ""
+       loc := "\t" + cfg.fqdn + "\t" + cfg.port + "\r\n"
+       for _, fi := range fi {
+               if fi.Mode().IsRegular() {
+                       list += "0" + fi.Name() + " (" + strconv.FormatInt(fi.Size(), 10) + ")\t" + selector + "/" + fi.Name() + loc
+               } else if fi.Mode().IsDir() {
+                       // TODO: determine file type
+                       list += "1" + fi.Name() + "\t" + selector + "/" + fi.Name() + loc
+               }
        }
-       resPath := cfg.docRoot + "/" + selector
-       res, err := ioutil.ReadFile(resPath)
-       if check(err,"ReadFile " + resPath) != nil { res = []byte(""); }
-       return res, err;
+       return list, error(nil)
 }
 
 func handleRequest(conn net.Conn) {
        defer conn.Close()
-       reply := []byte("")
        req, err := bufio.NewReader(conn).ReadString('\n')
-       if ( check(err,"ReadString") != nil ) {
+       if check(err, "ReadString") != nil {
                return
+       }
+       selector := sanitizeSelector("/" + req)
+       tracer.Print("selector: '", selector, "'")
+
+       path := cfg.docRoot + selector
+       fi, err := os.Stat(path)
+       if check(err, "Stat "+path) != nil {
+               return
+       }
+       var nb int64
+       if fi.IsDir() {
+               sres, err := makeIndex(selector)
+               if check(err, "makeIndex "+path) != nil {
+                       return
+               }
+               b, err := conn.Write([]byte(cfg.header + sres))
+               if check(err, "Write") != nil {
+                       return
+               }
+               nb = int64(b)
+       } else if fi.Mode().IsRegular() {
+               file, err := os.Open(path)
+               if check(err, "Open "+path) != nil {
+                       return
+               }
+               defer file.Close()
+               nb, err = io.Copy(conn, file)
+               if check(err, "Copy "+path) != nil {
+                       return
+               }
        } else {
-               tracer.Print("request: '", req, "'")
-               selector := sanitizeSelector(req)
-               tracer.Print("selector: '", selector, "'")
-               reply, err = getResource(selector)
-               if ( err != nil ) { reply = []byte(getErrorString("404") + selector) }
+               // TODO: handle other cases?
+               nb = -1
        }
-       conn.Write(reply)
+       tracer.Print(strconv.FormatInt(nb, 10) + " bytes sent.")
+       return
 }
 
 func serveTCP(sock net.Listener) {
@@ -140,9 +177,9 @@ func serveTCP(sock net.Listener) {
 
 func main() {
        initialize()
-       bindaddr := cfg.bindIface + ":" + cfg.bindPortTcp
+       bindaddr := cfg.iface + ":" + cfg.port
        tsock, err := net.Listen("tcp", bindaddr)
-       checkFatal(err, "net.Listen tcp " + bindaddr)
+       checkFatal(err, "net.Listen tcp "+bindaddr)
        defer tsock.Close()
        tracer.Print("listening on TCP ", bindaddr)
        go serveTCP(tsock)
diff --git a/index.gox b/index.gox
deleted file mode 100644 (file)
index ded7352..0000000
--- a/index.gox
+++ /dev/null
@@ -1,5 +0,0 @@
-iWelcome to gogopherd on localhost\r
-i---------------------------------\r
-0dummy.txt     /dummy.txt      localhost       7070\r
-0gogopherd source code /gogopherd.go   localhost       7070\r
-9gogopherd binary      /gogopherd      localhost       7070\r