partage

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.z3bra.org/partage.git
Log | Files | Refs

commit 598b884e65c18c8a239b87bb3c931c570027124a
Author: Willy Goiffon <dev@z3bra.org>
Date:   Sun, 10 Oct 2021 07:29:51 +0200

Provide basic GET/PUT HTTP methods

Diffstat:
Aconfig.mk | 2++
Ago.mod | 3+++
Amkfile | 21+++++++++++++++++++++
Apartage.go | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 183 insertions(+), 0 deletions(-)

diff --git a/config.mk b/config.mk @@ -0,0 +1,2 @@ +GO = go +GOOS = `{uname -s | tr A-Z a-z} diff --git a/go.mod b/go.mod @@ -0,0 +1,3 @@ +module git.z3bra.org/partage + +go 1.17 diff --git a/mkfile b/mkfile @@ -0,0 +1,21 @@ +<config.mk + +all:V: partage + +%: %.go + $GO build -o $stem + +clean:V: + rm -f partage + +install:V: partage + mkdir -p ${DESTDIR}${PREFIX}/bin + cp partage ${DESTDIR}${PREFIX}/bin/partage + chmod 755 ${DESTDIR}${PREFIX}/bin/partage + mkdir -p ${DESTDIR}${MANDIR}/man1 + cp partage.1 ${DESTDIR}${MANDIR}/man1/partage.1 + chmod 644 ${DESTDIR}${MANDIR}/man1/partage.1 + +uninstall:V: + rm ${DESTDIR}${PREFIX}/bin/partage + rm ${DESTDIR}${MANDIR}/man1/partage.1 diff --git a/partage.go b/partage.go @@ -0,0 +1,157 @@ +package main + +import ( + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "path" + "path/filepath" +) + +var conf struct { + bind string + filepath string + rootdir string + baseuri string + maxsize int64 +} + +func contenttype(f *os.File) string { + buffer := make([]byte, 512) + + _, err := f.Read(buffer) + if err != nil { + return "" + } + + mime := http.DetectContentType(buffer) + + return mime +} + +func writefile(f *os.File, s io.ReadCloser) int { + buffer := make([]byte, 4096) + + var sz int + + for { + n, err := s.Read(buffer) + + if err != nil { + if err == io.EOF { + n, err := f.Write(buffer[:n]) + if err != nil { + fmt.Println(err) + } + sz += n + break + } + fmt.Println(err) + return -1 + } + + n, err = f.Write(buffer[:n]) + if err != nil { + fmt.Println(err) + } + sz += n + } + + f.Sync() + return sz +} + +func servefile(f *os.File, w http.ResponseWriter) { + buffer := make([]byte, 4096) + + mime := contenttype(f) + w.Header().Set("Content-Type", mime) + + f.Seek(0, 0) + for { + n, err := f.Read(buffer) + + if err != nil { + if err == io.EOF { + _, err := w.Write(buffer[:n]) + if err != nil { + fmt.Println(err) + } + break + } + fmt.Println(err) + return + } + + _, err = w.Write(buffer[:n]) + if err != nil { + fmt.Println(err) + } + } +} + +func parse(w http.ResponseWriter, r *http.Request) { + + fmt.Printf("%s %s\n", r.Method, r.URL.Path) + + // Max 15 Gb uploads + if r.ContentLength > conf.maxsize { + w.WriteHeader(http.StatusRequestEntityTooLarge) + w.Write([]byte("File is too big")) + } + + err := r.ParseForm() + if err != nil { + fmt.Printf("%s %s: %s", r.Method, r.URL.Path, err) + } + + switch r.Method { + case "PUT": + tmp, _ := ioutil.TempFile(conf.filepath, "*"+path.Ext(r.URL.Path)) + f, err := os.Create(tmp.Name()) + if err != nil { + fmt.Println(err) + return + } + defer f.Close() + + if writefile(f, r.Body) < 0 { + w.WriteHeader(http.StatusInternalServerError) + return + } + + resp := conf.baseuri + "/" + filepath.Base(tmp.Name()) + w.Write([]byte(resp)) + + case "GET": + // r.URL.Path is sanitized regarding "." and ".." + filename := r.URL.Path + if r.URL.Path == "/" { + filename = "/index.html" + } + + f, err := os.Open(conf.rootdir + filename) + if err != nil { + w.WriteHeader(http.StatusNotFound) + fmt.Println(err) + return + } + defer f.Close() + + servefile(f, w) + } +} + +func main() { + + conf.bind = "0.0.0.0:8080" + conf.maxsize = 28 * 1024 * 1024 + conf.filepath = "/tmp" + conf.rootdir = "./static" + conf.baseuri = "http://192.168.0.3:8080" + + http.HandleFunc("/", parse) + http.ListenAndServe("0.0.0.0:8080", nil) +}