github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/Godeps/_workspace/src/k8s.io/kubernetes/pkg/util/framer/framer.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors 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 // Package framer implements simple frame decoding techniques for an io.ReadCloser 18 package framer 19 20 import ( 21 "encoding/binary" 22 "encoding/json" 23 "io" 24 ) 25 26 type lengthDelimitedFrameWriter struct { 27 w io.Writer 28 } 29 30 func NewLengthDelimitedFrameWriter(w io.Writer) io.Writer { 31 return &lengthDelimitedFrameWriter{w: w} 32 } 33 34 // Write writes a single frame to the nested writer, prepending it with the length in 35 // in bytes of data (as a 4 byte, bigendian uint32). 36 func (w *lengthDelimitedFrameWriter) Write(data []byte) (int, error) { 37 header := [4]byte{} 38 binary.BigEndian.PutUint32(header[:], uint32(len(data))) 39 n, err := w.w.Write(header[:]) 40 if err != nil { 41 return 0, err 42 } 43 if n != len(header) { 44 return 0, io.ErrShortWrite 45 } 46 return w.w.Write(data) 47 } 48 49 type lengthDelimitedFrameReader struct { 50 r io.ReadCloser 51 remaining int 52 } 53 54 // NewLengthDelimitedFrameReader returns an io.Reader that will decode length-prefixed 55 // frames off of a stream. 56 // 57 // The protocol is: 58 // 59 // stream: message ... 60 // message: prefix body 61 // prefix: 4 byte uint32 in BigEndian order, denotes length of body 62 // body: bytes (0..prefix) 63 // 64 // If the buffer passed to Read is not long enough to contain an entire frame, io.ErrShortRead 65 // will be returned along with the number of bytes read. 66 func NewLengthDelimitedFrameReader(r io.ReadCloser) io.ReadCloser { 67 return &lengthDelimitedFrameReader{r: r} 68 } 69 70 // Read attempts to read an entire frame into data. If that is not possible, io.ErrShortBuffer 71 // is returned and subsequent calls will attempt to read the last frame. A frame is complete when 72 // err is nil. 73 func (r *lengthDelimitedFrameReader) Read(data []byte) (int, error) { 74 if r.remaining <= 0 { 75 header := [4]byte{} 76 n, err := io.ReadAtLeast(r.r, header[:4], 4) 77 if err != nil { 78 return 0, err 79 } 80 if n != 4 { 81 return 0, io.ErrUnexpectedEOF 82 } 83 frameLength := int(binary.BigEndian.Uint32(header[:])) 84 r.remaining = frameLength 85 } 86 87 expect := r.remaining 88 max := expect 89 if max > len(data) { 90 max = len(data) 91 } 92 n, err := io.ReadAtLeast(r.r, data[:max], int(max)) 93 r.remaining -= n 94 if err == io.ErrShortBuffer || r.remaining > 0 { 95 return n, io.ErrShortBuffer 96 } 97 if err != nil { 98 return n, err 99 } 100 if n != expect { 101 return n, io.ErrUnexpectedEOF 102 } 103 104 return n, nil 105 } 106 107 func (r *lengthDelimitedFrameReader) Close() error { 108 return r.r.Close() 109 } 110 111 type jsonFrameReader struct { 112 r io.ReadCloser 113 decoder *json.Decoder 114 remaining []byte 115 } 116 117 // NewJSONFramedReader returns an io.Reader that will decode individual JSON objects off 118 // of a wire. 119 // 120 // The boundaries between each frame are valid JSON objects. A JSON parsing error will terminate 121 // the read. 122 func NewJSONFramedReader(r io.ReadCloser) io.ReadCloser { 123 return &jsonFrameReader{ 124 r: r, 125 decoder: json.NewDecoder(r), 126 } 127 } 128 129 // ReadFrame decodes the next JSON object in the stream, or returns an error. The returned 130 // byte slice will be modified the next time ReadFrame is invoked and should not be altered. 131 func (r *jsonFrameReader) Read(data []byte) (int, error) { 132 // Return whatever remaining data exists from an in progress frame 133 if n := len(r.remaining); n > 0 { 134 if n <= len(data) { 135 data = append(data[0:0], r.remaining...) 136 r.remaining = nil 137 return n, nil 138 } 139 140 n = len(data) 141 data = append(data[0:0], r.remaining[:n]...) 142 r.remaining = r.remaining[n:] 143 return n, io.ErrShortBuffer 144 } 145 146 // RawMessage#Unmarshal appends to data - we reset the slice down to 0 and will either see 147 // data written to data, or be larger than data and a different array. 148 n := len(data) 149 m := json.RawMessage(data[:0]) 150 if err := r.decoder.Decode(&m); err != nil { 151 return 0, err 152 } 153 154 // If capacity of data is less than length of the message, decoder will allocate a new slice 155 // and set m to it, which means we need to copy the partial result back into data and preserve 156 // the remaining result for subsequent reads. 157 if len(m) > n { 158 data = append(data[0:0], m[:n]...) 159 r.remaining = m[n:] 160 return n, io.ErrShortBuffer 161 } 162 return len(m), nil 163 } 164 165 func (r *jsonFrameReader) Close() error { 166 return r.r.Close() 167 }