gin icon indicating copy to clipboard operation
gin copied to clipboard

Fail to POST when omitting slash at the end with asterisk path parameter

Open yuqingc opened this issue 6 years ago • 6 comments

  • With issues:

    • Use the search tool before opening a new issue.
    • Please provide source code and commit sha if you found a bug.
    • Review existing issues and provide feedback or react to them.
  • go version: 1.11

  • gin version (or commit ref): 1.3.0

  • operating system: Ubuntu 18.04 & Ubuntu 16.04 & macOS 10.14(Mojave)

Description

Hi, guys. I use the POST function to handle an uploading request. The router part of my code is like this

Router.MaxMultipartMemory = 8 << 20 // 8 MiB
v1 := Router.Group("/api/v1")
{
	// some other routes
	v1.POST("/default/*contentPath", v1handlers.HandlePost)
}

The HandlePost function handles an uploading process. However, when I tried to request with the url api/v1/default. The following message showed up in the console:

redirecting request 307: /api/v1/default --> /api/v1/default/

and there was an error:

get form err: multipart: NextPart: bufio: buffer full

After that, I tried uploading a super small file. The console said redirecting request 307: /api/v1/default --> /api/v1/default/ and the request was just pending there forever... I breakpointed the handling function and found out that the function was never called.

By the way, everything works fine if I use the full path /api/v1/default/ or /api/v1/default/some/other/path.

How can I solve this problem? Is it a bug or is it because I didn't use the correct path parameters?

Screenshots

yuqingc avatar Oct 12 '18 08:10 yuqingc

redirecting request 307: /api/v1/default --> /api/v1/default/

had told you 307, so you should use api/v1/default/ not api/v1/default

thinkerou avatar Oct 12 '18 09:10 thinkerou

@thinkerou With other method like GET, the url api/v1/default is successfully redirected to api/v1/default/. Why does the redirecting mechanism not work when POSTing a file?

yuqingc avatar Oct 12 '18 10:10 yuqingc

url api/v1/default is successfully redirected to api/v1/default/

what's mean?

	r.GET("/get/*y", func(c *gin.Context) {
		c.JSON(200, gin.H{"msg": "hello"})
	})

curl:

➜  ~ curl -v localhost:8080/get
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /get HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Content-Type: text/html; charset=utf-8
< Location: /get/
< Date: Fri, 12 Oct 2018 11:44:17 GMT
< Content-Length: 40
<
<a href="/get/">Moved Permanently</a>.

* Connection #0 to host localhost left intact
➜  ~ curl -v localhost:8080/get/
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /get/ HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Date: Fri, 12 Oct 2018 11:44:31 GMT
< Content-Length: 15
<
* Connection #0 to host localhost left intact
{"msg":"hello"}

BTW, please post one mini simple which I can reproduce it?

thinkerou avatar Oct 12 '18 11:10 thinkerou

@thinkerou Thanks for your reply. This is a history version of my project where I use gin and get this issue. https://github.com/yuqingc/rmdashrf/tree/v0.2.0

This is the router file. Original file: https://github.com/yuqingc/rmdashrf/blob/v0.2.0/pkg/routes/api.go

var Router = gin.Default()
func init() {
	Router.MaxMultipartMemory = 8 << 20 // 8 MiB
	v1 := Router.Group("/api/v1")
	{
		v1.GET("/default/*contentPath", v1handlers.HandleGet)
		// some other routes
		v1.POST("/default/*contentPath", v1handlers.HandlePost)
	}
}

This is the handling function which processes uploading a file. Original file: https://github.com/yuqingc/rmdashrf/blob/v0.2.0/pkg/v1handlers/post.go

func handlePost(c *gin.Context) {
	paramContentPath := c.Param("contentPath")

	// upload filey
	file, err := c.FormFile("file")
	if err != nil {
		c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
		return
	}

	dst := path.Join(MountedVolume, paramContentPath, file.Filename)

	if err := c.SaveUploadedFile(file, dst); err != nil {
		c.String(http.StatusBadRequest, fmt.Sprintf("upload file err: %s", err.Error()))
		return
	}

	c.String(http.StatusOK, "file uploaded")
}

I tested my API with Postman. Everything works fine when I request with http://localhost:8080/api/v1/default/ or http://localhost:8080/api/v1/default/another/path. However, when I request http://localhost:8080/api/v1/default, I get the following problems.

  • Uploading a large file causes this error:
get form err: multipart: NextPart: bufio: buffer full
image
  • Uploading a small file makes the request stuck over there and no response is received.
image

This is the output of gin

image

I breakpointed the handling function. It seems that the handling function handlePost is never called when uploading a small file.

I understand the correct route should contain a slash at the end, but Gin should automatically redirect /api/v1/default to /api/v1/default/ according to gin doc. The redirecting works fine with other method, say, GET, PATCH and without uploading a file, etc.

yuqingc avatar Oct 12 '18 13:10 yuqingc

@yuqingc probably that's a problem of Postman not following the redirect (or there is an option to follow the redirects). The server responded with the redirect (see the log), it's the client that should make a new request

isgj avatar Oct 17 '18 13:10 isgj

@isgj Hey, I'm following this thread due to a similar problem with redirect, I'm requesting using curl and I'm getting 301 redirecting and the client side request just fails.

Image reference: Left terminal: Server Right terminal: Client image

prakharrai1609 avatar Nov 17 '23 14:11 prakharrai1609