Skip to content
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

net/gclient: fix parameters containing equal signs were tampered #3643

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions internal/httputil/httputils.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ func BuildParams(params interface{}, noUrlEncode ...bool) (encodedParamStr strin
urlEncode = !noUrlEncode[0]
}
// If there's file uploading, it ignores the url encoding.
if urlEncode {
if !urlEncode {
for k, v := range m {
if gstr.Contains(k, fileUploadingKey) || gstr.Contains(gconv.String(v), fileUploadingKey) {
urlEncode = false
urlEncode = true
break
}
}
Expand All @@ -67,6 +67,7 @@ func BuildParams(params interface{}, noUrlEncode ...bool) (encodedParamStr strin
if urlEncode {
if strings.HasPrefix(s, fileUploadingKey) && len(s) > len(fileUploadingKey) {
// No url encoding if uploading file.
s = fileUploadingKey + gurl.Encode(strings.TrimPrefix(s, fileUploadingKey))
} else {
s = gurl.Encode(s)
}
Expand Down
18 changes: 10 additions & 8 deletions net/gclient/gclient_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package gclient
import (
"bytes"
"context"
"github.com/gogf/gf/v2/encoding/gurl"
"io"
"mime/multipart"
"net/http"
Expand Down Expand Up @@ -230,16 +231,21 @@ func (c *Client) prepareRequest(ctx context.Context, method, url string, data ..
writer = multipart.NewWriter(buffer)
)
for _, item := range strings.Split(params, "&") {
array := strings.Split(item, "=")
if len(array[1]) > 6 && strings.Compare(array[1][0:6], httpParamFileHolder) == 0 {
path := array[1][6:]
array := strings.SplitN(item, "=", 2)
var (
fieldName = array[0]
fieldValue = array[1]
)
fieldValue, _ = gurl.Decode(fieldValue)
if len(fieldValue) > 6 && strings.Compare(fieldValue[0:6], httpParamFileHolder) == 0 {
path := fieldValue[6:]
if !gfile.Exists(path) {
return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `"%s" does not exist`, path)
}
var (
file io.Writer
formFileName = gfile.Basename(path)
formFieldName = array[0]
formFieldName = fieldName
)
if file, err = writer.CreateFormFile(formFieldName, formFileName); err != nil {
err = gerror.Wrapf(err, `CreateFormFile failed with "%s", "%s"`, formFieldName, formFileName)
Expand All @@ -257,10 +263,6 @@ func (c *Client) prepareRequest(ctx context.Context, method, url string, data ..
_ = f.Close()
}
} else {
var (
fieldName = array[0]
fieldValue = array[1]
)
if err = writer.WriteField(fieldName, fieldValue); err != nil {
err = gerror.Wrapf(err, `write form field failed with "%s", "%s"`, fieldName, fieldValue)
return nil, err
Expand Down
38 changes: 38 additions & 0 deletions net/gclient/gclient_z_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,44 @@ func Test_Client_File_And_Param(t *testing.T) {
})
}

// It posts data along with file uploading.
// It does not url-encodes the parameters.
func Test_Client_Complex_File_And_Complex_Param(t *testing.T) {
s := g.Server(guid.S())
s.BindHandler("/", func(r *ghttp.Request) {
tmpPath := gfile.Temp(guid.S())
err := gfile.Mkdir(tmpPath)
gtest.AssertNil(err)
defer gfile.Remove(tmpPath)

file := r.GetUploadFile("file")
_, err = file.Save(tmpPath)
gtest.AssertNil(err)
r.Response.Write(
r.Get("json"),
gfile.GetContents(gfile.Join(tmpPath, gfile.Basename(file.Filename))),
r.Get("url"),
)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()

time.Sleep(100 * time.Millisecond)

gtest.C(t, func(t *gtest.T) {
path := gtest.DataPath("upload", "file&&name=1.txt")
data := g.Map{
"file": "@file:" + path,
"json": `{"uuid": "luijquiopm", "isRelative": false, "fileName": "test111.xls"}`,
"url": fmt.Sprintf("https://127.0.0.1:%d/rand?key=%s&value=%s", s.GetListenedPort(), guid.S(), guid.S()),
}
c := g.Client()
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(c.PostContent(ctx, "/", data), data["json"].(string)+gfile.GetContents(path)+data["url"].(string))
})
}

func Test_Client_Middleware(t *testing.T) {
s := g.Server(guid.S())
isServerHandler := false
Expand Down
1 change: 1 addition & 0 deletions net/gclient/testdata/upload/file&&name=1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
file&&name1.txt: This file is for uploading unit test case.
28 changes: 28 additions & 0 deletions net/ghttp/ghttp_z_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,34 @@ func Test_BuildParams(t *testing.T) {
})
}

func Test_BuildParams_WithComplexFileName(t *testing.T) {
// normal && special cases
params := map[string]string{
"val": "12345678",
"code1": "x&a=1", // for fix
"code2": "x&a=111",
"id": "1+- ", // for fix
"f": "1#a=+- ",
"v": "",
"n": "null",
"file": "@file:text&name=1.xml",
}

gtest.C(t, func(t *gtest.T) {
res1 := httputil.BuildParams(params)
vs, _ := url.ParseQuery(res1)
t.Assert(len(params), len(vs))
for k := range vs {
vv := vs.Get(k)
_, ok := params[k]
// check no additional param
t.Assert(ok, true)
// check equal
t.AssertEQ(params[k], vv)
}
})
}

func Test_ServerSignal(t *testing.T) {
if runtime.GOOS == "windows" {
t.Log("skip windows")
Expand Down
Loading