Hello there.
I’m trying to build a small http API which received a file and perform some operations on it. I can successfully receive the base64 of the file, decode it and it to disk, but for some reason, my program does not free up memory afterwards.
Here is the complete code of the server:
package main
import (
"encoding/json"
"github.com/gorilla/mux"
"log"
"net/http"
"encoding/base64"
"os"
"io/ioutil"
"path"
"os/exec"
"fmt"
)
const progName = "dummy"
type Request struct {
FileBase64 string `json:"base64,omitempty"`
FileName string `json:"filename,omitempty"`
Auth string `json:"auth,omitempty"`
}
type Reply struct {
Success bool
Status string
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/put", processFile).Methods("POST")
log.Fatal(http.ListenAndServe("localhost:8000", router))
}
func processFile(w http.ResponseWriter, r *http.Request) {
var cmd Request
_ = json.NewDecoder(r.Body).Decode(&cmd)
log.Printf("request received")
// decode incoming data
dec, err := base64.StdEncoding.DecodeString(cmd.FileBase64)
if err != nil {
log.Println(r.RemoteAddr, "-", "cannot decode base64:", err)
reply := Reply{false, "cannot decode base64"}
json.NewEncoder(w).Encode(reply)
return
}
log.Printf("request decoded")
// create temp directory
// we need it to dump the input file and run AppImage on it.
tempDir, err := ioutil.TempDir("", progName+"-")
if err != nil {
log.Println(r.RemoteAddr, "-", "cannot create temp directory:", err)
reply := Reply{false, "cannot create temp directory"}
json.NewEncoder(w).Encode(reply)
return
}
defer os.RemoveAll(tempDir)
log.Printf("created temp dir")
// create output file
zipFile, err := os.Create(path.Join(tempDir, cmd.FileName))
if err != nil {
log.Println(r.RemoteAddr, "-", "cannot create output file:", err)
reply := Reply{false, "cannot create output file"}
json.NewEncoder(w).Encode(reply)
return
}
defer zipFile.Close()
log.Printf("output file created")
// write content
written, err := zipFile.Write(dec)
if err != nil {
log.Println(r.RemoteAddr, "-", "cannot write output file:", err)
reply := Reply{false, "cannot write output file"}
json.NewEncoder(w).Encode(reply)
return
}
log.Printf("content written")
// flush buffer
err = zipFile.Sync()
if err != nil {
log.Println(r.RemoteAddr, "-", "error while flushing buffer:", err)
reply := Reply{false, "error while flushing buffer"}
json.NewEncoder(w).Encode(reply)
return
}
log.Printf("buffer flushed")
reply := Reply{true, fmt.Sprintf("written %d bytes", written)}
json.NewEncoder(w).Encode(reply)
}
To send a file to the api, I use this command:
(echo -n '{"filename": "test.zip", "base64": "'; base64 500M.bin; echo '"}') | curl -H "Content-Type: application/json" -d @- http://127.0.0.1:8000/put
When testing with a 500MB file, the server component uses lots of RAM but more importantly, it does not releases it when the function processFile exits.
Any idea on what I’m doing wrong?
Thanks a lot
Matteo