...

Source file src/github.com/go-openapi/runtime/bytestream.go

Documentation: github.com/go-openapi/runtime

     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  
    15  package runtime
    16  
    17  import (
    18  	"bytes"
    19  	"encoding"
    20  	"errors"
    21  	"fmt"
    22  	"io"
    23  	"reflect"
    24  
    25  	"github.com/go-openapi/swag"
    26  )
    27  
    28  func defaultCloser() error { return nil }
    29  
    30  type byteStreamOpt func(opts *byteStreamOpts)
    31  
    32  // ClosesStream when the bytestream consumer or producer is finished
    33  func ClosesStream(opts *byteStreamOpts) {
    34  	opts.Close = true
    35  }
    36  
    37  type byteStreamOpts struct {
    38  	Close bool
    39  }
    40  
    41  // ByteStreamConsumer creates a consumer for byte streams.
    42  //
    43  // The consumer consumes from a provided reader into the data passed by reference.
    44  //
    45  // Supported output underlying types and interfaces, prioritized in this order:
    46  // - io.ReaderFrom (for maximum control)
    47  // - io.Writer (performs io.Copy)
    48  // - encoding.BinaryUnmarshaler
    49  // - *string
    50  // - *[]byte
    51  func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
    52  	var vals byteStreamOpts
    53  	for _, opt := range opts {
    54  		opt(&vals)
    55  	}
    56  
    57  	return ConsumerFunc(func(reader io.Reader, data interface{}) error {
    58  		if reader == nil {
    59  			return errors.New("ByteStreamConsumer requires a reader") // early exit
    60  		}
    61  		if data == nil {
    62  			return errors.New("nil destination for ByteStreamConsumer")
    63  		}
    64  
    65  		closer := defaultCloser
    66  		if vals.Close {
    67  			if cl, isReaderCloser := reader.(io.Closer); isReaderCloser {
    68  				closer = cl.Close
    69  			}
    70  		}
    71  		defer func() {
    72  			_ = closer()
    73  		}()
    74  
    75  		if readerFrom, isReaderFrom := data.(io.ReaderFrom); isReaderFrom {
    76  			_, err := readerFrom.ReadFrom(reader)
    77  			return err
    78  		}
    79  
    80  		if writer, isDataWriter := data.(io.Writer); isDataWriter {
    81  			_, err := io.Copy(writer, reader)
    82  			return err
    83  		}
    84  
    85  		// buffers input before writing to data
    86  		var buf bytes.Buffer
    87  		_, err := buf.ReadFrom(reader)
    88  		if err != nil {
    89  			return err
    90  		}
    91  		b := buf.Bytes()
    92  
    93  		switch destinationPointer := data.(type) {
    94  		case encoding.BinaryUnmarshaler:
    95  			return destinationPointer.UnmarshalBinary(b)
    96  		case *any:
    97  			switch (*destinationPointer).(type) {
    98  			case string:
    99  				*destinationPointer = string(b)
   100  
   101  				return nil
   102  
   103  			case []byte:
   104  				*destinationPointer = b
   105  
   106  				return nil
   107  			}
   108  		default:
   109  			// check for the underlying type to be pointer to []byte or string,
   110  			if ptr := reflect.TypeOf(data); ptr.Kind() != reflect.Ptr {
   111  				return errors.New("destination must be a pointer")
   112  			}
   113  
   114  			v := reflect.Indirect(reflect.ValueOf(data))
   115  			t := v.Type()
   116  
   117  			switch {
   118  			case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
   119  				v.SetBytes(b)
   120  				return nil
   121  
   122  			case t.Kind() == reflect.String:
   123  				v.SetString(string(b))
   124  				return nil
   125  			}
   126  		}
   127  
   128  		return fmt.Errorf("%v (%T) is not supported by the ByteStreamConsumer, %s",
   129  			data, data, "can be resolved by supporting Writer/BinaryUnmarshaler interface")
   130  	})
   131  }
   132  
   133  // ByteStreamProducer creates a producer for byte streams.
   134  //
   135  // The producer takes input data then writes to an output writer (essentially as a pipe).
   136  //
   137  // Supported input underlying types and interfaces, prioritized in this order:
   138  // - io.WriterTo (for maximum control)
   139  // - io.Reader (performs io.Copy). A ReadCloser is closed before exiting.
   140  // - encoding.BinaryMarshaler
   141  // - error (writes as a string)
   142  // - []byte
   143  // - string
   144  // - struct, other slices: writes as JSON
   145  func ByteStreamProducer(opts ...byteStreamOpt) Producer {
   146  	var vals byteStreamOpts
   147  	for _, opt := range opts {
   148  		opt(&vals)
   149  	}
   150  
   151  	return ProducerFunc(func(writer io.Writer, data interface{}) error {
   152  		if writer == nil {
   153  			return errors.New("ByteStreamProducer requires a writer") // early exit
   154  		}
   155  		if data == nil {
   156  			return errors.New("nil data for ByteStreamProducer")
   157  		}
   158  
   159  		closer := defaultCloser
   160  		if vals.Close {
   161  			if cl, isWriterCloser := writer.(io.Closer); isWriterCloser {
   162  				closer = cl.Close
   163  			}
   164  		}
   165  		defer func() {
   166  			_ = closer()
   167  		}()
   168  
   169  		if rc, isDataCloser := data.(io.ReadCloser); isDataCloser {
   170  			defer rc.Close()
   171  		}
   172  
   173  		switch origin := data.(type) {
   174  		case io.WriterTo:
   175  			_, err := origin.WriteTo(writer)
   176  			return err
   177  
   178  		case io.Reader:
   179  			_, err := io.Copy(writer, origin)
   180  			return err
   181  
   182  		case encoding.BinaryMarshaler:
   183  			bytes, err := origin.MarshalBinary()
   184  			if err != nil {
   185  				return err
   186  			}
   187  
   188  			_, err = writer.Write(bytes)
   189  			return err
   190  
   191  		case error:
   192  			_, err := writer.Write([]byte(origin.Error()))
   193  			return err
   194  
   195  		default:
   196  			v := reflect.Indirect(reflect.ValueOf(data))
   197  			t := v.Type()
   198  
   199  			switch {
   200  			case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
   201  				_, err := writer.Write(v.Bytes())
   202  				return err
   203  
   204  			case t.Kind() == reflect.String:
   205  				_, err := writer.Write([]byte(v.String()))
   206  				return err
   207  
   208  			case t.Kind() == reflect.Struct || t.Kind() == reflect.Slice:
   209  				b, err := swag.WriteJSON(data)
   210  				if err != nil {
   211  					return err
   212  				}
   213  
   214  				_, err = writer.Write(b)
   215  				return err
   216  			}
   217  		}
   218  
   219  		return fmt.Errorf("%v (%T) is not supported by the ByteStreamProducer, %s",
   220  			data, data, "can be resolved by supporting Reader/BinaryMarshaler interface")
   221  	})
   222  }
   223  

View as plain text