fix(script): convert non-string header, param and cookie values to text

This commit is contained in:
aykhans committed 2026-09-26 01:17:49 +04:00
1 parent a30c862936
commit c32949c8e0
3 files changed
+50 -23

No files matched your search

+2 -2
View File
@@ -456,7 +456,7 @@ function transform(req)
end end
``` ```
> **Note:** Header, parameter, and cookie values can be a single string or a table (array) for multiple values per key (e.g. `{"val1", "val2"}`). > **Note:** Header, parameter, and cookie values can be a single string or a table (array) for multiple values per key (e.g. `{"val1", "val2"}`). Numbers and booleans are converted to text, other values are skipped.
> **Note:** Lua scripts can send their own HTTP requests with `http` and work with JSON through the global `json` table. See [HTTP Requests in Scripts](#http-requests-in-scripts). > **Note:** Lua scripts can send their own HTTP requests with `http` and work with JSON through the global `json` table. See [HTTP Requests in Scripts](#http-requests-in-scripts).
@@ -523,7 +523,7 @@ function transform(req) {
} }
``` ```
> **Note:** Header, parameter, and cookie values can be a single string or an array for multiple values per key (e.g. `["val1", "val2"]`). > **Note:** Header, parameter, and cookie values can be a single string or an array for multiple values per key (e.g. `["val1", "val2"]`). Numbers and booleans are converted to text, other values are skipped.
> **Note:** JavaScript scripts can send their own HTTP requests with `http`. See [HTTP Requests in Scripts](#http-requests-in-scripts). > **Note:** JavaScript scripts can send their own HTTP requests with `http`. See [HTTP Requests in Scripts](#http-requests-in-scripts).
+24 -10
View File
@@ -2,6 +2,7 @@ package script
import ( import (
"errors" "errors"
"strconv"
"github.com/dop251/goja" "github.com/dop251/goja"
"go.aykhans.me/sarin/internal/types" "go.aykhans.me/sarin/internal/types"
@@ -195,22 +196,23 @@ func (e *JsEngine) objectToStringSliceMap(obj *goja.Object) map[string][]string
result := make(map[string][]string) result := make(map[string][]string)
for _, key := range obj.Keys() { for _, key := range obj.Keys() {
v := obj.Get(key) v := obj.Get(key)
if v == nil || goja.IsUndefined(v) || goja.IsNull(v) {
continue
}
// Check if it's an array // Check if it's an array
if arr, ok := v.Export().([]any); ok { if arr, ok := v.(*goja.Object); ok && arr.ClassName() == "Array" {
var values []string length := int(arr.Get("length").ToInteger())
for _, item := range arr { values := make([]string, 0, length)
if s, ok := item.(string); ok { for i := range length {
values = append(values, s) if text, ok := jsStringValue(arr.Get(strconv.Itoa(i))); ok {
values = append(values, text)
} }
} }
result[key] = values result[key] = values
} else { continue
}
// Single value, wrap it in a slice // Single value, wrap it in a slice
result[key] = []string{v.String()} if text, ok := jsStringValue(v); ok {
result[key] = []string{text}
} }
} }
return result return result
@@ -231,3 +233,15 @@ func (e *JsEngine) exceptionError(err error) error {
} }
return errors.New(message) return errors.New(message)
} }
// jsStringValue renders a JavaScript primitive the way the script would see it.
// Objects, arrays and functions have no useful text form, so they are skipped.
func jsStringValue(v goja.Value) (string, bool) {
if v == nil || goja.IsUndefined(v) || goja.IsNull(v) {
return "", false
}
if _, isObject := v.(*goja.Object); isObject {
return "", false
}
return v.String(), true
}
+24 -11
View File
@@ -168,20 +168,33 @@ func (e *LuaEngine) tableToStringSliceMap(t *lua.LTable) map[string][]string {
} }
key := string(k.(lua.LString)) key := string(k.(lua.LString))
switch v.Type() { if v.Type() == lua.LTTable {
case lua.LTString: // Array of values, keys outside 1..n are skipped
// Single string value arr := v.(*lua.LTable)
result[key] = []string{string(v.(lua.LString))} length := arr.Len()
case lua.LTTable: values := make([]string, 0, length)
// Array of strings for i := 1; i <= length; i++ {
var values []string if text, ok := luaScalarString(arr.RawGetInt(i)); ok {
v.(*lua.LTable).ForEach(func(_, item lua.LValue) { values = append(values, text)
if item.Type() == lua.LTString { }
values = append(values, string(item.(lua.LString)))
} }
})
result[key] = values result[key] = values
return
}
if text, ok := luaScalarString(v); ok {
result[key] = []string{text}
} }
}) })
return result return result
} }
// luaScalarString renders strings, numbers and booleans as text.
func luaScalarString(v lua.LValue) (string, bool) {
switch v.Type() {
case lua.LTString, lua.LTNumber, lua.LTBool:
return v.String(), true
default:
return "", false
}
}