...

Source file src/github.com/Azure/go-autorest/autorest/utility.go

Documentation: github.com/Azure/go-autorest/autorest

     1  package autorest
     2  
     3  // Copyright 2017 Microsoft Corporation
     4  //
     5  //  Licensed under the Apache License, Version 2.0 (the "License");
     6  //  you may not use this file except in compliance with the License.
     7  //  You may obtain a copy of the License at
     8  //
     9  //      http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  //  Unless required by applicable law or agreed to in writing, software
    12  //  distributed under the License is distributed on an "AS IS" BASIS,
    13  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  //  See the License for the specific language governing permissions and
    15  //  limitations under the License.
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/json"
    20  	"encoding/xml"
    21  	"fmt"
    22  	"io"
    23  	"io/ioutil"
    24  	"net"
    25  	"net/http"
    26  	"net/url"
    27  	"reflect"
    28  	"strings"
    29  )
    30  
    31  // EncodedAs is a series of constants specifying various data encodings
    32  type EncodedAs string
    33  
    34  const (
    35  	// EncodedAsJSON states that data is encoded as JSON
    36  	EncodedAsJSON EncodedAs = "JSON"
    37  
    38  	// EncodedAsXML states that data is encoded as Xml
    39  	EncodedAsXML EncodedAs = "XML"
    40  )
    41  
    42  // Decoder defines the decoding method json.Decoder and xml.Decoder share
    43  type Decoder interface {
    44  	Decode(v interface{}) error
    45  }
    46  
    47  // NewDecoder creates a new decoder appropriate to the passed encoding.
    48  // encodedAs specifies the type of encoding and r supplies the io.Reader containing the
    49  // encoded data.
    50  func NewDecoder(encodedAs EncodedAs, r io.Reader) Decoder {
    51  	if encodedAs == EncodedAsJSON {
    52  		return json.NewDecoder(r)
    53  	} else if encodedAs == EncodedAsXML {
    54  		return xml.NewDecoder(r)
    55  	}
    56  	return nil
    57  }
    58  
    59  // CopyAndDecode decodes the data from the passed io.Reader while making a copy. Having a copy
    60  // is especially useful if there is a chance the data will fail to decode.
    61  // encodedAs specifies the expected encoding, r provides the io.Reader to the data, and v
    62  // is the decoding destination.
    63  func CopyAndDecode(encodedAs EncodedAs, r io.Reader, v interface{}) (b bytes.Buffer, err error) {
    64  	err = NewDecoder(encodedAs, io.TeeReader(r, &b)).Decode(v)
    65  	return
    66  }
    67  
    68  // TeeReadCloser returns a ReadCloser that writes to w what it reads from rc.
    69  // It utilizes io.TeeReader to copy the data read and has the same behavior when reading.
    70  // Further, when it is closed, it ensures that rc is closed as well.
    71  func TeeReadCloser(rc io.ReadCloser, w io.Writer) io.ReadCloser {
    72  	return &teeReadCloser{rc, io.TeeReader(rc, w)}
    73  }
    74  
    75  type teeReadCloser struct {
    76  	rc io.ReadCloser
    77  	r  io.Reader
    78  }
    79  
    80  func (t *teeReadCloser) Read(p []byte) (int, error) {
    81  	return t.r.Read(p)
    82  }
    83  
    84  func (t *teeReadCloser) Close() error {
    85  	return t.rc.Close()
    86  }
    87  
    88  func containsInt(ints []int, n int) bool {
    89  	for _, i := range ints {
    90  		if i == n {
    91  			return true
    92  		}
    93  	}
    94  	return false
    95  }
    96  
    97  func escapeValueStrings(m map[string]string) map[string]string {
    98  	for key, value := range m {
    99  		m[key] = url.QueryEscape(value)
   100  	}
   101  	return m
   102  }
   103  
   104  func ensureValueStrings(mapOfInterface map[string]interface{}) map[string]string {
   105  	mapOfStrings := make(map[string]string)
   106  	for key, value := range mapOfInterface {
   107  		mapOfStrings[key] = ensureValueString(value)
   108  	}
   109  	return mapOfStrings
   110  }
   111  
   112  func ensureValueString(value interface{}) string {
   113  	if value == nil {
   114  		return ""
   115  	}
   116  	switch v := value.(type) {
   117  	case string:
   118  		return v
   119  	case []byte:
   120  		return string(v)
   121  	default:
   122  		return fmt.Sprintf("%v", v)
   123  	}
   124  }
   125  
   126  // MapToValues method converts map[string]interface{} to url.Values.
   127  func MapToValues(m map[string]interface{}) url.Values {
   128  	v := url.Values{}
   129  	for key, value := range m {
   130  		x := reflect.ValueOf(value)
   131  		if x.Kind() == reflect.Array || x.Kind() == reflect.Slice {
   132  			for i := 0; i < x.Len(); i++ {
   133  				v.Add(key, ensureValueString(x.Index(i)))
   134  			}
   135  		} else {
   136  			v.Add(key, ensureValueString(value))
   137  		}
   138  	}
   139  	return v
   140  }
   141  
   142  // AsStringSlice method converts interface{} to []string.
   143  // s must be of type slice or array or an error is returned.
   144  // Each element of s will be converted to its string representation.
   145  func AsStringSlice(s interface{}) ([]string, error) {
   146  	v := reflect.ValueOf(s)
   147  	if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
   148  		return nil, NewError("autorest", "AsStringSlice", "the value's type is not a slice or array.")
   149  	}
   150  	stringSlice := make([]string, 0, v.Len())
   151  
   152  	for i := 0; i < v.Len(); i++ {
   153  		stringSlice = append(stringSlice, fmt.Sprintf("%v", v.Index(i)))
   154  	}
   155  	return stringSlice, nil
   156  }
   157  
   158  // String method converts interface v to string. If interface is a list, it
   159  // joins list elements using the separator. Note that only sep[0] will be used for
   160  // joining if any separator is specified.
   161  func String(v interface{}, sep ...string) string {
   162  	if len(sep) == 0 {
   163  		return ensureValueString(v)
   164  	}
   165  	stringSlice, ok := v.([]string)
   166  	if ok == false {
   167  		var err error
   168  		stringSlice, err = AsStringSlice(v)
   169  		if err != nil {
   170  			panic(fmt.Sprintf("autorest: Couldn't convert value to a string %s.", err))
   171  		}
   172  	}
   173  	return ensureValueString(strings.Join(stringSlice, sep[0]))
   174  }
   175  
   176  // Encode method encodes url path and query parameters.
   177  func Encode(location string, v interface{}, sep ...string) string {
   178  	s := String(v, sep...)
   179  	switch strings.ToLower(location) {
   180  	case "path":
   181  		return pathEscape(s)
   182  	case "query":
   183  		return queryEscape(s)
   184  	default:
   185  		return s
   186  	}
   187  }
   188  
   189  func pathEscape(s string) string {
   190  	return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
   191  }
   192  
   193  func queryEscape(s string) string {
   194  	return url.QueryEscape(s)
   195  }
   196  
   197  // ChangeToGet turns the specified http.Request into a GET (it assumes it wasn't).
   198  // This is mainly useful for long-running operations that use the Azure-AsyncOperation
   199  // header, so we change the initial PUT into a GET to retrieve the final result.
   200  func ChangeToGet(req *http.Request) *http.Request {
   201  	req.Method = "GET"
   202  	req.Body = nil
   203  	req.ContentLength = 0
   204  	req.Header.Del("Content-Length")
   205  	return req
   206  }
   207  
   208  // IsTemporaryNetworkError returns true if the specified error is a temporary network error or false
   209  // if it's not.  If the error doesn't implement the net.Error interface the return value is true.
   210  func IsTemporaryNetworkError(err error) bool {
   211  	if netErr, ok := err.(net.Error); !ok || (ok && netErr.Temporary()) {
   212  		return true
   213  	}
   214  	return false
   215  }
   216  
   217  // DrainResponseBody reads the response body then closes it.
   218  func DrainResponseBody(resp *http.Response) error {
   219  	if resp != nil && resp.Body != nil {
   220  		_, err := io.Copy(ioutil.Discard, resp.Body)
   221  		resp.Body.Close()
   222  		return err
   223  	}
   224  	return nil
   225  }
   226  
   227  func setHeader(r *http.Request, key, value string) {
   228  	if r.Header == nil {
   229  		r.Header = make(http.Header)
   230  	}
   231  	r.Header.Set(key, value)
   232  }
   233  

View as plain text