-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🐛 [Bug]: BodyParser will fail to parse correctly into the slices of the struct if input data contains comma #2557
Comments
Thanks for opening your first issue here! 🎉 Be sure to follow the issue template! If you need help or want to chat with us, join us on Discord https://gofiber.io/discord |
the usage is incorrect, you cannot use the same key for multiple elements in one form regardless of the backend, the data is already overwritten during the transfer from the frontend and the last value with the same key should win |
Nope. The root cause of this bug is in the following implementation of BodyParser: if strings.HasPrefix(ctype, MIMEApplicationForm) {
data := make(map[string][]string)
var err error
c.fasthttp.PostArgs().VisitAll(func(key, val []byte) {
if err != nil {
return
}
k := c.app.getString(key)
v := c.app.getString(val)
if strings.Contains(k, "[") {
k, err = parseParamSquareBrackets(k)
}
//why do this ? split values by comma? this is input data from users.
if strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) {
values := strings.Split(v, ",")
for i := 0; i < len(values); i++ {
data[k] = append(data[k], values[i])
}
} else {
data[k] = append(data[k], v)
}
})
return c.parseToStruct(bodyTag, out, data)
} |
ok good to know |
why don't you send the structure right away as you expect it? <html>
<head>
</head>
<body>
<form method="post" action="/">
<input name='todo.0' type='text' value='a,b'>
<input name='todo.1' type='text' value='c'>
<input type='submit' value='submit'>
</form>
</body>
</html> |
Dear sir: Please see the following Go's standard net/http package for references, for my example, r.Form["todo"] will get multiple values . // FormValue returns the first value for the named component of the query.
// POST and PUT body parameters take precedence over URL query string values.
// FormValue calls ParseMultipartForm and ParseForm if necessary and ignores
// any errors returned by these functions.
// If key is not present, FormValue returns the empty string.
// To access multiple values of the same key, call ParseForm and
// then inspect Request.Form directly.
func (r *Request) FormValue(key string) string {
if r.Form == nil {
r.ParseMultipartForm(defaultMaxMemory)
}
if vs := r.Form[key]; len(vs) > 0 {
return vs[0]
}
return ""
}
// Form contains the parsed form data, including both the URL
// field's query parameters and the PATCH, POST, or PUT form data.
// This field is only available after ParseForm is called.
// The HTTP client ignores Form and uses Body instead.
Form url.Values
// PostForm contains the parsed form data from PATCH, POST
// or PUT body parameters.
//
// This field is only available after ParseForm is called.
// The HTTP client ignores PostForm and uses Body instead.
PostForm url.Values html sample: <html>
<head>
</head>
<body>
<form method="post" action="/">
<input name='todo' type='text' value='a,b'>
<input name='todo' type='text' value='c'>
<input type='submit' value='submit'>
</form>
</body>
</html> backend code sample with net/http: package main
import (
"fmt"
"log"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
r.ParseForm()
fmt.Println(r.Form["todo"])
fmt.Println(len(r.Form["todo"])) // slice size 2
}
}
func main() {
http.HandleFunc("/", hello)
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
} output:
but the usecases above in GoFiber will have the wrong result because the data contains comma: [a,b,c], and slice size is 3, that is GoFibier's different behavior compared to other framework or Go built-in net/http package. |
@ReneWerner87 Sorry for my bad English, I hope you understand what I mentioned. Could you please look at the implementation BodyParser() function. And please look at my explanation about how standard net/http respond this. In addition to standard net/http, I also try other web framework like gin, and the result is expected as size 2. <html>
<head>
</head>
<body>
<form method="post" action="http://localhost:8080/">
<input name='todo' type='text' value='a,b'>
<input name='todo' type='text' value='c'>
<input type='submit' value='submit'>
</form>
</body>
</html> package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
type Form struct {
Todo []string `form:"todo"`
}
func main() {
router := gin.Default()
router.POST("/", func(c *gin.Context) {
var frm Form
c.Bind(&frm)
fmt.Println(len(frm.Todo))
fmt.Println(frm.Todo)
})
router.Run(":8080")
} standard net/http: <html>
<head>
</head>
<body>
<form method="post" action="/">
<input name='todo' type='text' value='a,b'>
<input name='todo' type='text' value='c'>
<input type='submit' value='submit'>
</form>
</body>
</html> package main
import (
"fmt"
"log"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
r.ParseForm()
fmt.Println(r.Form["todo"])
fmt.Println(len(r.Form["todo"])) // slice size 2
}
}
func main() {
http.HandleFunc("/", hello)
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
} So the problem is the following code in GoFiber as I mentioned: if strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) {
values := strings.Split(v, ",")
for i := 0; i < len(values); i++ {
data[k] = append(data[k], values[i])
}
} else {
data[k] = append(data[k], v)
} |
Release https://github.com/gofiber/fiber/releases/tag/v2.0.3 |
@renanbastos93 |
@ReneWerner87 please guest what will happen in GoFiber、net/http、Gin or other frameworks ?
Oh My, GoFiber split two teachers name by '," in the format "Family name, Given name" to a slice containing 4 elements,
and tell backend code: " User just enter 4 teachers " |
@rere61, Thank you so much. |
You can update gofiber to the latest version, and your problem should be solved. |
Bug Description
In an HTML form, if there are multiple input elements with same name and the user enters content containing commas(,), thenBodyParser() function will fail to parse correctly into the slices member of the struct
How to Reproduce
Steps to reproduce the behavior:
Expected Behavior
The number of elements in the slice member parsed into the struct must be the same as the number of input elements in the HTML form, and their content must also match.
Fiber Version
v2.48.0
Code Snippet (optional)
Checklist:
The text was updated successfully, but these errors were encountered: