How to dump both HTTP request and response in golang - go

I'm using gorilla web tool kit. There's a LoggingHandler available in the handler package, however it can only log the request data via the handler.
r := mux.NewRouter()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("This is a catch-all route"))
})
// This can only log the request, how can we log the response?
loggedRouter := handlers.LoggingHandler(os.Stdout, r)
http.ListenAndServe(":1123", loggedRouter)
httputil has the same feature available via DumpRequest(). In my case client is a browser, and I'm looking for a handler approach to log the response rather than logging it inside each and every handler.

Related

Golang net/http/httptest error crypto/x509.unknownauthorityerror

I am trying to mock out a response from a HTTPS web service responding to my Golang package.
In my unit test I am using net/http/httptest.
My function is
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello")
}))
defer ts.Close()
tr := &http.Transport{TLSClientConfig: &TLS.Config{InsecureSkipVerify: true}}
client := ts.Client()
client= &http.Client{Transport:tr}
res, err := client.Get(ts.URL)
When I step through the code and my package makes the call to the mock service, it errors with error (crypto/x509.UnknownAuthorityError)
I thought the skip verify is meant ignore verifying any certificates? Yes, I am mocking out certificates when my package is instantiated, but for the purpose of the test, I am not interested in the certificates all I want to do is verify the response coming back and the code after.
What am I doing wrong with mocking a HTTPS request response?

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

how to proxy GET request in golang with URL manipulation

I want to build a golang service which will listen for GET request, do some URL manipulation and then proxy a new request (to the manipulated URL) back to the browser:
(from browser -> server) GET http://www.example.com/7fbsjfhfh93hdkwhfbf398fhkef93..
(server manipulates URL - decrypts "7fbsjfhfh93hdkwhfbf398fhkef93.." -> "my-super-resource")
(server -> URL resource) GET http://www.somewhereelse.com/my-super-resource
(server -> browser) Response from http://www.somewhereelse.com/my-super-resource passed on to browser (using cors)
The whole chain will need to be synchronous which is ok. Is there a decent proxy library which allows for this sort of thing?
You can do something like this in less than 10 lines of code with the Sling package:
type Foo struct {
Bar string `json:"bar"`
}
func Handler(w http.ResponseWriter, r *http.Request) {
// Get the URL and decrypt it
url := getUrl(r)
decryptedUrl := decryptUrl(url)
// Use the decrypted URL to make a request to another service
var data *Foo
req, err := sling.New().Get(decryptedUrl).Receive(data)
if err != nil {
// Handle error...
}
// Respond to the original request using the data from the other service
respond(w, http.StatusOK, data)
}

How to set HTTP status code on http.ResponseWriter

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

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