Not able to save uploaded file on server using GOLANG and POLYMER http: no such file
Asked Answered
P

3

6

I am using vaadin upload to upload files on web application with polymer. And I am using golang for back-end.

<vaadin-upload target="../upload" max-files="20" accept="application/pdf,image/*" 
method="POST"> </vaadin-upload>

I checked that encoding type used in vaadin upload is multipart/form-data. My golang code is below.

func upload(w http.ResponseWriter, r *http.Request) {
    fmt.Println("method:", r.Method)
    if r.Method == "GET" {
        crutime := time.Now().Unix()
        h := md5.New()
        io.WriteString(h, strconv.FormatInt(crutime, 10))
        token := fmt.Sprintf("%x", h.Sum(nil))

        t, _ := template.ParseFiles("upload.gtpl")
        t.Execute(w, token)
    } else {
        r.ParseMultipartForm(32 << 20)
        file, handler, err := r.FormFile("uploadFile")
        if err != nil {
            fmt.Println(err)
            return
        }
        defer file.Close()
        fmt.Fprintf(w, "%v", handler.Header)
        f, err := os.OpenFile("./test/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
        if err != nil {
            fmt.Println(err)
            return
        }
        defer f.Close()
        io.Copy(f, file)
    }
}

It gives error on server side http: no such file. I checked this error is returned by FormFile when the provided file field name is either not present in the request or not a file field.

How do I correct my form file name. Although everything seems fine on front-end enter image description here

Prostatitis answered 10/10, 2016 at 9:20 Comment(5)
1. Find out where your code fails. 2. Make sure stuff like "./test/"+handler.Filename actually produces something suitable for writing (e.g. ./test must exist).Utilitarianism
My code fails at this part file, handler, err := r.FormFile("uploadFile")Prostatitis
That is what I want to know how do I handle this. I don't know what to write here FormFile("WHAT!!"). Because of this the code is giving errorProstatitis
Well, that's a vaadin-only question. Dump the request and see. Or track what your browser does with the developer tools of your browser.Utilitarianism
May you add the full line of error? just to check what line is failing. Also I don't see the name field in your html tag, remember the value of the attribute name has to be the same for r.FormFile("value_name")Uphemia
P
3

Answering my own question for those who are facing same problem. Found out some code which can access file without knowing the key value.

func UploadHandler(res http.ResponseWriter, req *http.Request) {  
      var (  
           status int  
           err  error  
      )  
      defer func() {  
           if nil != err {  
                http.Error(res, err.Error(), status)  
           }  
      }()  
      // parse request  
     // const _24K = (1 << 20) * 24  
      if err = req.ParseMultipartForm(32 << 20); nil != err {  
           status = http.StatusInternalServerError  
           return  
      } 
        fmt.Println("No memory problem")
      for _, fheaders := range req.MultipartForm.File {  
           for _, hdr := range fheaders {  
                // open uploaded  
                var infile multipart.File  
                if infile, err = hdr.Open(); nil != err {  
                     status = http.StatusInternalServerError  
                     return  
                }  
                // open destination  
                var outfile *os.File  
                if outfile, err = os.Create("./uploaded/" + hdr.Filename); nil != err {  
                     status = http.StatusInternalServerError  
                     return  
                }  
                // 32K buffer copy  
                var written int64  
                if written, err = io.Copy(outfile, infile); nil != err {  
                     status = http.StatusInternalServerError  
                     return  
                }  
                res.Write([]byte("uploaded file:" + hdr.Filename + ";length:" + strconv.Itoa(int(written))))  
           }  
      }  
 } 
Prostatitis answered 11/10, 2016 at 18:13 Comment(2)
Thank you for your final implementation. While posting your final solution for future programmers is very good, the accepted answer should go to @ain.Hyperopia
32 << 20 is 32Mb. not 32KbChassepot
O
4

Did a quick test and it appears that the vaadin-upload uses file as the form data parameter name for the file. So in the line

file, handler, err := r.FormFile("uploadFile")

replace uploadFile with file and it should work.

It is documented on the vaadin homepage that

In order to support simultaneous uploads, instead of reusing the same FormData and XMLHttpRequest, we create a new one for each file. It is therefore alright for the server to only consider receiving one file per request.

However, I didn't see the parameter name (file) documented, so to be safe you should write your code so that it wouldn't use the name, ie something like

r.ParseMultipartForm(32 << 20)
m := r.MultipartForm
for _, v := range m.File {
    for _, f := range v {
        file, err := f.Open()
        if err != nil {
            fmt.Println(err)
            return
        }
        defer file.Close()
        // do something with the file data
        ...
    }
}
Oho answered 11/10, 2016 at 16:33 Comment(2)
Thanks for the answer. Yes you are right. After posting this question I found some code same as your code for uploading without knowing the key value.Prostatitis
What headeache, I had the problem that only one file will upload and the others remain in cero bytes, thanks !!Yare
P
3

Answering my own question for those who are facing same problem. Found out some code which can access file without knowing the key value.

func UploadHandler(res http.ResponseWriter, req *http.Request) {  
      var (  
           status int  
           err  error  
      )  
      defer func() {  
           if nil != err {  
                http.Error(res, err.Error(), status)  
           }  
      }()  
      // parse request  
     // const _24K = (1 << 20) * 24  
      if err = req.ParseMultipartForm(32 << 20); nil != err {  
           status = http.StatusInternalServerError  
           return  
      } 
        fmt.Println("No memory problem")
      for _, fheaders := range req.MultipartForm.File {  
           for _, hdr := range fheaders {  
                // open uploaded  
                var infile multipart.File  
                if infile, err = hdr.Open(); nil != err {  
                     status = http.StatusInternalServerError  
                     return  
                }  
                // open destination  
                var outfile *os.File  
                if outfile, err = os.Create("./uploaded/" + hdr.Filename); nil != err {  
                     status = http.StatusInternalServerError  
                     return  
                }  
                // 32K buffer copy  
                var written int64  
                if written, err = io.Copy(outfile, infile); nil != err {  
                     status = http.StatusInternalServerError  
                     return  
                }  
                res.Write([]byte("uploaded file:" + hdr.Filename + ";length:" + strconv.Itoa(int(written))))  
           }  
      }  
 } 
Prostatitis answered 11/10, 2016 at 18:13 Comment(2)
Thank you for your final implementation. While posting your final solution for future programmers is very good, the accepted answer should go to @ain.Hyperopia
32 << 20 is 32Mb. not 32KbChassepot
D
0

Use exactly the same name for doing r.FormFile("selectedFile") that is there in your HTML tag. The key is mapped to input name used in your frontend HTML tag.

Below is my implementation:

<file
    type="file"
    name="selectedFile"
/>

const (
    S3_REGION = "Your region"
    S3_BUCKET = "Your Bucket Name"
)

func uploadFile(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Uploading File")
    r.ParseMultipartForm(32 << 20)

    file, handler, err := r.FormFile("selectedFile") // 
    if err != nil {
            fmt.Println("Error Retrieving the File")
            fmt.Println(err)
            return
    }

    defer file.Close()

    fmt.Printf("Uploaded File: %+v\n", handler.Filename)
    fmt.Printf("File Size: %+v\n", handler.Size)
    fmt.Printf("MIME Header: %+v\n", handler.Header)

    s, err := session.NewSession(&aws.Config{Region: aws.String(S3_REGION)})
    if err != nil {
        log.Fatal(err)
    }

    var size int64 = handler.Size
    buffer := make([]byte, size)
    file.Read(buffer)

    _, err = s3.New(s).PutObject(&s3.PutObjectInput{
        Bucket:               aws.String(S3_BUCKET),
        Key:                  aws.String(handler.Filename),
        ACL:                  aws.String("private"),
        Body:                 bytes.NewReader(buffer),
        ContentLength:        aws.Int64(size),
        ContentType:          aws.String(http.DetectContentType(buffer)),
        ContentDisposition:   aws.String("attachment"),
        ServerSideEncryption: aws.String("AES256"),
    })       
}
Dryad answered 2/5, 2019 at 16:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.