8 // A Handlers provides a collection of request handlers for various
9 // stages of handling requests.
10 type Handlers struct {
15 ValidateResponse HandlerList
17 UnmarshalMeta HandlerList
18 UnmarshalError HandlerList
20 AfterRetry HandlerList
24 // Copy returns of this handler's lists.
25 func (h *Handlers) Copy() Handlers {
27 Validate: h.Validate.copy(),
28 Build: h.Build.copy(),
31 ValidateResponse: h.ValidateResponse.copy(),
32 Unmarshal: h.Unmarshal.copy(),
33 UnmarshalError: h.UnmarshalError.copy(),
34 UnmarshalMeta: h.UnmarshalMeta.copy(),
35 Retry: h.Retry.copy(),
36 AfterRetry: h.AfterRetry.copy(),
37 Complete: h.Complete.copy(),
41 // Clear removes callback functions for all handlers
42 func (h *Handlers) Clear() {
48 h.UnmarshalMeta.Clear()
49 h.UnmarshalError.Clear()
50 h.ValidateResponse.Clear()
56 // A HandlerListRunItem represents an entry in the HandlerList which
58 type HandlerListRunItem struct {
64 // A HandlerList manages zero or more handlers in a list.
65 type HandlerList struct {
68 // Called after each request handler in the list is called. If set
69 // and the func returns true the HandlerList will continue to iterate
70 // over the request handlers. If false is returned the HandlerList
71 // will stop iterating.
73 // Should be used if extra logic to be performed between each handler
74 // in the list. This can be used to terminate a list's iteration
75 // based on a condition such as error like, HandlerListStopOnError.
76 // Or for logging like HandlerListLogItem.
77 AfterEachFn func(item HandlerListRunItem) bool
80 // A NamedHandler is a struct that contains a name and function callback.
81 type NamedHandler struct {
86 // copy creates a copy of the handler list.
87 func (l *HandlerList) copy() HandlerList {
89 AfterEachFn: l.AfterEachFn,
95 n.list = append(make([]NamedHandler, 0, len(l.list)), l.list...)
99 // Clear clears the handler list.
100 func (l *HandlerList) Clear() {
104 // Len returns the number of handlers in the list.
105 func (l *HandlerList) Len() int {
109 // PushBack pushes handler f to the back of the handler list.
110 func (l *HandlerList) PushBack(f func(*Request)) {
111 l.PushBackNamed(NamedHandler{"__anonymous", f})
114 // PushBackNamed pushes named handler f to the back of the handler list.
115 func (l *HandlerList) PushBackNamed(n NamedHandler) {
116 if cap(l.list) == 0 {
117 l.list = make([]NamedHandler, 0, 5)
119 l.list = append(l.list, n)
122 // PushFront pushes handler f to the front of the handler list.
123 func (l *HandlerList) PushFront(f func(*Request)) {
124 l.PushFrontNamed(NamedHandler{"__anonymous", f})
127 // PushFrontNamed pushes named handler f to the front of the handler list.
128 func (l *HandlerList) PushFrontNamed(n NamedHandler) {
129 if cap(l.list) == len(l.list) {
130 // Allocating new list required
131 l.list = append([]NamedHandler{n}, l.list...)
133 // Enough room to prepend into list.
134 l.list = append(l.list, NamedHandler{})
135 copy(l.list[1:], l.list)
140 // Remove removes a NamedHandler n
141 func (l *HandlerList) Remove(n NamedHandler) {
142 l.RemoveByName(n.Name)
145 // RemoveByName removes a NamedHandler by name.
146 func (l *HandlerList) RemoveByName(name string) {
147 for i := 0; i < len(l.list); i++ {
150 // Shift array preventing creating new arrays
151 copy(l.list[i:], l.list[i+1:])
152 l.list[len(l.list)-1] = NamedHandler{}
153 l.list = l.list[:len(l.list)-1]
155 // decrement list so next check to length is correct
161 // SwapNamed will swap out any existing handlers with the same name as the
162 // passed in NamedHandler returning true if handlers were swapped. False is
163 // returned otherwise.
164 func (l *HandlerList) SwapNamed(n NamedHandler) (swapped bool) {
165 for i := 0; i < len(l.list); i++ {
166 if l.list[i].Name == n.Name {
175 // SetBackNamed will replace the named handler if it exists in the handler list.
176 // If the handler does not exist the handler will be added to the end of the list.
177 func (l *HandlerList) SetBackNamed(n NamedHandler) {
183 // SetFrontNamed will replace the named handler if it exists in the handler list.
184 // If the handler does not exist the handler will be added to the beginning of
186 func (l *HandlerList) SetFrontNamed(n NamedHandler) {
192 // Run executes all handlers in the list with a given request object.
193 func (l *HandlerList) Run(r *Request) {
194 for i, h := range l.list {
196 item := HandlerListRunItem{
197 Index: i, Handler: h, Request: r,
199 if l.AfterEachFn != nil && !l.AfterEachFn(item) {
205 // HandlerListLogItem logs the request handler and the state of the
206 // request's Error value. Always returns true to continue iterating
207 // request handlers in a HandlerList.
208 func HandlerListLogItem(item HandlerListRunItem) bool {
209 if item.Request.Config.Logger == nil {
212 item.Request.Config.Logger.Log("DEBUG: RequestHandler",
213 item.Index, item.Handler.Name, item.Request.Error)
218 // HandlerListStopOnError returns false to stop the HandlerList iterating
219 // over request handlers if Request.Error is not nil. True otherwise
220 // to continue iterating.
221 func HandlerListStopOnError(item HandlerListRunItem) bool {
222 return item.Request.Error == nil
225 // WithAppendUserAgent will add a string to the user agent prefixed with a
226 // single white space.
227 func WithAppendUserAgent(s string) Option {
228 return func(r *Request) {
229 r.Handlers.Build.PushBack(func(r2 *Request) {
235 // MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request
236 // header. If the extra parameters are provided they will be added as metadata to the
237 // name/version pair resulting in the following format.
238 // "name/version (extra0; extra1; ...)"
239 // The user agent part will be concatenated with this current request's user agent string.
240 func MakeAddToUserAgentHandler(name, version string, extra ...string) func(*Request) {
241 ua := fmt.Sprintf("%s/%s", name, version)
243 ua += fmt.Sprintf(" (%s)", strings.Join(extra, "; "))
245 return func(r *Request) {
246 AddToUserAgent(r, ua)
250 // MakeAddToUserAgentFreeFormHandler adds the input to the User-Agent request header.
251 // The input string will be concatenated with the current request's user agent string.
252 func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
253 return func(r *Request) {