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  }