選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 

241 行
6.3 KiB

  1. // Copyright 2015 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Package priority allows grouping modifiers and applying them in priority order.
  15. package priority
  16. import (
  17. "encoding/json"
  18. "errors"
  19. "net/http"
  20. "sync"
  21. "github.com/google/martian"
  22. "github.com/google/martian/parse"
  23. )
  24. var (
  25. // ErrModifierNotFound is the error returned when attempting to remove a
  26. // modifier when the modifier does not exist in the group.
  27. ErrModifierNotFound = errors.New("modifier not found in group")
  28. )
  29. // priorityRequestModifier is a request modifier with a priority.
  30. type priorityRequestModifier struct {
  31. reqmod martian.RequestModifier
  32. priority int64
  33. }
  34. // priorityResponseModifier is a response modifier with a priority.
  35. type priorityResponseModifier struct {
  36. resmod martian.ResponseModifier
  37. priority int64
  38. }
  39. // Group is a group of request and response modifiers ordered by their priority.
  40. type Group struct {
  41. reqmu sync.RWMutex
  42. reqmods []*priorityRequestModifier
  43. resmu sync.RWMutex
  44. resmods []*priorityResponseModifier
  45. }
  46. type groupJSON struct {
  47. Modifiers []modifierJSON `json:"modifiers"`
  48. Scope []parse.ModifierType `json:"scope"`
  49. }
  50. type modifierJSON struct {
  51. Priority int64 `json:"priority"`
  52. Modifier json.RawMessage `json:"modifier"`
  53. }
  54. func init() {
  55. parse.Register("priority.Group", groupFromJSON)
  56. }
  57. // NewGroup returns a priority group.
  58. func NewGroup() *Group {
  59. return &Group{}
  60. }
  61. // AddRequestModifier adds a RequestModifier with the given priority.
  62. //
  63. // If a modifier is added with a priority that is equal to an existing priority
  64. // the newer modifier will be added before the existing modifier in the chain.
  65. func (pg *Group) AddRequestModifier(reqmod martian.RequestModifier, priority int64) {
  66. pg.reqmu.Lock()
  67. defer pg.reqmu.Unlock()
  68. preqmod := &priorityRequestModifier{
  69. reqmod: reqmod,
  70. priority: priority,
  71. }
  72. for i, m := range pg.reqmods {
  73. if preqmod.priority >= m.priority {
  74. pg.reqmods = append(pg.reqmods, nil)
  75. copy(pg.reqmods[i+1:], pg.reqmods[i:])
  76. pg.reqmods[i] = preqmod
  77. return
  78. }
  79. }
  80. // Either this is the first modifier in the list, or the priority is less
  81. // than all existing modifiers.
  82. pg.reqmods = append(pg.reqmods, preqmod)
  83. }
  84. // RemoveRequestModifier removes the the highest priority given RequestModifier.
  85. // Returns ErrModifierNotFound if the given modifier does not exist in the group.
  86. func (pg *Group) RemoveRequestModifier(reqmod martian.RequestModifier) error {
  87. pg.reqmu.Lock()
  88. defer pg.reqmu.Unlock()
  89. for i, m := range pg.reqmods {
  90. if m.reqmod == reqmod {
  91. copy(pg.reqmods[i:], pg.reqmods[i+1:])
  92. pg.reqmods[len(pg.reqmods)-1] = nil
  93. pg.reqmods = pg.reqmods[:len(pg.reqmods)-1]
  94. return nil
  95. }
  96. }
  97. return ErrModifierNotFound
  98. }
  99. // AddResponseModifier adds a ResponseModifier with the given priority.
  100. //
  101. // If a modifier is added with a priority that is equal to an existing priority
  102. // the newer modifier will be added before the existing modifier in the chain.
  103. func (pg *Group) AddResponseModifier(resmod martian.ResponseModifier, priority int64) {
  104. pg.resmu.Lock()
  105. defer pg.resmu.Unlock()
  106. presmod := &priorityResponseModifier{
  107. resmod: resmod,
  108. priority: priority,
  109. }
  110. for i, m := range pg.resmods {
  111. if presmod.priority >= m.priority {
  112. pg.resmods = append(pg.resmods, nil)
  113. copy(pg.resmods[i+1:], pg.resmods[i:])
  114. pg.resmods[i] = presmod
  115. return
  116. }
  117. }
  118. // Either this is the first modifier in the list, or the priority is less
  119. // than all existing modifiers.
  120. pg.resmods = append(pg.resmods, presmod)
  121. }
  122. // RemoveResponseModifier removes the the highest priority given ResponseModifier.
  123. // Returns ErrModifierNotFound if the given modifier does not exist in the group.
  124. func (pg *Group) RemoveResponseModifier(resmod martian.ResponseModifier) error {
  125. pg.resmu.Lock()
  126. defer pg.resmu.Unlock()
  127. for i, m := range pg.resmods {
  128. if m.resmod == resmod {
  129. copy(pg.resmods[i:], pg.resmods[i+1:])
  130. pg.resmods[len(pg.resmods)-1] = nil
  131. pg.resmods = pg.resmods[:len(pg.resmods)-1]
  132. return nil
  133. }
  134. }
  135. return ErrModifierNotFound
  136. }
  137. // ModifyRequest modifies the request. Modifiers are run in descending order of
  138. // their priority. If an error is returned by a RequestModifier the error is
  139. // returned and no further modifiers are run.
  140. func (pg *Group) ModifyRequest(req *http.Request) error {
  141. pg.reqmu.RLock()
  142. defer pg.reqmu.RUnlock()
  143. for _, m := range pg.reqmods {
  144. if err := m.reqmod.ModifyRequest(req); err != nil {
  145. return err
  146. }
  147. }
  148. return nil
  149. }
  150. // ModifyResponse modifies the response. Modifiers are run in descending order
  151. // of their priority. If an error is returned by a ResponseModifier the error
  152. // is returned and no further modifiers are run.
  153. func (pg *Group) ModifyResponse(res *http.Response) error {
  154. pg.resmu.RLock()
  155. defer pg.resmu.RUnlock()
  156. for _, m := range pg.resmods {
  157. if err := m.resmod.ModifyResponse(res); err != nil {
  158. return err
  159. }
  160. }
  161. return nil
  162. }
  163. // groupFromJSON builds a priority.Group from JSON.
  164. //
  165. // Example JSON:
  166. // {
  167. // "priority.Group": {
  168. // "scope": ["request", "response"],
  169. // "modifiers": [
  170. // {
  171. // "priority": 100, // Will run first.
  172. // "modifier": { ... },
  173. // },
  174. // {
  175. // "priority": 0, // Will run last.
  176. // "modifier": { ... },
  177. // }
  178. // ]
  179. // }
  180. // }
  181. func groupFromJSON(b []byte) (*parse.Result, error) {
  182. msg := &groupJSON{}
  183. if err := json.Unmarshal(b, msg); err != nil {
  184. return nil, err
  185. }
  186. pg := NewGroup()
  187. for _, m := range msg.Modifiers {
  188. r, err := parse.FromJSON(m.Modifier)
  189. if err != nil {
  190. return nil, err
  191. }
  192. reqmod := r.RequestModifier()
  193. if reqmod != nil {
  194. pg.AddRequestModifier(reqmod, m.Priority)
  195. }
  196. resmod := r.ResponseModifier()
  197. if resmod != nil {
  198. pg.AddResponseModifier(resmod, m.Priority)
  199. }
  200. }
  201. return parse.NewResult(pg, msg.Scope)
  202. }