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
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).
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.
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)
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.
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)
}
}
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)
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With