blobserviceclient.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package storage
  2. // Copyright 2017 Microsoft Corporation
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. import (
  16. "encoding/xml"
  17. "fmt"
  18. "net/http"
  19. "net/url"
  20. "strconv"
  21. "strings"
  22. )
  23. // BlobStorageClient contains operations for Microsoft Azure Blob Storage
  24. // Service.
  25. type BlobStorageClient struct {
  26. client Client
  27. auth authentication
  28. }
  29. // GetServiceProperties gets the properties of your storage account's blob service.
  30. // See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-blob-service-properties
  31. func (b *BlobStorageClient) GetServiceProperties() (*ServiceProperties, error) {
  32. return b.client.getServiceProperties(blobServiceName, b.auth)
  33. }
  34. // SetServiceProperties sets the properties of your storage account's blob service.
  35. // See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-blob-service-properties
  36. func (b *BlobStorageClient) SetServiceProperties(props ServiceProperties) error {
  37. return b.client.setServiceProperties(props, blobServiceName, b.auth)
  38. }
  39. // ListContainersParameters defines the set of customizable parameters to make a
  40. // List Containers call.
  41. //
  42. // See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx
  43. type ListContainersParameters struct {
  44. Prefix string
  45. Marker string
  46. Include string
  47. MaxResults uint
  48. Timeout uint
  49. }
  50. // GetContainerReference returns a Container object for the specified container name.
  51. func (b *BlobStorageClient) GetContainerReference(name string) *Container {
  52. return &Container{
  53. bsc: b,
  54. Name: name,
  55. }
  56. }
  57. // GetContainerReferenceFromSASURI returns a Container object for the specified
  58. // container SASURI
  59. func GetContainerReferenceFromSASURI(sasuri url.URL) (*Container, error) {
  60. path := strings.Split(sasuri.Path, "/")
  61. if len(path) <= 1 {
  62. return nil, fmt.Errorf("could not find a container in URI: %s", sasuri.String())
  63. }
  64. c, err := newSASClientFromURL(&sasuri)
  65. if err != nil {
  66. return nil, err
  67. }
  68. cli := c.GetBlobService()
  69. return &Container{
  70. bsc: &cli,
  71. Name: path[1],
  72. sasuri: sasuri,
  73. }, nil
  74. }
  75. // ListContainers returns the list of containers in a storage account along with
  76. // pagination token and other response details.
  77. //
  78. // See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx
  79. func (b BlobStorageClient) ListContainers(params ListContainersParameters) (*ContainerListResponse, error) {
  80. q := mergeParams(params.getParameters(), url.Values{"comp": {"list"}})
  81. uri := b.client.getEndpoint(blobServiceName, "", q)
  82. headers := b.client.getStandardHeaders()
  83. type ContainerAlias struct {
  84. bsc *BlobStorageClient
  85. Name string `xml:"Name"`
  86. Properties ContainerProperties `xml:"Properties"`
  87. Metadata BlobMetadata
  88. sasuri url.URL
  89. }
  90. type ContainerListResponseAlias struct {
  91. XMLName xml.Name `xml:"EnumerationResults"`
  92. Xmlns string `xml:"xmlns,attr"`
  93. Prefix string `xml:"Prefix"`
  94. Marker string `xml:"Marker"`
  95. NextMarker string `xml:"NextMarker"`
  96. MaxResults int64 `xml:"MaxResults"`
  97. Containers []ContainerAlias `xml:"Containers>Container"`
  98. }
  99. var outAlias ContainerListResponseAlias
  100. resp, err := b.client.exec(http.MethodGet, uri, headers, nil, b.auth)
  101. if err != nil {
  102. return nil, err
  103. }
  104. defer resp.Body.Close()
  105. err = xmlUnmarshal(resp.Body, &outAlias)
  106. if err != nil {
  107. return nil, err
  108. }
  109. out := ContainerListResponse{
  110. XMLName: outAlias.XMLName,
  111. Xmlns: outAlias.Xmlns,
  112. Prefix: outAlias.Prefix,
  113. Marker: outAlias.Marker,
  114. NextMarker: outAlias.NextMarker,
  115. MaxResults: outAlias.MaxResults,
  116. Containers: make([]Container, len(outAlias.Containers)),
  117. }
  118. for i, cnt := range outAlias.Containers {
  119. out.Containers[i] = Container{
  120. bsc: &b,
  121. Name: cnt.Name,
  122. Properties: cnt.Properties,
  123. Metadata: map[string]string(cnt.Metadata),
  124. sasuri: cnt.sasuri,
  125. }
  126. }
  127. return &out, err
  128. }
  129. func (p ListContainersParameters) getParameters() url.Values {
  130. out := url.Values{}
  131. if p.Prefix != "" {
  132. out.Set("prefix", p.Prefix)
  133. }
  134. if p.Marker != "" {
  135. out.Set("marker", p.Marker)
  136. }
  137. if p.Include != "" {
  138. out.Set("include", p.Include)
  139. }
  140. if p.MaxResults != 0 {
  141. out.Set("maxresults", strconv.FormatUint(uint64(p.MaxResults), 10))
  142. }
  143. if p.Timeout != 0 {
  144. out.Set("timeout", strconv.FormatUint(uint64(p.Timeout), 10))
  145. }
  146. return out
  147. }
  148. func writeMetadata(h http.Header) map[string]string {
  149. metadata := make(map[string]string)
  150. for k, v := range h {
  151. // Can't trust CanonicalHeaderKey() to munge case
  152. // reliably. "_" is allowed in identifiers:
  153. // https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
  154. // https://msdn.microsoft.com/library/aa664670(VS.71).aspx
  155. // http://tools.ietf.org/html/rfc7230#section-3.2
  156. // ...but "_" is considered invalid by
  157. // CanonicalMIMEHeaderKey in
  158. // https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542
  159. // so k can be "X-Ms-Meta-Lol" or "x-ms-meta-lol_rofl".
  160. k = strings.ToLower(k)
  161. if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) {
  162. continue
  163. }
  164. // metadata["lol"] = content of the last X-Ms-Meta-Lol header
  165. k = k[len(userDefinedMetadataHeaderPrefix):]
  166. metadata[k] = v[len(v)-1]
  167. }
  168. return metadata
  169. }