oalmgren
oalmgren

Reputation: 435

Unable to extract value from r.PostFormValue in Go?

I'm trying to extract a value from an HTTP POST request body (in my simple Go HTTP server) using the net/http PostFormValue and my output is an empty string when I'm looking for the any key in general, but in my case trying to fetch the hub.secret for use in a HMAC check. I use Postman to send the request to my localhost:8080 instance using the Gorilla/mux router, with header Content-Type: application/x-www-form-urlencoded set.

My handler looks like so:

func rootPostHandler(w http.ResponseWriter, r *http.Request) {

    var expectedMac []byte

    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    log.Println("r.Body is:", string(body)) // debug: print the request POST body

    message := body // debug: set message just for extra clarity

    errParse := r.ParseForm()
    if errParse != nil {
        // handle err
    }
    secret := []byte(r.PostFormValue("hub.secret"))
    log.Println("secret is: ", string(secret))
    
    
    mac := hmac.New(sha256.New, secret)
    mac.Write(message)
    expectedMac = mac.Sum(nil)
    fmt.Println("Is HMAC equal? ", hmac.Equal(message, expectedMac))

    w.Header().Add("X-Hub-Signature", "sha256="+string(message))
}

The r.Body:

hub.callback=http%253A%252F%252Fweb-sub-client%253A8080%252FbRxvcmOcNk&hub.mode=subscribe&hub.secret=xTgSGLOtPNrBLLgYcKnL&hub.topic=%252Fa%252Ftopic

And the output for print secret etc is empty string, meaning it can't find hub.secret, right? What am I missing here?

Upvotes: 1

Views: 889

Answers (1)

Thundercat
Thundercat

Reputation: 121119

The application reads the request body to EOF on this line:

body, err := ioutil.ReadAll(r.Body)

ParseForm returns an empty form because the body is at EOF at this line:

errParse := r.ParseForm()

The request body is read from the network connection. The request body cannot be read a second time.

Remove the call to ioutil.ReadAll or create a new body reader using the data returned from ioutil.ReadAll:

r.Body = io.NopCloser(bytes.NewReader(body))

Upvotes: 2

Related Questions