diff --git a/main.go b/main.go index e4c332f..61de969 100755 --- a/main.go +++ b/main.go @@ -9,15 +9,28 @@ listing file. package main import ( + "errors" + "fmt" + "io" "local/args" "local/gziphttp" "log" "net/http" + "os" + "path" "strings" ) +const ( + ENDPOINT_UPLOAD = "__upload__" +) + +var ( + fs *args.ArgSet +) + func main() { - fs := args.NewArgSet() + fs = args.NewArgSet() fs.Append(args.STRING, "p", "port to serve", "8100") fs.Append(args.STRING, "d", "static path to serve", "./public") if err := fs.Parse(); err != nil { @@ -34,14 +47,94 @@ func main() { log.Fatal(http.ListenAndServe(":"+p, nil)) } -func handler(d string) func(http.ResponseWriter, *http.Request) { - h := http.FileServer(http.Dir(d)) +func handler(d string) http.HandlerFunc { + return gzip(endpoints(fserve(d))) +} + +func writeMeta(w http.ResponseWriter) { + fmt.Fprintf(w, ` +
+ + + + `) +} + +func writeForm(w http.ResponseWriter) { + fmt.Fprintf(w, ` + + `, ENDPOINT_UPLOAD) +} + +func gzip(foo http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if gziphttp.Can(r) { gz := gziphttp.New(w) defer gz.Close() w = gz } - h.ServeHTTP(w, r) + foo(w, r) } } + +func endpoints(foo http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if isDir(r) { + writeMeta(w) + writeForm(w) + } + if isUploaded(r) { + if err := upload(w, r); err != nil { + fmt.Fprintln(w, err.Error()) + } + } else { + foo(w, r) + } + } +} + +func isUploaded(r *http.Request) bool { + return path.Base(r.URL.Path) == ENDPOINT_UPLOAD +} + +func isDir(r *http.Request) bool { + d := toRealPath(r.URL.Path) + fi, err := os.Stat(d) + return err == nil && fi.IsDir() +} + +func fserve(d string) http.HandlerFunc { + h := http.FileServer(http.Dir(d)) + return h.ServeHTTP +} + +func upload(w http.ResponseWriter, r *http.Request) error { + r.ParseMultipartForm(100 << 20) + file, handler, err := r.FormFile("file") + if err != nil { + return err + } + defer file.Close() + p := toRealPath(path.Join(path.Dir(r.URL.Path), handler.Filename)) + if fi, err := os.Stat(p); err == nil && !fi.IsDir() { + return errors.New("already exists") + } + f, err := os.Create(p) + if err != nil { + return err + } + defer f.Close() + if _, err := io.Copy(f, file); err != nil { + return err + } + http.Redirect(w, r, path.Dir(r.URL.Path)+"/", http.StatusSeeOther) + return nil +} + +func toRealPath(p string) string { + d := path.Join(fs.Get("d").GetString()) + return path.Join(d, p) +}