Moonshark/utils/formData.go
2025-06-06 18:57:47 -05:00

116 lines
2.5 KiB
Go

package utils
import (
"mime/multipart"
"strings"
"github.com/goccy/go-json"
"github.com/valyala/fasthttp"
)
func ParseForm(ctx *fasthttp.RequestCtx) (map[string]any, error) {
contentType := string(ctx.Request.Header.ContentType())
formData := make(map[string]any)
switch {
case strings.Contains(contentType, "multipart/form-data"):
if err := parseMultipartInto(ctx, formData); err != nil {
return nil, err
}
case strings.Contains(contentType, "application/x-www-form-urlencoded"):
args := ctx.PostArgs()
args.VisitAll(func(key, value []byte) {
appendValue(formData, string(key), string(value))
})
case strings.Contains(contentType, "application/json"):
if err := json.Unmarshal(ctx.PostBody(), &formData); err != nil {
return nil, err
}
default:
// Leave formData empty if content-type is unrecognized
}
return formData, nil
}
func parseMultipartInto(ctx *fasthttp.RequestCtx, formData map[string]any) error {
form, err := ctx.MultipartForm()
if err != nil {
return err
}
for key, values := range form.Value {
if len(values) == 1 {
formData[key] = values[0]
} else if len(values) > 1 {
formData[key] = values
}
}
if len(form.File) > 0 {
files := make(map[string]any, len(form.File))
for fieldName, fileHeaders := range form.File {
if len(fileHeaders) == 1 {
files[fieldName] = fileInfoToMap(fileHeaders[0])
} else {
fileInfos := make([]map[string]any, len(fileHeaders))
for i, fh := range fileHeaders {
fileInfos[i] = fileInfoToMap(fh)
}
files[fieldName] = fileInfos
}
}
formData["_files"] = files
}
return nil
}
func appendValue(formData map[string]any, key, value string) {
if existing, exists := formData[key]; exists {
switch v := existing.(type) {
case string:
formData[key] = []string{v, value}
case []string:
formData[key] = append(v, value)
}
} else {
formData[key] = value
}
}
func fileInfoToMap(fh *multipart.FileHeader) map[string]any {
ct := fh.Header.Get("Content-Type")
if ct == "" {
ct = getMimeType(fh.Filename)
}
return map[string]any{
"filename": fh.Filename,
"size": fh.Size,
"mimetype": ct,
}
}
func getMimeType(filename string) string {
if i := strings.LastIndex(filename, "."); i >= 0 {
switch filename[i:] {
case ".pdf":
return "application/pdf"
case ".png":
return "image/png"
case ".jpg", ".jpeg":
return "image/jpeg"
case ".gif":
return "image/gif"
case ".svg":
return "image/svg+xml"
}
}
return "application/octet-stream"
}