handlers.go 9.1 KB

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