Blame vendor/github.com/Azure/go-autorest/autorest/utility.go

Packit 63bb0d
package autorest
Packit 63bb0d
Packit 63bb0d
// Copyright 2017 Microsoft Corporation
Packit 63bb0d
//
Packit 63bb0d
//  Licensed under the Apache License, Version 2.0 (the "License");
Packit 63bb0d
//  you may not use this file except in compliance with the License.
Packit 63bb0d
//  You may obtain a copy of the License at
Packit 63bb0d
//
Packit 63bb0d
//      http://www.apache.org/licenses/LICENSE-2.0
Packit 63bb0d
//
Packit 63bb0d
//  Unless required by applicable law or agreed to in writing, software
Packit 63bb0d
//  distributed under the License is distributed on an "AS IS" BASIS,
Packit 63bb0d
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 63bb0d
//  See the License for the specific language governing permissions and
Packit 63bb0d
//  limitations under the License.
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"bytes"
Packit 63bb0d
	"encoding/json"
Packit 63bb0d
	"encoding/xml"
Packit 63bb0d
	"fmt"
Packit 63bb0d
	"io"
Packit 63bb0d
	"io/ioutil"
Packit 63bb0d
	"net"
Packit 63bb0d
	"net/http"
Packit 63bb0d
	"net/url"
Packit 63bb0d
	"reflect"
Packit 63bb0d
	"strings"
Packit 63bb0d
Packit 63bb0d
	"github.com/Azure/go-autorest/autorest/adal"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// EncodedAs is a series of constants specifying various data encodings
Packit 63bb0d
type EncodedAs string
Packit 63bb0d
Packit 63bb0d
const (
Packit 63bb0d
	// EncodedAsJSON states that data is encoded as JSON
Packit 63bb0d
	EncodedAsJSON EncodedAs = "JSON"
Packit 63bb0d
Packit 63bb0d
	// EncodedAsXML states that data is encoded as Xml
Packit 63bb0d
	EncodedAsXML EncodedAs = "XML"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// Decoder defines the decoding method json.Decoder and xml.Decoder share
Packit 63bb0d
type Decoder interface {
Packit 63bb0d
	Decode(v interface{}) error
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// NewDecoder creates a new decoder appropriate to the passed encoding.
Packit 63bb0d
// encodedAs specifies the type of encoding and r supplies the io.Reader containing the
Packit 63bb0d
// encoded data.
Packit 63bb0d
func NewDecoder(encodedAs EncodedAs, r io.Reader) Decoder {
Packit 63bb0d
	if encodedAs == EncodedAsJSON {
Packit 63bb0d
		return json.NewDecoder(r)
Packit 63bb0d
	} else if encodedAs == EncodedAsXML {
Packit 63bb0d
		return xml.NewDecoder(r)
Packit 63bb0d
	}
Packit 63bb0d
	return nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// CopyAndDecode decodes the data from the passed io.Reader while making a copy. Having a copy
Packit 63bb0d
// is especially useful if there is a chance the data will fail to decode.
Packit 63bb0d
// encodedAs specifies the expected encoding, r provides the io.Reader to the data, and v
Packit 63bb0d
// is the decoding destination.
Packit 63bb0d
func CopyAndDecode(encodedAs EncodedAs, r io.Reader, v interface{}) (bytes.Buffer, error) {
Packit 63bb0d
	b := bytes.Buffer{}
Packit 63bb0d
	return b, NewDecoder(encodedAs, io.TeeReader(r, &b)).Decode(v)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// TeeReadCloser returns a ReadCloser that writes to w what it reads from rc.
Packit 63bb0d
// It utilizes io.TeeReader to copy the data read and has the same behavior when reading.
Packit 63bb0d
// Further, when it is closed, it ensures that rc is closed as well.
Packit 63bb0d
func TeeReadCloser(rc io.ReadCloser, w io.Writer) io.ReadCloser {
Packit 63bb0d
	return &teeReadCloser{rc, io.TeeReader(rc, w)}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
type teeReadCloser struct {
Packit 63bb0d
	rc io.ReadCloser
Packit 63bb0d
	r  io.Reader
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (t *teeReadCloser) Read(p []byte) (int, error) {
Packit 63bb0d
	return t.r.Read(p)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (t *teeReadCloser) Close() error {
Packit 63bb0d
	return t.rc.Close()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func containsInt(ints []int, n int) bool {
Packit 63bb0d
	for _, i := range ints {
Packit 63bb0d
		if i == n {
Packit 63bb0d
			return true
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return false
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func escapeValueStrings(m map[string]string) map[string]string {
Packit 63bb0d
	for key, value := range m {
Packit 63bb0d
		m[key] = url.QueryEscape(value)
Packit 63bb0d
	}
Packit 63bb0d
	return m
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func ensureValueStrings(mapOfInterface map[string]interface{}) map[string]string {
Packit 63bb0d
	mapOfStrings := make(map[string]string)
Packit 63bb0d
	for key, value := range mapOfInterface {
Packit 63bb0d
		mapOfStrings[key] = ensureValueString(value)
Packit 63bb0d
	}
Packit 63bb0d
	return mapOfStrings
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func ensureValueString(value interface{}) string {
Packit 63bb0d
	if value == nil {
Packit 63bb0d
		return ""
Packit 63bb0d
	}
Packit 63bb0d
	switch v := value.(type) {
Packit 63bb0d
	case string:
Packit 63bb0d
		return v
Packit 63bb0d
	case []byte:
Packit 63bb0d
		return string(v)
Packit 63bb0d
	default:
Packit 63bb0d
		return fmt.Sprintf("%v", v)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// MapToValues method converts map[string]interface{} to url.Values.
Packit 63bb0d
func MapToValues(m map[string]interface{}) url.Values {
Packit 63bb0d
	v := url.Values{}
Packit 63bb0d
	for key, value := range m {
Packit 63bb0d
		x := reflect.ValueOf(value)
Packit 63bb0d
		if x.Kind() == reflect.Array || x.Kind() == reflect.Slice {
Packit 63bb0d
			for i := 0; i < x.Len(); i++ {
Packit 63bb0d
				v.Add(key, ensureValueString(x.Index(i)))
Packit 63bb0d
			}
Packit 63bb0d
		} else {
Packit 63bb0d
			v.Add(key, ensureValueString(value))
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return v
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// AsStringSlice method converts interface{} to []string.
Packit 63bb0d
// s must be of type slice or array or an error is returned.
Packit 63bb0d
// Each element of s will be converted to its string representation.
Packit 63bb0d
func AsStringSlice(s interface{}) ([]string, error) {
Packit 63bb0d
	v := reflect.ValueOf(s)
Packit 63bb0d
	if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
Packit 63bb0d
		return nil, NewError("autorest", "AsStringSlice", "the value's type is not a slice or array.")
Packit 63bb0d
	}
Packit 63bb0d
	stringSlice := make([]string, 0, v.Len())
Packit 63bb0d
Packit 63bb0d
	for i := 0; i < v.Len(); i++ {
Packit 63bb0d
		stringSlice = append(stringSlice, fmt.Sprintf("%v", v.Index(i)))
Packit 63bb0d
	}
Packit 63bb0d
	return stringSlice, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// String method converts interface v to string. If interface is a list, it
Packit 63bb0d
// joins list elements using the separator. Note that only sep[0] will be used for
Packit 63bb0d
// joining if any separator is specified.
Packit 63bb0d
func String(v interface{}, sep ...string) string {
Packit 63bb0d
	if len(sep) == 0 {
Packit 63bb0d
		return ensureValueString(v)
Packit 63bb0d
	}
Packit 63bb0d
	stringSlice, ok := v.([]string)
Packit 63bb0d
	if ok == false {
Packit 63bb0d
		var err error
Packit 63bb0d
		stringSlice, err = AsStringSlice(v)
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			panic(fmt.Sprintf("autorest: Couldn't convert value to a string %s.", err))
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return ensureValueString(strings.Join(stringSlice, sep[0]))
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Encode method encodes url path and query parameters.
Packit 63bb0d
func Encode(location string, v interface{}, sep ...string) string {
Packit 63bb0d
	s := String(v, sep...)
Packit 63bb0d
	switch strings.ToLower(location) {
Packit 63bb0d
	case "path":
Packit 63bb0d
		return pathEscape(s)
Packit 63bb0d
	case "query":
Packit 63bb0d
		return queryEscape(s)
Packit 63bb0d
	default:
Packit 63bb0d
		return s
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func pathEscape(s string) string {
Packit 63bb0d
	return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func queryEscape(s string) string {
Packit 63bb0d
	return url.QueryEscape(s)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// ChangeToGet turns the specified http.Request into a GET (it assumes it wasn't).
Packit 63bb0d
// This is mainly useful for long-running operations that use the Azure-AsyncOperation
Packit 63bb0d
// header, so we change the initial PUT into a GET to retrieve the final result.
Packit 63bb0d
func ChangeToGet(req *http.Request) *http.Request {
Packit 63bb0d
	req.Method = "GET"
Packit 63bb0d
	req.Body = nil
Packit 63bb0d
	req.ContentLength = 0
Packit 63bb0d
	req.Header.Del("Content-Length")
Packit 63bb0d
	return req
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// IsTokenRefreshError returns true if the specified error implements the TokenRefreshError
Packit 63bb0d
// interface.  If err is a DetailedError it will walk the chain of Original errors.
Packit 63bb0d
func IsTokenRefreshError(err error) bool {
Packit 63bb0d
	if _, ok := err.(adal.TokenRefreshError); ok {
Packit 63bb0d
		return true
Packit 63bb0d
	}
Packit 63bb0d
	if de, ok := err.(DetailedError); ok {
Packit 63bb0d
		return IsTokenRefreshError(de.Original)
Packit 63bb0d
	}
Packit 63bb0d
	return false
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// IsTemporaryNetworkError returns true if the specified error is a temporary network error or false
Packit 63bb0d
// if it's not.  If the error doesn't implement the net.Error interface the return value is true.
Packit 63bb0d
func IsTemporaryNetworkError(err error) bool {
Packit 63bb0d
	if netErr, ok := err.(net.Error); !ok || (ok && netErr.Temporary()) {
Packit 63bb0d
		return true
Packit 63bb0d
	}
Packit 63bb0d
	return false
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// DrainResponseBody reads the response body then closes it.
Packit 63bb0d
func DrainResponseBody(resp *http.Response) error {
Packit 63bb0d
	if resp != nil && resp.Body != nil {
Packit 63bb0d
		_, err := io.Copy(ioutil.Discard, resp.Body)
Packit 63bb0d
		resp.Body.Close()
Packit 63bb0d
		return err
Packit 63bb0d
	}
Packit 63bb0d
	return nil
Packit 63bb0d
}