zai chang
zai chang

Reputation: 759

In go, how to inspect the http response that is written to http.ResponseWriter?

There's probably something obvious that I'm missing but I'm trying to debug the HTTP response written by my go server.

I see that there's httputil.DumpResponse available but it takes a http.Response object and what I have available is http.ResponseWriter

Is there a way to extract the http.Response from http.ResponseWriter so I can inspect the content of the response to console or log?

Context:

I'm writing a simple server-side authentication using https://github.com/RangelReale/osin and it's default example, but could not understand why the front-end (using http://ember-simple-auth.com) interprets a failed authentication (incorrect password) as success.

Here's the snippet:

r = mux.NewRouter()
r.HandleFunc("/token", func (w http.ResponseWriter, r *http.Request) {

    fmt.Printf("r.HandleFunc /token\n")

    resp := server.NewResponse()
    defer resp.Close()

    r.ParseForm()

    grantType := r.FormValue("grant_type")
    username := r.FormValue("username")
    password := r.FormValue("password")
    fmt.Printf("/token : grantType=%s  username=%s  password=%s\n", grantType, username, password)

    if ar := server.HandleAccessRequest(resp, r); ar != nil {
        if username == "user" && password == "correct-password" {
            ar.Authorized = true
        } else {
            ar.Authorized = false
        }
        server.FinishAccessRequest(resp, r, ar)
    }

    osin.OutputJSON(resp, w, r)

    // Debug - doesn't work yet
    dump, err := httputil.DumpResponse(w, true)
    if err != nil {
        fmt.Printf("%s\n", dump)
    }
});
http.Handle("/token", r)

Upvotes: 15

Views: 10644

Answers (1)

thwd
thwd

Reputation: 24818

Write to an *httptest.ResponseRecorder (which implements http.ResponseWriter) and inspect it.

Example from the package:

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httptest"
)

func main() {
    handler := func(w http.ResponseWriter, r *http.Request) {
        http.Error(w, "something failed", http.StatusInternalServerError)
    }

    req, err := http.NewRequest("GET", "http://example.com/foo", nil)
    if err != nil {
        log.Fatal(err)
    }

    w := httptest.NewRecorder()
    handler(w, req)

    fmt.Printf("%d - %s", w.Code, w.Body.String())
}

Edit to answer question in comments:

If I understand your question correctly, then yes, you can make use of closures for this.

Consider the following to be your handler:

func MyHandler(w http.ResponseWriter, r *http.Request) {
    // do useful stuff...
}

You could then register the following closure with your servemux to attain the desired effect:

http.HandleFunc("/my/url", func(w http.ResponseWriter, r *http.Request) {
    // first call MyHandler
    MyHandler(w, r)

    // then log whatever you need
    log.Printf("%#v\n", w)
})

If this pattern proves useful to you then you could write a higher-order method that wraps any func(http.ResponseWriter, *http.Request) in such a closure. That's a topic for itself, though.

Upvotes: 10

Related Questions