-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
Fiber version/commit
v1.10.1
Issue description
The method fiber.Ctx.Params(key string) string returns strings that share the same data buffer. This means that once a new string is returned, all previously returned strings will be changed to the new string's content, no matter how much they have been copied and passed around, since their data buffer is the same. This behavior is clearly seen in PoC below. unsafe is used to parse the header of each string returned from the Params method and then its content is printed. Notice how the data pointer is identical for all strings, meaning that they all use the same data buffer.
The only workaround right now is to explicitly copy the data buffer into a new buffer and create a string from the new buffer:
newBuffer := make([]byte, len(result))
copy(newBuffer, result)
newResult := string(newBuffer)This behavior is absolutely unexpected, as strings in Go are expected to be immutable. I have not tracked down exactly what causes this issue, but I suspect that it may be a side effect from an inherited optimization by fasthttp. If this is true, I suspect that there are other methods that behave the same way as well. This behavior should be changed, or a clear documentation notice should be placed that indicates this side effect.
PoC
package main
import (
"fmt"
"github.com/gofiber/fiber"
"net/http"
"reflect"
"sync"
"unsafe"
)
var results []string
var wg sync.WaitGroup
func main() {
go server()
client()
wg.Wait()
}
func client() {
wg.Add(3)
http.Get("http://127.0.0.1:3000/aaa")
http.Get("http://127.0.0.1:3000/bbbb")
http.Get("http://127.0.0.1:3000/c")
}
func server() {
app := fiber.New()
app.Get("/:test", func(c *fiber.Ctx) {
result := c.Params("test")
hdr := (*reflect.StringHeader)(unsafe.Pointer(&result))
results = append(results, result)
fmt.Printf("Param string: %+v Value:%s\n", hdr, result)
fmt.Printf("Results: %+v\n", results)
wg.Done()
})
app.Listen(3000)
}Output
Param string: &{Data:824633868529 Len:3} Value:aaa
Results: [aaa]
Param string: &{Data:824633868529 Len:4} Value:bbbb
Results: [bbb bbbb]
Param string: &{Data:824633868529 Len:1} Value:c
Results: [cbb cbbb c]