handlers.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. package request
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. // A Handlers provides a collection of request handlers for various
  7. // stages of handling requests.
  8. type Handlers struct {
  9. Validate HandlerList
  10. Build HandlerList
  11. Sign HandlerList
  12. Send HandlerList
  13. ValidateResponse HandlerList
  14. Unmarshal HandlerList
  15. UnmarshalMeta HandlerList
  16. UnmarshalError HandlerList
  17. Retry HandlerList
  18. AfterRetry HandlerList
  19. Complete HandlerList
  20. }
  21. // Copy returns of this handler's lists.
  22. func (h *Handlers) Copy() Handlers {
  23. return Handlers{
  24. Validate: h.Validate.copy(),
  25. Build: h.Build.copy(),
  26. Sign: h.Sign.copy(),
  27. Send: h.Send.copy(),
  28. ValidateResponse: h.ValidateResponse.copy(),
  29. Unmarshal: h.Unmarshal.copy(),
  30. UnmarshalError: h.UnmarshalError.copy(),
  31. UnmarshalMeta: h.UnmarshalMeta.copy(),
  32. Retry: h.Retry.copy(),
  33. AfterRetry: h.AfterRetry.copy(),
  34. Complete: h.Complete.copy(),
  35. }
  36. }
  37. // Clear removes callback functions for all handlers
  38. func (h *Handlers) Clear() {
  39. h.Validate.Clear()
  40. h.Build.Clear()
  41. h.Send.Clear()
  42. h.Sign.Clear()
  43. h.Unmarshal.Clear()
  44. h.UnmarshalMeta.Clear()
  45. h.UnmarshalError.Clear()
  46. h.ValidateResponse.Clear()
  47. h.Retry.Clear()
  48. h.AfterRetry.Clear()
  49. h.Complete.Clear()
  50. }
  51. // A HandlerListRunItem represents an entry in the HandlerList which
  52. // is being run.
  53. type HandlerListRunItem struct {
  54. Index int
  55. Handler NamedHandler
  56. Request *Request
  57. }
  58. // A HandlerList manages zero or more handlers in a list.
  59. type HandlerList struct {
  60. list []NamedHandler
  61. // Called after each request handler in the list is called. If set
  62. // and the func returns true the HandlerList will continue to iterate
  63. // over the request handlers. If false is returned the HandlerList
  64. // will stop iterating.
  65. //
  66. // Should be used if extra logic to be performed between each handler
  67. // in the list. This can be used to terminate a list's iteration
  68. // based on a condition such as error like, HandlerListStopOnError.
  69. // Or for logging like HandlerListLogItem.
  70. AfterEachFn func(item HandlerListRunItem) bool
  71. }
  72. // A NamedHandler is a struct that contains a name and function callback.
  73. type NamedHandler struct {
  74. Name string
  75. Fn func(*Request)
  76. }
  77. // copy creates a copy of the handler list.
  78. func (l *HandlerList) copy() HandlerList {
  79. n := HandlerList{
  80. AfterEachFn: l.AfterEachFn,
  81. }
  82. if len(l.list) == 0 {
  83. return n
  84. }
  85. n.list = append(make([]NamedHandler, 0, len(l.list)), l.list...)
  86. return n
  87. }
  88. // Clear clears the handler list.
  89. func (l *HandlerList) Clear() {
  90. l.list = l.list[0:0]
  91. }
  92. // Len returns the number of handlers in the list.
  93. func (l *HandlerList) Len() int {
  94. return len(l.list)
  95. }
  96. // PushBack pushes handler f to the back of the handler list.
  97. func (l *HandlerList) PushBack(f func(*Request)) {
  98. l.PushBackNamed(NamedHandler{"__anonymous", f})
  99. }
  100. // PushBackNamed pushes named handler f to the back of the handler list.
  101. func (l *HandlerList) PushBackNamed(n NamedHandler) {
  102. if cap(l.list) == 0 {
  103. l.list = make([]NamedHandler, 0, 5)
  104. }
  105. l.list = append(l.list, n)
  106. }
  107. // PushFront pushes handler f to the front of the handler list.
  108. func (l *HandlerList) PushFront(f func(*Request)) {
  109. l.PushFrontNamed(NamedHandler{"__anonymous", f})
  110. }
  111. // PushFrontNamed pushes named handler f to the front of the handler list.
  112. func (l *HandlerList) PushFrontNamed(n NamedHandler) {
  113. if cap(l.list) == len(l.list) {
  114. // Allocating new list required
  115. l.list = append([]NamedHandler{n}, l.list...)
  116. } else {
  117. // Enough room to prepend into list.
  118. l.list = append(l.list, NamedHandler{})
  119. copy(l.list[1:], l.list)
  120. l.list[0] = n
  121. }
  122. }
  123. // Remove removes a NamedHandler n
  124. func (l *HandlerList) Remove(n NamedHandler) {
  125. l.RemoveByName(n.Name)
  126. }
  127. // RemoveByName removes a NamedHandler by name.
  128. func (l *HandlerList) RemoveByName(name string) {
  129. for i := 0; i < len(l.list); i++ {
  130. m := l.list[i]
  131. if m.Name == name {
  132. // Shift array preventing creating new arrays
  133. copy(l.list[i:], l.list[i+1:])
  134. l.list[len(l.list)-1] = NamedHandler{}
  135. l.list = l.list[:len(l.list)-1]
  136. // decrement list so next check to length is correct
  137. i--
  138. }
  139. }
  140. }
  141. // SwapNamed will swap out any existing handlers with the same name as the
  142. // passed in NamedHandler returning true if handlers were swapped. False is
  143. // returned otherwise.
  144. func (l *HandlerList) SwapNamed(n NamedHandler) (swapped bool) {
  145. for i := 0; i < len(l.list); i++ {
  146. if l.list[i].Name == n.Name {
  147. l.list[i].Fn = n.Fn
  148. swapped = true
  149. }
  150. }
  151. return swapped
  152. }
  153. // SetBackNamed will replace the named handler if it exists in the handler list.
  154. // If the handler does not exist the handler will be added to the end of the list.
  155. func (l *HandlerList) SetBackNamed(n NamedHandler) {
  156. if !l.SwapNamed(n) {
  157. l.PushBackNamed(n)
  158. }
  159. }
  160. // SetFrontNamed will replace the named handler if it exists in the handler list.
  161. // If the handler does not exist the handler will be added to the beginning of
  162. // the list.
  163. func (l *HandlerList) SetFrontNamed(n NamedHandler) {
  164. if !l.SwapNamed(n) {
  165. l.PushFrontNamed(n)
  166. }
  167. }
  168. // Run executes all handlers in the list with a given request object.
  169. func (l *HandlerList) Run(r *Request) {
  170. for i, h := range l.list {
  171. h.Fn(r)
  172. item := HandlerListRunItem{
  173. Index: i, Handler: h, Request: r,
  174. }
  175. if l.AfterEachFn != nil && !l.AfterEachFn(item) {
  176. return
  177. }
  178. }
  179. }
  180. // HandlerListLogItem logs the request handler and the state of the
  181. // request's Error value. Always returns true to continue iterating
  182. // request handlers in a HandlerList.
  183. func HandlerListLogItem(item HandlerListRunItem) bool {
  184. if item.Request.Config.Logger == nil {
  185. return true
  186. }
  187. item.Request.Config.Logger.Log("DEBUG: RequestHandler",
  188. item.Index, item.Handler.Name, item.Request.Error)
  189. return true
  190. }
  191. // HandlerListStopOnError returns false to stop the HandlerList iterating
  192. // over request handlers if Request.Error is not nil. True otherwise
  193. // to continue iterating.
  194. func HandlerListStopOnError(item HandlerListRunItem) bool {
  195. return item.Request.Error == nil
  196. }
  197. // WithAppendUserAgent will add a string to the user agent prefixed with a
  198. // single white space.
  199. func WithAppendUserAgent(s string) Option {
  200. return func(r *Request) {
  201. r.Handlers.Build.PushBack(func(r2 *Request) {
  202. AddToUserAgent(r, s)
  203. })
  204. }
  205. }
  206. // MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request
  207. // header. If the extra parameters are provided they will be added as metadata to the
  208. // name/version pair resulting in the following format.
  209. // "name/version (extra0; extra1; ...)"
  210. // The user agent part will be concatenated with this current request's user agent string.
  211. func MakeAddToUserAgentHandler(name, version string, extra ...string) func(*Request) {
  212. ua := fmt.Sprintf("%s/%s", name, version)
  213. if len(extra) > 0 {
  214. ua += fmt.Sprintf(" (%s)", strings.Join(extra, "; "))
  215. }
  216. return func(r *Request) {
  217. AddToUserAgent(r, ua)
  218. }
  219. }
  220. // MakeAddToUserAgentFreeFormHandler adds the input to the User-Agent request header.
  221. // The input string will be concatenated with the current request's user agent string.
  222. func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
  223. return func(r *Request) {
  224. AddToUserAgent(r, s)
  225. }
  226. }