package http import ( "crypto/rand" "encoding/base64" "mime/multipart" "strings" "sync" "github.com/valyala/fasthttp" ) var formDataPool = sync.Pool{ New: func() any { return make(map[string]any, 16) }, } func QueryToLua(ctx *fasthttp.RequestCtx) map[string]any { args := ctx.QueryArgs() if args.Len() == 0 { return emptyMap } queryMap := make(map[string]any, args.Len()) args.VisitAll(func(key, value []byte) { k := string(key) v := string(value) appendValue(queryMap, k, v) }) return queryMap } func ParseForm(ctx *fasthttp.RequestCtx) (map[string]any, error) { if strings.Contains(string(ctx.Request.Header.ContentType()), "multipart/form-data") { return parseMultipartForm(ctx) } args := ctx.PostArgs() if args.Len() == 0 { return emptyMap, nil } formData := formDataPool.Get().(map[string]any) for k := range formData { delete(formData, k) } args.VisitAll(func(key, value []byte) { k := string(key) v := string(value) appendValue(formData, k, v) }) return formData, nil } func parseMultipartForm(ctx *fasthttp.RequestCtx) (map[string]any, error) { form, err := ctx.MultipartForm() if err != nil { return nil, err } formData := formDataPool.Get().(map[string]any) for k := range formData { delete(formData, k) } 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 formData, nil } 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" } func appendValue(m map[string]any, k, v string) { if existing, exists := m[k]; exists { switch typed := existing.(type) { case []string: m[k] = append(typed, v) case string: m[k] = []string{typed, v} } } else { m[k] = v } } func GenerateSecureToken(length int) (string, error) { b := make([]byte, length) if _, err := rand.Read(b); err != nil { return "", err } return base64.URLEncoding.EncodeToString(b)[:length], nil }