get cp paste file upload gogo via multipart form

master
Bel LaPointe 2022-02-08 14:56:08 -07:00
parent 34b964e0bb
commit f24a8c2907
5 changed files with 99 additions and 16 deletions

3
.gitignore vendored
View File

@ -1,2 +1,5 @@
**/*.sw* **/*.sw*
spike/review/reinvent/ezmded/server/ezmded 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/*

View File

@ -3,15 +3,17 @@ module ezmded
go 1.17 go 1.17
require ( require (
github.com/google/uuid v1.3.0
gopkg.in/yaml.v2 v2.4.0
local/args v0.0.0-00010101000000-000000000000 local/args v0.0.0-00010101000000-000000000000
local/notes-server v0.0.0-00010101000000-000000000000
local/router v0.0.0-00010101000000-000000000000 local/router v0.0.0-00010101000000-000000000000
) local/simpleserve v0.0.0-00010101000000-000000000000
local/gziphttp v0.0.0-00010101000000-000000000000
require (
github.com/google/uuid v1.3.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
) )
replace local/args => ../../../../../../../../args replace local/args => ../../../../../../../../args
replace local/router => ../../../../../../../../router replace local/router => ../../../../../../../../router
replace local/simpleserve => ../../../../../../../../simpleserve
replace local/gziphttp => ../../../../../../../../gziphttp
replace local/notes-server => ../../../../../../../../notes-server

View File

@ -3,9 +3,12 @@ package main
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"local/gziphttp"
"local/router" "local/router"
"local/simpleserve/simpleserve"
"net/http" "net/http"
"os" "os"
"path" "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 { func (server *Server) tryCatchHttpHandler(handler func(http.ResponseWriter, *http.Request) error) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { 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 { if err := handler(w, r); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) 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 { 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() tree := server.tree()
branches, err := tree.Get() branches, err := tree.Get()
if err != nil { 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 { func (server *Server) apiV0MediaHandler(w http.ResponseWriter, r *http.Request) error {
id := uuid.New().String() id, err := server.postContentHandler(path.Dir(server.diskMediaPath("id")), w, r)
filePath := server.diskMediaPath(id) if err != nil {
if err := server.postContentHandler(filePath, w, r); err != nil {
return err return err
} }
return json.NewEncoder(w).Encode(map[string]map[string]string{ 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 return err
} }
defer f.Close() defer f.Close()
simpleserve.SetContentTypeIfMedia(w, r)
io.Copy(w, f) io.Copy(w, f)
return nil 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 { 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 { 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 { func (server *Server) apiV0FilesHandler(w http.ResponseWriter, r *http.Request) error {
id := uuid.New().String() id, err := server.postContentHandler(path.Dir(server.diskFilePath("id")), w, r)
filePath := server.diskFilePath(id) if err != nil {
if err := server.postContentHandler(filePath, w, r); err != nil {
return err return err
} }
tree := server.tree() tree := server.tree()

View File

@ -42,10 +42,15 @@ func TestServerRoutes(t *testing.T) {
method: http.MethodGet, method: http.MethodGet,
want: `["getfid"]`, want: `["getfid"]`,
}, },
"v0: tree: get pretty": {
path: "/api/v0/tree?pretty",
method: http.MethodGet,
want: `{"delfid":{"Title":"delfid title","Children":[`,
},
"v0: tree: get": { "v0: tree: get": {
path: "/api/v0/tree", path: "/api/v0/tree",
method: http.MethodGet, method: http.MethodGet,
want: `{"delfid":{"Title":"delfid title",`, want: `":{"Title":"getfid title",`,
}, },
"v0: media: post": { "v0: media: post": {
path: "/api/v0/media", path: "/api/v0/media",

View File

@ -20,12 +20,28 @@ type Branch struct {
PID string PID string
} }
type Pretty struct {
Title string
Children map[string]Pretty
}
func NewTree(path string) *Tree { func NewTree(path string) *Tree {
return &Tree{ return &Tree{
path: path, 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) { func (tree *Tree) Get() (map[string]Branch, error) {
b, err := ioutil.ReadFile(tree.path) b, err := ioutil.ReadFile(tree.path)
if os.IsNotExist(err) { if os.IsNotExist(err) {