handlers.go 7.6 KB

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