-
Notifications
You must be signed in to change notification settings - Fork 836
/
response.go
145 lines (133 loc) · 3.62 KB
/
response.go
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
//go:build go1.16
// +build go1.16
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package runtime
import (
"bytes"
"encoding/base64"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"io/ioutil"
"net/http"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
)
// Payload reads and returns the response body or an error.
// On a successful read, the response body is cached.
func Payload(resp *http.Response) ([]byte, error) {
// r.Body won't be a nopClosingBytesReader if downloading was skipped
if buf, ok := resp.Body.(*nopClosingBytesReader); ok {
return buf.Bytes(), nil
}
bytesBody, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, err
}
resp.Body = &nopClosingBytesReader{s: bytesBody, i: 0}
return bytesBody, nil
}
// HasStatusCode returns true if the Response's status code is one of the specified values.
func HasStatusCode(resp *http.Response, statusCodes ...int) bool {
return shared.HasStatusCode(resp, statusCodes...)
}
// UnmarshalAsByteArray will base-64 decode the received payload and place the result into the value pointed to by v.
func UnmarshalAsByteArray(resp *http.Response, v *[]byte, format Base64Encoding) error {
p, err := Payload(resp)
if err != nil {
return err
}
return DecodeByteArray(string(p), v, format)
}
// UnmarshalAsJSON calls json.Unmarshal() to unmarshal the received payload into the value pointed to by v.
func UnmarshalAsJSON(resp *http.Response, v interface{}) error {
payload, err := Payload(resp)
if err != nil {
return err
}
// TODO: verify early exit is correct
if len(payload) == 0 {
return nil
}
err = removeBOM(resp)
if err != nil {
return err
}
err = json.Unmarshal(payload, v)
if err != nil {
err = fmt.Errorf("unmarshalling type %T: %s", v, err)
}
return err
}
// UnmarshalAsXML calls xml.Unmarshal() to unmarshal the received payload into the value pointed to by v.
func UnmarshalAsXML(resp *http.Response, v interface{}) error {
payload, err := Payload(resp)
if err != nil {
return err
}
// TODO: verify early exit is correct
if len(payload) == 0 {
return nil
}
err = removeBOM(resp)
if err != nil {
return err
}
err = xml.Unmarshal(payload, v)
if err != nil {
err = fmt.Errorf("unmarshalling type %T: %s", v, err)
}
return err
}
// Drain reads the response body to completion then closes it. The bytes read are discarded.
func Drain(resp *http.Response) {
if resp != nil && resp.Body != nil {
_, _ = io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}
}
// removeBOM removes any byte-order mark prefix from the payload if present.
func removeBOM(resp *http.Response) error {
payload, err := Payload(resp)
if err != nil {
return err
}
// UTF8
trimmed := bytes.TrimPrefix(payload, []byte("\xef\xbb\xbf"))
if len(trimmed) < len(payload) {
resp.Body.(*nopClosingBytesReader).Set(trimmed)
}
return nil
}
// DecodeByteArray will base-64 decode the provided string into v.
func DecodeByteArray(s string, v *[]byte, format Base64Encoding) error {
if len(s) == 0 {
return nil
}
payload := string(s)
if payload[0] == '"' {
// remove surrounding quotes
payload = payload[1 : len(payload)-1]
}
switch format {
case Base64StdFormat:
decoded, err := base64.StdEncoding.DecodeString(payload)
if err == nil {
*v = decoded
return nil
}
return err
case Base64URLFormat:
// use raw encoding as URL format should not contain any '=' characters
decoded, err := base64.RawURLEncoding.DecodeString(payload)
if err == nil {
*v = decoded
return nil
}
return err
default:
return fmt.Errorf("unrecognized byte array format: %d", format)
}
}