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()
}

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 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

Merging #2169 into master will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #2169   +/-   ##
=======================================
  Coverage   98.47%   98.47%           
=======================================
  Files          41       41           
  Lines        2298     2302    +4     
=======================================
+ Hits         2263     2267    +4     
  Misses         20       20           
  Partials       15       15           
Impacted Files Coverage Δ
binding/form_mapping.go 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 73ccfea...6655232. Read the comment docs.

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
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