Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to server a file from a handler in golang

Tags:

go

I was wondering how to serve a file from a handler. I'm using go and gin and I've tried to do.

func DownloadHandler(c *gin.Context) {
   c.File("./downloads/file.zip")
}

and

func DownloadConfigs(c *gin.Context) {
   http.ServeFile(c.Writer, c.Request, "./downloads/file.zip")
}

and both of those solutions without the dot as well.

I'm open to any solution and because gin is compatible with the standard http lib, I can use non-gin specific solutions as well

like image 216
Ousmane Traore Avatar asked Jul 26 '15 14:07

Ousmane Traore


People also ask

How do I serve a static file in go?

Once you run the command $ go run server.go it will open the index. html file on the browser and will forward the rest of the traffic inside your project as you specified in the code (make sure you've placed all your files inside the static folder before you run your code).

How do I run a go Lang server?

Start the web server with go run server.go and visit http://localhost:8080/hello . If the server responds with "Hello!" , you can continue to the next step, where you'll learn how to add basic security to your Golang web server routes.

What is http handler Golang?

The Handler interface is an interface with a single method ServeHTTP which takes a http. Response and a http. Request as inputs. type Handler interface { ServeHTTP(ResponseWriter, *Request)

What is Servemux in Golang?

Whereas a servemux (also known as a router) stores a mapping between the predefined URL paths for your application and the corresponding handlers. Usually you have one servemux for your application containing all your routes. Go's net/http package ships with the simple but effective http.


2 Answers

Here is a complete working example using the standard http package. Please note, that the filename or path you use is relative to your current working directory.

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request)     {
        http.ServeFile(w, r, "file")
    })

    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}
like image 53
csabiftw Avatar answered Sep 27 '22 03:09

csabiftw


Just use this function from gin.Context: https://godoc.org/github.com/gin-gonic/gin#Context.File

Something like this:

const DOWNLOADS_PATH = "downloads/"

ginRouter.GET("/download-user-file/:filename", func (ctx *gin.Context) {
    fileName := ctx.Param("filename")
    targetPath := filepath.Join(DOWNLOADS_PATH, fileName)
    //This ckeck is for example, I not sure is it can prevent all possible filename attacks - will be much better if real filename will not come from user side. I not even tryed this code
    if !strings.HasPrefix(filepath.Clean(targetPath), DOWNLOADS_PATH) {
        ctx.String(403, "Look like you attacking me")
        return
    }
    //Seems this headers needed for some browsers (for example without this headers Chrome will download files as txt)
    ctx.Header("Content-Description", "File Transfer")
    ctx.Header("Content-Transfer-Encoding", "binary")
    ctx.Header("Content-Disposition", "attachment; filename="+fileName )
    ctx.Header("Content-Type", "application/octet-stream")
    ctx.File(targetPath)
})
like image 23
Fedir Tsapana Avatar answered Sep 26 '22 03:09

Fedir Tsapana