Skip to content

Commit

Permalink
fix(net/ghttp) parseForm MakeBodyRepeatableRead not effective
Browse files Browse the repository at this point in the history
  • Loading branch information
cyjaysong committed Feb 11, 2025
1 parent 20b1987 commit 7f199fe
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 10 deletions.
16 changes: 16 additions & 0 deletions net/ghttp/ghttp_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,22 @@ func (r *Request) IsAjaxRequest() bool {
return strings.EqualFold(r.Header.Get("X-Requested-With"), "XMLHttpRequest")
}

// IsMultiPartRequest checks and returns whether current request is an MultiPart request.
func (r *Request) IsMultiPartRequest() bool {
if contentType := r.Header.Get("Content-Type"); contentType != "" {
return gstr.Contains(contentType, "multipart/")
}
return false
}

// IsFormRequest checks and returns whether current request is an Form request.
func (r *Request) IsFormRequest() bool {
if contentType := r.Header.Get("Content-Type"); contentType != "" {
return gstr.Contains(contentType, "form")
}
return false
}

// GetClientIp returns the client ip of this request without port.
// Note that this ip address might be modified by client header.
func (r *Request) GetClientIp() string {
Expand Down
16 changes: 6 additions & 10 deletions net/ghttp/ghttp_request_param.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,27 +269,23 @@ func (r *Request) parseForm() {
return
}
if contentType := r.Header.Get("Content-Type"); contentType != "" {
var (
err error
repeatableRead = true
)
if gstr.Contains(contentType, "multipart/") {
var err error
if !r.IsMultiPartRequest() {
// To avoid big memory consuming.
// The `multipart/` type form always contains binary data, which is not necessary read twice.
repeatableRead = false
r.MakeBodyRepeatableRead(true)
}
if r.IsMultiPartRequest() {
// multipart/form-data, multipart/mixed
if err = r.ParseMultipartForm(r.Server.config.FormParsingMemory); err != nil {
panic(gerror.WrapCode(gcode.CodeInvalidRequest, err, "r.ParseMultipartForm failed"))
}
} else if gstr.Contains(contentType, "form") {
} else if r.IsFormRequest() {
// application/x-www-form-urlencoded
if err = r.Request.ParseForm(); err != nil {
panic(gerror.WrapCode(gcode.CodeInvalidRequest, err, "r.Request.ParseForm failed"))
}
}
if repeatableRead {
r.MakeBodyRepeatableRead(true)
}
if len(r.PostForm) > 0 {
// Parse the form data using united parsing way.
params := ""
Expand Down
36 changes: 36 additions & 0 deletions net/ghttp/ghttp_z_unit_feature_request_struct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,42 @@ func Test_Params_ParseForm(t *testing.T) {
})
}

// https://github.com/gogf/gf/pull/4143
func Test_Params_ParseForm_FixMakeBodyRepeatableRead(t *testing.T) {
type User struct {
Id int
Name string
}
s := g.Server(guid.S())
s.BindHandler("/parse-form", func(r *ghttp.Request) {
var user *User
if err := r.ParseForm(&user); err != nil {
r.Response.WriteExit(err)
}
hasBody := len(r.GetBody()) > 0
r.Response.WriteExit(hasBody)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()

time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
c := g.Client()
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(c.GetContent(ctx, "/parse-form"), `false`)
t.Assert(c.GetContent(ctx, "/parse-form", g.Map{
"id": 1,
"name": "john",
}), false)
t.Assert(c.PostContent(ctx, "/parse-form"), `false`)
t.Assert(c.PostContent(ctx, "/parse-form", g.Map{
"id": 1,
"name": "john",
}), true)
})
}

func Test_Params_ComplexJsonStruct(t *testing.T) {
type ItemEnv struct {
Type string
Expand Down

0 comments on commit 7f199fe

Please sign in to comment.