How to set HTTP status code on http.ResponseWriter - go

How do I set the HTTP status code on an http.ResponseWriter (e.g. to 500 or 403)?
I can see that requests normally have a status code of 200 attached to them.

Use http.ResponseWriter.WriteHeader. From the documentation:
WriteHeader sends an HTTP response header with status code. If WriteHeader is not called explicitly, the first call to Write will trigger an implicit WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly used to send error codes.
Example:
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - Something bad happened!"))
}

Apart from WriteHeader(int) you can use the helper method http.Error, for example:
func yourFuncHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "my own error message", http.StatusForbidden)
// or using the default message error
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
http.Error() and http.StatusText() methods are your friends

w.WriteHeader(http.StatusInternalServerError)
w.WriteHeader(http.StatusForbidden)
full list here

Related

How to log the HTTP return code with the chi router?

I use chi as my router and wrote a simple middleware that logs the request being made:
func logCalls(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Info().Msgf("%v → %v", r.URL, r.RemoteAddr)
next.ServeHTTP(w, r)
})
}
It works great but I am missing the HTTP return code.
The HTTP return code will obviously be available once all the routes are exhausted but at the same time I have to use my middleware before the routes.
Is there a way to hook it after the routing is done, and therefore have the return code I can log?
I think you need render from go-chi library.
https://github.com/go-chi/render/tree/v1.0.1
Example of usage is here:
https://github.com/go-chi/chi/blob/master/_examples/rest/main.go

307 redirect with Authorization header

In looking at the Go docs for http it looks like the Authorization header is removed when a response is a 307. Obviously it makes sense for almost every case but is there a way not to remove the Authorization header?
You can modify your http.Client to add the header again after it has been removed using CheckRedirect:
CheckRedirect func(req *Request, via []*Request) error
Since req is the upcoming request, it can be modified before it is sent. After making the changes, return nil to indicate that the request should still be sent.
Since this is a change to the http client instead of the request, you should check that this redirect is only used for the one URL where you need it (in case you use that client to do other requests).
You client definition could look like this:
http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
// you can check old responses for a status code
if len(via) != 0 && via[0].Response.StatusCode == http.StatusTemporaryRedirect {
req.Header.Add("Authorization", "some-value")
}
return nil
},
}

Why does http.NotFound() take the request as an argument?

The http.NotFound() method has the following signature:
func NotFound(w ResponseWriter, r *Request)
What is/was the purpose of the *Request argument?
Currently the value seems to be unused, and I find it hard to imagine what it might have been used for in the past.
This signature is the standard http.Handler signature.
NotFound obviously does not use the request:
// NotFound replies to the request with an HTTP 404 not found error.
func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) }
However, by sticking to the standard interface it interoperates with the rest of the http package:
http.HandleFunc("/favicon.ico", http.NotFound)

Go http response few headers

I'm want send to user alert if he type wrong password and return it to page were he type password. I'm making it like this
func sendJSONHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
http.ServeFile(w, r, "template/api/api.html")
} else if r.Method == "POST" {
r.ParseForm()
if r.Form["password"][0] == "apiPassword" {
j := struct {
Proxies []string
}{Proxies: code.UP.Proxy}
w.Header().Set("Access-Control-Allow-Origin", corsAddrSite)
json.NewEncoder(w).Encode(j)
} else {
// here is a problem
fmt.Fprintln(w, "<script>alert('Wrong Password')</script>")
http.ServeFile(w, r, "template/api/api.html")
}
}
}
But i'v get http: multiple response.WriteHeader calls error.
How to do it right?
You cannot write to the http.ResponseWriter more than once depending on the HTTP spec.
from the go docs https://golang.org/pkg/net/http/#ResponseWriter
To solve your issue, you could have the script tags inside the template file, or make a new template. You could also tailor the response by adding the alert script before you send it. Maybe with template files.
However a proper solution to this problem might be to have more logic in the actual html served, the front end should display a response based on the status code or response body.

How to pass along an http Request in golang?

I have a Request object in golang, and I would like to feed the contents of this object through a net.Conn as part of the task of a proxy.
I want to call something like
req, err := http.ReadRequest(bufio.NewReader(conn_to_client))
conn_to_remote_server.Write(... ? ... )
but I have no idea what I would be passing in as the arguments. Any advice would be appreciated.
Check out Negroni middleware. It let's you pass your HTTP request through different middleware and custom HandlerFuncs.
Something like this:
n := negroni.New(
negroni.NewRecovery(),
negroni.HandlerFunc(myMiddleware),
negroni.NewLogger(),
negroni.NewStatic(http.Dir("public")),
)
...
...
func myMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
log.Println("Logging on the way there...")
if r.URL.Query().Get("password") == "secret123" {
next(rw, r) //**<--------passing the request to next middleware/func**
} else {
http.Error(rw, "Not Authorized", 401)
}
log.Println("Logging on the way back...")
}
Notice how next(rw,r) is used to pass along the HTTP request
If you don't want to use Negroni, you can always look at it's implementation on how it passes the HTTP request to another middleware.
It uses custom handler which looks something like:
handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
Ref: https://gobridge.gitbooks.io/building-web-apps-with-go/content/en/middleware/index.html

Resources