From 786ae6ad9425905c1d15533fff28cf7602382580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Sun, 16 Jan 2022 21:29:42 +0100 Subject: [PATCH] Handle multipart form files --- .vscode/launch.json | 16 ++++++++++++++ cmd/server/server.go | 1 + filestore.go | 5 +++-- http.go | 50 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..fc2d387 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Debug server", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/server/server.go", + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/cmd/server/server.go b/cmd/server/server.go index 976ba98..9527441 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -69,6 +69,7 @@ func ActionServe(c *cli.Context) error { go func() { srv := gpaste.NewHTTPServer(cfg) srv.Addr = cfg.ListenAddr + srv.Logger = serverLogger // Wait for cancel go func() { diff --git a/filestore.go b/filestore.go index 94ed297..21cad4f 100644 --- a/filestore.go +++ b/filestore.go @@ -6,8 +6,9 @@ import ( ) type File struct { - ID string - Body io.ReadCloser + ID string + OriginalFilename string + Body io.ReadCloser MaxViews uint ExpiresOn time.Time diff --git a/http.go b/http.go index dd37ea8..9bcc962 100644 --- a/http.go +++ b/http.go @@ -4,6 +4,7 @@ import ( "encoding/json" "io" "net/http" + "strings" "github.com/go-chi/chi/v5" "github.com/google/uuid" @@ -43,6 +44,12 @@ func (s *HTTPServer) HandlerAPIFilePost(w http.ResponseWriter, r *http.Request) Body: r.Body, } + // Check if multipart form + ct := r.Header.Get("Content-Type") + if strings.Contains(ct, "multipart/form-data") { + s.processMultiPartFormUpload(w, r) + return + } err := s.store.Store(f) if err != nil { w.WriteHeader(http.StatusInternalServerError) @@ -85,3 +92,46 @@ func (s *HTTPServer) HandlerAPIFileGet(w http.ResponseWriter, r *http.Request) { s.Logger.Warnw("Error writing file to client.", "error", err, "remote_addr", r.RemoteAddr) } } + +func (s *HTTPServer) processMultiPartFormUpload(w http.ResponseWriter, r *http.Request) { + s.Logger.Debugw("Processing multipart form.") + type resp struct { + Message string `json:"message"` + ID string `json:"id"` + URL string `json:"url"` + } + + var responses []resp + + if err := r.ParseMultipartForm(1024 * 1024 * 10); err != nil { + s.Logger.Warnw("Error parsin multipart form.", "err", err) + } + for k := range r.MultipartForm.File { + ff, fh, err := r.FormFile(k) + if err != nil { + s.Logger.Warnw("Error reading file from multipart form.", "error", err) + return + } + f := &File{ + ID: uuid.Must(uuid.NewRandom()).String(), + OriginalFilename: fh.Filename, + Body: ff, + } + + if err := s.store.Store(f); err != nil { + w.WriteHeader(http.StatusInternalServerError) + s.Logger.Warnw("Error storing file.", "erorr", err, "id", f.ID, "remote_addr", r.RemoteAddr) + return + } + s.Logger.Infow("Stored file.", "id", f.ID, "filename", f.OriginalFilename, "remote_addr", r.RemoteAddr) + + responses = append(responses, resp{Message: "OK", ID: f.ID, URL: "TODO"}) + + } + + w.WriteHeader(http.StatusAccepted) + encoder := json.NewEncoder(w) + if err := encoder.Encode(&responses); err != nil { + s.Logger.Warnw("Error encoding response to client.", "error", err, "remote_addr", r.RemoteAddr) + } +}