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