From 232962256404900d68db44879c626dae121c3761 Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 25 May 2023 10:58:06 +0800 Subject: [PATCH] add multiple methods support for united routes registering (#2664) --- internal/utils/utils_io.go | 28 ++++--------------- net/ghttp/ghttp_request_param.go | 13 +++++++-- net/ghttp/ghttp_z_unit_feature_config_test.go | 2 +- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/internal/utils/utils_io.go b/internal/utils/utils_io.go index f51bbe3b8..c2916937f 100644 --- a/internal/utils/utils_io.go +++ b/internal/utils/utils_io.go @@ -8,9 +8,6 @@ package utils import ( "io" - "io/ioutil" - - "github.com/gogf/gf/v2/errors/gerror" ) // ReadCloser implements the io.ReadCloser interface @@ -20,7 +17,7 @@ import ( type ReadCloser struct { index int // Current read position. content []byte // Content. - repeatable bool + repeatable bool // Mark the content can be repeatable read. } // NewReadCloser creates and returns a RepeatReadCloser object. @@ -31,30 +28,15 @@ func NewReadCloser(content []byte, repeatable bool) io.ReadCloser { } } -// NewReadCloserWithReadCloser creates and returns a RepeatReadCloser object -// with given io.ReadCloser. -func NewReadCloserWithReadCloser(r io.ReadCloser, repeatable bool) (io.ReadCloser, error) { - content, err := ioutil.ReadAll(r) - if err != nil { - err = gerror.Wrapf(err, `ioutil.ReadAll failed`) - return nil, err - } - defer r.Close() - return &ReadCloser{ - content: content, - repeatable: repeatable, - }, nil -} - // Read implements the io.ReadCloser interface. func (b *ReadCloser) Read(p []byte) (n int, err error) { + // Make it repeatable reading. + if b.index >= len(b.content) && b.repeatable { + b.index = 0 + } n = copy(p, b.content[b.index:]) b.index += n if b.index >= len(b.content) { - // Make it repeatable reading. - if b.repeatable { - b.index = 0 - } return n, io.EOF } return n, nil diff --git a/net/ghttp/ghttp_request_param.go b/net/ghttp/ghttp_request_param.go index 5c30f9346..dc4898612 100644 --- a/net/ghttp/ghttp_request_param.go +++ b/net/ghttp/ghttp_request_param.go @@ -153,6 +153,13 @@ func (r *Request) Get(key string, def ...interface{}) *gvar.Var { // GetBody retrieves and returns request body content as bytes. // It can be called multiple times retrieving the same body content. func (r *Request) GetBody() []byte { + if r.bodyContent == nil { + r.bodyContent = r.makeBodyRepeatableRead(true) + } + return r.bodyContent +} + +func (r *Request) makeBodyRepeatableRead(repeatableRead bool) []byte { if r.bodyContent == nil { var err error if r.bodyContent, err = ioutil.ReadAll(r.Body); err != nil { @@ -162,8 +169,8 @@ func (r *Request) GetBody() []byte { } panic(gerror.WrapCode(gcode.CodeInternalError, err, errMsg)) } - r.Body = utils.NewReadCloser(r.bodyContent, true) } + r.Body = utils.NewReadCloser(r.bodyContent, repeatableRead) return r.bodyContent } @@ -261,6 +268,8 @@ func (r *Request) parseForm() { return } if contentType := r.Header.Get("Content-Type"); contentType != "" { + // Mark the request body content can be read just once next time. + r.makeBodyRepeatableRead(false) var err error if gstr.Contains(contentType, "multipart/") { // multipart/form-data, multipart/mixed @@ -274,7 +283,7 @@ func (r *Request) parseForm() { } } if len(r.PostForm) > 0 { - // Re-parse the form data using united parsing way. + // Parse the form data using united parsing way. params := "" for name, values := range r.PostForm { // Invalid parameter name. diff --git a/net/ghttp/ghttp_z_unit_feature_config_test.go b/net/ghttp/ghttp_z_unit_feature_config_test.go index 9fad70d73..e3542ce2a 100644 --- a/net/ghttp/ghttp_z_unit_feature_config_test.go +++ b/net/ghttp/ghttp_z_unit_feature_config_test.go @@ -155,7 +155,7 @@ func Test_ClientMaxBodySize_File(t *testing.T) { defer gfile.Remove(path) t.Assert( gstr.Trim(c.PostContent(ctx, "/", "name=john&file=@file:"+path)), - "r.ParseMultipartForm failed: http: request body too large", + "Read from request Body failed: http: request body too large", ) }) }