gofiber / fiber

⚡️ Express inspired web framework written in Go
https://gofiber.io
MIT License
33.2k stars 1.64k forks source link

🐛 [Bug]: c.Download returns 404 error when file is over 2gb #2377

Closed G2G2G2G closed 1 year ago

G2G2G2G commented 1 year ago

Bug Description

title

How to Reproduce

Steps to reproduce the behavior:

  1. create a file that is over 2gb to test this dd if=/dev/zero of=filetest.mp4 bs=10M count=210
  2. use the c.Download return c.Download("./filetest.mp4", "wtf.mp4")

Expected Behavior

it should download.

You can do

dd if=/dev/zero of=filetest.mp4 bs=10M count=200

which will give you a 2GB file this will work fine. and it will ask you to save the file as normal but if you do

dd if=/dev/zero of=filetest.mp4 bs=10M count=210

it is now going to send a 404 error header

Fiber Version

tested the last 4 ones

Code Snippet (optional)

package main

import "github.com/gofiber/fiber/v2"
import "log"

func main() {
  app := fiber.New()

app.Get("/:id/:uid", dler)

  log.Fatal(app.Listen(":3000"))
}

func dler(c *fiber.Ctx) error {
    log.Println("dling")

    return c.Download("./filetest.mp4", "wtf.mp4")
}

Checklist:

ghost commented 1 year ago

I created the file using dd, and copied your code, but I can't replicate this issue at all.

(or, maybe it's a browser bug? It always seems to return a 200 - OK for me) (or, did you misspell the url? like http://localhost:3000/d?)

ss

G2G2G2G commented 1 year ago

If I misspelled the URL how would lower sized files work? anyway could it be due to 32bit Go? the server is a small ARM SBC that is 32bit.

I went and tested both net/http servefile and gin framework. Both worked.

ghost commented 1 year ago

If I misspelled the URL how would lower sized files work?

Ah yeah, sorry, that was my mistake,

anyway could it be due to 32bit Go? the server is a small ARM SBC that is 32bit.

Yup.. that's exactly the reason. I just tried it using GOARCH=386, and it returned a 404

err := c.Download("./filetest.mp4", "wtf.mp4")
if err != nil {
    log.Println(err)
}

says that the issue is that 2023/03/18 16:21:39 sendfile: file ./filetest.mp4 not found but, if I debug it, everything seems to work in c.SendFile

file = filepath.ToSlash(file) is set without issues, and even c.fasthttp.Request.SetRequestURI(file) returns a 200

until Line 1667, where it serves the file via sendFileHandler(c.fasthttp), which returns a status of 404.. so it's likely an issue with fasthttp, and not fiber (I think, though I'm not really sure..)

gaby commented 1 year ago

@G2G2G2G have you found anything related to this issue on the fasthttp repo?

G2G2G2G commented 1 year ago

@cmd777 Yea so I posted it in their issue thread too. Not sure about debugging it or anything. I just used some several other frameworks & normal net/http to test and found none had issues.

I went with net/http since it uses virtually no RAM same as gofiber is. Gin framework used like a few MB for some reason lol (like 5-6MB while transferring) I figure if I ever am transferring a thousand files at once (probably never) it'll add up.

w.Header().Set("Content-Disposition", "attachment; filename="+strconv.Quote(fileName))
w.Header().Set("Content-Type", "application/octet-stream")
http.ServeFile(w, r, filePath)

seems to do basically the exact same thing

@gaby No I didn't look, I am completely unfamiliar with fasthttp, just use gofiber for some stuff. I posted it though as seen above

I guess this can be closed if it isn't going to be fixed here

gaby commented 1 year ago

@G2G2G2G We can keep open for now. Lets see what fasthttp says.

erikdubbelboer commented 1 year ago

Fasthttp is not going to fix this as this is not a use case that fasthttp was build for at all. Anyone wanting to do this should be using net/http. But what fiber could potentially do is not use the fasthttp file API but instead use response streaming and pass the file to that itself.

gaby commented 1 year ago

Just a note for the future. I have done this before by using io.CopyBuffer to copy from a File to a net buffer using this hack from https://github.com/golang/go/issues/16474 to avoid buffer allocations.

buf := make([]byte, 1024*1024)
io.CopyBuffer(struct{ io.Writer }{dst}, struct{ io.Reader }{src}, buf)