Skip to content

Commit

Permalink
Support OAuth servers using standard responses
Browse files Browse the repository at this point in the history
  • Loading branch information
jamierocks committed Apr 7, 2021
1 parent 9a6335a commit 7d51c27
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 25 deletions.
13 changes: 6 additions & 7 deletions api/access_token_test.go
@@ -1,7 +1,6 @@
package api

import (
"net/url"
"reflect"
"testing"
)
Expand All @@ -16,10 +15,10 @@ func TestFormResponse_AccessToken(t *testing.T) {
{
name: "with token",
response: FormResponse{
values: url.Values{
"access_token": []string{"ATOKEN"},
"token_type": []string{"bearer"},
"scope": []string{"repo gist"},
values: map[string]string{
"access_token": "ATOKEN",
"token_type": "bearer",
"scope": "repo gist",
},
},
want: &AccessToken{
Expand All @@ -33,8 +32,8 @@ func TestFormResponse_AccessToken(t *testing.T) {
name: "no token",
response: FormResponse{
StatusCode: 200,
values: url.Values{
"error": []string{"access_denied"},
values: map[string]string{
"error": "access_denied",
},
},
want: nil,
Expand Down
66 changes: 57 additions & 9 deletions 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 {
Expand All @@ -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.
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}
18 changes: 9 additions & 9 deletions api/form_test.go
Expand Up @@ -25,8 +25,8 @@ func TestFormResponse_Get(t *testing.T) {
{
name: "with value",
response: FormResponse{
values: url.Values{
"access_token": []string{"ATOKEN"},
values: map[string]string{
"access_token": "ATOKEN",
},
},
key: "access_token",
Expand Down Expand Up @@ -60,9 +60,9 @@ func TestFormResponse_Err(t *testing.T) {
response: FormResponse{
StatusCode: 422,
requestURI: "http://example.com/path",
values: url.Values{
"error": []string{"try_again"},
"error_description": []string{"maybe it works later"},
values: map[string]string{
"error": "try_again",
"error_description": "maybe it works later",
},
},
wantErr: Error{
Expand Down Expand Up @@ -153,9 +153,9 @@ func TestPostForm(t *testing.T) {
want: &FormResponse{
StatusCode: 200,
requestURI: "https://github.com/oauth",
values: url.Values{
"access_token": {"123abc"},
"scopes": {"repo gist"},
values: map[string]string{
"access_token": "123abc",
"scopes": "repo gist",
},
},
wantErr: false,
Expand All @@ -173,7 +173,7 @@ func TestPostForm(t *testing.T) {
want: &FormResponse{
StatusCode: 502,
requestURI: "https://github.com/oauth",
values: url.Values(nil),
values: make(map[string]string),
},
wantErr: false,
},
Expand Down

0 comments on commit 7d51c27

Please sign in to comment.