Question
If there any bug on multipart form data file receiving? Browser on windows 10 cannot receive response correctly when use auth middleware to reject the request before execute any operational function.
Description
-
Env Windows 10 Edge browser (Chromium)
-
Process to error:
- Big size file, over 2 MB
- Uploading file with multipart form with any browser supported js function such as xhr, fetch or others
- If server code do not process the received form data in handler, but return response directly such as when auth fails.
-
You will get connection_reset error on browser.
-
Process to success: Just change the place of return statement on server code to be after any codes that have processed the received data.
By the way, no problem if use curl to send request directly or use postman to help construct the request.
// c.ShouldBind(&obj) -- before return, browser received 401 correctly
c.JSON(401, gin.H{"test": "test"})
return
// c.ShouldBind(&obj) -- after return, which means server does not do anything about the post data, browser will get connection_reset error
How to reproduce
- Server Side
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-contrib/cors"
"mime/multipart"
"net/http"
"strings"
)
type ProfileForm struct {
Files []*multipart.FileHeader `form:"files" binding:"required"`
Json string `form:"json" binding:"required"`
}
func main() {
router := gin.Default()
router.Use(cors.New(cors.Config{
AllowMethods: []string{"PUT", "PATCH", "POST", "OPTIONS"},
AllowHeaders: []string{"Origin"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
AllowOriginFunc: func(origin string) bool {
return true
},
MaxAge: 12 * time.Hour,
}))
// Set a lower memory limit for multipart forms (default is 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
obj := ProfileForm{}
if strings.Contains(c.GetHeader("content-type"), "multipart") {
c.JSON(401, gin.H{"test": "test"})
return
}
// Multipart form
if err := c.ShouldBind(&obj); err != nil {
c.JSON(406, gin.H{"error": err.Error()})
return
}
form, _ := c.MultipartForm()
files := form.File["upload[]"]
for _, file := range files {
log.Println(file.Filename)
// Upload the file to specific dst.
c.SaveUploadedFile(file, "./files")
}
c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
})
router.Run(":8080")
}
- Client Side
<!DOCTYPE html>
<body>
<input type="file" id="file_upload">
<button id="btn">send</button>
<script>
document.getElementById("btn").addEventListener("click", sendRequest);
function sendRequest(){
var data = new FormData()
data.append("json", JSON.stringify(
{"data": "test"}
))
var file = document.getElementById("file_upload").files[0]
data.append("files", file)
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function(){
if (xhr.status === 200 && xhr.readyState === 4) {
console.log(xhr.responseText)
} else{
console.log(xhr.responseText)
}
}
xhr.open("post", "http://127.0.0.1:8080/upload")
xhr.send(data)
}
</script>
</body>
Comment From: batara666
any update?
Comment From: lifest01
same problem