From cd9041d2d1e50a43d9b0e1c90d98ebeae09fe22e Mon Sep 17 00:00:00 2001 From: Urban Wallasch Date: Thu, 4 Apr 2019 01:42:41 +0200 Subject: [PATCH] * Auto generate directory indexes. * Use io.Copy to send file contents. * Refactored and reformatted source. * Removed stage 1 test files. --- dummy.txt | 2 - gogopherd.go | 127 +++++++++++++++++++++++++++++++++------------------ index.gox | 5 -- 3 files changed, 82 insertions(+), 52 deletions(-) delete mode 100644 dummy.txt delete mode 100644 index.gox diff --git a/dummy.txt b/dummy.txt deleted file mode 100644 index e2da9dc..0000000 --- a/dummy.txt +++ /dev/null @@ -1,2 +0,0 @@ -Hello, world! -Delirium Solarium Besenstiel diff --git a/gogopherd.go b/gogopherd.go index c1aadd7..70caffe 100644 --- a/gogopherd.go +++ b/gogopherd.go @@ -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 index ded7352..0000000 --- a/index.gox +++ /dev/null @@ -1,5 +0,0 @@ -iWelcome to gogopherd on localhost -i--------------------------------- -0dummy.txt /dummy.txt localhost 7070 -0gogopherd source code /gogopherd.go localhost 7070 -9gogopherd binary /gogopherd localhost 7070 -- 2.30.2