I am trying to deploy an app to Heroku, which temporarily stores uploaded files in /tmp.
ioutil.TempDir
creates the directory inside /tmp
just fine. Because it’s Heroku, perms are set to 0600, but the owner is the same as the user running the app.
The issue happens when I call os.Create
, that ends up throwing out permission errors:
2019-12-12T12:09:21.681565+00:00 app[web.1]: 2019/12/12 12:09:21 open /tmp/stream-hot146966131/stream/1080p_001.ts: permission denied
2019-12-12T12:09:21.681571+00:00 app[web.1]: 2019/12/12 12:09:21 drw-------
I added logging to show the error in log, and show the /tmp/stream-hot146966131/stream
permissions, which, as you can see, are set up correctly.
The stream
directory is created if it doesn’t exist (that name can be different, it is based on the request URL)
Of course, when I run it on my system (which is Windows), that works perfectly fine.
Code:
var tempDir string
func streamHandler(w http.ResponseWriter, r *http.Request) {
var rex = regexp.MustCompile("^\\/([a-zA-Z0-9]*)\\/([a-zA-Z0-9_]*\\.(?:m3u8|ts))$")
url := rex.FindStringSubmatch(r.URL.String())
if r.Method == "PUT" {
if url == nil {
http.Error(w, "URL has to be a path to HLS fragment/playlist.", http.StatusBadRequest)
return
}
stat, err := os.Stat(filepath.Join(tempDir, url[1]))
if os.IsNotExist(err) {
os.MkdirAll(filepath.Join(tempDir, url[1]), 0666)
}
f, err := os.Create(filepath.Join(tempDir, url[1], url[2]))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Println(err.Error())
if stat != nil {
log.Println(stat.Mode())
}
return
}
defer f.Close()
_, err = io.Copy(f, r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.WriteHeader(200)
w.Write([]byte("OK"))
return
}
}
func registerHandlers() {
var err error
tempDir, err = ioutil.TempDir("", "stream-hot")
if err != nil {
panic(err)
}
http.HandleFunc("/", streamHandler)
}