0

I am trying to add validation for the go based web application based on GIN framework. On the web page I am selecting a file and submitting and the server is processing it. On the server side I am try to add validation to check if the file has been given or not. If not then redirect back to original page.

    func panic(err error)  {
        if err != nil {
            log.Println(err)
        }
    }

    func displayTable (c *gin.Context) {    
    file, _ , err := c.Request.FormFile("file")
    panic(err)
    if file == nil {
        log.Println("File is nil.")
        log.Println(err)
        log.Println("*****")
        c.HTML(http.StatusInternalServerError, "index.tmpl", gin.H{
            "title": "Select the input file","error" : "Please select the input file.",
        })      
    } else {
        defer file.Close()
    }
    filename := strconv.FormatInt(time.Now().Unix(),10) 
    out, err := os.Create("./tmp/"+filename+".xml")
    panic(err)
    defer out.Close()
    _, err = io.Copy(out, file)
    panic(err)
    xmlFile, err := os.Open("./tmp/"+filename+".xml")
    panic(err)
    defer xmlFile.Close()

    // Other Implementation Details 
}

Even after providing the handling I am getting a panic in the go code. Please let me know what in the implementation am I missing.

Thanks.

    http: no such file
    File is nil.
    http: no such file
    *****
    2015/08/04 13:19:10 Panic recovery -> runtime error: invalid memory address or nil pointer dereference
    c:/go/src/runtime/panic.go:387 (0x414d36)
    c:/go/src/runtime/panic.go:42 (0x4142a5)
    c:/go/src/runtime/os_windows.go:42 (0x414066)
    c:/go/src/io/io.go:362 (0x45268f)
    D:/code/src/exmp/serverexmaple.go:45 (0x40168f)
            displayTable: _, err = io.Copy(out, file)
    D:/code/src/github.com/gin-gonic/gin/context.go:95 (0x49f8ea)
            (*Context).Next: c.handlers[c.index](c)
    D:/code/src/github.com/gin-gonic/gin/logger.go:56 (0x4ac490)
            func.007: c.Next()
    D:/code/src/github.com/gin-gonic/gin/context.go:95 (0x49f8ea)
            (*Context).Next: c.handlers[c.index](c)
    D:/code/src/github.com/gin-gonic/gin/recovery.go:43 (0x4acc80)
            func.009: c.Next()
    D:/code/src/github.com/gin-gonic/gin/context.go:95 (0x49f8ea)
            (*Context).Next: c.handlers[c.index](c)
    D:/code/src/github.com/gin-gonic/gin/gin.go:292 (0x4a46d5)
            (*Engine).handleHTTPRequest: context.Next()
    D:/code/src/github.com/gin-gonic/gin/gin.go:273 (0x4a4459)
            (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
    c:/go/src/net/http/server.go:1703 (0x468415)
    c:/go/src/net/http/server.go:1204 (0x466408)
    c:/go/src/runtime/asm_386.s:2287 (0x438ea1)
Zoyd
  • 3,449
  • 1
  • 18
  • 27
Kunal Jha
  • 2,102
  • 4
  • 24
  • 34
  • 2
    You should gofmt your code and actually include what you have, this can't be your real code: `file, _ , err := c.Request.FormFile("file"); panic(err)` Anyway, the error is pretty clear, `2015/08/04 13:19:10 Panic recovery -> runtime error: invalid memory address or nil pointer dereference` you're most likely trying to dereference a `nil`. – user3591723 Aug 04 '15 at 06:51
  • @user3591723 If you see the error `D:/code/src/exmp/serverexmaple.go:45 (0x40168f) displayTable: _, err = io.Copy(out, file)` which matches with the code is the problem area. The problem is when the file value is nil it doesn't redirect to the error page instead it executes the rest of the code and hence getting the panic when trying to read a nil value. Is this common behaviour for gin framework ? – Kunal Jha Aug 04 '15 at 07:03
  • 1
    I'm not sure what is common behavior for gin, why not just return from your function? Also, why are you redefining `panic`?.. That is a builtin function and it is kinda important for readability to not have that redefined. – user3591723 Aug 04 '15 at 08:59

2 Answers2

4
  1. Please do not redefine panic. It will confuse everyone who knows how panic works.
  2. Comparison with nil is a bit tricky in Go. It may work not as you expect: Check for nil and nil interface in Go. FormFile returns interface so you have to cast it to underlying structure if you want to check it with nil OR use the second parameter, type of which is available.
  3. This is not specific to GIN, it is part of the Go's HTTP implementation: http://golang.org/pkg/net/http/#Request.FormFile
Community
  • 1
  • 1
Alex Netkachov
  • 13,172
  • 6
  • 53
  • 85
  • Thanks for the point #1 and #2 will keep in mind in future. But if I add the `return` statement after ` c.HTML(http.StatusInternalServerError, "index.tmpl", gin.H{"title": "Select the input file","error" : "Please select the input file.",}) ` the panic is not shown and the redirection seems to work. – Kunal Jha Aug 04 '15 at 09:54
  • Ha, obviously! In the original code you check that the file is nil and call `_, err = io.Copy(out, file)` even though it is nil. Of course you the return should be added. – Alex Netkachov Aug 04 '15 at 11:15
0

I understand that I have made mistake with the panic handling. The validation is working if I add the return statement after the c.HTML. This will stop the function from executing the rest of the code. Thanks to @AlexAtNet for his advice and I will keep in mind in future.

if file == nil {
    log.Println("File is nil.")
    log.Println(err)
    log.Println("*****")
    c.HTML(http.StatusInternalServerError, "index.tmpl", gin.H{
        "title": "Select the input file","error" : "Please select the input file.",
    })   
    return 
} 
Kunal Jha
  • 2,102
  • 4
  • 24
  • 34