1// Copyright 2015 go-swagger maintainers 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 15package runtime 16 17import ( 18 "bytes" 19 "encoding" 20 "errors" 21 "fmt" 22 "io" 23 "reflect" 24 25 "github.com/go-openapi/swag" 26) 27 28func defaultCloser() error { return nil } 29 30type byteStreamOpt func(opts *byteStreamOpts) 31 32// ClosesStream when the bytestream consumer or producer is finished 33func ClosesStream(opts *byteStreamOpts) { 34 opts.Close = true 35} 36 37type byteStreamOpts struct { 38 Close bool 39} 40 41// ByteStreamConsumer creates a consumer for byte streams, 42// takes a Writer/BinaryUnmarshaler interface or binary slice by reference, 43// and reads from the provided reader 44func ByteStreamConsumer(opts ...byteStreamOpt) Consumer { 45 var vals byteStreamOpts 46 for _, opt := range opts { 47 opt(&vals) 48 } 49 50 return ConsumerFunc(func(reader io.Reader, data interface{}) error { 51 if reader == nil { 52 return errors.New("ByteStreamConsumer requires a reader") // early exit 53 } 54 55 close := defaultCloser 56 if vals.Close { 57 if cl, ok := reader.(io.Closer); ok { 58 close = cl.Close 59 } 60 } 61 defer close() 62 63 if wrtr, ok := data.(io.Writer); ok { 64 _, err := io.Copy(wrtr, reader) 65 return err 66 } 67 68 buf := new(bytes.Buffer) 69 _, err := buf.ReadFrom(reader) 70 if err != nil { 71 return err 72 } 73 b := buf.Bytes() 74 75 if bu, ok := data.(encoding.BinaryUnmarshaler); ok { 76 return bu.UnmarshalBinary(b) 77 } 78 79 if data != nil { 80 if str, ok := data.(*string); ok { 81 *str = string(b) 82 return nil 83 } 84 } 85 86 if t := reflect.TypeOf(data); data != nil && t.Kind() == reflect.Ptr { 87 v := reflect.Indirect(reflect.ValueOf(data)) 88 if t = v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 { 89 v.SetBytes(b) 90 return nil 91 } 92 } 93 94 return fmt.Errorf("%v (%T) is not supported by the ByteStreamConsumer, %s", 95 data, data, "can be resolved by supporting Writer/BinaryUnmarshaler interface") 96 }) 97} 98 99// ByteStreamProducer creates a producer for byte streams, 100// takes a Reader/BinaryMarshaler interface or binary slice, 101// and writes to a writer (essentially a pipe) 102func ByteStreamProducer(opts ...byteStreamOpt) Producer { 103 var vals byteStreamOpts 104 for _, opt := range opts { 105 opt(&vals) 106 } 107 return ProducerFunc(func(writer io.Writer, data interface{}) error { 108 if writer == nil { 109 return errors.New("ByteStreamProducer requires a writer") // early exit 110 } 111 close := defaultCloser 112 if vals.Close { 113 if cl, ok := writer.(io.Closer); ok { 114 close = cl.Close 115 } 116 } 117 defer close() 118 119 if rc, ok := data.(io.ReadCloser); ok { 120 defer rc.Close() 121 } 122 123 if rdr, ok := data.(io.Reader); ok { 124 _, err := io.Copy(writer, rdr) 125 return err 126 } 127 128 if bm, ok := data.(encoding.BinaryMarshaler); ok { 129 bytes, err := bm.MarshalBinary() 130 if err != nil { 131 return err 132 } 133 134 _, err = writer.Write(bytes) 135 return err 136 } 137 138 if data != nil { 139 if str, ok := data.(string); ok { 140 _, err := writer.Write([]byte(str)) 141 return err 142 } 143 144 if e, ok := data.(error); ok { 145 _, err := writer.Write([]byte(e.Error())) 146 return err 147 } 148 149 v := reflect.Indirect(reflect.ValueOf(data)) 150 if t := v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 { 151 _, err := writer.Write(v.Bytes()) 152 return err 153 } 154 if t := v.Type(); t.Kind() == reflect.Struct || t.Kind() == reflect.Slice { 155 b, err := swag.WriteJSON(data) 156 if err != nil { 157 return err 158 } 159 _, err = writer.Write(b) 160 return err 161 } 162 } 163 164 return fmt.Errorf("%v (%T) is not supported by the ByteStreamProducer, %s", 165 data, data, "can be resolved by supporting Reader/BinaryMarshaler interface") 166 }) 167} 168