diff options
| author | Julian Hurst <ark@mansus.space> | 2022-12-08 18:34:25 +0100 |
|---|---|---|
| committer | Julian Hurst <ark@mansus.space> | 2022-12-08 18:34:25 +0100 |
| commit | 238d7a12de4ad095c297f214a76438110798208b (patch) | |
| tree | 104f42f9f4a1bfc8b3a32723091a229e384e50a4 /autoindex.go | |
| download | autoindex-238d7a12de4ad095c297f214a76438110798208b.tar.gz | |
Initial commit
Diffstat (limited to 'autoindex.go')
| -rw-r--r-- | autoindex.go | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/autoindex.go b/autoindex.go new file mode 100644 index 0000000..6a388a6 --- /dev/null +++ b/autoindex.go @@ -0,0 +1,270 @@ +package main + +import ( + "fmt" + "flag" + "archive/tar" + "compress/gzip" + "log" + "net/http" + "os" + "os/exec" + "path/filepath" + "html/template" + "io" + "io/ioutil" + "time" + "strings" +) + +const pwdlen int = 32 +var salt []byte = nil + +type IndexHandler struct { + docPath string + binPath string +} + +type File struct { + Info os.FileInfo + Path string +} + +func format(t time.Time) string { + return t.Format("2006-01-02 15:04") +} + +func (handler IndexHandler) writeDirToTar(tw *tar.Writer, file os.FileInfo, name string) { + //hdr := &tar.Header{ + //Name: name, + //Mode: int64(file.Mode()), + //ModTime: file.ModTime(), + //Typeflag: tar.TypeDir, + //} + //if err := tw.WriteHeader(hdr); err != nil { + //log.Fatal(err) + //} + p := filepath.Join(handler.docPath, name) + fileInfos, err := ioutil.ReadDir(p) + if err != nil { + panic(err) + } + for _, info := range fileInfos { + path := filepath.Join(name, info.Name()) + path = strings.TrimPrefix(path, "/") + if info.IsDir() { + handler.writeDirToTar(tw, info, path) + } else { + hdr := &tar.Header{ + Name: path, + Mode: int64(info.Mode()), + Size: info.Size(), + ModTime: info.ModTime(), + } + if err := tw.WriteHeader(hdr); err != nil { + log.Fatal(err) + } + absFilePath := filepath.Join(handler.docPath, path) + openFile, err := os.Open(absFilePath) + if err != nil { + panic(err) + } + defer openFile.Close() + _, err = io.Copy(tw, openFile) + if err != nil { + panic(err) + } + } + } +} + +func (handler IndexHandler) TarArchive(w io.Writer, r *http.Request, s string) { + p := filepath.Join(handler.docPath, s) + f, err := os.Stat(p) + if err != nil { + log.Println(err) + return + } + if f.IsDir() { + s = strings.TrimPrefix(s, "/") + //gw := gzip.NewWriter(w) + //defer gw.Close() + var tw *tar.Writer + tw = tar.NewWriter(w) + defer tw.Close() + handler.writeDirToTar(tw, f, s) + //w.WriteHeader(http.StatusCreated) + } else { + return + } +} + +func (handler IndexHandler) IsExistingIndex() (bool, string) { + ind := filepath.Join(handler.docPath, "index.html") + f, err := os.Stat(ind) + if err == nil && !f.IsDir() { + return true, ind + } + ind = filepath.Join(handler.docPath, "index.htm") + f, err = os.Stat(ind) + if err == nil && !f.IsDir() { + return true, ind + } + return false, "" +} + +func (handler IndexHandler) ServeDir(w http.ResponseWriter, r *http.Request, dir string) { + fileInfos, err := ioutil.ReadDir(dir) + if err != nil { + panic(err) + } + var files []File = nil + for _, info := range fileInfos { + path := filepath.Join(r.URL.Path, info.Name()) + files = append(files, File{info, path}) + } + funcs := template.FuncMap { + "format": format, + } + tmpl, err := template.New("index.html").Funcs(funcs).ParseFiles(GetIndexPath()) + if err != nil { + panic(err) + } + data := struct { + DocDir string + CurrentPath string + Parent string + Files []File + }{ + filepath.Base(handler.docPath), + r.URL.Path, + filepath.Dir(r.URL.Path), + files, + } + tmpl.Execute(w, data) +} + +func (handler IndexHandler) Execute(w http.ResponseWriter, r *http.Request, s string) { + b := filepath.Join(handler.binPath, s) + _, err := os.Stat(b) + if err != nil { + log.Println("stat") + log.Println(err) + return + } + log.Printf("Executing %s\n", b) + //out, err := exec.Command(b).CombinedOutput() + cmd := exec.Command(b) + out, err := cmd.StdoutPipe() + if err != nil { + log.Println(err) + return + } + if err := cmd.Start(); err != nil { + log.Println(err) + return + } + //_, err = w.Write(out) + _, err = io.Copy(w, out) + if err != nil { + log.Println(err) + return + } +} + +func (handler IndexHandler) ServeFile(w http.ResponseWriter, r *http.Request, p string) { + http.ServeFile(w, r, p) +} + +func (handler IndexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.URL.Path, "/tararchive") { + s := strings.TrimPrefix(r.URL.Path, "/tararchive") + contentDisposition := fmt.Sprintf("attachment; filename=\"%v\"", filepath.Base(s) + ".tar") + log.Println(contentDisposition) + w.Header().Set("Content-Disposition", contentDisposition) + handler.TarArchive(w, r, s) + return + } else if strings.HasPrefix(r.URL.Path, "/gzarchive") { + s := strings.TrimPrefix(r.URL.Path, "/gzarchive") + contentDisposition := fmt.Sprintf("attachment; filename=\"%v\"", filepath.Base(s) + ".tar.gz") + log.Println(contentDisposition) + w.Header().Set("Content-Disposition", contentDisposition) + gw := gzip.NewWriter(w) + defer gw.Close() + handler.TarArchive(gw, r, s) + return + } else if r.URL.Path == "/ai_execute" && handler.binPath != "" { + handler.ServeDir(w, r, handler.binPath) + return + } else if strings.HasPrefix(r.URL.Path, "/ai_execute") { + s := strings.TrimPrefix(r.URL.Path, "/ai_execute") + handler.Execute(w, r, s) + return + } + + p := filepath.Join(handler.docPath, r.URL.Path) + if r.URL.Path == "/" { + if ok, ind := handler.IsExistingIndex(); ok && r.URL.Path == "/" { + http.ServeFile(w, r, ind) + return + } + } + f, err := os.Stat(p) + if err != nil { + log.Println(err) + w.WriteHeader(http.StatusNotFound) + return + } + if f.IsDir() { + fileInfos, err := ioutil.ReadDir(p) + if err != nil { + panic(err) + } + var files []File = nil + for _, info := range fileInfos { + path := filepath.Join(r.URL.Path, info.Name()) + files = append(files, File{info, path}) + } + funcs := template.FuncMap { + "format": format, + } + tmpl, err := template.New("index.html").Funcs(funcs).ParseFiles(GetIndexPath()) + if err != nil { + panic(err) + } + data := struct { + DocDir string + CurrentPath string + Parent string + Files []File + }{ + filepath.Base(handler.docPath), + r.URL.Path, + filepath.Dir(r.URL.Path), + files, + } + tmpl.Execute(w, data) + } else { + handler.ServeFile(w, r, p) + } +} + +func usage() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [OPTIONS] pathtodocdir\n", os.Args[0]) + fmt.Fprint(flag.CommandLine.Output(), "\nOptions:\n") + flag.PrintDefaults() +} + +func main() { + port := flag.Int("p", 8080, "The port to bind to.") + binPath := flag.String("b", "", "The autoindex executables directory.") + flag.Parse() + args := flag.Args() + if len(args) != 1 { + usage() + os.Exit(1) + } + handler := IndexHandler{args[0], *binPath} + log.Printf("Listening on port %d with docPath=%s", *port, handler.docPath) + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", *port), handler)) +} |
