request_params.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package context
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strconv"
  6. "strings"
  7. "github.com/kataras/iris/core/memstore"
  8. )
  9. // RequestParams is a key string - value string storage which
  10. // context's request dynamic path params are being kept.
  11. // Empty if the route is static.
  12. type RequestParams struct {
  13. memstore.Store
  14. }
  15. // Set inserts a parameter value.
  16. // See `Get` too.
  17. func (r *RequestParams) Set(key, value string) {
  18. if ln := len(r.Store); cap(r.Store) > ln {
  19. r.Store = r.Store[:ln+1]
  20. p := &r.Store[ln]
  21. p.Key = key
  22. p.ValueRaw = value
  23. return
  24. }
  25. r.Store = append(r.Store, memstore.Entry{
  26. Key: key,
  27. ValueRaw: value,
  28. })
  29. }
  30. // Get returns a path parameter's value based on its route's dynamic path key.
  31. func (r *RequestParams) Get(key string) string {
  32. for i := 0; i < len(r.Store); i++ {
  33. if kv := r.Store[i]; kv.Key == key {
  34. if v, ok := kv.ValueRaw.(string); ok {
  35. return v // it should always be string here on :string parameter.
  36. }
  37. return fmt.Sprintf("%s", kv.ValueRaw)
  38. }
  39. }
  40. return ""
  41. }
  42. // GetEntryAt will return the parameter's internal store's `Entry` based on the index.
  43. // If not found it will return an emptry `Entry`.
  44. func (r *RequestParams) GetEntryAt(index int) memstore.Entry {
  45. entry, _ := r.Store.GetEntryAt(index)
  46. return entry
  47. }
  48. // GetEntry will return the parameter's internal store's `Entry` based on its name/key.
  49. // If not found it will return an emptry `Entry`.
  50. func (r *RequestParams) GetEntry(key string) memstore.Entry {
  51. entry, _ := r.Store.GetEntry(key)
  52. return entry
  53. }
  54. // Visit accepts a visitor which will be filled
  55. // by the key-value params.
  56. func (r *RequestParams) Visit(visitor func(key string, value string)) {
  57. r.Store.Visit(func(k string, v interface{}) {
  58. visitor(k, fmt.Sprintf("%v", v)) // always string here.
  59. })
  60. }
  61. // GetTrim returns a path parameter's value without trailing spaces based on its route's dynamic path key.
  62. func (r *RequestParams) GetTrim(key string) string {
  63. return strings.TrimSpace(r.Get(key))
  64. }
  65. // GetEscape returns a path parameter's double-url-query-escaped value based on its route's dynamic path key.
  66. func (r *RequestParams) GetEscape(key string) string {
  67. return DecodeQuery(DecodeQuery(r.Get(key)))
  68. }
  69. // GetDecoded returns a path parameter's double-url-query-escaped value based on its route's dynamic path key.
  70. // same as `GetEscape`.
  71. func (r *RequestParams) GetDecoded(key string) string {
  72. return r.GetEscape(key)
  73. }
  74. // GetIntUnslashed same as Get but it removes the first slash if found.
  75. // Usage: Get an id from a wildcard path.
  76. //
  77. // Returns -1 and false if not path parameter with that "key" found.
  78. func (r *RequestParams) GetIntUnslashed(key string) (int, bool) {
  79. v := r.Get(key)
  80. if v != "" {
  81. if len(v) > 1 {
  82. if v[0] == '/' {
  83. v = v[1:]
  84. }
  85. }
  86. vInt, err := strconv.Atoi(v)
  87. if err != nil {
  88. return -1, false
  89. }
  90. return vInt, true
  91. }
  92. return -1, false
  93. }
  94. // ParamResolvers is the global param resolution for a parameter type for a specific go std or custom type.
  95. //
  96. // Key is the specific type, which should be unique.
  97. // The value is a function which accepts the parameter index
  98. // and it should return the value as the parameter type evaluator expects it.
  99. // i.e [reflect.TypeOf("string")] = func(paramIndex int) interface{} {
  100. // return func(ctx *Context) <T> {
  101. // return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(<T>)
  102. // }
  103. // }
  104. //
  105. // Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
  106. // Checks for total available request parameters length
  107. // and parameter index based on the hero/mvc function added
  108. // in order to support the MVC.HandleMany("GET", "/path/{ps}/{pssecond} /path/{ps}")
  109. // when on the second requested path, the 'pssecond' should be empty.
  110. var ParamResolvers = map[reflect.Type]func(paramIndex int) interface{}{
  111. reflect.TypeOf(""): func(paramIndex int) interface{} {
  112. return func(ctx *Context) string {
  113. if ctx.Params().Len() <= paramIndex {
  114. return ""
  115. }
  116. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(string)
  117. }
  118. },
  119. reflect.TypeOf(int(1)): func(paramIndex int) interface{} {
  120. return func(ctx *Context) int {
  121. if ctx.Params().Len() <= paramIndex {
  122. return 0
  123. }
  124. // v, _ := ctx.Params().GetEntryAt(paramIndex).IntDefault(0)
  125. // return v
  126. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(int)
  127. }
  128. },
  129. reflect.TypeOf(int8(1)): func(paramIndex int) interface{} {
  130. return func(ctx *Context) int8 {
  131. if ctx.Params().Len() <= paramIndex {
  132. return 0
  133. }
  134. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(int8)
  135. }
  136. },
  137. reflect.TypeOf(int16(1)): func(paramIndex int) interface{} {
  138. return func(ctx *Context) int16 {
  139. if ctx.Params().Len() <= paramIndex {
  140. return 0
  141. }
  142. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(int16)
  143. }
  144. },
  145. reflect.TypeOf(int32(1)): func(paramIndex int) interface{} {
  146. return func(ctx *Context) int32 {
  147. if ctx.Params().Len() <= paramIndex {
  148. return 0
  149. }
  150. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(int32)
  151. }
  152. },
  153. reflect.TypeOf(int64(1)): func(paramIndex int) interface{} {
  154. return func(ctx *Context) int64 {
  155. if ctx.Params().Len() <= paramIndex {
  156. return 0
  157. }
  158. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(int64)
  159. }
  160. },
  161. reflect.TypeOf(uint(1)): func(paramIndex int) interface{} {
  162. return func(ctx *Context) uint {
  163. if ctx.Params().Len() <= paramIndex {
  164. return 0
  165. }
  166. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(uint)
  167. }
  168. },
  169. reflect.TypeOf(uint8(1)): func(paramIndex int) interface{} {
  170. return func(ctx *Context) uint8 {
  171. if ctx.Params().Len() <= paramIndex {
  172. return 0
  173. }
  174. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(uint8)
  175. }
  176. },
  177. reflect.TypeOf(uint16(1)): func(paramIndex int) interface{} {
  178. return func(ctx *Context) uint16 {
  179. if ctx.Params().Len() <= paramIndex {
  180. return 0
  181. }
  182. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(uint16)
  183. }
  184. },
  185. reflect.TypeOf(uint32(1)): func(paramIndex int) interface{} {
  186. return func(ctx *Context) uint32 {
  187. if ctx.Params().Len() <= paramIndex {
  188. return 0
  189. }
  190. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(uint32)
  191. }
  192. },
  193. reflect.TypeOf(uint64(1)): func(paramIndex int) interface{} {
  194. return func(ctx *Context) uint64 {
  195. if ctx.Params().Len() <= paramIndex {
  196. return 0
  197. }
  198. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(uint64)
  199. }
  200. },
  201. reflect.TypeOf(true): func(paramIndex int) interface{} {
  202. return func(ctx *Context) bool {
  203. if ctx.Params().Len() <= paramIndex {
  204. return false
  205. }
  206. return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(bool)
  207. }
  208. },
  209. }
  210. // ParamResolverByTypeAndIndex will return a function that can be used to bind path parameter's exact value by its Go std type
  211. // and the parameter's index based on the registered path.
  212. // Usage: nameResolver := ParamResolverByKindAndKey(reflect.TypeOf(""), 0)
  213. // Inside a Handler: nameResolver.Call(ctx)[0]
  214. // it will return the reflect.Value Of the exact type of the parameter(based on the path parameters and macros).
  215. // It is only useful for dynamic binding of the parameter, it is used on "hero" package and it should be modified
  216. // only when Macros are modified in such way that the default selections for the available go std types are not enough.
  217. //
  218. // Returns empty value and false if "k" does not match any valid parameter resolver.
  219. func ParamResolverByTypeAndIndex(typ reflect.Type, paramIndex int) (reflect.Value, bool) {
  220. /* NO:
  221. // This could work but its result is not exact type, so direct binding is not possible.
  222. resolver := m.ParamResolver
  223. fn := func(ctx *context.Context) interface{} {
  224. entry, _ := ctx.Params().GetEntry(paramName)
  225. return resolver(entry)
  226. }
  227. //
  228. // This works but it is slower on serve-time.
  229. paramNameValue := []reflect.Value{reflect.ValueOf(paramName)}
  230. var fnSignature func(*context.Context) string
  231. return reflect.MakeFunc(reflect.ValueOf(&fnSignature).Elem().Type(), func(in []reflect.Value) []reflect.Value {
  232. return in[0].MethodByName("Params").Call(emptyIn)[0].MethodByName("Get").Call(paramNameValue)
  233. // return []reflect.Value{reflect.ValueOf(in[0].Interface().(*context.Context).Params().Get(paramName))}
  234. })
  235. //
  236. */
  237. r, ok := ParamResolvers[typ]
  238. if !ok || r == nil {
  239. return reflect.Value{}, false
  240. }
  241. return reflect.ValueOf(r(paramIndex)), true
  242. }