handlers.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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. // Run executes all handlers in the list with a given request object.
  142. func (l *HandlerList) Run(r *Request) {
  143. for i, h := range l.list {
  144. h.Fn(r)
  145. item := HandlerListRunItem{
  146. Index: i, Handler: h, Request: r,
  147. }
  148. if l.AfterEachFn != nil && !l.AfterEachFn(item) {
  149. return
  150. }
  151. }
  152. }
  153. // HandlerListLogItem logs the request handler and the state of the
  154. // request's Error value. Always returns true to continue iterating
  155. // request handlers in a HandlerList.
  156. func HandlerListLogItem(item HandlerListRunItem) bool {
  157. if item.Request.Config.Logger == nil {
  158. return true
  159. }
  160. item.Request.Config.Logger.Log("DEBUG: RequestHandler",
  161. item.Index, item.Handler.Name, item.Request.Error)
  162. return true
  163. }
  164. // HandlerListStopOnError returns false to stop the HandlerList iterating
  165. // over request handlers if Request.Error is not nil. True otherwise
  166. // to continue iterating.
  167. func HandlerListStopOnError(item HandlerListRunItem) bool {
  168. return item.Request.Error == nil
  169. }
  170. // WithAppendUserAgent will add a string to the user agent prefixed with a
  171. // single white space.
  172. func WithAppendUserAgent(s string) Option {
  173. return func(r *Request) {
  174. r.Handlers.Build.PushBack(func(r2 *Request) {
  175. AddToUserAgent(r, s)
  176. })
  177. }
  178. }
  179. // MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request
  180. // header. If the extra parameters are provided they will be added as metadata to the
  181. // name/version pair resulting in the following format.
  182. // "name/version (extra0; extra1; ...)"
  183. // The user agent part will be concatenated with this current request's user agent string.
  184. func MakeAddToUserAgentHandler(name, version string, extra ...string) func(*Request) {
  185. ua := fmt.Sprintf("%s/%s", name, version)
  186. if len(extra) > 0 {
  187. ua += fmt.Sprintf(" (%s)", strings.Join(extra, "; "))
  188. }
  189. return func(r *Request) {
  190. AddToUserAgent(r, ua)
  191. }
  192. }
  193. // MakeAddToUserAgentFreeFormHandler adds the input to the User-Agent request header.
  194. // The input string will be concatenated with the current request's user agent string.
  195. func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
  196. return func(r *Request) {
  197. AddToUserAgent(r, s)
  198. }
  199. }