forked from theplant/osin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
response.go
151 lines (131 loc) · 3.53 KB
/
response.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package osin
import (
"errors"
"fmt"
"net/http"
"net/url"
)
// Data for response output
type ResponseData map[string]interface{}
// Response type enum
type ResponseType int
const (
DATA ResponseType = iota
REDIRECT
)
// Server response
type Response struct {
Type ResponseType
StatusCode int
StatusText string
ErrorStatusCode int
URL string
Output ResponseData
Headers http.Header
IsError bool
ErrorId string
InternalError error
RedirectInFragment bool
// Storage to use in this response - required
Storage Storage
}
func NewResponse(storage Storage) *Response {
r := &Response{
Type: DATA,
StatusCode: 200,
ErrorStatusCode: 200,
Output: make(ResponseData),
Headers: make(http.Header),
IsError: false,
Storage: storage.Clone(),
}
r.Headers.Add(
"Cache-Control",
"no-cache, no-store, max-age=0, must-revalidate",
)
r.Headers.Add("Pragma", "no-cache")
r.Headers.Add("Expires", "Fri, 01 Jan 1990 00:00:00 GMT")
return r
}
// SetError sets an error id and description on the Response
// state and uri are left blank
func (r *Response) SetError(id string, description string) {
r.SetErrorUri(id, description, "", "")
}
// SetErrorState sets an error id, description, and state on the Response
// uri is left blank
func (r *Response) SetErrorState(id string, description string, state string) {
r.SetErrorUri(id, description, "", state)
}
// SetErrorUri sets an error id, description, state, and uri on the Response
func (r *Response) SetErrorUri(id string, description string, uri string, state string) {
// get default error message
if description == "" {
description = deferror.Get(id)
}
// set error parameters
r.IsError = true
r.ErrorId = id
r.StatusCode = r.ErrorStatusCode
if r.StatusCode != 200 {
r.StatusText = description
} else {
r.StatusText = ""
}
r.Output = make(ResponseData) // clear output
r.Output["error"] = id
r.Output["error_description"] = description
if uri != "" {
r.Output["error_uri"] = uri
}
if state != "" {
r.Output["state"] = state
}
}
// SetRedirect changes the response to redirect to the given url
func (r *Response) SetRedirect(url string) {
// set redirect parameters
r.Type = REDIRECT
r.URL = url
}
// SetRedirectFragment sets redirect values to be passed in fragment instead of as query parameters
func (r *Response) SetRedirectFragment(f bool) {
r.RedirectInFragment = f
}
// GetRedirectUrl returns the redirect url with all query string parameters
func (r *Response) GetRedirectUrl() (string, error) {
if r.Type != REDIRECT {
return "", errors.New("Not a redirect response")
}
u, err := url.Parse(r.URL)
if err != nil {
return "", err
}
var q url.Values
if r.RedirectInFragment {
// start with empty set for fragment
q = url.Values{}
} else {
// add parameters to existing query
q = u.Query()
}
// add parameters
for n, v := range r.Output {
q.Set(n, fmt.Sprint(v))
}
// https://tools.ietf.org/html/rfc6749#section-4.2.2
// Fragment should be encoded as application/x-www-form-urlencoded (%-escaped, spaces are represented as '+')
// The stdlib URL#String() doesn't make that easy to accomplish, so build this ourselves
if r.RedirectInFragment {
u.Fragment = ""
redirectURI := u.String() + "#" + q.Encode()
return redirectURI, nil
}
// Otherwise, update the query and encode normally
u.RawQuery = q.Encode()
u.Fragment = ""
return u.String(), nil
}
func (r *Response) Close() {
r.Storage.Close()
}