79 lines
1.8 KiB
Go
79 lines
1.8 KiB
Go
|
package ws
|
||
|
|
||
|
import (
|
||
|
"crypto/rand"
|
||
|
"encoding/base64"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
|
||
|
"sectorinf.com/emilis/fupie/ws/route"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
base64Stripper = strings.NewReplacer("/", "", "+", "", "=", "")
|
||
|
)
|
||
|
|
||
|
func Upload(rootDir, redirect string, maxBytes int64) (route.HandlerFunc, error) {
|
||
|
stat, err := os.Stat(rootDir)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("stat [%s]: %w", rootDir, err)
|
||
|
}
|
||
|
if !stat.IsDir() {
|
||
|
return nil, fmt.Errorf("root path [%s] is not a directory", rootDir)
|
||
|
}
|
||
|
rootDir, err = filepath.Abs(rootDir)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("abs filepath [%s]: %w", rootDir, err)
|
||
|
}
|
||
|
redirect = strings.TrimRight(redirect, "/")
|
||
|
return func(ctx route.Context) {
|
||
|
if err := ctx.Request.ParseMultipartForm(maxBytes); err != nil {
|
||
|
ctx.Status(http.StatusBadRequest)
|
||
|
return
|
||
|
}
|
||
|
uploads := ctx.Request.MultipartForm.File["upload"]
|
||
|
if len(uploads) != 1 {
|
||
|
ctx.Status(http.StatusBadRequest)
|
||
|
return
|
||
|
}
|
||
|
header := uploads[0]
|
||
|
file, err := header.Open()
|
||
|
if err != nil {
|
||
|
ctx.InternalServerErrorf("header.Open: %s", err.Error())
|
||
|
return
|
||
|
}
|
||
|
newFilename := rename(header.Filename)
|
||
|
path := filepath.Join(rootDir, newFilename)
|
||
|
fsFile, err := os.Create(path)
|
||
|
if err != nil {
|
||
|
ctx.InternalServerErrorf("creating file at [%s]: %s", path, err.Error())
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if _, err := io.CopyBuffer(fsFile, file, nil); err != nil {
|
||
|
ctx.InternalServerErrorf("writing file at [%s]: %s", path, err.Error())
|
||
|
return
|
||
|
}
|
||
|
fsFile.Close()
|
||
|
ctx.SeeOther(fmt.Sprintf("%s/%s", redirect, newFilename))
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func rename(name string) string {
|
||
|
return fmt.Sprintf("%s_%s", randName(4), name)
|
||
|
}
|
||
|
|
||
|
func randName(bytes int) string {
|
||
|
buffer := make([]byte, bytes)
|
||
|
_, err := rand.Read(buffer)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
return base64Stripper.Replace(base64.StdEncoding.EncodeToString(buffer))
|
||
|
}
|