"flag"
"fmt"
"os"
+ "path/filepath"
+ "strings"
)
var cfg = struct {
port string
fqdn string
docRoot string
- message string
+ dirIdx string
fsymln bool
showdot bool
noidx bool
port: "7070",
fqdn: "localhost",
docRoot: ".",
- message: "",
+ dirIdx: "index.goph",
fsymln: false,
showdot: false,
noidx: false,
flag.StringVar(&cfg.port, "p", cfg.port, "TCP port to listen on")
flag.StringVar(&cfg.fqdn, "f", cfg.fqdn, "fully qualified domain name")
flag.StringVar(&cfg.docRoot, "r", cfg.docRoot, "document root directory")
- flag.StringVar(&cfg.message, "M", cfg.message, "index greeter message")
+ flag.StringVar(&cfg.dirIdx, "I", cfg.dirIdx, "directory index page")
flag.BoolVar(&help, "h", help, "show this help page")
flag.BoolVar(&cfg.fsymln, "s", cfg.fsymln, "follow symbolic links")
flag.BoolVar(&cfg.showdot, "d", cfg.showdot, "allow access to dotfiles")
cfg.docRoot, err = canonicalizePath(cfg.docRoot)
checkFatal(err, "canonicalizePath "+cfg.docRoot)
- if cfg.message != "" {
- cfg.message = fmt.Sprintf("i%s\t\t\t\r\n", cfg.message)
+ cfg.dirIdx = filepath.Base(strings.TrimSpace(cfg.dirIdx))
+ if cfg.dirIdx == "." || cfg.dirIdx == pathSep {
+ cfg.dirIdx = ""
}
tracer.Print("Version ", version)
+ tracer.Print("fqdn: ", cfg.fqdn)
tracer.Print("interface: ", cfg.iface)
tracer.Print("TCP port: ", cfg.port)
tracer.Print("doc root: ", cfg.docRoot)
+ tracer.Print("dir index: ", cfg.dirIdx)
tracer.Print("fsymlinks: ", cfg.fsymln)
tracer.Print("showdot: ", cfg.showdot)
tracer.Print("noidx: ", cfg.noidx)
- tracer.Print("fqdn: ", cfg.fqdn)
- tracer.Print("message: ", cfg.message)
tracer.Print("verbose: ", cfg.verbose)
}
"strings"
)
-func createIndex(selector string) (string, error) {
- dirname := cfg.docRoot + selector
+func createIndex(dirname string, selector string) (string, error) {
fi, err := ioutil.ReadDir(dirname)
if check(err, "Readdir "+dirname) != nil {
return "", err
return list, error(nil)
}
+func sendIndex(conn net.Conn, path string, selector string) (int64, error) {
+ var nbytes int
+ nbytes = 0
+ diridx, err := createIndex(path, selector)
+ if err == nil {
+ if selector == "" {
+ selector = pathSep
+ }
+ page := ""
+ // TODO append banner
+ page += "iIndex of " + selector + "\tErr\t" + cfg.fqdn + "\t" + cfg.port + "\r\n"
+ page += diridx
+ // TODO append footer
+ nbytes, err = conn.Write([]byte(page))
+ }
+ return int64(nbytes), err
+}
+
+func sendFile(conn net.Conn, path string) (int64, error) {
+ var nbytes int64
+ nbytes = 0
+ file, err := os.Open(path)
+ if err == nil {
+ defer file.Close()
+ nbytes, err = io.Copy(conn, file)
+ }
+ return nbytes, err
+}
+
func replyErr(conn net.Conn, msg string) {
tracer.Print("sending error reply: " + msg)
s := "3Gopher Meditation: " + msg + "\tErr\t" + cfg.fqdn + "\t" + cfg.port + "\r\n"
tracer.Print("selector: '", selector, "'")
var nbytes int64
if fmode.IsDir() {
- if cfg.noidx {
- replyErr(conn, "403")
- return
- }
- diridx, err := createIndex(selector)
- if check(err, "makeIndex "+path) != nil {
- replyErr(conn, "404")
- return
+ err = nil
+ if cfg.dirIdx != "" {
+ // send directory index file
+ idxpath := path + pathSep + cfg.dirIdx
+ nbytes, err = sendFile(conn, idxpath)
+ if err != nil {
+ tracer.Print("no index file in " + path)
+ }
}
- nb, err := conn.Write([]byte(cfg.message + diridx))
- if check(err, "Write") != nil {
- return
+ if err != nil {
+ // failed to send directory index file
+ if cfg.noidx {
+ replyErr(conn, "403")
+ return
+ }
+ // generate and send directory listing
+ nbytes, err = sendIndex(conn, path, selector)
+ if check(err, "sendIndex ") != nil {
+ replyErr(conn, "403")
+ return
+ }
}
- nbytes = int64(nb)
} else if fmode.IsRegular() {
- file, err := os.Open(path)
- if check(err, "Open "+path) != nil {
+ nbytes, err = sendFile(conn, path)
+ if check(err, "sendFile "+path) != nil {
replyErr(conn, "404")
return
}
- defer file.Close()
- nbytes, err = io.Copy(conn, file)
- if check(err, "Copy "+path) != nil {
- return
- }
} else {
replyErr(conn, "404")
return