From c6183dce061302571bb49601b247c9438706589e Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Wed, 7 Apr 2021 12:22:00 +0100 Subject: [PATCH] Support OAuth servers using standard responses --- api/form.go | 66 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/api/form.go b/api/form.go index 2b370a4..9856b9f 100644 --- a/api/form.go +++ b/api/form.go @@ -1,12 +1,14 @@ package api import ( + "encoding/json" "fmt" "io" "io/ioutil" + "mime" "net/http" "net/url" - "strings" + "strconv" ) type httpClient interface { @@ -18,12 +20,16 @@ type FormResponse struct { StatusCode int requestURI string - values url.Values + values map[string]string } // Get the response value named k. func (f FormResponse) Get(k string) string { - return f.values.Get(k) + v, ok := f.values[k] + if !ok { + return "" + } + return v } // Err returns an Error object extracted from the response. @@ -69,19 +75,40 @@ func PostForm(c httpClient, u string, params url.Values) (*FormResponse, error) r := &FormResponse{ StatusCode: resp.StatusCode, requestURI: u, + values: make(map[string]string), } - if contentType(resp.Header.Get("Content-Type")) == formType { + // since mine.ParseMediaType always returns the media type regardless of error, and + // that we don't use the params - we can just ignore any errors. + mediaType, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type")) + + if mediaType == formType { + var bb []byte + bb, err = ioutil.ReadAll(resp.Body) + if err != nil { + return r, err + } + + values, err := url.ParseQuery(string(bb)) + if err != nil { + return r, err + } + + readFormValues(r, values) + } else if mediaType == jsonType { var bb []byte bb, err = ioutil.ReadAll(resp.Body) if err != nil { return r, err } - r.values, err = url.ParseQuery(string(bb)) + var values map[string]interface{} + err = json.Unmarshal(bb, &values) if err != nil { return r, err } + + readJsonValues(r, values) } else { _, err = io.Copy(ioutil.Discard, resp.Body) if err != nil { @@ -93,10 +120,31 @@ func PostForm(c httpClient, u string, params url.Values) (*FormResponse, error) } const formType = "application/x-www-form-urlencoded" +const jsonType = "application/json" + +// readFormValues feeds information from a url.Values into a FormResponse's values +// map. +func readFormValues(r *FormResponse, values url.Values) { + for key, value := range values { + if len(value) < 1 { + continue + } -func contentType(t string) string { - if i := strings.IndexRune(t, ';'); i >= 0 { - return t[0:i] + r.values[key] = value[0] + } +} + +// readJsonValues feeds information from an un-marshaled JSON response into a +// FormResponse's values map. +func readJsonValues(r *FormResponse, values map[string]interface{}) { + for key, value := range values { + // Go's JSON library uses float64 and int64 for numbers. + if v, ok := value.(string); ok { + r.values[key] = v + } else if v, ok := value.(int64); ok { + r.values[key] = strconv.FormatInt(v, 10) + } else if v, ok := value.(float64); ok { + r.values[key] = strconv.FormatFloat(v, 'f', -1, 64) + } } - return t }