From 9ecff00f7f4bd84bf84829c96e07371739132606 Mon Sep 17 00:00:00 2001 From: Pinghao Wu Date: Tue, 14 Jan 2025 22:39:56 +0800 Subject: [PATCH] serve files, dirlisting, unshare+chroot --- server.go | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 server.go diff --git a/server.go b/server.go new file mode 100644 index 0000000..0ebae31 --- /dev/null +++ b/server.go @@ -0,0 +1,183 @@ +package main + +// #cgo LDFLAGS: -static +// #define _GNU_SOURCE +// #include +// __attribute__((constructor)) void f() { +// unshare(CLONE_NEWUSER); +// } +import "C" + +import ( + "html/template" + "io/fs" + "net" + "net/http" + "os" + "path" + "strconv" + "syscall" + "time" +) + +var ( + numfmtSuffix = []string{"", "K", "M", "G", "T"} + + tpl = template.Must(template.New("dirlisting").Funcs(template.FuncMap{ + "timefmt": func(t time.Time) string { + return t.Format(time.RFC3339) + }, + "numfmt": func(i int64) string { + f := float64(i) + idx := 0 + for f > 1000 && idx < len(numfmtSuffix)-1 { + f /= 1000 + idx += 1 + } + return strconv.FormatFloat(f, 'f', 1, 64) + numfmtSuffix[idx] + }, + }).Parse(` + + + + + Index of {{.Path}} + + +

Index of {{.Path}}

+
+ + + + + + {{range .Entries}} + + + {{with .Info}} + + + {{end}} + + {{end}} + +
NameLast ModifiedSize
..
{{.Name}}{{if .IsDir}}/{{end}}{{.ModTime | timefmt}}{{if .IsDir}}-{{else}}{{.Size | numfmt}}{{end}}
+ + +`)) +) + +type Data struct { + Path string + Entries []fs.DirEntry +} + +func main() { + if err := syscall.Chroot("."); err != nil { + panic(err) + } + + l, err := net.Listen("tcp", "0.0.0.0:8000") + if err != nil { + panic(err) + } + f, ok := os.DirFS(".").(fs.ReadDirFS) + if !ok { + panic("fs impl not supporting fs.ReadDirFS") + } + staticHandler := http.FileServerFS(f) + h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + l := len(r.URL.Path) + if r.URL.Path[l-1] == '/' { + p := r.URL.Path + if r.URL.Path[0] != '/' { + p = "/" + r.URL.Path + } + p = path.Clean(p) + // net/http.ioFS + if p == "/" { + p = "." + } else { + p = p[1:] + } + ds, err := f.ReadDir(p) + if err != nil { + w.WriteHeader(404) + return + } + tpl.Execute(w, Data{r.URL.Path, ds}) + } else { + staticHandler.ServeHTTP(w, r) + } + }) + + s := http.Server{Handler: h} + if err := s.Serve(l); err != nil { + panic(err) + } +} -- 2.45.2