Files
mq/utils/form.go
2024-11-24 11:35:38 +05:45

121 lines
2.2 KiB
Go

package utils
import (
"fmt"
"net/url"
"strings"
)
type form struct {
dest map[string]any
raw string
pathCache map[string]int
}
func newForm(raw string) *form {
f := new(form)
f.raw = raw
f.pathCache = make(map[string]int)
return f
}
func (f *form) reset() {
f.dest = make(map[string]any)
}
func (f *form) decode() (map[string]any, error) {
f.reset()
vals := make(map[string]any)
for _, v := range strings.Split(f.raw, "&") {
if v == "" {
continue
}
index := strings.Index(v, "=")
if index > 0 {
key := v[:index]
val := v[index+1:]
f.insertValue(&vals, key, val)
} else {
f.insertValue(&vals, v, "")
}
}
return f.parseArray(vals), nil
}
func (f *form) insertValue(destP *map[string]any, key string, val string) {
key, _ = url.PathUnescape(key)
var path []string
if strings.Contains(key, "[") || strings.Contains(key, "]") {
var current string
for _, c := range key {
switch c {
case '[':
if len(current) > 0 {
path = append(path, current)
current = ""
}
case ']':
path = append(path, current)
current = ""
continue
default:
current += string(c)
}
}
if len(current) > 0 {
path = append(path, current)
}
} else {
path = append(path, key)
}
dest := *destP
for i, k := range path {
if i == len(path)-1 {
break
}
if k == "" {
c := strings.Join(path, ",")
k = fmt.Sprint(f.pathCache[c])
f.pathCache[c] = f.pathCache[c] + 1
}
if _, ok := dest[k].(map[string]any); !ok {
dest[k] = make(map[string]any)
}
dest = dest[k].(map[string]any)
}
p := path[len(path)-1]
if p == "" {
p = fmt.Sprint(len(dest))
}
val, _ = url.QueryUnescape(val)
dest[p] = val
}
func (f *form) parseArrayItem(dest map[string]any) any {
var arr []any
for i := 0; i < len(dest); i++ {
item, ok := dest[fmt.Sprint(i)]
if !ok {
return dest
}
arr = append(arr, item)
}
return arr
}
func (f *form) parseArray(dest map[string]any) map[string]any {
for k, v := range dest {
mv, ok := v.(map[string]any)
if ok {
f.parseArray(mv)
dest[k] = f.parseArrayItem(mv)
}
}
return dest
}
func DecodeForm(src []byte) (map[string]any, error) {
return newForm(FromByte(src)).decode()
}