From f24a8c2907f1f42af5b75cac35cc914793929832 Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Tue, 8 Feb 2022 14:56:08 -0700 Subject: [PATCH] get cp paste file upload gogo via multipart form --- .gitignore | 3 + spike/review/reinvent/ezmded/server/go.mod | 14 ++-- spike/review/reinvent/ezmded/server/server.go | 75 ++++++++++++++++--- .../reinvent/ezmded/server/server_test.go | 7 +- spike/review/reinvent/ezmded/server/tree.go | 16 ++++ 5 files changed, 99 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 16a415a..e967b99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ **/*.sw* spike/review/reinvent/ezmded/server/ezmded +spike/review/reinvent/ezmded/server/ezmded/testdata/**/* +spike/review/reinvent/ezmded/server/ezmded/testdata/media/* +spike/review/reinvent/ezmded/server/ezmded/testdata/files/* diff --git a/spike/review/reinvent/ezmded/server/go.mod b/spike/review/reinvent/ezmded/server/go.mod index 0557643..aec41b8 100644 --- a/spike/review/reinvent/ezmded/server/go.mod +++ b/spike/review/reinvent/ezmded/server/go.mod @@ -3,15 +3,17 @@ module ezmded go 1.17 require ( + github.com/google/uuid v1.3.0 + gopkg.in/yaml.v2 v2.4.0 local/args v0.0.0-00010101000000-000000000000 + local/notes-server v0.0.0-00010101000000-000000000000 local/router v0.0.0-00010101000000-000000000000 -) - -require ( - github.com/google/uuid v1.3.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + local/simpleserve v0.0.0-00010101000000-000000000000 + local/gziphttp v0.0.0-00010101000000-000000000000 ) replace local/args => ../../../../../../../../args - replace local/router => ../../../../../../../../router +replace local/simpleserve => ../../../../../../../../simpleserve +replace local/gziphttp => ../../../../../../../../gziphttp +replace local/notes-server => ../../../../../../../../notes-server diff --git a/spike/review/reinvent/ezmded/server/server.go b/spike/review/reinvent/ezmded/server/server.go index fee7581..37c08e5 100644 --- a/spike/review/reinvent/ezmded/server/server.go +++ b/spike/review/reinvent/ezmded/server/server.go @@ -3,9 +3,12 @@ package main import ( "encoding/json" "errors" + "fmt" "io" "io/ioutil" + "local/gziphttp" "local/router" + "local/simpleserve/simpleserve" "net/http" "os" "path" @@ -59,6 +62,11 @@ func (server *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (server *Server) tryCatchHttpHandler(handler func(http.ResponseWriter, *http.Request) error) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + if gziphttp.Can(r) { + w2 := gziphttp.New(w) + defer w2.Close() + w = w2 + } if err := handler(w, r); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } @@ -66,6 +74,23 @@ func (server *Server) tryCatchHttpHandler(handler func(http.ResponseWriter, *htt } func (server *Server) apiV0TreeHandler(w http.ResponseWriter, r *http.Request) error { + _, pretty := r.URL.Query()["pretty"] + if pretty { + return server.apiV0TreePrettyHandler(w, r) + } + return server.apiV0TreePlainHandler(w, r) +} + +func (server *Server) apiV0TreePrettyHandler(w http.ResponseWriter, r *http.Request) error { + tree := server.tree() + branches, err := tree.GetPretty() + if err != nil { + return err + } + return json.NewEncoder(w).Encode(branches) +} + +func (server *Server) apiV0TreePlainHandler(w http.ResponseWriter, r *http.Request) error { tree := server.tree() branches, err := tree.Get() if err != nil { @@ -82,9 +107,8 @@ func ensureAndWrite(p string, b []byte) error { } func (server *Server) apiV0MediaHandler(w http.ResponseWriter, r *http.Request) error { - id := uuid.New().String() - filePath := server.diskMediaPath(id) - if err := server.postContentHandler(filePath, w, r); err != nil { + id, err := server.postContentHandler(path.Dir(server.diskMediaPath("id")), w, r) + if err != nil { return err } return json.NewEncoder(w).Encode(map[string]map[string]string{ @@ -129,15 +153,49 @@ func (server *Server) getContentHandler(filePath string, w http.ResponseWriter, return err } defer f.Close() + simpleserve.SetContentTypeIfMedia(w, r) io.Copy(w, f) return nil } -func (server *Server) postContentHandler(filePath string, w http.ResponseWriter, r *http.Request) error { +func (server *Server) postContentHandler(fileDir string, w http.ResponseWriter, r *http.Request) (string, error) { if r.Method != http.MethodPost { - return errors.New("not found") + return "", errors.New("not found") } - return server.putContentHandler(filePath, w, r) + id := uuid.New().String() + if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") { + kb := int64(1 << 10) + mb := kb << 10 + if err := r.ParseMultipartForm(10 * mb); err != nil { + return "", err + } + if len(r.MultipartForm.File) != 1 { + return "", errors.New("not exactly 1 file found in request") + } + for _, infos := range r.MultipartForm.File { + if len(infos) != 1 { + return "", errors.New("not exactly 1 file info found in request") + } + ext := path.Ext(infos[0].Filename) + if h, ok := infos[0].Header["Content-Type"]; ok { + ext = path.Base(h[0]) + } + id += "." + ext + f, err := infos[0].Open() + if err != nil { + return "", err + } + defer f.Close() + r.Body = f + } + } else if strings.HasPrefix(r.Header.Get("Content-Type"), "application/x-www-form-urlencoded") { + if err := r.ParseForm(); err != nil { + return "", err + } + return "", fmt.Errorf("parse form: %+v", r.PostForm) + } + filePath := path.Join(fileDir, id) + return id, server.putContentHandler(filePath, w, r) } func (server *Server) putContentHandler(filePath string, w http.ResponseWriter, r *http.Request) error { @@ -166,9 +224,8 @@ func (server *Server) diskMediaPath(id string) string { } func (server *Server) apiV0FilesHandler(w http.ResponseWriter, r *http.Request) error { - id := uuid.New().String() - filePath := server.diskFilePath(id) - if err := server.postContentHandler(filePath, w, r); err != nil { + id, err := server.postContentHandler(path.Dir(server.diskFilePath("id")), w, r) + if err != nil { return err } tree := server.tree() diff --git a/spike/review/reinvent/ezmded/server/server_test.go b/spike/review/reinvent/ezmded/server/server_test.go index d77021b..e588ff5 100644 --- a/spike/review/reinvent/ezmded/server/server_test.go +++ b/spike/review/reinvent/ezmded/server/server_test.go @@ -42,10 +42,15 @@ func TestServerRoutes(t *testing.T) { method: http.MethodGet, want: `["getfid"]`, }, + "v0: tree: get pretty": { + path: "/api/v0/tree?pretty", + method: http.MethodGet, + want: `{"delfid":{"Title":"delfid title","Children":[`, + }, "v0: tree: get": { path: "/api/v0/tree", method: http.MethodGet, - want: `{"delfid":{"Title":"delfid title",`, + want: `":{"Title":"getfid title",`, }, "v0: media: post": { path: "/api/v0/media", diff --git a/spike/review/reinvent/ezmded/server/tree.go b/spike/review/reinvent/ezmded/server/tree.go index 2b93d9b..5aa6463 100644 --- a/spike/review/reinvent/ezmded/server/tree.go +++ b/spike/review/reinvent/ezmded/server/tree.go @@ -20,12 +20,28 @@ type Branch struct { PID string } +type Pretty struct { + Title string + Children map[string]Pretty +} + func NewTree(path string) *Tree { return &Tree{ path: path, } } +func (tree *Tree) GetPretty() (map[string]Pretty, error) { + branches, err := tree.Get() + if err != nil { + return nil, err + } + _ = branches + pretty := map[string]Pretty{} + // TODO: rm del + return pretty, errors.New("not impl") +} + func (tree *Tree) Get() (map[string]Branch, error) { b, err := ioutil.ReadFile(tree.path) if os.IsNotExist(err) {