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

Description

How to reproduce

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    g := gin.Default()
    g.GET("/_download", func(c *gin.Context) {
        c.FileAttachment("C:\temp\file", "test.txt")
    })
    g.Run(":9000")
}

Expectations

Get  http://localhost:9000/_download

Actual result

Get  http://localhost:9000/_download

[GIN-debug] redirecting request 301: /_download --> /_download
[GIN] 2023/10/17 - 09:41:23 | 301 |       456.6µs |             ::1 | GET      "/_download"
[GIN-debug] redirecting request 301: /_download --> /_download
[GIN] 2023/10/17 - 09:41:23 | 301 |       412.9µs |             ::1 | GET      "/_download"
[GIN-debug] redirecting request 301: /_download --> /_download

Environment

  • go version: go version go1.21.2 windows/amd64
  • gin version (or commit ref): v1.9.1
  • operating system: windows10

Comment From: shawn1251

In my experience, the 'redirecting request 301' error often occurs when only the directory path is provided instead of the full file path. Could you please double-check and ensure that the file path is specified?

The solution can be found in the documentation. The filename argument in the FileAttachment function is the name that will be used when the file is downloaded on the client side. It is important to provide the full file path instead of just the folder path.

Here is the relevant code snippet:

// FileAttachment writes the specified file into the body stream in an efficient way
// On the client side, the file will typically be downloaded with the given filename
func (c *Context) FileAttachment(filepath, filename string) {
    if isASCII(filename) {
        c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+escapeQuotes(filename)+`"`)
    } else {
        c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename))
    }
    http.ServeFile(c.Writer, c.Request, filepath)
}

Make sure to include the complete file path in the filepath parameter for the function to work correctly.

Comment From: ergudu

Here is the relevant code snippet: if d.IsDir() { url := r.URL.Path // redirect if the directory name doesn't end in a slash if url == "" || url[len(url)-1] != '/' { localRedirect(w, r, path.Base(url)+"/") return } }

Therefore, the correct way to write it is to add "/":

package main

import ( "github.com/gin-gonic/gin" )

func main() { g := gin.Default() g.GET("/_download/", func(c *gin.Context) { c.FileAttachment("C:\temp\file", "test.txt") }) g.Run(":9000") }

GET http://localhost:9000/_download/