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" }