mirror of
https://github.com/oarkflow/mq.git
synced 2025-10-06 16:36:53 +08:00
feat: [wip] - Implement html node
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
package dag
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@@ -14,6 +12,7 @@ import (
|
||||
"github.com/oarkflow/errors"
|
||||
|
||||
"github.com/oarkflow/mq"
|
||||
"github.com/oarkflow/mq/utils"
|
||||
|
||||
"github.com/oarkflow/mq/consts"
|
||||
"github.com/oarkflow/mq/jsonparser"
|
||||
@@ -216,9 +215,12 @@ func parseRequest(c *fiber.Ctx) (context.Context, []byte, error) {
|
||||
if body == nil {
|
||||
return ctx, nil, errors.New("empty form body")
|
||||
}
|
||||
formData := ParseFormToMap(body, &userContext.Query)
|
||||
if formData != nil {
|
||||
return ctx, nil, fmt.Errorf("failed to parse form data: %v", formData)
|
||||
val, err := utils.DecodeForm(body)
|
||||
if err != nil {
|
||||
return ctx, nil, fmt.Errorf("failed to parse form data: %v", err.Error())
|
||||
}
|
||||
for key, v := range val {
|
||||
userContext.Query[key] = v
|
||||
}
|
||||
result = userContext.Query
|
||||
default:
|
||||
@@ -232,52 +234,3 @@ func parseRequest(c *fiber.Ctx) (context.Context, []byte, error) {
|
||||
|
||||
return ctx, bt, nil
|
||||
}
|
||||
|
||||
// ParseFormToMap parses form-encoded data into the provided map
|
||||
func ParseFormToMap(body []byte, data *map[string]any) error {
|
||||
if data == nil {
|
||||
return errors.New("data map is nil")
|
||||
}
|
||||
if len(body) == 0 {
|
||||
return errors.New("empty form body")
|
||||
}
|
||||
start := 0
|
||||
for i := 0; i <= len(body); i++ {
|
||||
if i == len(body) || body[i] == '&' {
|
||||
if err := processPair(body[start:i], data); err != nil {
|
||||
return err
|
||||
}
|
||||
start = i + 1
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// processPair processes a key-value pair and inserts it into the map
|
||||
func processPair(pair []byte, data *map[string]any) error {
|
||||
if len(pair) == 0 {
|
||||
return nil // Ignore empty pairs
|
||||
}
|
||||
eqIndex := bytes.IndexByte(pair, '=')
|
||||
if eqIndex == -1 {
|
||||
return errors.New("malformed key-value pair")
|
||||
}
|
||||
|
||||
// Extract key and value
|
||||
key := pair[:eqIndex]
|
||||
value := pair[eqIndex+1:]
|
||||
|
||||
// Decode key and value (zero-allocation alternatives can replace this)
|
||||
decodedKey, err := url.QueryUnescape(string(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
decodedValue, err := url.QueryUnescape(string(value))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Insert into the map
|
||||
(*data)[decodedKey] = decodedValue
|
||||
return nil
|
||||
}
|
||||
|
12
examples/parse.go
Normal file
12
examples/parse.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/oarkflow/mq/utils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
queryString := []byte("fields[0][method]=GET&fields[0][path]=/user/:id&fields[0][handlerMsg]=User Profile&fields[1][method]=POST&fields[1][path]=/user/create&fields[1][handlerMsg]=Create User")
|
||||
fmt.Println(utils.DecodeForm(queryString))
|
||||
}
|
120
utils/form.go
Normal file
120
utils/form.go
Normal file
@@ -0,0 +1,120 @@
|
||||
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()
|
||||
}
|
Reference in New Issue
Block a user