diff --git a/pkg/runtime/serializer/json/json.go b/pkg/runtime/serializer/json/json.go index bbc5adc1034..bba89b1fa01 100644 --- a/pkg/runtime/serializer/json/json.go +++ b/pkg/runtime/serializer/json/json.go @@ -194,7 +194,7 @@ func (s *Serializer) RecognizesData(peek io.Reader) (ok, unknown bool, err error // we could potentially look for '---' return false, true, nil } - _, ok = utilyaml.GuessJSONStream(peek, 2048) + _, _, ok = utilyaml.GuessJSONStream(peek, 2048) return ok, false, nil } diff --git a/pkg/util/yaml/decoder.go b/pkg/util/yaml/decoder.go index ed503d03905..27b7500eba9 100644 --- a/pkg/util/yaml/decoder.go +++ b/pkg/util/yaml/decoder.go @@ -181,6 +181,7 @@ type YAMLOrJSONDecoder struct { bufferSize int decoder decoder + rawData []byte } // NewYAMLOrJSONDecoder returns a decoder that will process YAML documents @@ -198,10 +199,11 @@ func NewYAMLOrJSONDecoder(r io.Reader, bufferSize int) *YAMLOrJSONDecoder { // provide object, or returns an error. func (d *YAMLOrJSONDecoder) Decode(into interface{}) error { if d.decoder == nil { - buffer, isJSON := GuessJSONStream(d.r, d.bufferSize) + buffer, origData, isJSON := GuessJSONStream(d.r, d.bufferSize) if isJSON { glog.V(4).Infof("decoding stream as JSON") d.decoder = json.NewDecoder(buffer) + d.rawData = origData } else { glog.V(4).Infof("decoding stream as YAML") d.decoder = NewYAMLToJSONDecoder(buffer) @@ -215,6 +217,13 @@ func (d *YAMLOrJSONDecoder) Decode(into interface{}) error { glog.V(4).Infof("reading stream failed: %v", readErr) } js := string(data) + + // if contents from io.Reader are not complete, + // use the original raw data to prevent panic + if int64(len(js)) <= syntax.Offset { + js = string(d.rawData) + } + start := strings.LastIndex(js[:syntax.Offset], "\n") + 1 line := strings.Count(js[:start], "\n") return fmt.Errorf("json: line %d: %s", line, syntax.Error()) @@ -296,10 +305,10 @@ func (r *LineReader) Read() ([]byte, error) { // GuessJSONStream scans the provided reader up to size, looking // for an open brace indicating this is JSON. It will return the // bufio.Reader it creates for the consumer. -func GuessJSONStream(r io.Reader, size int) (io.Reader, bool) { +func GuessJSONStream(r io.Reader, size int) (io.Reader, []byte, bool) { buffer := bufio.NewReaderSize(r, size) b, _ := buffer.Peek(size) - return buffer, hasJSONPrefix(b) + return buffer, b, hasJSONPrefix(b) } var jsonPrefix = []byte("{") diff --git a/pkg/util/yaml/decoder_test.go b/pkg/util/yaml/decoder_test.go index b8c5e6987e3..5712b30794a 100644 --- a/pkg/util/yaml/decoder_test.go +++ b/pkg/util/yaml/decoder_test.go @@ -65,7 +65,7 @@ func TestSplitYAMLDocument(t *testing.T) { } func TestGuessJSON(t *testing.T) { - if r, isJSON := GuessJSONStream(bytes.NewReader([]byte(" \n{}")), 100); !isJSON { + if r, _, isJSON := GuessJSONStream(bytes.NewReader([]byte(" \n{}")), 100); !isJSON { t.Fatalf("expected stream to be JSON") } else { b := make([]byte, 30)