Error Handling For ResposeWriter / Write - go

I am using osin, Go Lang oAuth Server to try and build a oAuth sever.
So I have used, or i am trying to use the complete example given, to give me a good place to start playing with the code to see what I can do.
However, I have a lot of errors with the file. Now most seem to be about error checking and i have seem to fix them (I am using Visual Code, which as very good Go Lang support). However, no matter what I try I cant seem to fix the error handling for w.Write,
http.HandleFunc("/appauth/code", func(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm() //*1
if err != nil {
log.Panic(err)
}
code := r.Form.Get("code")
w.Write([]byte("<html><body>")) *2
*1 - This was also missing an error and found my understanding this is how that is meant to be dealt with, please tell me if I am wrong?
*2 - With this I am getting, a errors unhandled call within Visual Code, and no matter how I try to deal with it, it will not work?
This is what I have tried,
err := w.Write([]byte("<html><body>"))
w.Write([]byte("<html><body>") (int, error) ) <- the Write seems to return an int and error?
So I am not sure how to deal with this type of error?

Discard the int if you don't need it:
_, err := w.Write([]byte("<html><body>"))

Related

Error checking while type casting in Go

I am currently adding JWT authentication to my Go web app and I have some concerns when it comes to type casting in go and the automatic Panic if it fails. My code looks like this: (c being the context package)
user := c.Get("user")
token := user.(*jwt.Token)
claims := token.Claims.(jwt.MapClaims)
fmt.Println("Username: ", claims["name"], "User ID: ", claims["jti"])
As you can see I use type casting on multiple lines, yet if this operation failed it will panic and ultimately cause the server to crash. Is there any possible way to check for an error in this case? I am quite new to web development in Go so my apologies, all help is appreciated!
Type assertions (somevar.(sometype)) return a (sometype, bool), so you can check the bool. Idiomatically that's:
token, ok := user.(*jwt.Token)
if !ok {
// handle the fail case. `token` is nil here.
}

Basic web tweaks that all applications should have

Currently my web app is just a router and handlers.
What are some important things I am missing to make this production worthy?
I believe I have to set the # of procs to ensure this uses maximum goroutines?
Should I be using output buffering?
Anything else you see missing that is best-practise?
var (
templates = template.Must(template.ParseFiles("templates/home.html")
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/", WelcomeHandler)
http.ListenAndServe(":9000", r)
}
func WelcomeHandler(w http.ResponseWriter, r *http.Request) {
homePage, err := api.LoadHomePage()
if err != nil {
}
tmpl := "home"
renderTemplate(w, tmpl, homePage)
}
func renderTemplate(w http.ResponseWriter, tmpl string, hp *HomePage) {
err := templates.ExecuteTemplate(w, tmpl+".html", hp)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
You don't need to set/change runtime.GOMAXPROCS() as since Go 1.5 it defaults to the number of available CPU cores.
Buffering output? From the performance point of view, you don't need to. But there may be other considerations for which you may.
For example, your renderTemplate() function may potentially panic. If executing the template starts writing to the output, it involves setting the HTTP response code and other headers prior to writing data. And if a template execution error occurs after that, it will return an error, and so your code attempts to send back an error response. At this point HTTP headers are already written, and this http.Error() function will try to set headers again => panic.
One way to avoid this is to first render the template into a buffer (e.g. bytes.Buffer), and if no error is returned by the template execution, then you can write the content of the buffer to the response writer. If error occurs, then of course you won't write the content of the buffer, but send back an error response just like you did.
To sum it up, your code is production ready performance-wise (excluding the way you handle template execution errors).
WelcomeHandler should return when err != nil is true.
Log the error when one is hit to help investigation.
Place templates = template.Must(template.ParseFiles("templates/home.html") in the init. Split it into separate lines. If template.ParseFiles returns an then error make a Fatal log. And if you have multiple templates to initialize then initialize them in goroutines with a common WaitGroup to speed up the startup.
Since you are using mux, HTTP Server is too clean with its URLs might also be good to know.
You might also want to reconsider the decision of letting the user's know why they got the http.StatusInternalServerError response.
Setting the GOMAXPROCS > 1 if you have more the one core would definitely be a good idea but I would keep it less than number of cores available.

What would happen if an error happened and my golang app didn't handle it?

I'm currently using gorm and gin framework. I wonder what would happen if an error happened and my app didn't handle it?
Example:
if err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil {
// error handling...
}
In the above example, the error is being handled.
if db.Model(&user).Related(&credit_card).RecordNotFound() {
// no credit card found error handling
}
In the next example above, only the RecordNotFound() error is being handled, but what if it throws a different error? what will happen?
Will my app automatically respond with a 500 server internal error and will the app keep on running properly?
In the next example above, only the RecordNotFound() error is being handled, but what if it throws a different error?
If you won't catch the error it will continue on the code. Error is not a special type it's a simple struct
err := FunctionThatReturnsError()
if err == myError.RecordNotFound() { // if err is not RecordNotFound then it won't enter the if simple as that.
// Do something.
}
// continue code.
Will my app automatically respond with a 500 server internal error and will the app keep on running properly?
There will be no response if the go routine doesn't panic or you return a response. If you want to handle it you can do:
err := FunctionThatReturnsError()
if err == myError.RecordNotFound() {
panic("RecordNotFound")
}
or
err := FunctionThatReturnsError()
if err == myError.RecordNotFound() {
c.JSON(500, "Record not found"}
}
I don't recommend the panic method. If you're curious google why.
Go doesn't have exceptions. Instead of catching exceptions, you get errors via return values from functions. So there's no throwing or anything special going on behind the scenes, just a function that returns an error value, and like any other return value - you can discard it.
I wouldn't recommend discarding errors though. If you feel lazy or lost about what to do with an error - just log it:
log.Error(err)
You never know if an error you discarded is causing this mysterious bug you can swear is coming from anywhere but your own code.
I wonder what would happen if an error happened and my app didn't handle it?
Then the state of the app is undefined. If you don't check error values your app will be using values which are undefined (probably nil for pointers and "zeros" for values) or assuming that side effect occurred but it might not.
Let's say you have a function with signature func CreateStruct() (T, err)
and call it like that t, _ := CreateStruct() (not checking for error) you should not expect t variable to have a proper value set.
If you have function like func Update() err and you call it without error checking then you can't know whether update was performed or not.
Of course everything depends on API and implementation. But you get the idea.
but what if it throws a different error?
It's impossible. There is not throwing error mechanism in Go. Error can only be returned as a normal value.
You should never be lazy with handling errors. It's very important part of programming and Go makes it easier to realize.

Is it advisable to (further) limit the size of forms when using golang?

I searched around and as far as I can tell, POST form requests are already limited to 10MB (http://golang.org/src/net/http/request.go#L721).
If I were to go about reducing this in my ServeHTTP method, I'm not sure how to properly do it. I would try something like this:
r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize)
err := r.ParseForm()
if err != nil {
//redirect to some error page
return
}
But would returning upon error close the connection as well? How would I prevent having to read everything? I found this: https://stackoverflow.com/a/26393261/2202497, but what if content length is not set and in the middle of reading I realize that the file is too big.
I'm using this as a security measure to prevent someone from hogging my server's resources.
The correct way to limit the size of the request body is to do as you suggested:
r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize)
err := r.ParseForm()
if err != nil {
// redirect or set error status code.
return
}
MaxBytesReader sets a flag on the response when the limit is reached. When this flag is set, the server does not read the remainder of the request body and the server closes the connection on return from the handler.
If you are concerned about malicious clients, then you should also set Server.ReadTimeout, Server.WriteTimeout and possibly Server.MaxHeaderBytes.
If you want to set the request body limit for all of your handlers, then wrap root handler with a handler that sets the limit before delegating to the root handler:
type maxBytesHandler struct {
h http.Handler
n int64
}
func (h *maxBytesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, h.n)
h.h.ServeHTTP(w, r)
}
Wrap the root handler when calling ListenAndServe:
log.Fatal(http.ListenAndServe(":8080", &maxBytesHandler{h:mux, n:4096))
or when configuring a server:
s := http.Server{
Addr: ":8080",
Handler: &maxBytesReader{h:mux, n:4096},
}
log.Fatal(s.ListenAndServe())
There's no need for a patch as suggested in another answer. MaxBytesReader is the official way to limit the size of the request body.
Edit: As others cited MaxByteReader is the supported way. It is interesting that the default reader is instead, limitreader after type asserting for max byte reader.
Submit a patch to the Go source code and make it configurable! You are working with an open source project after all. Adding a setter to http.Request and some unit tests for it is probably only 20 minutes worth of work. Having a hardcoded value here is a bit clunky, give back and fix it :).
You can of course implement your own ParseForm(r *http.Request) method if you really need to override this. Go is essentially BSD, so you can copy paste the library ParseForm and change the limit, but thats a bit ugly no?

Safely terminating a request outside of handlefunc

How can I safely terminate a request outside of a dispatcher (handlefunc) without an explicit return in handlefunc? In the code below, I end up seeing both "Bad request" and "Not found" in my response, but I'd like f() to abort the request -- so I wouldn't have to clutter dispatcher with error checks and returns.
package main
import (
"net/http"
)
func f(w http.ResponseWriter, r *http.Request, k string) string{
if v, ok := r.Form[k]; !ok{
http.Error(w, "Bad request", http.StatusBadRequest)
return ""
}else{
return v[0]
}
}
func main(){
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
foo := f(w, r, "foo") //make sure foo is passed, if not abort with "bad request" without requiring an explicit return here
bar := f(w, r, "bar") //make sure bar is passed, if not abort with "bad request" without requiring an explicit return here
//lookup in db...
//abort with a 404 if not found in db
http.NotFound(w, r)
})
http.ListenAndServe(":6000", nil)
}
The above was an attempt to refactor the following:
func main(){
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
if foo,ok:=r.Form["foo"];!ok{
http.Error(w, "Bad request", http.StatusBadRequest)
return
}
if bar,ok:=r.Form["bar"];!ok{
http.Error(w, "Bad request", http.StatusBadRequest)
return
}
//lookup in db...
//abort with a 404 if not found in db
http.NotFound(w, r)
})
http.ListenAndServe(":6000", nil)
}
I don't think trying to abort from within a function is what you want to do here. Instead, make the validation less repetitive. You could write something like package validate with func Require(form url.Values, required ...string) error, and, in your handler, if err := validate.Require(r.Form, "foo", "bar"); err != nil { ... }.
Or you could do a more general validator: maybe take a map of field name to validation type (number, string, etc.) and return another map that's nil if no errors and {"fieldName": error} otherwise.
Redditors talked some about this and one wrote a library that uses struct tags to validate. There's another struct-based validation implementation in a new form rendering/validation toolkit. (I've tried neither.) The Redditors raised the tricky question of how much you can abstract validation before getting a "framework" that gets in the way when your app gets more complicated, and I don't have a simple answer.
There are cases where something really unexpected happens and the server can't do anything better than give the user an opaque "500 Internal Server Error" response, but the problem manifests deep below your HandlerFunc. The canonical example is a programming error like a nil pointer dereference. The advice from the Go team is to use panic when "the error is unrecoverable." (A tool like negroni.Recovery can help log panics, etc.)
Unnecessary panics are lame because:
panics make it easier to forget necessary error handling entirely, because it's implied that things can panic but explicit they can err
panic/recover error handling code is ugly and hard to maintain
panics introduce inconsistency with the standard err returns
panics use stack unwinding, which is much slower than normal control flow
I did a quick grep and essentially all calls to panic in the standard library and other official repositories are there to catch programming/internal errors, not crash on surprise external conditions like bad input or I/O errors. Things like file/object not found or invalid user input can usually be handled more gracefully than by crashing the request (it's at least possible to return a specific error), and they aren't really unexpected (it's the Internet; you'll get invalid input and requests for things that don't exist). So panic is not for normal request aborts--it's for crashing when what "can't happen" has happened and the request can't continue.
Again, here, I'd handle invalid input with a standard if block in the handler function, but rearrange your validation so that it doesn't require a lot of code per required argument.

Resources