Skip to content

Conversation

@guonaihong
Copy link
Contributor

Here is the code that can report an error

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"net/http"
	"os"
	"time"
)

type header struct {
	Duration   time.Duration `header:"duration"`
	CreateTime time.Time     `header:"createTime" time_format:"unix"`
}

func needFix1() {
	g := gin.Default()
	g.GET("/", func(c *gin.Context) {
		h := header{}
		err := c.ShouldBindHeader(&h)
		if err != nil {
			c.JSON(500, fmt.Sprintf("fail:%s\n", err))
			return
		}

		c.JSON(200, h)
	})

	g.Run(":8081")
}

func needFix2() {
	g := gin.Default()
	g.GET("/", func(c *gin.Context) {
		h := header{}
		err := c.ShouldBindHeader(&h)
		if err != nil {
			c.JSON(500, fmt.Sprintf("fail:%s\n", err))
			return
		}

		c.JSON(200, h)
	})

	g.Run(":8082")
}

func sendNeedFix1() {
	// send to needFix1
	sendBadData("http://127.0.0.1:8081", "duration")
}

func sendNeedFix2() {
	// send to needFix2
	sendBadData("http://127.0.0.1:8082", "createTime")
}

func sendBadData(url, key string) {
	req, err := http.NewRequest("GET", "http://127.0.0.1:8081", nil)
	if err != nil {
		fmt.Printf("err:%s\n", err)
		return
	}

	// Only the key and no value can cause an error
	req.Header.Add(key, "")
	rsp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	io.Copy(os.Stdout, rsp.Body)
	rsp.Body.Close()
}

func main() {
	go needFix1()
	go needFix2()

	time.Sleep(time.Second / 1000 * 200) // 200ms
	sendNeedFix1()
	sendNeedFix2()
}

@guonaihong guonaihong changed the title fix empty value error binding:fix empty value error Dec 6, 2019
@codecov
Copy link

codecov bot commented Dec 6, 2019

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.68%. Comparing base (3dc1cd6) to head (e0ee47d).
⚠️ Report is 222 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2169      +/-   ##
==========================================
- Coverage   99.21%   98.68%   -0.53%     
==========================================
  Files          42       44       +2     
  Lines        3182     2976     -206     
==========================================
- Hits         3157     2937     -220     
- Misses         17       26       +9     
- Partials        8       13       +5     
Flag Coverage Δ
?
--ldflags="-checklinkname=0" -tags sonic 98.67% <100.00%> (?)
-tags go_json 98.61% <100.00%> (?)
-tags nomsgpack 98.67% <100.00%> (?)
go-1.18 ?
go-1.19 ?
go-1.20 ?
go-1.21 ?
go-1.24 98.68% <100.00%> (?)
go-1.25 98.68% <100.00%> (?)
macos-latest 98.68% <100.00%> (-0.53%) ⬇️
ubuntu-latest 98.68% <100.00%> (-0.53%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

appleboy
appleboy previously approved these changes Jan 16, 2020
@appleboy appleboy added the type/bug Found something you weren't expecting? Report it here! label Jan 16, 2020
@appleboy appleboy added this to the 1.6 milestone Jan 16, 2020
@appleboy
Copy link
Member

@vkd @thinkerou Any feedbacks?


// ok
tests := []bindTestData{
{need: &needFixUnixNanoEmpty{}, got: &needFixUnixNanoEmpty{}, in: formSource{"createTime": []string{" "}}},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-empty string does not look to me as a default empty value. For me it looks like a wrong value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The strconv.ParseInt function in Go will report an error when it encounters data beginning with a space. The function of removing spaces is added so that the function does not report an error.

package main

import (
	"fmt"
	"strconv"
)

func main() {
	fmt.Println(strconv.ParseInt("  5", 10, 0))
	fmt.Println(strconv.ParseInt("5", 10, 0))
}

/*
0 strconv.ParseInt: parsing "  5": invalid syntax
5 <nil>

*/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and from my point of view the binding shouldn't do this.

}

func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
if value.Kind() != reflect.String {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not explained by the PR description.
Please update PR description with explanation what cases have you fixed and why.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is a string type, no spaces are removed, and the user data is not modified here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document your changes in the PR's description. Just add information about what is changed and why.

@guonaihong
Copy link
Contributor Author

Vote for this pr dispute. @appleboy @vkd @thinkerou
When dealing with int, float and other types, I recommend adding the string.TrimSpace function. The reason is that go's strconv.ParseUint and other functions will report an error when encountering data beginning with a space.

package main

import (
	"fmt"
	"strconv"
)

func main() {
	fmt.Println(strconv.ParseInt("  5", 10, 0))
	fmt.Println(strconv.ParseInt("5", 10, 0))
}

/*
0 strconv.ParseInt: parsing "  5": invalid syntax
5 <nil>

*/

strings.TrimSpace + 1

@vkd
Copy link
Contributor

vkd commented Jan 19, 2020

By my perspective, adding strings.TrimSpace will make the gin bindings is not unified.
It looks not usual for gin - because, as example, json binding doesn't do that kind of conversion.
I think keeping the same behavior for all kind of bindings is better.
@guonaihong thanks for your PR, but I vote for the not using the strings.TrimSpace in headers/form bindings.

strings.TrimSpace - 1

func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
// If it is a string type, no spaces are removed, and the user data is not modified here
if value.Kind() != reflect.String {
val = strings.TrimSpace(val)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If val is not string type, can call func TrimSpace(s string) string?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type of val is string, as explained below.
If the client command is the following code

curl -H 'intkey: v1" -H "strkey: v2" url
We define the following structure to parse the http header

type needHeader struct {
    IntKey int `header:"intkey"
    StrKey string `header:"strkey"
}

Such a data structure.
Before setting into the structure, regardless of the int or string required by the structure, it is of type string before being parsed.

@appleboy
Copy link
Member

@thinkerou move to 1.7 milestones?

@thinkerou
Copy link
Member

@thinkerou move to 1.7 milestones?

OK, thanks!

@thinkerou thinkerou modified the milestones: 1.6, 1.7 Mar 21, 2020
@thinkerou thinkerou modified the milestones: 1.7, v1.8 Nov 8, 2020
@thinkerou thinkerou modified the milestones: v1.8, v1.9 May 28, 2022
@thinkerou thinkerou modified the milestones: v1.9, v1.10 Jan 20, 2023
@appleboy appleboy modified the milestones: v1.10, v1.11 Mar 21, 2024
@appleboy appleboy modified the milestones: v1.11, v1.12 Jun 21, 2025
@appleboy
Copy link
Member

@guonaihong, please help resolve conflicts

@guonaihong
Copy link
Contributor Author

guonaihong commented Nov 28, 2025 via email

Here is the code that can report an error
```go
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"net/http"
	"os"
	"time"
)

type header struct {
	Duration   time.Duration `header:"duration"`
	CreateTime time.Time     `header:"createTime" time_format:"unix"`
}

func needFix1() {
	g := gin.Default()
	g.GET("/", func(c *gin.Context) {
		h := header{}
		err := c.ShouldBindHeader(&h)
		if err != nil {
			c.JSON(500, fmt.Sprintf("fail:%s\n", err))
			return
		}

		c.JSON(200, h)
	})

	g.Run(":8081")
}

func needFix2() {
	g := gin.Default()
	g.GET("/", func(c *gin.Context) {
		h := header{}
		err := c.ShouldBindHeader(&h)
		if err != nil {
			c.JSON(500, fmt.Sprintf("fail:%s\n", err))
			return
		}

		c.JSON(200, h)
	})

	g.Run(":8082")
}

func sendNeedFix1() {
	// send to needFix1
	sendBadData("http://127.0.0.1:8081", "duration")
}

func sendNeedFix2() {
	// send to needFix2
	sendBadData("http://127.0.0.1:8082", "createTime")
}

func sendBadData(url, key string) {
	req, err := http.NewRequest("GET", "http://127.0.0.1:8081", nil)
	if err != nil {
		fmt.Printf("err:%s\n", err)
		return
	}

	// Only the key and no value can cause an error
	req.Header.Add(key, "")
	rsp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	io.Copy(os.Stdout, rsp.Body)
	rsp.Body.Close()
}

func main() {
	go needFix1()
	go needFix2()

	time.Sleep(time.Second / 1000 * 200) // 200ms
	sendNeedFix1()
	sendNeedFix2()
}

```
@guonaihong guonaihong force-pushed the fix-binding-empty-value branch from 6655232 to 2891214 Compare November 30, 2025 13:05
- Replace 'interface{}' with 'any' alias in bindTestData struct
- Change assert.NoError to require.NoError in TestMappingTimeUnixNano and TestMappingTimeDuration to fail fast on mapping errors
@appleboy appleboy requested review from thinkerou and vkd November 30, 2025 13:30
@appleboy
Copy link
Member

@thinkerou @vkd Please help review the PR.

@guonaihong
Copy link
Contributor Author

Conflicts have been resolved @appleboy

Copy link
Contributor

@vkd vkd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good to me!

@appleboy appleboy merged commit b917b14 into gin-gonic:master Dec 3, 2025
26 of 27 checks passed
@appleboy
Copy link
Member

appleboy commented Dec 3, 2025

@guonaihong Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/bug Found something you weren't expecting? Report it here!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants