github.com/adecaro/fabric-ca@v2.0.0-alpha+incompatible/lib/streamer/jsonstreamer.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // StreamJSONArray scans the JSON stream associated with 'decoder' to find 18 // an array value associated with the json element at 'pathToArray'. 19 // It then calls the 'cb' callback function so that it can decode one element 20 // in the stream at a time. 21 22 package streamer 23 24 import ( 25 "encoding/json" 26 "fmt" 27 "os" 28 "reflect" 29 "strings" 30 31 "github.com/cloudflare/cfssl/api" 32 "github.com/cloudflare/cfssl/log" 33 "github.com/pkg/errors" 34 ) 35 36 // SearchElement defines the JSON arrays for which to search 37 type SearchElement struct { 38 Path string 39 CB func(*json.Decoder) error 40 } 41 42 // StreamJSONArray searches the JSON stream for an array matching 'path'. 43 // For each element of this array, it streams one element at a time. 44 func StreamJSONArray(decoder *json.Decoder, path string, cb func(*json.Decoder) error) (bool, error) { 45 ses := []SearchElement{ 46 SearchElement{Path: path, CB: cb}, 47 SearchElement{Path: "errors", CB: errCB}, 48 } 49 return StreamJSON(decoder, ses) 50 } 51 52 // StreamJSON searches the JSON stream for arrays matching a search element. 53 // For each array that it finds, it streams them one element at a time. 54 func StreamJSON(decoder *json.Decoder, search []SearchElement) (bool, error) { 55 js := &jsonStream{decoder: decoder, search: search, stack: []string{}} 56 err := js.stream() 57 return js.gotResults, err 58 } 59 60 type jsonStream struct { 61 decoder *json.Decoder 62 search []SearchElement 63 stack []string 64 gotResults bool 65 } 66 67 func (js *jsonStream) stream() error { 68 t, err := js.getToken() 69 if err != nil { 70 return err 71 } 72 if _, ok := t.(json.Delim); !ok { 73 return nil 74 } 75 path := strings.Join(js.stack, ".") 76 se := js.getSearchElement(path) 77 d := fmt.Sprintf("%s", t) 78 switch d { 79 case "[": 80 if se != nil { 81 for js.decoder.More() { 82 err = se.CB(js.decoder) 83 if err != nil { 84 return err 85 } 86 js.gotResults = true 87 } 88 } 89 err = js.skipToDelim("]") 90 if err != nil { 91 return err 92 } 93 case "]": 94 return errors.Errorf("Unexpected '%s'", d) 95 case "{": 96 if se != nil { 97 return errors.Errorf("Expecting array for value of '%s'", path) 98 } 99 for { 100 name, err := js.getNextName() 101 if err != nil { 102 return err 103 } 104 if name == "" { 105 return nil 106 } 107 stack := js.stack 108 js.stack = append(stack, name) 109 err = js.stream() 110 if err != nil { 111 return err 112 } 113 js.stack = stack 114 } 115 case "}": 116 return errors.Errorf("Unexpected '%s'", d) 117 default: 118 return errors.Errorf("unknown JSON delimiter: '%s'", d) 119 } 120 return nil 121 } 122 123 // Find a search element named 'path' 124 func (js *jsonStream) getSearchElement(path string) *SearchElement { 125 for _, ele := range js.search { 126 if ele.Path == path { 127 return &ele 128 } 129 } 130 return nil 131 } 132 133 // Skip over tokens until we hit the delimiter 134 func (js *jsonStream) skipToDelim(delim string) error { 135 for { 136 t, err := js.getToken() 137 if err != nil { 138 return err 139 } 140 // Skip anything that isn't a delimiter 141 if _, ok := t.(json.Delim); !ok { 142 continue 143 } 144 // It is a delimiter 145 d := fmt.Sprintf("%s", t) 146 if d == delim { 147 return nil 148 } 149 switch d { 150 case "[": 151 err = js.skipToDelim("]") 152 case "]": 153 err = errors.Errorf("Expecting '%s' but found '%s'", delim, d) 154 case "{": 155 err = js.skipToDelim("}") 156 case "}": 157 err = errors.Errorf("Expecting '%s' but found '%s'", delim, d) 158 default: 159 err = errors.Errorf("unknown JSON delimiter: '%s'", d) 160 } 161 if err != nil { 162 return err 163 } 164 } 165 } 166 167 func (js *jsonStream) getNextName() (string, error) { 168 token, err := js.getToken() 169 if err != nil { 170 return "", err 171 } 172 switch v := token.(type) { 173 case string: 174 return v, nil 175 case json.Delim: 176 d := fmt.Sprintf("%s", v) 177 if d == "}" { 178 return "", nil 179 } 180 return "", errors.Errorf("Expecting '}' delimiter but found '%s'", d) 181 default: 182 return "", errors.Errorf("Expecting string or delimiter but found '%s'", v) 183 } 184 } 185 186 func (js *jsonStream) getToken() (interface{}, error) { 187 token, err := js.decoder.Token() 188 if os.Getenv("FABRIC_CA_JSON_STREAM_DEBUG") != "" { 189 log.Debugf("TOKEN: type=%s, %+v\n", reflect.TypeOf(token), token) 190 } 191 return token, err 192 } 193 194 func errCB(decoder *json.Decoder) error { 195 errMsg := &api.ResponseMessage{} 196 err := decoder.Decode(errMsg) 197 if err != nil { 198 return errors.Errorf("Invalid JSON error format: %s", err) 199 } 200 return errors.Errorf("%+v", errMsg) 201 }