blob: 0ab5e17111550868d2deba08dee2dda5a41469f1 [file] [log] [blame]
Jon Perritt816d2a02014-03-11 20:49:46 -05001package objects
2
3import (
Jon Perrittfea90732016-03-15 02:57:05 -05004 "bytes"
Jon Perritt90957602015-02-01 17:03:06 -07005 "crypto/hmac"
Jamie Hannaford08096232015-07-13 12:47:28 +02006 "crypto/md5"
Jon Perritt90957602015-02-01 17:03:06 -07007 "crypto/sha1"
Jon Perritt816d2a02014-03-11 20:49:46 -05008 "fmt"
Jon Perritt8c93a302014-09-28 22:35:57 -05009 "io"
Jon Perritt90957602015-02-01 17:03:06 -070010 "strings"
Jon Perritt8c93a302014-09-28 22:35:57 -050011 "time"
Ash Wilson604320e2014-09-10 16:02:28 -040012
Jon Perritt27249f42016-02-18 10:35:59 -060013 "github.com/gophercloud/gophercloud"
14 "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/accounts"
15 "github.com/gophercloud/gophercloud/pagination"
Jon Perritt816d2a02014-03-11 20:49:46 -050016)
17
Jon Perritte90aced2014-10-12 23:24:06 -050018// ListOptsBuilder allows extensions to add additional parameters to the List
19// request.
20type ListOptsBuilder interface {
21 ToObjectListParams() (bool, string, error)
22}
23
Jon Perritt8c93a302014-09-28 22:35:57 -050024// ListOpts is a structure that holds parameters for listing objects.
25type ListOpts struct {
Jon Perritt9415ca72014-11-03 11:58:48 -060026 // Full is a true/false value that represents the amount of object information
27 // returned. If Full is set to true, then the content-type, number of bytes, hash
28 // date last modified, and name are returned. If set to false or not set, then
29 // only the object names are returned.
Jon Perritt8c93a302014-09-28 22:35:57 -050030 Full bool
Jon Perritt04851d32014-10-14 02:07:13 -050031 Limit int `q:"limit"`
32 Marker string `q:"marker"`
33 EndMarker string `q:"end_marker"`
34 Format string `q:"format"`
35 Prefix string `q:"prefix"`
36 Delimiter string `q:"delimiter"`
37 Path string `q:"path"`
Ash Wilsonca6f7562014-09-16 15:43:54 -040038}
39
Jon Perritte90aced2014-10-12 23:24:06 -050040// ToObjectListParams formats a ListOpts into a query string and boolean
41// representing whether to list complete information for each object.
42func (opts ListOpts) ToObjectListParams() (bool, string, error) {
43 q, err := gophercloud.BuildQueryString(opts)
Jon Perrittfea90732016-03-15 02:57:05 -050044 return opts.Full, q.String(), err
Jon Perritte90aced2014-10-12 23:24:06 -050045}
46
Jon Perritt816d2a02014-03-11 20:49:46 -050047// List is a function that retrieves all objects in a container. It also returns the details
48// for the container. To extract only the object information or names, pass the ListResult
Jon Perritteb575642014-04-24 15:16:31 -050049// response to the ExtractInfo or ExtractNames function, respectively.
Jon Perritte90aced2014-10-12 23:24:06 -050050func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager {
51 headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"}
Jon Perritt816d2a02014-03-11 20:49:46 -050052
Jon Perrittea4e3012014-10-09 22:03:19 -050053 url := listURL(c, containerName)
Jon Perrittde47eac2014-09-30 15:34:17 -050054 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -050055 full, query, err := opts.ToObjectListParams()
Jon Perrittde47eac2014-09-30 15:34:17 -050056 if err != nil {
Jon Perrittde47eac2014-09-30 15:34:17 -050057 return pagination.Pager{Err: err}
58 }
Jon Perritte90aced2014-10-12 23:24:06 -050059 url += query
Jon Perritt816d2a02014-03-11 20:49:46 -050060
Jon Perritte90aced2014-10-12 23:24:06 -050061 if full {
62 headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"}
Jon Perrittde47eac2014-09-30 15:34:17 -050063 }
Ash Wilsonca6f7562014-09-16 15:43:54 -040064 }
65
Jon Perrittfea90732016-03-15 02:57:05 -050066 pager := pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
Ash Wilsonb8b16f82014-10-20 10:19:49 -040067 p := ObjectPage{pagination.MarkerPageBase{PageResult: r}}
Ash Wilsonca6f7562014-09-16 15:43:54 -040068 p.MarkerPageBase.Owner = p
69 return p
Jon Perrittfea90732016-03-15 02:57:05 -050070 })
Ash Wilsonca6f7562014-09-16 15:43:54 -040071 pager.Headers = headers
72 return pager
Jon Perritt816d2a02014-03-11 20:49:46 -050073}
74
Jon Perritte90aced2014-10-12 23:24:06 -050075// DownloadOptsBuilder allows extensions to add additional parameters to the
76// Download request.
77type DownloadOptsBuilder interface {
78 ToObjectDownloadParams() (map[string]string, string, error)
79}
80
Jon Perritt8c93a302014-09-28 22:35:57 -050081// DownloadOpts is a structure that holds parameters for downloading an object.
82type DownloadOpts struct {
83 IfMatch string `h:"If-Match"`
84 IfModifiedSince time.Time `h:"If-Modified-Since"`
85 IfNoneMatch string `h:"If-None-Match"`
86 IfUnmodifiedSince time.Time `h:"If-Unmodified-Since"`
87 Range string `h:"Range"`
88 Expires string `q:"expires"`
89 MultipartManifest string `q:"multipart-manifest"`
90 Signature string `q:"signature"`
91}
92
Jon Perritte90aced2014-10-12 23:24:06 -050093// ToObjectDownloadParams formats a DownloadOpts into a query string and map of
94// headers.
Paul Querna7dc6fe62014-11-01 08:09:41 -070095func (opts DownloadOpts) ToObjectDownloadParams() (map[string]string, string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -050096 q, err := gophercloud.BuildQueryString(opts)
97 if err != nil {
98 return nil, "", err
99 }
100 h, err := gophercloud.BuildHeaders(opts)
101 if err != nil {
102 return nil, q.String(), err
103 }
104 return h, q.String(), nil
105}
106
Jon Perritt816d2a02014-03-11 20:49:46 -0500107// Download is a function that retrieves the content and metadata for an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500108// To extract just the content, pass the DownloadResult response to the
109// ExtractContent function.
Jon Perritt3860b512016-03-29 12:01:48 -0500110func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) (r DownloadResult) {
Jon Perrittea4e3012014-10-09 22:03:19 -0500111 url := downloadURL(c, containerName, objectName)
Jon Perrittfea90732016-03-15 02:57:05 -0500112 h := make(map[string]string)
Jon Perrittde47eac2014-09-30 15:34:17 -0500113 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500114 headers, query, err := opts.ToObjectDownloadParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500115 if err != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500116 r.Err = err
Jon Perritt3860b512016-03-29 12:01:48 -0500117 return
Jon Perrittde47eac2014-09-30 15:34:17 -0500118 }
Jon Perrittde47eac2014-09-30 15:34:17 -0500119 for k, v := range headers {
120 h[k] = v
121 }
Jon Perritte90aced2014-10-12 23:24:06 -0500122 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500123 }
124
Jon Perrittfea90732016-03-15 02:57:05 -0500125 resp, err := c.Get(url, nil, &gophercloud.RequestOpts{
Jon Perritt816d2a02014-03-11 20:49:46 -0500126 MoreHeaders: h,
Paul Querna9163df22014-11-01 09:38:51 -0700127 OkCodes: []int{200, 304},
Jon Perritt816d2a02014-03-11 20:49:46 -0500128 })
Jon Perritta2c88b22015-05-18 11:23:30 -0600129 if resp != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500130 r.Header = resp.Header
131 r.Body = resp.Body
Jon Perritta2c88b22015-05-18 11:23:30 -0600132 }
Jon Perrittfea90732016-03-15 02:57:05 -0500133 r.Err = err
jrperritt29ae6b32016-04-13 12:59:37 -0500134 return
Jon Perritt8c93a302014-09-28 22:35:57 -0500135}
136
Jon Perritte90aced2014-10-12 23:24:06 -0500137// CreateOptsBuilder allows extensions to add additional parameters to the
138// Create request.
139type CreateOptsBuilder interface {
Jon Perrittfea90732016-03-15 02:57:05 -0500140 ToObjectCreateParams() (io.Reader, map[string]string, string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500141}
142
Jon Perritt8c93a302014-09-28 22:35:57 -0500143// CreateOpts is a structure that holds parameters for creating an object.
144type CreateOpts struct {
Jon Perrittfea90732016-03-15 02:57:05 -0500145 Content io.Reader
Jon Perritt8c93a302014-09-28 22:35:57 -0500146 Metadata map[string]string
Rodrigo Lourencod1c7d252016-05-23 14:11:03 -0300147 CacheControl string `h:"Cache-Control"`
Jon Perritt8c93a302014-09-28 22:35:57 -0500148 ContentDisposition string `h:"Content-Disposition"`
149 ContentEncoding string `h:"Content-Encoding"`
Jon Perritte376fa52014-11-03 11:35:48 -0600150 ContentLength int64 `h:"Content-Length"`
Jon Perritt8c93a302014-09-28 22:35:57 -0500151 ContentType string `h:"Content-Type"`
152 CopyFrom string `h:"X-Copy-From"`
153 DeleteAfter int `h:"X-Delete-After"`
154 DeleteAt int `h:"X-Delete-At"`
155 DetectContentType string `h:"X-Detect-Content-Type"`
156 ETag string `h:"ETag"`
157 IfNoneMatch string `h:"If-None-Match"`
158 ObjectManifest string `h:"X-Object-Manifest"`
159 TransferEncoding string `h:"Transfer-Encoding"`
160 Expires string `q:"expires"`
jrperritt4fcd3b72015-09-23 11:17:23 -0600161 MultipartManifest string `q:"multipart-manifest"`
Jon Perritt8c93a302014-09-28 22:35:57 -0500162 Signature string `q:"signature"`
Jon Perritt816d2a02014-03-11 20:49:46 -0500163}
164
Jon Perritte90aced2014-10-12 23:24:06 -0500165// ToObjectCreateParams formats a CreateOpts into a query string and map of
166// headers.
Jon Perrittfea90732016-03-15 02:57:05 -0500167func (opts CreateOpts) ToObjectCreateParams() (io.Reader, map[string]string, string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500168 q, err := gophercloud.BuildQueryString(opts)
169 if err != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500170 return nil, nil, "", err
Jon Perritte90aced2014-10-12 23:24:06 -0500171 }
172 h, err := gophercloud.BuildHeaders(opts)
173 if err != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500174 return nil, nil, "", err
Jon Perritte90aced2014-10-12 23:24:06 -0500175 }
176
177 for k, v := range opts.Metadata {
178 h["X-Object-Meta-"+k] = v
179 }
180
Jon Perrittfea90732016-03-15 02:57:05 -0500181 hash := md5.New()
182 buf := bytes.NewBuffer([]byte{})
183 _, err = io.Copy(io.MultiWriter(hash, buf), opts.Content)
184 if err != nil {
185 return nil, nil, "", err
186 }
187 localChecksum := fmt.Sprintf("%x", hash.Sum(nil))
188 h["ETag"] = localChecksum
189
190 return buf, h, q.String(), nil
Jon Perritte90aced2014-10-12 23:24:06 -0500191}
192
Jamie Hannaford50fc97d2015-07-16 12:29:01 +0200193// Create is a function that creates a new object or replaces an existing object. If the returned response's ETag
194// header fails to match the local checksum, the failed request will automatically be retried up to a maximum of 3 times.
Jon Perritt3860b512016-03-29 12:01:48 -0500195func Create(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateOptsBuilder) (r CreateResult) {
Jon Perrittea4e3012014-10-09 22:03:19 -0500196 url := createURL(c, containerName, objectName)
Ash Wilson322a7e62015-02-12 16:25:26 -0500197 h := make(map[string]string)
Jon Perrittfea90732016-03-15 02:57:05 -0500198 var b io.Reader
Jon Perrittde47eac2014-09-30 15:34:17 -0500199 if opts != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500200 tmpB, headers, query, err := opts.ToObjectCreateParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500201 if err != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500202 r.Err = err
Jon Perritt3860b512016-03-29 12:01:48 -0500203 return
Jon Perrittde47eac2014-09-30 15:34:17 -0500204 }
Jon Perrittde47eac2014-09-30 15:34:17 -0500205 for k, v := range headers {
206 h[k] = v
207 }
Jon Perritte90aced2014-10-12 23:24:06 -0500208 url += query
Jon Perrittfea90732016-03-15 02:57:05 -0500209 b = tmpB
Jon Perritt8c93a302014-09-28 22:35:57 -0500210 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500211
Jon Perrittfea90732016-03-15 02:57:05 -0500212 resp, err := c.Put(url, nil, nil, &gophercloud.RequestOpts{
213 RawBody: b,
jrperritt56d51e92015-07-30 11:50:53 -0600214 MoreHeaders: h,
Jon Perrittfea90732016-03-15 02:57:05 -0500215 })
216 r.Err = err
jrperritt433cc792015-07-31 18:53:12 -0600217 if resp != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500218 r.Header = resp.Header
Jamie Hannaford08096232015-07-13 12:47:28 +0200219 }
jrperritt29ae6b32016-04-13 12:59:37 -0500220 return
Jon Perritt816d2a02014-03-11 20:49:46 -0500221}
222
Jon Perritte90aced2014-10-12 23:24:06 -0500223// CopyOptsBuilder allows extensions to add additional parameters to the
224// Copy request.
225type CopyOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500226 ToObjectCopyMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500227}
228
229// CopyOpts is a structure that holds parameters for copying one object to
230// another.
Jon Perritt8c93a302014-09-28 22:35:57 -0500231type CopyOpts struct {
232 Metadata map[string]string
233 ContentDisposition string `h:"Content-Disposition"`
234 ContentEncoding string `h:"Content-Encoding"`
235 ContentType string `h:"Content-Type"`
Jon Perrittfea90732016-03-15 02:57:05 -0500236 Destination string `h:"Destination" required:"true"`
Jon Perritt8c93a302014-09-28 22:35:57 -0500237}
238
Jon Perritt04851d32014-10-14 02:07:13 -0500239// ToObjectCopyMap formats a CopyOpts into a map of headers.
240func (opts CopyOpts) ToObjectCopyMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500241 h, err := gophercloud.BuildHeaders(opts)
242 if err != nil {
243 return nil, err
244 }
245 for k, v := range opts.Metadata {
246 h["X-Object-Meta-"+k] = v
247 }
248 return h, nil
249}
250
Jon Perritt816d2a02014-03-11 20:49:46 -0500251// Copy is a function that copies one object to another.
Jon Perritt3860b512016-03-29 12:01:48 -0500252func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) (r CopyResult) {
Jon Perrittfea90732016-03-15 02:57:05 -0500253 h := make(map[string]string)
Jon Perritt04851d32014-10-14 02:07:13 -0500254 headers, err := opts.ToObjectCopyMap()
Jon Perritt8c93a302014-09-28 22:35:57 -0500255 if err != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500256 r.Err = err
Jon Perritt3860b512016-03-29 12:01:48 -0500257 return
Jon Perritt816d2a02014-03-11 20:49:46 -0500258 }
Jon Perritte90aced2014-10-12 23:24:06 -0500259
Jon Perritt8c93a302014-09-28 22:35:57 -0500260 for k, v := range headers {
Jon Perritt816d2a02014-03-11 20:49:46 -0500261 h[k] = v
262 }
263
Jon Perrittea4e3012014-10-09 22:03:19 -0500264 url := copyURL(c, containerName, objectName)
Jon Perritta33da232016-03-02 04:43:08 -0600265 resp, err := c.Request("COPY", url, &gophercloud.RequestOpts{
Jon Perritt8c93a302014-09-28 22:35:57 -0500266 MoreHeaders: h,
267 OkCodes: []int{201},
268 })
Jon Perritta2c88b22015-05-18 11:23:30 -0600269 if resp != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500270 r.Header = resp.Header
Jon Perritta2c88b22015-05-18 11:23:30 -0600271 }
Jon Perrittfea90732016-03-15 02:57:05 -0500272 r.Err = err
jrperritt29ae6b32016-04-13 12:59:37 -0500273 return
Jon Perritt8c93a302014-09-28 22:35:57 -0500274}
275
Jon Perritte90aced2014-10-12 23:24:06 -0500276// DeleteOptsBuilder allows extensions to add additional parameters to the
277// Delete request.
278type DeleteOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500279 ToObjectDeleteQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500280}
281
Jon Perritt8c93a302014-09-28 22:35:57 -0500282// DeleteOpts is a structure that holds parameters for deleting an object.
283type DeleteOpts struct {
284 MultipartManifest string `q:"multipart-manifest"`
285}
286
Jon Perritt26780d52014-10-14 11:35:58 -0500287// ToObjectDeleteQuery formats a DeleteOpts into a query string.
288func (opts DeleteOpts) ToObjectDeleteQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500289 q, err := gophercloud.BuildQueryString(opts)
Jon Perrittfea90732016-03-15 02:57:05 -0500290 return q.String(), err
Jon Perritte90aced2014-10-12 23:24:06 -0500291}
292
Jon Perritt8c93a302014-09-28 22:35:57 -0500293// Delete is a function that deletes an object.
Jon Perritt3860b512016-03-29 12:01:48 -0500294func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) (r DeleteResult) {
Jon Perrittea4e3012014-10-09 22:03:19 -0500295 url := deleteURL(c, containerName, objectName)
Jon Perrittde47eac2014-09-30 15:34:17 -0500296 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500297 query, err := opts.ToObjectDeleteQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500298 if err != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500299 r.Err = err
Jon Perritt3860b512016-03-29 12:01:48 -0500300 return
Jon Perrittde47eac2014-09-30 15:34:17 -0500301 }
Jon Perritte90aced2014-10-12 23:24:06 -0500302 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500303 }
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100304 resp, err := c.Delete(url, nil)
Jon Perritta2c88b22015-05-18 11:23:30 -0600305 if resp != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500306 r.Header = resp.Header
Jon Perritta2c88b22015-05-18 11:23:30 -0600307 }
Jon Perrittfea90732016-03-15 02:57:05 -0500308 r.Err = err
jrperritt29ae6b32016-04-13 12:59:37 -0500309 return
Jon Perritt8c93a302014-09-28 22:35:57 -0500310}
311
Jon Perritte90aced2014-10-12 23:24:06 -0500312// GetOptsBuilder allows extensions to add additional parameters to the
313// Get request.
314type GetOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500315 ToObjectGetQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500316}
317
Jon Perritt8c93a302014-09-28 22:35:57 -0500318// GetOpts is a structure that holds parameters for getting an object's metadata.
319type GetOpts struct {
320 Expires string `q:"expires"`
321 Signature string `q:"signature"`
322}
323
Jon Perritt26780d52014-10-14 11:35:58 -0500324// ToObjectGetQuery formats a GetOpts into a query string.
325func (opts GetOpts) ToObjectGetQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500326 q, err := gophercloud.BuildQueryString(opts)
Jon Perrittfea90732016-03-15 02:57:05 -0500327 return q.String(), err
Jon Perritte90aced2014-10-12 23:24:06 -0500328}
329
Jon Perritt8c93a302014-09-28 22:35:57 -0500330// Get is a function that retrieves the metadata of an object. To extract just the custom
331// metadata, pass the GetResult response to the ExtractMetadata function.
Jon Perritt3860b512016-03-29 12:01:48 -0500332func Get(c *gophercloud.ServiceClient, containerName, objectName string, opts GetOptsBuilder) (r GetResult) {
Jon Perrittea4e3012014-10-09 22:03:19 -0500333 url := getURL(c, containerName, objectName)
Jon Perrittde47eac2014-09-30 15:34:17 -0500334 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500335 query, err := opts.ToObjectGetQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500336 if err != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500337 r.Err = err
Jon Perritt3860b512016-03-29 12:01:48 -0500338 return
Jon Perrittde47eac2014-09-30 15:34:17 -0500339 }
Jon Perritte90aced2014-10-12 23:24:06 -0500340 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500341 }
Jon Perritta33da232016-03-02 04:43:08 -0600342 resp, err := c.Request("HEAD", url, &gophercloud.RequestOpts{
Ash Wilson4bf41a32015-02-12 15:52:44 -0500343 OkCodes: []int{200, 204},
Jon Perritt8c93a302014-09-28 22:35:57 -0500344 })
Jon Perritta2c88b22015-05-18 11:23:30 -0600345 if resp != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500346 r.Header = resp.Header
Jon Perritta2c88b22015-05-18 11:23:30 -0600347 }
Jon Perrittfea90732016-03-15 02:57:05 -0500348 r.Err = err
jrperritt29ae6b32016-04-13 12:59:37 -0500349 return
Jon Perritt8c93a302014-09-28 22:35:57 -0500350}
351
Jon Perritte90aced2014-10-12 23:24:06 -0500352// UpdateOptsBuilder allows extensions to add additional parameters to the
353// Update request.
354type UpdateOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500355 ToObjectUpdateMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500356}
357
Jon Perritt8c93a302014-09-28 22:35:57 -0500358// UpdateOpts is a structure that holds parameters for updating, creating, or deleting an
359// object's metadata.
360type UpdateOpts struct {
361 Metadata map[string]string
362 ContentDisposition string `h:"Content-Disposition"`
363 ContentEncoding string `h:"Content-Encoding"`
364 ContentType string `h:"Content-Type"`
365 DeleteAfter int `h:"X-Delete-After"`
366 DeleteAt int `h:"X-Delete-At"`
367 DetectContentType bool `h:"X-Detect-Content-Type"`
368}
369
Jon Perritt04851d32014-10-14 02:07:13 -0500370// ToObjectUpdateMap formats a UpdateOpts into a map of headers.
371func (opts UpdateOpts) ToObjectUpdateMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500372 h, err := gophercloud.BuildHeaders(opts)
373 if err != nil {
374 return nil, err
375 }
376 for k, v := range opts.Metadata {
377 h["X-Object-Meta-"+k] = v
378 }
379 return h, nil
380}
381
Jon Perritt8c93a302014-09-28 22:35:57 -0500382// Update is a function that creates, updates, or deletes an object's metadata.
Jon Perritt3860b512016-03-29 12:01:48 -0500383func Update(c *gophercloud.ServiceClient, containerName, objectName string, opts UpdateOptsBuilder) (r UpdateResult) {
jrperritt0c9032f2016-05-23 15:01:15 -0500384 h := make(map[string]string)
Jon Perrittde47eac2014-09-30 15:34:17 -0500385 if opts != nil {
Jon Perritt04851d32014-10-14 02:07:13 -0500386 headers, err := opts.ToObjectUpdateMap()
Jon Perrittde47eac2014-09-30 15:34:17 -0500387 if err != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500388 r.Err = err
Jon Perritt3860b512016-03-29 12:01:48 -0500389 return
Jon Perrittde47eac2014-09-30 15:34:17 -0500390 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500391
Jon Perrittde47eac2014-09-30 15:34:17 -0500392 for k, v := range headers {
393 h[k] = v
394 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500395 }
Jon Perrittea4e3012014-10-09 22:03:19 -0500396 url := updateURL(c, containerName, objectName)
Jon Perrittfea90732016-03-15 02:57:05 -0500397 resp, err := c.Post(url, nil, nil, &gophercloud.RequestOpts{
Jon Perritt816d2a02014-03-11 20:49:46 -0500398 MoreHeaders: h,
Jon Perritt816d2a02014-03-11 20:49:46 -0500399 })
Jon Perritta2c88b22015-05-18 11:23:30 -0600400 if resp != nil {
Jon Perrittfea90732016-03-15 02:57:05 -0500401 r.Header = resp.Header
Jon Perritta2c88b22015-05-18 11:23:30 -0600402 }
Jon Perrittfea90732016-03-15 02:57:05 -0500403 r.Err = err
jrperritt29ae6b32016-04-13 12:59:37 -0500404 return
Jon Perritt816d2a02014-03-11 20:49:46 -0500405}
Jon Perritt90957602015-02-01 17:03:06 -0700406
407// HTTPMethod represents an HTTP method string (e.g. "GET").
408type HTTPMethod string
409
410var (
411 // GET represents an HTTP "GET" method.
412 GET HTTPMethod = "GET"
413 // POST represents an HTTP "POST" method.
414 POST HTTPMethod = "POST"
415)
416
417// CreateTempURLOpts are options for creating a temporary URL for an object.
418type CreateTempURLOpts struct {
Jon Perritt28792af2015-02-02 11:00:04 -0700419 // (REQUIRED) Method is the HTTP method to allow for users of the temp URL. Valid values
Jon Perritt90957602015-02-01 17:03:06 -0700420 // are "GET" and "POST".
421 Method HTTPMethod
Jon Perritt28792af2015-02-02 11:00:04 -0700422 // (REQUIRED) TTL is the number of seconds the temp URL should be active.
Jon Perritt90957602015-02-01 17:03:06 -0700423 TTL int
Jon Perritt28792af2015-02-02 11:00:04 -0700424 // (Optional) Split is the string on which to split the object URL. Since only
425 // the object path is used in the hash, the object URL needs to be parsed. If
426 // empty, the default OpenStack URL split point will be used ("/v1/").
427 Split string
Jon Perritt90957602015-02-01 17:03:06 -0700428}
429
430// CreateTempURL is a function for creating a temporary URL for an object. It
431// allows users to have "GET" or "POST" access to a particular tenant's object
432// for a limited amount of time.
433func CreateTempURL(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateTempURLOpts) (string, error) {
Jon Perritt28792af2015-02-02 11:00:04 -0700434 if opts.Split == "" {
435 opts.Split = "/v1/"
436 }
Jon Perritt90957602015-02-01 17:03:06 -0700437 duration := time.Duration(opts.TTL) * time.Second
438 expiry := time.Now().Add(duration).Unix()
439 getHeader, err := accounts.Get(c, nil).Extract()
440 if err != nil {
441 return "", err
442 }
443 secretKey := []byte(getHeader.TempURLKey)
444 url := getURL(c, containerName, objectName)
Jon Perritt28792af2015-02-02 11:00:04 -0700445 splitPath := strings.Split(url, opts.Split)
Jon Perritt90957602015-02-01 17:03:06 -0700446 baseURL, objectPath := splitPath[0], splitPath[1]
Jon Perritt28792af2015-02-02 11:00:04 -0700447 objectPath = opts.Split + objectPath
Jon Perritt90957602015-02-01 17:03:06 -0700448 body := fmt.Sprintf("%s\n%d\n%s", opts.Method, expiry, objectPath)
449 hash := hmac.New(sha1.New, secretKey)
450 hash.Write([]byte(body))
451 hexsum := fmt.Sprintf("%x", hash.Sum(nil))
452 return fmt.Sprintf("%s%s?temp_url_sig=%s&temp_url_expires=%d", baseURL, objectPath, hexsum, expiry), nil
453}