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

Context Copy Problem getting data. #1883

Open
JomperBytes opened this issue May 6, 2019 · 1 comment
Open

Context Copy Problem getting data. #1883

JomperBytes opened this issue May 6, 2019 · 1 comment

Comments

@JomperBytes
Copy link

JomperBytes commented May 6, 2019

  • go version: 1.12

Description

Using FetRawData from an copied context delete the original context body

func RequestLogger() gin.HandlerFunc {

	return func(c *gin.Context) {

		c.Set("HostIP", c.ClientIP())
		cCp := c.Copy()

		go func() {
			logger := cCp.MustGet("logger").(utils.LogDataInterface)
			internalCode := msgmanager.CreateInternalCode(severities.INFO, services.PDF, sources.SAMESERVICE, operations.NA, entities.NA)

			if cCp.Request.Method == "POST" {
				data, _ := cCp.GetRawData()
				logger.LogData(0, cCp, "Request using POST Method", gelf.LOG_INFO, data, internalCode, nil)
			} else {
				logger.LogData(0, cCp, "Request using GET Method, look at URL for data", gelf.LOG_INFO, nil, internalCode, nil)
			}
		}()

		c.Next()
	}
}

data, _ := cCp.GetRawData() This line sometimes delete "c" body.

This happen just like in 10% of calls.

Changing GetRawData for ShouldBindBodyWith fix the problem.

func RequestLogger() gin.HandlerFunc {

	return func(c *gin.Context) {

		c.Set("HostIP", c.ClientIP())
		cCp := c.Copy()

		go func() {
			logger := cCp.MustGet("logger").(utils.LogDataInterface)
			internalCode := msgmanager.CreateInternalCode(severities.INFO, services.PDF, sources.SAMESERVICE, operations.NA, entities.NA)

			if cCp.Request.Method == "POST" {
				var data interface{}
				_ = cCp.ShouldBindBodyWith(&data, binding.JSON)
				logger.LogData(0, cCp, "Request using POST Method", gelf.LOG_INFO, data, internalCode, nil)
			} else {
				logger.LogData(0, cCp, "Request using GET Method, look at URL for data", gelf.LOG_INFO, nil, internalCode, nil)
			}
		}()

		c.Next()
	}
}

Screenshots

image

@dmarkham
Copy link
Contributor

dmarkham commented May 8, 2019

So I have not yet tried to reproduce this. But I have some ideas.

In short once someone reads c.Request.Body it is drained and empty, GetRawData in this case is racing for the data with other parts of the system your other middleware/handler or gin internals to read and close c.Request.Body

ShouldBindBodyWith is set up to be called more than once and saves a copy of the c.Request.Body. I'm not yet sure how it's fixing your issue, but as you report it is.

Guess in general rule for something that reads c.Request.Body means you have taken ownership of that data and need to be responsible for moving it to your next needed middleware or handlerFunc.

I'm not sure to many reasonable ways around this. when I get some time unless someone else does... I'll try to dig in at least enough to know for sure why.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants