validator.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package rule
  2. import (
  3. "github.com/kataras/iris/context"
  4. )
  5. // Validators are introduced to implement the RFC about cache (https://tools.ietf.org/html/rfc7234#section-1.1).
  6. // PreValidator like middleware, executes before the cache action begins, if a callback returns false
  7. // then this specific cache action, with specific request, is ignored and the real (original)
  8. // handler is executed instead.
  9. //
  10. // I'll not add all specifications here I'll give the opportunity (public API in the httpcache package-level)
  11. // to the end-user to specify her/his ignore rules too (ignore-only for now).
  12. //
  13. // Each package, nethttp and fhttp should implement their own encapsulations because of different request object.
  14. //
  15. // One function, accepts the request and returns false if should be denied/ignore, otherwise true.
  16. // if at least one return false then the original handler will execute as it's
  17. // and the whole cache action(set & get) should be ignored, it will be never go to the step of post-cache validations.
  18. type PreValidator func(context.Context) bool
  19. // PostValidator type is is introduced to implement the second part of the RFC about cache.
  20. //
  21. // Q: What's the difference between this and a PreValidator?
  22. // A: PreValidator runs BEFORE trying to get the cache, it cares only for the request
  23. // and if at least one PreValidator returns false then it just runs the original handler and stop there, at the other hand
  24. // a PostValidator runs if all PreValidators returns true and original handler is executed but with a response recorder,
  25. // also the PostValidator should return true to store the cached response.
  26. // Last, a PostValidator accepts a context
  27. // in order to be able to catch the original handler's response,
  28. // the PreValidator checks only for request.
  29. //
  30. // If a function of type of PostValidator returns true then the (shared-always) cache is allowed to be stored.
  31. type PostValidator func(context.Context) bool
  32. // validatorRule is a rule witch receives PreValidators and PostValidators
  33. // it's a 'complete set of rules', you can call it as a Responsible Validator,
  34. // it's used when you the user wants to check for special things inside a request and a response.
  35. type validatorRule struct {
  36. // preValidators a list of PreValidator functions, execute before real cache begins
  37. // if at least one of them returns false then the original handler will execute as it's
  38. // and the whole cache action(set & get) will be skipped for this specific client's request.
  39. //
  40. // Read-only 'runtime'
  41. preValidators []PreValidator
  42. // postValidators a list of PostValidator functions, execute after the original handler is executed with the response recorder
  43. // and exactly before this cached response is saved,
  44. // if at least one of them returns false then the response will be not saved for this specific client's request.
  45. //
  46. // Read-only 'runtime'
  47. postValidators []PostValidator
  48. }
  49. var _ Rule = &validatorRule{}
  50. // DefaultValidator returns a new validator which contains the default pre and post cache validators
  51. func DefaultValidator() Rule { return Validator(nil, nil) }
  52. // Validator receives the preValidators and postValidators and returns a new Validator rule
  53. func Validator(preValidators []PreValidator, postValidators []PostValidator) Rule {
  54. return &validatorRule{
  55. preValidators: preValidators,
  56. postValidators: postValidators,
  57. }
  58. }
  59. // Claim returns true if incoming request can claim for a cached handler
  60. // the original handler should run as it is and exit
  61. func (v *validatorRule) Claim(ctx context.Context) bool {
  62. // check for pre-cache validators, if at least one of them return false
  63. // for this specific request, then skip the whole cache
  64. for _, shouldProcess := range v.preValidators {
  65. if !shouldProcess(ctx) {
  66. return false
  67. }
  68. }
  69. return true
  70. }
  71. // Valid returns true if incoming request and post-response from the original handler
  72. // is valid to be store to the cache, if not(false) then the consumer should just exit
  73. // otherwise(true) the consumer should store the cached response
  74. func (v *validatorRule) Valid(ctx context.Context) bool {
  75. // check if it's a valid response, if it's not then just return.
  76. for _, valid := range v.postValidators {
  77. if !valid(ctx) {
  78. return false
  79. }
  80. }
  81. return true
  82. }