1 package storage
2
3
4
5
6 import (
7 "bytes"
8 "crypto/hmac"
9 "crypto/rand"
10 "crypto/sha256"
11 "encoding/base64"
12 "encoding/xml"
13 "fmt"
14 "io"
15 "io/ioutil"
16 "net/http"
17 "net/url"
18 "reflect"
19 "strconv"
20 "strings"
21 "time"
22
23 "github.com/gofrs/uuid"
24 )
25
26 var (
27 fixedTime = time.Date(2050, time.December, 20, 21, 55, 0, 0, time.FixedZone("GMT", -6))
28 accountSASOptions = AccountSASTokenOptions{
29 Services: Services{
30 Blob: true,
31 },
32 ResourceTypes: ResourceTypes{
33 Service: true,
34 Container: true,
35 Object: true,
36 },
37 Permissions: Permissions{
38 Read: true,
39 Write: true,
40 Delete: true,
41 List: true,
42 Add: true,
43 Create: true,
44 Update: true,
45 Process: true,
46 },
47 Expiry: fixedTime,
48 UseHTTPS: true,
49 }
50 )
51
52 func (c Client) computeHmac256(message string) string {
53 h := hmac.New(sha256.New, c.accountKey)
54 h.Write([]byte(message))
55 return base64.StdEncoding.EncodeToString(h.Sum(nil))
56 }
57
58 func currentTimeRfc1123Formatted() string {
59 return timeRfc1123Formatted(time.Now().UTC())
60 }
61
62 func timeRfc1123Formatted(t time.Time) string {
63 return t.Format(http.TimeFormat)
64 }
65
66 func timeRFC3339Formatted(t time.Time) string {
67 return t.Format("2006-01-02T15:04:05.0000000Z")
68 }
69
70 func mergeParams(v1, v2 url.Values) url.Values {
71 out := url.Values{}
72 for k, v := range v1 {
73 out[k] = v
74 }
75 for k, v := range v2 {
76 vals, ok := out[k]
77 if ok {
78 vals = append(vals, v...)
79 out[k] = vals
80 } else {
81 out[k] = v
82 }
83 }
84 return out
85 }
86
87 func prepareBlockListRequest(blocks []Block) string {
88 s := `<?xml version="1.0" encoding="utf-8"?><BlockList>`
89 for _, v := range blocks {
90 s += fmt.Sprintf("<%s>%s</%s>", v.Status, v.ID, v.Status)
91 }
92 s += `</BlockList>`
93 return s
94 }
95
96 func xmlUnmarshal(body io.Reader, v interface{}) error {
97 data, err := ioutil.ReadAll(body)
98 if err != nil {
99 return err
100 }
101 return xml.Unmarshal(data, v)
102 }
103
104 func xmlMarshal(v interface{}) (io.Reader, int, error) {
105 b, err := xml.Marshal(v)
106 if err != nil {
107 return nil, 0, err
108 }
109 return bytes.NewReader(b), len(b), nil
110 }
111
112 func headersFromStruct(v interface{}) map[string]string {
113 headers := make(map[string]string)
114 value := reflect.ValueOf(v)
115 for i := 0; i < value.NumField(); i++ {
116 key := value.Type().Field(i).Tag.Get("header")
117 if key != "" {
118 reflectedValue := reflect.Indirect(value.Field(i))
119 var val string
120 if reflectedValue.IsValid() {
121 switch reflectedValue.Type() {
122 case reflect.TypeOf(fixedTime):
123 val = timeRfc1123Formatted(reflectedValue.Interface().(time.Time))
124 case reflect.TypeOf(uint64(0)), reflect.TypeOf(uint(0)):
125 val = strconv.FormatUint(reflectedValue.Uint(), 10)
126 case reflect.TypeOf(int(0)):
127 val = strconv.FormatInt(reflectedValue.Int(), 10)
128 default:
129 val = reflectedValue.String()
130 }
131 }
132 if val != "" {
133 headers[key] = val
134 }
135 }
136 }
137 return headers
138 }
139
140
141 func mergeHeaders(headers, extraHeaders map[string]string) map[string]string {
142 for k, v := range extraHeaders {
143 headers[k] = v
144 }
145 return headers
146 }
147
148 func addToHeaders(h map[string]string, key, value string) map[string]string {
149 if value != "" {
150 h[key] = value
151 }
152 return h
153 }
154
155 func addTimeToHeaders(h map[string]string, key string, value *time.Time) map[string]string {
156 if value != nil {
157 h = addToHeaders(h, key, timeRfc1123Formatted(*value))
158 }
159 return h
160 }
161
162 func addTimeout(params url.Values, timeout uint) url.Values {
163 if timeout > 0 {
164 params.Add("timeout", fmt.Sprintf("%v", timeout))
165 }
166 return params
167 }
168
169 func addSnapshot(params url.Values, snapshot *time.Time) url.Values {
170 if snapshot != nil {
171 params.Add("snapshot", timeRFC3339Formatted(*snapshot))
172 }
173 return params
174 }
175
176 func getTimeFromHeaders(h http.Header, key string) (*time.Time, error) {
177 var out time.Time
178 var err error
179 outStr := h.Get(key)
180 if outStr != "" {
181 out, err = time.Parse(time.RFC1123, outStr)
182 if err != nil {
183 return nil, err
184 }
185 }
186 return &out, nil
187 }
188
189
190 type TimeRFC1123 time.Time
191
192
193 func (t *TimeRFC1123) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
194 var value string
195 d.DecodeElement(&value, &start)
196 parse, err := time.Parse(time.RFC1123, value)
197 if err != nil {
198 return err
199 }
200 *t = TimeRFC1123(parse)
201 return nil
202 }
203
204
205 func (t *TimeRFC1123) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
206 return e.EncodeElement(time.Time(*t).Format(time.RFC1123), start)
207 }
208
209
210 func getMetadataFromHeaders(header http.Header) map[string]string {
211 metadata := make(map[string]string)
212 for k, v := range header {
213
214
215
216
217
218
219
220
221
222 k = strings.ToLower(k)
223 if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) {
224 continue
225 }
226
227 k = k[len(userDefinedMetadataHeaderPrefix):]
228 metadata[k] = v[len(v)-1]
229 }
230
231 if len(metadata) == 0 {
232 return nil
233 }
234
235 return metadata
236 }
237
238
239 func newUUID() (uuid.UUID, error) {
240 u := [16]byte{}
241
242 _, err := rand.Read(u[:])
243 if err != nil {
244 return uuid.UUID{}, err
245 }
246 u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
247 u[6] = (u[6] & 0xF) | (uuid.V4 << 4)
248 return uuid.FromBytes(u[:])
249 }
250
View as plain text