You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

148 lines
4.0 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 parse constructs martian modifiers from JSON messages.
  15. package parse
  16. import (
  17. "encoding/json"
  18. "fmt"
  19. "sync"
  20. "github.com/google/martian"
  21. )
  22. // ModifierType is the HTTP message type.
  23. type ModifierType string
  24. const (
  25. // Request modifies an HTTP request.
  26. Request ModifierType = "request"
  27. // Response modifies an HTTP response.
  28. Response ModifierType = "response"
  29. )
  30. // Result holds the parsed modifier and its type.
  31. type Result struct {
  32. reqmod martian.RequestModifier
  33. resmod martian.ResponseModifier
  34. }
  35. // NewResult returns a new parse.Result for a given interface{} that implements a modifier
  36. // and a slice of scopes to generate the result for.
  37. //
  38. // Returns nil, error if a given modifier does not support a given scope
  39. func NewResult(mod interface{}, scope []ModifierType) (*Result, error) {
  40. reqmod, reqOk := mod.(martian.RequestModifier)
  41. resmod, resOk := mod.(martian.ResponseModifier)
  42. result := &Result{}
  43. if scope == nil {
  44. result.reqmod = reqmod
  45. result.resmod = resmod
  46. return result, nil
  47. }
  48. for _, s := range scope {
  49. switch s {
  50. case Request:
  51. if !reqOk {
  52. return nil, fmt.Errorf("parse: invalid scope %q for modifier", "request")
  53. }
  54. result.reqmod = reqmod
  55. case Response:
  56. if !resOk {
  57. return nil, fmt.Errorf("parse: invalid scope %q for modifier", "response")
  58. }
  59. result.resmod = resmod
  60. default:
  61. return nil, fmt.Errorf("parse: invalid scope: %s not in [%q, %q]", s, "request", "response")
  62. }
  63. }
  64. return result, nil
  65. }
  66. // RequestModifier returns the parsed RequestModifier.
  67. //
  68. // Returns nil if the message has no request modifier.
  69. func (r *Result) RequestModifier() martian.RequestModifier {
  70. return r.reqmod
  71. }
  72. // ResponseModifier returns the parsed ResponseModifier.
  73. //
  74. // Returns nil if the message has no response modifier.
  75. func (r *Result) ResponseModifier() martian.ResponseModifier {
  76. return r.resmod
  77. }
  78. var (
  79. parseMu sync.RWMutex
  80. parseFuncs = make(map[string]func(b []byte) (*Result, error))
  81. )
  82. // ErrUnknownModifier is the error returned when the message does not
  83. // contain a field representing a known modifier type.
  84. type ErrUnknownModifier struct {
  85. name string
  86. }
  87. // Error returns a formatted error message for an ErrUnknownModifier.
  88. func (e ErrUnknownModifier) Error() string {
  89. return fmt.Sprintf("parse: unknown modifier: %s", e.name)
  90. }
  91. // Register registers a parsing function for name that will be used to unmarshal
  92. // a JSON message into the appropriate modifier.
  93. func Register(name string, parseFunc func(b []byte) (*Result, error)) {
  94. parseMu.Lock()
  95. defer parseMu.Unlock()
  96. parseFuncs[name] = parseFunc
  97. }
  98. // FromJSON parses a Modifier JSON message by looking up the named modifier in parseFuncs
  99. // and passing its modifier to the registered parseFunc. Returns a parse.Result containing
  100. // the top-level parsed modifier. If no parser has been registered with the given name
  101. // it returns an error of type ErrUnknownModifier.
  102. func FromJSON(b []byte) (*Result, error) {
  103. msg := make(map[string]json.RawMessage)
  104. if err := json.Unmarshal(b, &msg); err != nil {
  105. return nil, err
  106. }
  107. if len(msg) != 1 {
  108. ks := ""
  109. for k := range msg {
  110. ks += ", " + k
  111. }
  112. return nil, fmt.Errorf("parse: expected one modifier, received %d: %s", len(msg), ks)
  113. }
  114. parseMu.RLock()
  115. defer parseMu.RUnlock()
  116. for k, m := range msg {
  117. parseFunc, ok := parseFuncs[k]
  118. if !ok {
  119. return nil, ErrUnknownModifier{name: k}
  120. }
  121. return parseFunc(m)
  122. }
  123. return nil, fmt.Errorf("parse: no modifiers found: %v", msg)
  124. }