|
Packit Service |
4d2de5 |
package request
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
import (
|
|
Packit Service |
4d2de5 |
"fmt"
|
|
Packit Service |
4d2de5 |
"strings"
|
|
Packit Service |
4d2de5 |
)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// A Handlers provides a collection of request handlers for various
|
|
Packit Service |
4d2de5 |
// stages of handling requests.
|
|
Packit Service |
4d2de5 |
type Handlers struct {
|
|
Packit Service |
4d2de5 |
Validate HandlerList
|
|
Packit Service |
4d2de5 |
Build HandlerList
|
|
Packit Service |
4d2de5 |
Sign HandlerList
|
|
Packit Service |
4d2de5 |
Send HandlerList
|
|
Packit Service |
4d2de5 |
ValidateResponse HandlerList
|
|
Packit Service |
4d2de5 |
Unmarshal HandlerList
|
|
Packit Service |
4d2de5 |
UnmarshalStream HandlerList
|
|
Packit Service |
4d2de5 |
UnmarshalMeta HandlerList
|
|
Packit Service |
4d2de5 |
UnmarshalError HandlerList
|
|
Packit Service |
4d2de5 |
Retry HandlerList
|
|
Packit Service |
4d2de5 |
AfterRetry HandlerList
|
|
Packit Service |
4d2de5 |
CompleteAttempt HandlerList
|
|
Packit Service |
4d2de5 |
Complete HandlerList
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Copy returns a copy of this handler's lists.
|
|
Packit Service |
4d2de5 |
func (h *Handlers) Copy() Handlers {
|
|
Packit Service |
4d2de5 |
return Handlers{
|
|
Packit Service |
4d2de5 |
Validate: h.Validate.copy(),
|
|
Packit Service |
4d2de5 |
Build: h.Build.copy(),
|
|
Packit Service |
4d2de5 |
Sign: h.Sign.copy(),
|
|
Packit Service |
4d2de5 |
Send: h.Send.copy(),
|
|
Packit Service |
4d2de5 |
ValidateResponse: h.ValidateResponse.copy(),
|
|
Packit Service |
4d2de5 |
Unmarshal: h.Unmarshal.copy(),
|
|
Packit Service |
4d2de5 |
UnmarshalStream: h.UnmarshalStream.copy(),
|
|
Packit Service |
4d2de5 |
UnmarshalError: h.UnmarshalError.copy(),
|
|
Packit Service |
4d2de5 |
UnmarshalMeta: h.UnmarshalMeta.copy(),
|
|
Packit Service |
4d2de5 |
Retry: h.Retry.copy(),
|
|
Packit Service |
4d2de5 |
AfterRetry: h.AfterRetry.copy(),
|
|
Packit Service |
4d2de5 |
CompleteAttempt: h.CompleteAttempt.copy(),
|
|
Packit Service |
4d2de5 |
Complete: h.Complete.copy(),
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Clear removes callback functions for all handlers.
|
|
Packit Service |
4d2de5 |
func (h *Handlers) Clear() {
|
|
Packit Service |
4d2de5 |
h.Validate.Clear()
|
|
Packit Service |
4d2de5 |
h.Build.Clear()
|
|
Packit Service |
4d2de5 |
h.Send.Clear()
|
|
Packit Service |
4d2de5 |
h.Sign.Clear()
|
|
Packit Service |
4d2de5 |
h.Unmarshal.Clear()
|
|
Packit Service |
4d2de5 |
h.UnmarshalStream.Clear()
|
|
Packit Service |
4d2de5 |
h.UnmarshalMeta.Clear()
|
|
Packit Service |
4d2de5 |
h.UnmarshalError.Clear()
|
|
Packit Service |
4d2de5 |
h.ValidateResponse.Clear()
|
|
Packit Service |
4d2de5 |
h.Retry.Clear()
|
|
Packit Service |
4d2de5 |
h.AfterRetry.Clear()
|
|
Packit Service |
4d2de5 |
h.CompleteAttempt.Clear()
|
|
Packit Service |
4d2de5 |
h.Complete.Clear()
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// IsEmpty returns if there are no handlers in any of the handlerlists.
|
|
Packit Service |
4d2de5 |
func (h *Handlers) IsEmpty() bool {
|
|
Packit Service |
4d2de5 |
if h.Validate.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.Build.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.Send.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.Sign.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.Unmarshal.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.UnmarshalStream.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.UnmarshalMeta.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.UnmarshalError.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.ValidateResponse.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.Retry.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.AfterRetry.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.CompleteAttempt.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if h.Complete.Len() != 0 {
|
|
Packit Service |
4d2de5 |
return false
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
return true
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// A HandlerListRunItem represents an entry in the HandlerList which
|
|
Packit Service |
4d2de5 |
// is being run.
|
|
Packit Service |
4d2de5 |
type HandlerListRunItem struct {
|
|
Packit Service |
4d2de5 |
Index int
|
|
Packit Service |
4d2de5 |
Handler NamedHandler
|
|
Packit Service |
4d2de5 |
Request *Request
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// A HandlerList manages zero or more handlers in a list.
|
|
Packit Service |
4d2de5 |
type HandlerList struct {
|
|
Packit Service |
4d2de5 |
list []NamedHandler
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Called after each request handler in the list is called. If set
|
|
Packit Service |
4d2de5 |
// and the func returns true the HandlerList will continue to iterate
|
|
Packit Service |
4d2de5 |
// over the request handlers. If false is returned the HandlerList
|
|
Packit Service |
4d2de5 |
// will stop iterating.
|
|
Packit Service |
4d2de5 |
//
|
|
Packit Service |
4d2de5 |
// Should be used if extra logic to be performed between each handler
|
|
Packit Service |
4d2de5 |
// in the list. This can be used to terminate a list's iteration
|
|
Packit Service |
4d2de5 |
// based on a condition such as error like, HandlerListStopOnError.
|
|
Packit Service |
4d2de5 |
// Or for logging like HandlerListLogItem.
|
|
Packit Service |
4d2de5 |
AfterEachFn func(item HandlerListRunItem) bool
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// A NamedHandler is a struct that contains a name and function callback.
|
|
Packit Service |
4d2de5 |
type NamedHandler struct {
|
|
Packit Service |
4d2de5 |
Name string
|
|
Packit Service |
4d2de5 |
Fn func(*Request)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// copy creates a copy of the handler list.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) copy() HandlerList {
|
|
Packit Service |
4d2de5 |
n := HandlerList{
|
|
Packit Service |
4d2de5 |
AfterEachFn: l.AfterEachFn,
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if len(l.list) == 0 {
|
|
Packit Service |
4d2de5 |
return n
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
n.list = append(make([]NamedHandler, 0, len(l.list)), l.list...)
|
|
Packit Service |
4d2de5 |
return n
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Clear clears the handler list.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) Clear() {
|
|
Packit Service |
4d2de5 |
l.list = l.list[0:0]
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Len returns the number of handlers in the list.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) Len() int {
|
|
Packit Service |
4d2de5 |
return len(l.list)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// PushBack pushes handler f to the back of the handler list.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) PushBack(f func(*Request)) {
|
|
Packit Service |
4d2de5 |
l.PushBackNamed(NamedHandler{"__anonymous", f})
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// PushBackNamed pushes named handler f to the back of the handler list.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) PushBackNamed(n NamedHandler) {
|
|
Packit Service |
4d2de5 |
if cap(l.list) == 0 {
|
|
Packit Service |
4d2de5 |
l.list = make([]NamedHandler, 0, 5)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
l.list = append(l.list, n)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// PushFront pushes handler f to the front of the handler list.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) PushFront(f func(*Request)) {
|
|
Packit Service |
4d2de5 |
l.PushFrontNamed(NamedHandler{"__anonymous", f})
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// PushFrontNamed pushes named handler f to the front of the handler list.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) PushFrontNamed(n NamedHandler) {
|
|
Packit Service |
4d2de5 |
if cap(l.list) == len(l.list) {
|
|
Packit Service |
4d2de5 |
// Allocating new list required
|
|
Packit Service |
4d2de5 |
l.list = append([]NamedHandler{n}, l.list...)
|
|
Packit Service |
4d2de5 |
} else {
|
|
Packit Service |
4d2de5 |
// Enough room to prepend into list.
|
|
Packit Service |
4d2de5 |
l.list = append(l.list, NamedHandler{})
|
|
Packit Service |
4d2de5 |
copy(l.list[1:], l.list)
|
|
Packit Service |
4d2de5 |
l.list[0] = n
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Remove removes a NamedHandler n
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) Remove(n NamedHandler) {
|
|
Packit Service |
4d2de5 |
l.RemoveByName(n.Name)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// RemoveByName removes a NamedHandler by name.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) RemoveByName(name string) {
|
|
Packit Service |
4d2de5 |
for i := 0; i < len(l.list); i++ {
|
|
Packit Service |
4d2de5 |
m := l.list[i]
|
|
Packit Service |
4d2de5 |
if m.Name == name {
|
|
Packit Service |
4d2de5 |
// Shift array preventing creating new arrays
|
|
Packit Service |
4d2de5 |
copy(l.list[i:], l.list[i+1:])
|
|
Packit Service |
4d2de5 |
l.list[len(l.list)-1] = NamedHandler{}
|
|
Packit Service |
4d2de5 |
l.list = l.list[:len(l.list)-1]
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// decrement list so next check to length is correct
|
|
Packit Service |
4d2de5 |
i--
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// SwapNamed will swap out any existing handlers with the same name as the
|
|
Packit Service |
4d2de5 |
// passed in NamedHandler returning true if handlers were swapped. False is
|
|
Packit Service |
4d2de5 |
// returned otherwise.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) SwapNamed(n NamedHandler) (swapped bool) {
|
|
Packit Service |
4d2de5 |
for i := 0; i < len(l.list); i++ {
|
|
Packit Service |
4d2de5 |
if l.list[i].Name == n.Name {
|
|
Packit Service |
4d2de5 |
l.list[i].Fn = n.Fn
|
|
Packit Service |
4d2de5 |
swapped = true
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
return swapped
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Swap will swap out all handlers matching the name passed in. The matched
|
|
Packit Service |
4d2de5 |
// handlers will be swapped in. True is returned if the handlers were swapped.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) Swap(name string, replace NamedHandler) bool {
|
|
Packit Service |
4d2de5 |
var swapped bool
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
for i := 0; i < len(l.list); i++ {
|
|
Packit Service |
4d2de5 |
if l.list[i].Name == name {
|
|
Packit Service |
4d2de5 |
l.list[i] = replace
|
|
Packit Service |
4d2de5 |
swapped = true
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
return swapped
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// SetBackNamed will replace the named handler if it exists in the handler list.
|
|
Packit Service |
4d2de5 |
// If the handler does not exist the handler will be added to the end of the list.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) SetBackNamed(n NamedHandler) {
|
|
Packit Service |
4d2de5 |
if !l.SwapNamed(n) {
|
|
Packit Service |
4d2de5 |
l.PushBackNamed(n)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// SetFrontNamed will replace the named handler if it exists in the handler list.
|
|
Packit Service |
4d2de5 |
// If the handler does not exist the handler will be added to the beginning of
|
|
Packit Service |
4d2de5 |
// the list.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) SetFrontNamed(n NamedHandler) {
|
|
Packit Service |
4d2de5 |
if !l.SwapNamed(n) {
|
|
Packit Service |
4d2de5 |
l.PushFrontNamed(n)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Run executes all handlers in the list with a given request object.
|
|
Packit Service |
4d2de5 |
func (l *HandlerList) Run(r *Request) {
|
|
Packit Service |
4d2de5 |
for i, h := range l.list {
|
|
Packit Service |
4d2de5 |
h.Fn(r)
|
|
Packit Service |
4d2de5 |
item := HandlerListRunItem{
|
|
Packit Service |
4d2de5 |
Index: i, Handler: h, Request: r,
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if l.AfterEachFn != nil && !l.AfterEachFn(item) {
|
|
Packit Service |
4d2de5 |
return
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// HandlerListLogItem logs the request handler and the state of the
|
|
Packit Service |
4d2de5 |
// request's Error value. Always returns true to continue iterating
|
|
Packit Service |
4d2de5 |
// request handlers in a HandlerList.
|
|
Packit Service |
4d2de5 |
func HandlerListLogItem(item HandlerListRunItem) bool {
|
|
Packit Service |
4d2de5 |
if item.Request.Config.Logger == nil {
|
|
Packit Service |
4d2de5 |
return true
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
item.Request.Config.Logger.Log("DEBUG: RequestHandler",
|
|
Packit Service |
4d2de5 |
item.Index, item.Handler.Name, item.Request.Error)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
return true
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// HandlerListStopOnError returns false to stop the HandlerList iterating
|
|
Packit Service |
4d2de5 |
// over request handlers if Request.Error is not nil. True otherwise
|
|
Packit Service |
4d2de5 |
// to continue iterating.
|
|
Packit Service |
4d2de5 |
func HandlerListStopOnError(item HandlerListRunItem) bool {
|
|
Packit Service |
4d2de5 |
return item.Request.Error == nil
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// WithAppendUserAgent will add a string to the user agent prefixed with a
|
|
Packit Service |
4d2de5 |
// single white space.
|
|
Packit Service |
4d2de5 |
func WithAppendUserAgent(s string) Option {
|
|
Packit Service |
4d2de5 |
return func(r *Request) {
|
|
Packit Service |
4d2de5 |
r.Handlers.Build.PushBack(func(r2 *Request) {
|
|
Packit Service |
4d2de5 |
AddToUserAgent(r, s)
|
|
Packit Service |
4d2de5 |
})
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request
|
|
Packit Service |
4d2de5 |
// header. If the extra parameters are provided they will be added as metadata to the
|
|
Packit Service |
4d2de5 |
// name/version pair resulting in the following format.
|
|
Packit Service |
4d2de5 |
// "name/version (extra0; extra1; ...)"
|
|
Packit Service |
4d2de5 |
// The user agent part will be concatenated with this current request's user agent string.
|
|
Packit Service |
4d2de5 |
func MakeAddToUserAgentHandler(name, version string, extra ...string) func(*Request) {
|
|
Packit Service |
4d2de5 |
ua := fmt.Sprintf("%s/%s", name, version)
|
|
Packit Service |
4d2de5 |
if len(extra) > 0 {
|
|
Packit Service |
4d2de5 |
ua += fmt.Sprintf(" (%s)", strings.Join(extra, "; "))
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
return func(r *Request) {
|
|
Packit Service |
4d2de5 |
AddToUserAgent(r, ua)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// MakeAddToUserAgentFreeFormHandler adds the input to the User-Agent request header.
|
|
Packit Service |
4d2de5 |
// The input string will be concatenated with the current request's user agent string.
|
|
Packit Service |
4d2de5 |
func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
|
|
Packit Service |
4d2de5 |
return func(r *Request) {
|
|
Packit Service |
4d2de5 |
AddToUserAgent(r, s)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|