aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/Azure/go-autorest/autorest/utility.go
blob: 78067148b28d9e980b52ad70353e3d3f7df353fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package autorest

import (
    "bytes"
    "encoding/json"
    "encoding/xml"
    "fmt"
    "io"
    "net/url"
    "reflect"
    "sort"
    "strings"
)

// EncodedAs is a series of constants specifying various data encodings
type EncodedAs string

const (
    // EncodedAsJSON states that data is encoded as JSON
    EncodedAsJSON EncodedAs = "JSON"

    // EncodedAsXML states that data is encoded as Xml
    EncodedAsXML EncodedAs = "XML"
)

// Decoder defines the decoding method json.Decoder and xml.Decoder share
type Decoder interface {
    Decode(v interface{}) error
}

// NewDecoder creates a new decoder appropriate to the passed encoding.
// encodedAs specifies the type of encoding and r supplies the io.Reader containing the
// encoded data.
func NewDecoder(encodedAs EncodedAs, r io.Reader) Decoder {
    if encodedAs == EncodedAsJSON {
        return json.NewDecoder(r)
    } else if encodedAs == EncodedAsXML {
        return xml.NewDecoder(r)
    }
    return nil
}

// CopyAndDecode decodes the data from the passed io.Reader while making a copy. Having a copy
// is especially useful if there is a chance the data will fail to decode.
// encodedAs specifies the expected encoding, r provides the io.Reader to the data, and v
// is the decoding destination.
func CopyAndDecode(encodedAs EncodedAs, r io.Reader, v interface{}) (bytes.Buffer, error) {
    b := bytes.Buffer{}
    return b, NewDecoder(encodedAs, io.TeeReader(r, &b)).Decode(v)
}

// TeeReadCloser returns a ReadCloser that writes to w what it reads from rc.
// It utilizes io.TeeReader to copy the data read and has the same behavior when reading.
// Further, when it is closed, it ensures that rc is closed as well.
func TeeReadCloser(rc io.ReadCloser, w io.Writer) io.ReadCloser {
    return &teeReadCloser{rc, io.TeeReader(rc, w)}
}

type teeReadCloser struct {
    rc io.ReadCloser
    r  io.Reader
}

func (t *teeReadCloser) Read(p []byte) (int, error) {
    return t.r.Read(p)
}

func (t *teeReadCloser) Close() error {
    return t.rc.Close()
}

func containsInt(ints []int, n int) bool {
    for _, i := range ints {
        if i == n {
            return true
        }
    }
    return false
}

func escapeValueStrings(m map[string]string) map[string]string {
    for key, value := range m {
        m[key] = url.QueryEscape(value)
    }
    return m
}

func ensureValueStrings(mapOfInterface map[string]interface{}) map[string]string {
    mapOfStrings := make(map[string]string)
    for key, value := range mapOfInterface {
        mapOfStrings[key] = ensureValueString(value)
    }
    return mapOfStrings
}

func ensureValueString(value interface{}) string {
    if value == nil {
        return ""
    }
    switch v := value.(type) {
    case string:
        return v
    case []byte:
        return string(v)
    default:
        return fmt.Sprintf("%v", v)
    }
}

// MapToValues method converts map[string]interface{} to url.Values.
func MapToValues(m map[string]interface{}) url.Values {
    v := url.Values{}
    for key, value := range m {
        x := reflect.ValueOf(value)
        if x.Kind() == reflect.Array || x.Kind() == reflect.Slice {
            for i := 0; i < x.Len(); i++ {
                v.Add(key, ensureValueString(x.Index(i)))
            }
        } else {
            v.Add(key, ensureValueString(value))
        }
    }
    return v
}

// String method converts interface v to string. If interface is a list, it
// joins list elements using separator.
func String(v interface{}, sep ...string) string {
    if len(sep) > 0 {
        return ensureValueString(strings.Join(v.([]string), sep[0]))
    }
    return ensureValueString(v)
}

// Encode method encodes url path and query parameters.
func Encode(location string, v interface{}, sep ...string) string {
    s := String(v, sep...)
    switch strings.ToLower(location) {
    case "path":
        return pathEscape(s)
    case "query":
        return queryEscape(s)
    default:
        return s
    }
}

func pathEscape(s string) string {
    return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
}

func queryEscape(s string) string {
    return url.QueryEscape(s)
}

// This method is same as Encode() method of "net/url" go package,
// except it does not encode the query parameters because they
// already come encoded. It formats values map in query format (bar=foo&a=b).
func createQuery(v url.Values) string {
    var buf bytes.Buffer
    keys := make([]string, 0, len(v))
    for k := range v {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    for _, k := range keys {
        vs := v[k]
        prefix := url.QueryEscape(k) + "="
        for _, v := range vs {
            if buf.Len() > 0 {
                buf.WriteByte('&')
            }
            buf.WriteString(prefix)
            buf.WriteString(v)
        }
    }
    return buf.String()
}