...

Source file src/github.com/Azure/azure-sdk-for-go/storage/util.go

Documentation: github.com/Azure/azure-sdk-for-go/storage

     1  package storage
     2  
     3  // Copyright (c) Microsoft Corporation. All rights reserved.
     4  // Licensed under the MIT License. See License.txt in the project root for license information.
     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  // merges extraHeaders into headers and returns headers
   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  // TimeRFC1123 is an alias for time.Time needed for custom Unmarshalling
   190  type TimeRFC1123 time.Time
   191  
   192  // UnmarshalXML is a custom unmarshaller that overrides the default time unmarshal which uses a different time layout.
   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  // MarshalXML marshals using time.RFC1123.
   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  // returns a map of custom metadata values from the specified HTTP header
   210  func getMetadataFromHeaders(header http.Header) map[string]string {
   211  	metadata := make(map[string]string)
   212  	for k, v := range header {
   213  		// Can't trust CanonicalHeaderKey() to munge case
   214  		// reliably. "_" is allowed in identifiers:
   215  		// https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
   216  		// https://msdn.microsoft.com/library/aa664670(VS.71).aspx
   217  		// http://tools.ietf.org/html/rfc7230#section-3.2
   218  		// ...but "_" is considered invalid by
   219  		// CanonicalMIMEHeaderKey in
   220  		// https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542
   221  		// so k can be "X-Ms-Meta-Lol" or "x-ms-meta-lol_rofl".
   222  		k = strings.ToLower(k)
   223  		if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) {
   224  			continue
   225  		}
   226  		// metadata["lol"] = content of the last X-Ms-Meta-Lol header
   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  // newUUID returns a new uuid using RFC 4122 algorithm.
   239  func newUUID() (uuid.UUID, error) {
   240  	u := [16]byte{}
   241  	// Set all bits to randomly (or pseudo-randomly) chosen values.
   242  	_, err := rand.Read(u[:])
   243  	if err != nil {
   244  		return uuid.UUID{}, err
   245  	}
   246  	u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) // u.setVariant(ReservedRFC4122)
   247  	u[6] = (u[6] & 0xF) | (uuid.V4 << 4)  // u.setVersion(V4)
   248  	return uuid.FromBytes(u[:])
   249  }
   250  

View as plain text