echo icon indicating copy to clipboard operation
echo copied to clipboard

Empty string turns into "false" bool during binding

Open mariaefi29 opened this issue 5 years ago • 12 comments

Issue Description

Empty string turns into false bool during binding in requests with content types multipart/form-data and application/x-www-form-urlencoded.

Checklist

  • [x] Dependencies installed
  • [x] No typos
  • [x] Searched existing issues and docs

Expected behaviour

When we bind requests parameters into a struct with a bool field, we expect binding to fail with http.StatusBadRequest if the required bool parameter contains an empty string.

We have this similar behaviour during json.Unmarshal: it cannot unmarshal empty string into a bool variable. It throws an explicit error.

Actual behaviour

If the required bool parameter is an empty string in a request with content types multipart/form-data and application/x-www-form-urlencoded, binding into a struct makes this parameter a bool variable with false value. It doesn't throw any errors.

Steps to reproduce

This unexpected behaviour is due to the function in bind.go file:

func setBoolField(value string, field reflect.Value) error {
	if value == "" {
		value = "false"
	}
	boolVal, err := strconv.ParseBool(value)
	if err == nil {
		field.SetBool(boolVal)
	}
	return err
}

Working code to debug

type request struct {
	Activate bool `form:"activate" `
}

var req UploadRequest
if err := c.Bind(&req); err != nil {
	return err
}

Version/commit

v4.1.15

mariaefi29 avatar Mar 03 '20 12:03 mariaefi29

Dear developers,

Do you have any updates on that issue?

mariaefi29 avatar Mar 26 '20 08:03 mariaefi29

This does not sound wrong actually. A boolean is either true or false and you declare Activate as a bool. You should change it to string if you expected an empty string to be a valid value.

Strings should not change "" to "false" of course, so I hope this does solve your problem.

lammel avatar Mar 30 '20 10:03 lammel

Dear @lammel,

I don't expect empty string to be a valid value for a bool type :) quite the opposite. That's what I was talking about: empty string is invalid value and it shouldn't turn into a valid one like false.

I would remove this from your function:

if value == "" {
		value = "false"
	}

What do you think? Do you need a PR for that?

mariaefi29 avatar Mar 30 '20 10:03 mariaefi29

I'm only a contributor not the owner of the function.

The same handling to set a valid value for an empty string is done for int, uint, float. Which is probably that way since in Go a string is initialized as an empty string anyway.

This would definitely be a breaking change and can be considered for v5. Some users out there might even rely on that behaviour to retrieve bad values in Params.

@vishr Should we tag issue as "v5" or create a new ticket for strict JSON validation?

lammel avatar Mar 30 '20 11:03 lammel

Should we tag issue as "v5" or create a new ticket for strict JSON validation?

@lammel Thanks. Will tag as v5.

vishr avatar Mar 30 '20 19:03 vishr

Thank you!!

mariaefi29 avatar Mar 31 '20 05:03 mariaefi29

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar May 30 '20 07:05 stale[bot]

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jul 29 '20 22:07 stale[bot]

https://github.com/labstack/echo/pull/1578

mariaefi29 avatar Jul 30 '20 05:07 mariaefi29

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Oct 04 '20 02:10 stale[bot]

This issue has been automatically marked as stale because it has not had recent activity. It will be closed within a month if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Dec 25 '20 13:12 stale[bot]

@lammel maybe we should consider changing this now.

We recently had https://github.com/labstack/echo/discussions/2055#discussioncomment-1879293 and I started to think that this "defaulting" makes e.Bind() quite unintuitive or code like that

		if err := (&echo.DefaultBinder{}).BindPathParams(c, u); err != nil {
			return err
		}
		if err := (&echo.DefaultBinder{}).BindQueryParams(c, u); err != nil {
			return err
		}
func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
	if err := b.BindPathParams(c, i); err != nil {
		return err
	}
	if c.Request().Method == http.MethodGet || c.Request().Method == http.MethodDelete {
		if err = b.BindQueryParams(c, i); err != nil {
			return err
		}
	}
	return b.BindBody(c, i)
}

if path params are successfully bound and now we do query params binding - binder will zero/default these values if there are no query values. which is counterintiutive - which makes "priorities" nonexistent. Body binding does not do that as json/xml encoder do not overwrite non-existent fields.

aldas avatar Jan 02 '22 18:01 aldas