handlers.go 7.7 KB

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