blob: d82aeb297a806fa58429c9cf4734a4484ac22c06 [file] [log] [blame]
Jon Perritt816d2a02014-03-11 20:49:46 -05001package objects
2
3import (
jrperritt05e31e62015-09-22 21:00:33 -06004 "bufio"
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"
jrperritt05e31e62015-09-22 21:00:33 -060010 "io/ioutil"
Jon Perritt90957602015-02-01 17:03:06 -070011 "strings"
Jon Perritt8c93a302014-09-28 22:35:57 -050012 "time"
Ash Wilson604320e2014-09-10 16:02:28 -040013
Jon Perritt27249f42016-02-18 10:35:59 -060014 "github.com/gophercloud/gophercloud"
15 "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/accounts"
16 "github.com/gophercloud/gophercloud/pagination"
Jon Perritt816d2a02014-03-11 20:49:46 -050017)
18
Jon Perritte90aced2014-10-12 23:24:06 -050019// ListOptsBuilder allows extensions to add additional parameters to the List
20// request.
21type ListOptsBuilder interface {
22 ToObjectListParams() (bool, string, error)
23}
24
Jon Perritt8c93a302014-09-28 22:35:57 -050025// ListOpts is a structure that holds parameters for listing objects.
26type ListOpts struct {
Jon Perritt9415ca72014-11-03 11:58:48 -060027 // Full is a true/false value that represents the amount of object information
28 // returned. If Full is set to true, then the content-type, number of bytes, hash
29 // date last modified, and name are returned. If set to false or not set, then
30 // only the object names are returned.
Jon Perritt8c93a302014-09-28 22:35:57 -050031 Full bool
Jon Perritt04851d32014-10-14 02:07:13 -050032 Limit int `q:"limit"`
33 Marker string `q:"marker"`
34 EndMarker string `q:"end_marker"`
35 Format string `q:"format"`
36 Prefix string `q:"prefix"`
37 Delimiter string `q:"delimiter"`
38 Path string `q:"path"`
Ash Wilsonca6f7562014-09-16 15:43:54 -040039}
40
Jon Perritte90aced2014-10-12 23:24:06 -050041// ToObjectListParams formats a ListOpts into a query string and boolean
42// representing whether to list complete information for each object.
43func (opts ListOpts) ToObjectListParams() (bool, string, error) {
44 q, err := gophercloud.BuildQueryString(opts)
45 if err != nil {
46 return false, "", err
47 }
48 return opts.Full, q.String(), nil
49}
50
Jon Perritt816d2a02014-03-11 20:49:46 -050051// List is a function that retrieves all objects in a container. It also returns the details
52// for the container. To extract only the object information or names, pass the ListResult
Jon Perritteb575642014-04-24 15:16:31 -050053// response to the ExtractInfo or ExtractNames function, respectively.
Jon Perritte90aced2014-10-12 23:24:06 -050054func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager {
55 headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"}
Jon Perritt816d2a02014-03-11 20:49:46 -050056
Jon Perrittea4e3012014-10-09 22:03:19 -050057 url := listURL(c, containerName)
Jon Perrittde47eac2014-09-30 15:34:17 -050058 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -050059 full, query, err := opts.ToObjectListParams()
Jon Perrittde47eac2014-09-30 15:34:17 -050060 if err != nil {
Jon Perrittde47eac2014-09-30 15:34:17 -050061 return pagination.Pager{Err: err}
62 }
Jon Perritte90aced2014-10-12 23:24:06 -050063 url += query
Jon Perritt816d2a02014-03-11 20:49:46 -050064
Jon Perritte90aced2014-10-12 23:24:06 -050065 if full {
66 headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"}
Jon Perrittde47eac2014-09-30 15:34:17 -050067 }
Ash Wilsonca6f7562014-09-16 15:43:54 -040068 }
69
Ash Wilsonb8b16f82014-10-20 10:19:49 -040070 createPage := func(r pagination.PageResult) pagination.Page {
71 p := ObjectPage{pagination.MarkerPageBase{PageResult: r}}
Ash Wilsonca6f7562014-09-16 15:43:54 -040072 p.MarkerPageBase.Owner = p
73 return p
Jon Perritt816d2a02014-03-11 20:49:46 -050074 }
75
Ash Wilsonca6f7562014-09-16 15:43:54 -040076 pager := pagination.NewPager(c, url, createPage)
77 pager.Headers = headers
78 return pager
Jon Perritt816d2a02014-03-11 20:49:46 -050079}
80
Jon Perritte90aced2014-10-12 23:24:06 -050081// DownloadOptsBuilder allows extensions to add additional parameters to the
82// Download request.
83type DownloadOptsBuilder interface {
84 ToObjectDownloadParams() (map[string]string, string, error)
85}
86
Jon Perritt8c93a302014-09-28 22:35:57 -050087// DownloadOpts is a structure that holds parameters for downloading an object.
88type DownloadOpts struct {
89 IfMatch string `h:"If-Match"`
90 IfModifiedSince time.Time `h:"If-Modified-Since"`
91 IfNoneMatch string `h:"If-None-Match"`
92 IfUnmodifiedSince time.Time `h:"If-Unmodified-Since"`
93 Range string `h:"Range"`
94 Expires string `q:"expires"`
95 MultipartManifest string `q:"multipart-manifest"`
96 Signature string `q:"signature"`
97}
98
Jon Perritte90aced2014-10-12 23:24:06 -050099// ToObjectDownloadParams formats a DownloadOpts into a query string and map of
100// headers.
Paul Querna7dc6fe62014-11-01 08:09:41 -0700101func (opts DownloadOpts) ToObjectDownloadParams() (map[string]string, string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500102 q, err := gophercloud.BuildQueryString(opts)
103 if err != nil {
104 return nil, "", err
105 }
106 h, err := gophercloud.BuildHeaders(opts)
107 if err != nil {
108 return nil, q.String(), err
109 }
110 return h, q.String(), nil
111}
112
Jon Perritt816d2a02014-03-11 20:49:46 -0500113// Download is a function that retrieves the content and metadata for an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500114// To extract just the content, pass the DownloadResult response to the
115// ExtractContent function.
116func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) DownloadResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500117 var res DownloadResult
Jon Perritt8c93a302014-09-28 22:35:57 -0500118
Jon Perrittea4e3012014-10-09 22:03:19 -0500119 url := downloadURL(c, containerName, objectName)
Ash Wilson77857dc2014-10-22 09:09:02 -0400120 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500121
Jon Perrittde47eac2014-09-30 15:34:17 -0500122 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500123 headers, query, err := opts.ToObjectDownloadParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500124 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500125 res.Err = err
126 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500127 }
128
129 for k, v := range headers {
130 h[k] = v
131 }
132
Jon Perritte90aced2014-10-12 23:24:06 -0500133 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500134 }
135
Jon Perritta33da232016-03-02 04:43:08 -0600136 resp, err := c.Request("GET", url, &gophercloud.RequestOpts{
Jon Perritt816d2a02014-03-11 20:49:46 -0500137 MoreHeaders: h,
Paul Querna9163df22014-11-01 09:38:51 -0700138 OkCodes: []int{200, 304},
Jon Perritt816d2a02014-03-11 20:49:46 -0500139 })
Jon Perritta2c88b22015-05-18 11:23:30 -0600140 if resp != nil {
141 res.Header = resp.Header
142 res.Body = resp.Body
143 }
Jon Perritt5db08922014-09-30 21:32:48 -0500144 res.Err = err
Jamie Hannaford2e784862014-10-27 10:40:27 +0100145
Jon Perritt5db08922014-09-30 21:32:48 -0500146 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500147}
148
Jon Perritte90aced2014-10-12 23:24:06 -0500149// CreateOptsBuilder allows extensions to add additional parameters to the
150// Create request.
151type CreateOptsBuilder interface {
152 ToObjectCreateParams() (map[string]string, string, error)
153}
154
Jon Perritt8c93a302014-09-28 22:35:57 -0500155// CreateOpts is a structure that holds parameters for creating an object.
156type CreateOpts struct {
157 Metadata map[string]string
158 ContentDisposition string `h:"Content-Disposition"`
159 ContentEncoding string `h:"Content-Encoding"`
Jon Perritte376fa52014-11-03 11:35:48 -0600160 ContentLength int64 `h:"Content-Length"`
Jon Perritt8c93a302014-09-28 22:35:57 -0500161 ContentType string `h:"Content-Type"`
162 CopyFrom string `h:"X-Copy-From"`
163 DeleteAfter int `h:"X-Delete-After"`
164 DeleteAt int `h:"X-Delete-At"`
165 DetectContentType string `h:"X-Detect-Content-Type"`
166 ETag string `h:"ETag"`
167 IfNoneMatch string `h:"If-None-Match"`
168 ObjectManifest string `h:"X-Object-Manifest"`
169 TransferEncoding string `h:"Transfer-Encoding"`
170 Expires string `q:"expires"`
jrperritt4fcd3b72015-09-23 11:17:23 -0600171 MultipartManifest string `q:"multipart-manifest"`
Jon Perritt8c93a302014-09-28 22:35:57 -0500172 Signature string `q:"signature"`
Jon Perritt816d2a02014-03-11 20:49:46 -0500173}
174
Jon Perritte90aced2014-10-12 23:24:06 -0500175// ToObjectCreateParams formats a CreateOpts into a query string and map of
176// headers.
177func (opts CreateOpts) ToObjectCreateParams() (map[string]string, string, error) {
178 q, err := gophercloud.BuildQueryString(opts)
179 if err != nil {
180 return nil, "", err
181 }
182 h, err := gophercloud.BuildHeaders(opts)
183 if err != nil {
184 return nil, q.String(), err
185 }
186
187 for k, v := range opts.Metadata {
188 h["X-Object-Meta-"+k] = v
189 }
190
191 return h, q.String(), nil
192}
193
Jamie Hannaford50fc97d2015-07-16 12:29:01 +0200194// Create is a function that creates a new object or replaces an existing object. If the returned response's ETag
195// header fails to match the local checksum, the failed request will automatically be retried up to a maximum of 3 times.
Brendan ODonnella69b3472015-04-27 13:59:41 -0500196func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.ReadSeeker, opts CreateOptsBuilder) CreateResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500197 var res CreateResult
Jon Perritt816d2a02014-03-11 20:49:46 -0500198
Jon Perrittea4e3012014-10-09 22:03:19 -0500199 url := createURL(c, containerName, objectName)
Ash Wilson322a7e62015-02-12 16:25:26 -0500200 h := make(map[string]string)
Jon Perritt816d2a02014-03-11 20:49:46 -0500201
Jon Perrittde47eac2014-09-30 15:34:17 -0500202 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500203 headers, query, err := opts.ToObjectCreateParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500204 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500205 res.Err = err
206 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500207 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500208
Jon Perrittde47eac2014-09-30 15:34:17 -0500209 for k, v := range headers {
210 h[k] = v
211 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500212
Jon Perritte90aced2014-10-12 23:24:06 -0500213 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500214 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500215
Jamie Hannaford08096232015-07-13 12:47:28 +0200216 hash := md5.New()
jrperritt05e31e62015-09-22 21:00:33 -0600217 bufioReader := bufio.NewReader(io.TeeReader(content, hash))
218 io.Copy(ioutil.Discard, bufioReader)
219 localChecksum := hash.Sum(nil)
Jamie Hannaford08096232015-07-13 12:47:28 +0200220
jrperritt05e31e62015-09-22 21:00:33 -0600221 h["ETag"] = fmt.Sprintf("%x", localChecksum)
222
223 _, err := content.Seek(0, 0)
jrperritte6e8c652015-07-30 12:17:01 -0600224 if err != nil {
225 res.Err = err
226 return res
227 }
228
Jon Perritta33da232016-03-02 04:43:08 -0600229 ropts := &gophercloud.RequestOpts{
jrperritt05e31e62015-09-22 21:00:33 -0600230 RawBody: content,
jrperritt56d51e92015-07-30 11:50:53 -0600231 MoreHeaders: h,
232 }
233
jrperritt433cc792015-07-31 18:53:12 -0600234 resp, err := c.Request("PUT", url, ropts)
235 if err != nil {
236 res.Err = err
237 return res
238 }
239 if resp != nil {
240 res.Header = resp.Header
241 if resp.Header.Get("ETag") == fmt.Sprintf("%x", localChecksum) {
242 res.Err = err
Jamie Hannaford08096232015-07-13 12:47:28 +0200243 return res
244 }
Jon Perritt852278c2016-03-09 00:13:34 -0600245 err := ErrWrongChecksum{}
246 err.Function = "objects.Create"
247 res.Err = err
248
Jamie Hannaford08096232015-07-13 12:47:28 +0200249 }
250
Jon Perritt5db08922014-09-30 21:32:48 -0500251 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500252}
253
Jon Perritte90aced2014-10-12 23:24:06 -0500254// CopyOptsBuilder allows extensions to add additional parameters to the
255// Copy request.
256type CopyOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500257 ToObjectCopyMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500258}
259
260// CopyOpts is a structure that holds parameters for copying one object to
261// another.
Jon Perritt8c93a302014-09-28 22:35:57 -0500262type CopyOpts struct {
263 Metadata map[string]string
264 ContentDisposition string `h:"Content-Disposition"`
265 ContentEncoding string `h:"Content-Encoding"`
266 ContentType string `h:"Content-Type"`
267 Destination string `h:"Destination,required"`
268}
269
Jon Perritt04851d32014-10-14 02:07:13 -0500270// ToObjectCopyMap formats a CopyOpts into a map of headers.
271func (opts CopyOpts) ToObjectCopyMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500272 if opts.Destination == "" {
Jon Perritt852278c2016-03-09 00:13:34 -0600273 err := gophercloud.ErrMissingInput{}
274 err.Function = "objects.ToObjectCopyMap"
275 err.Argument = "objects.CopyOpts.Destination"
276 return nil, err
Jon Perritte90aced2014-10-12 23:24:06 -0500277 }
278 h, err := gophercloud.BuildHeaders(opts)
279 if err != nil {
280 return nil, err
281 }
282 for k, v := range opts.Metadata {
283 h["X-Object-Meta-"+k] = v
284 }
285 return h, nil
286}
287
Jon Perritt816d2a02014-03-11 20:49:46 -0500288// Copy is a function that copies one object to another.
Jon Perritte90aced2014-10-12 23:24:06 -0500289func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) CopyResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500290 var res CopyResult
Ash Wilson77857dc2014-10-22 09:09:02 -0400291 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500292
Jon Perritt04851d32014-10-14 02:07:13 -0500293 headers, err := opts.ToObjectCopyMap()
Jon Perritt8c93a302014-09-28 22:35:57 -0500294 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500295 res.Err = err
296 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500297 }
Jon Perritte90aced2014-10-12 23:24:06 -0500298
Jon Perritt8c93a302014-09-28 22:35:57 -0500299 for k, v := range headers {
Jon Perritt816d2a02014-03-11 20:49:46 -0500300 h[k] = v
301 }
302
Jon Perrittea4e3012014-10-09 22:03:19 -0500303 url := copyURL(c, containerName, objectName)
Jon Perritta33da232016-03-02 04:43:08 -0600304 resp, err := c.Request("COPY", url, &gophercloud.RequestOpts{
Jon Perritt8c93a302014-09-28 22:35:57 -0500305 MoreHeaders: h,
306 OkCodes: []int{201},
307 })
Jon Perritta2c88b22015-05-18 11:23:30 -0600308 if resp != nil {
309 res.Header = resp.Header
310 }
jrperrittf7a8e282014-10-28 10:00:48 -0500311 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500312 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500313}
314
Jon Perritte90aced2014-10-12 23:24:06 -0500315// DeleteOptsBuilder allows extensions to add additional parameters to the
316// Delete request.
317type DeleteOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500318 ToObjectDeleteQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500319}
320
Jon Perritt8c93a302014-09-28 22:35:57 -0500321// DeleteOpts is a structure that holds parameters for deleting an object.
322type DeleteOpts struct {
323 MultipartManifest string `q:"multipart-manifest"`
324}
325
Jon Perritt26780d52014-10-14 11:35:58 -0500326// ToObjectDeleteQuery formats a DeleteOpts into a query string.
327func (opts DeleteOpts) ToObjectDeleteQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500328 q, err := gophercloud.BuildQueryString(opts)
329 if err != nil {
330 return "", err
331 }
332 return q.String(), nil
333}
334
Jon Perritt8c93a302014-09-28 22:35:57 -0500335// Delete is a function that deletes an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500336func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) DeleteResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500337 var res DeleteResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500338 url := deleteURL(c, containerName, objectName)
Jon Perritt8c93a302014-09-28 22:35:57 -0500339
Jon Perrittde47eac2014-09-30 15:34:17 -0500340 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500341 query, err := opts.ToObjectDeleteQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500342 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500343 res.Err = err
344 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500345 }
Jon Perritte90aced2014-10-12 23:24:06 -0500346 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500347 }
348
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100349 resp, err := c.Delete(url, nil)
Jon Perritta2c88b22015-05-18 11:23:30 -0600350 if resp != nil {
351 res.Header = resp.Header
352 }
Jon Perritt10a7ec12014-10-27 11:29:33 -0500353 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500354 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500355}
356
Jon Perritte90aced2014-10-12 23:24:06 -0500357// GetOptsBuilder allows extensions to add additional parameters to the
358// Get request.
359type GetOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500360 ToObjectGetQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500361}
362
Jon Perritt8c93a302014-09-28 22:35:57 -0500363// GetOpts is a structure that holds parameters for getting an object's metadata.
364type GetOpts struct {
365 Expires string `q:"expires"`
366 Signature string `q:"signature"`
367}
368
Jon Perritt26780d52014-10-14 11:35:58 -0500369// ToObjectGetQuery formats a GetOpts into a query string.
370func (opts GetOpts) ToObjectGetQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500371 q, err := gophercloud.BuildQueryString(opts)
372 if err != nil {
373 return "", err
374 }
375 return q.String(), nil
376}
377
Jon Perritt8c93a302014-09-28 22:35:57 -0500378// Get is a function that retrieves the metadata of an object. To extract just the custom
379// metadata, pass the GetResult response to the ExtractMetadata function.
Jon Perritte90aced2014-10-12 23:24:06 -0500380func Get(c *gophercloud.ServiceClient, containerName, objectName string, opts GetOptsBuilder) GetResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500381 var res GetResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500382 url := getURL(c, containerName, objectName)
Jon Perrittde47eac2014-09-30 15:34:17 -0500383
384 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500385 query, err := opts.ToObjectGetQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500386 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500387 res.Err = err
388 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500389 }
Jon Perritte90aced2014-10-12 23:24:06 -0500390 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500391 }
392
Jon Perritta33da232016-03-02 04:43:08 -0600393 resp, err := c.Request("HEAD", url, &gophercloud.RequestOpts{
Ash Wilson4bf41a32015-02-12 15:52:44 -0500394 OkCodes: []int{200, 204},
Jon Perritt8c93a302014-09-28 22:35:57 -0500395 })
Jon Perritta2c88b22015-05-18 11:23:30 -0600396 if resp != nil {
397 res.Header = resp.Header
398 }
Jon Perritt5db08922014-09-30 21:32:48 -0500399 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500400 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500401}
402
Jon Perritte90aced2014-10-12 23:24:06 -0500403// UpdateOptsBuilder allows extensions to add additional parameters to the
404// Update request.
405type UpdateOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500406 ToObjectUpdateMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500407}
408
Jon Perritt8c93a302014-09-28 22:35:57 -0500409// UpdateOpts is a structure that holds parameters for updating, creating, or deleting an
410// object's metadata.
411type UpdateOpts struct {
412 Metadata map[string]string
413 ContentDisposition string `h:"Content-Disposition"`
414 ContentEncoding string `h:"Content-Encoding"`
415 ContentType string `h:"Content-Type"`
416 DeleteAfter int `h:"X-Delete-After"`
417 DeleteAt int `h:"X-Delete-At"`
418 DetectContentType bool `h:"X-Detect-Content-Type"`
419}
420
Jon Perritt04851d32014-10-14 02:07:13 -0500421// ToObjectUpdateMap formats a UpdateOpts into a map of headers.
422func (opts UpdateOpts) ToObjectUpdateMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500423 h, err := gophercloud.BuildHeaders(opts)
424 if err != nil {
425 return nil, err
426 }
427 for k, v := range opts.Metadata {
428 h["X-Object-Meta-"+k] = v
429 }
430 return h, nil
431}
432
Jon Perritt8c93a302014-09-28 22:35:57 -0500433// Update is a function that creates, updates, or deletes an object's metadata.
Jon Perritte90aced2014-10-12 23:24:06 -0500434func Update(c *gophercloud.ServiceClient, containerName, objectName string, opts UpdateOptsBuilder) UpdateResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500435 var res UpdateResult
Ash Wilson77857dc2014-10-22 09:09:02 -0400436 h := c.AuthenticatedHeaders()
Jon Perritt8c93a302014-09-28 22:35:57 -0500437
Jon Perrittde47eac2014-09-30 15:34:17 -0500438 if opts != nil {
Jon Perritt04851d32014-10-14 02:07:13 -0500439 headers, err := opts.ToObjectUpdateMap()
Jon Perrittde47eac2014-09-30 15:34:17 -0500440 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500441 res.Err = err
442 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500443 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500444
Jon Perrittde47eac2014-09-30 15:34:17 -0500445 for k, v := range headers {
446 h[k] = v
447 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500448 }
449
Jon Perrittea4e3012014-10-09 22:03:19 -0500450 url := updateURL(c, containerName, objectName)
Jon Perritta33da232016-03-02 04:43:08 -0600451 resp, err := c.Request("POST", url, &gophercloud.RequestOpts{
Jon Perritt816d2a02014-03-11 20:49:46 -0500452 MoreHeaders: h,
Jon Perritt816d2a02014-03-11 20:49:46 -0500453 })
Jon Perritta2c88b22015-05-18 11:23:30 -0600454 if resp != nil {
455 res.Header = resp.Header
456 }
Jon Perritt5db08922014-09-30 21:32:48 -0500457 res.Err = err
458 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500459}
Jon Perritt90957602015-02-01 17:03:06 -0700460
461// HTTPMethod represents an HTTP method string (e.g. "GET").
462type HTTPMethod string
463
464var (
465 // GET represents an HTTP "GET" method.
466 GET HTTPMethod = "GET"
467 // POST represents an HTTP "POST" method.
468 POST HTTPMethod = "POST"
469)
470
471// CreateTempURLOpts are options for creating a temporary URL for an object.
472type CreateTempURLOpts struct {
Jon Perritt28792af2015-02-02 11:00:04 -0700473 // (REQUIRED) Method is the HTTP method to allow for users of the temp URL. Valid values
Jon Perritt90957602015-02-01 17:03:06 -0700474 // are "GET" and "POST".
475 Method HTTPMethod
Jon Perritt28792af2015-02-02 11:00:04 -0700476 // (REQUIRED) TTL is the number of seconds the temp URL should be active.
Jon Perritt90957602015-02-01 17:03:06 -0700477 TTL int
Jon Perritt28792af2015-02-02 11:00:04 -0700478 // (Optional) Split is the string on which to split the object URL. Since only
479 // the object path is used in the hash, the object URL needs to be parsed. If
480 // empty, the default OpenStack URL split point will be used ("/v1/").
481 Split string
Jon Perritt90957602015-02-01 17:03:06 -0700482}
483
484// CreateTempURL is a function for creating a temporary URL for an object. It
485// allows users to have "GET" or "POST" access to a particular tenant's object
486// for a limited amount of time.
487func CreateTempURL(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateTempURLOpts) (string, error) {
Jon Perritt28792af2015-02-02 11:00:04 -0700488 if opts.Split == "" {
489 opts.Split = "/v1/"
490 }
Jon Perritt90957602015-02-01 17:03:06 -0700491 duration := time.Duration(opts.TTL) * time.Second
492 expiry := time.Now().Add(duration).Unix()
493 getHeader, err := accounts.Get(c, nil).Extract()
494 if err != nil {
495 return "", err
496 }
497 secretKey := []byte(getHeader.TempURLKey)
498 url := getURL(c, containerName, objectName)
Jon Perritt28792af2015-02-02 11:00:04 -0700499 splitPath := strings.Split(url, opts.Split)
Jon Perritt90957602015-02-01 17:03:06 -0700500 baseURL, objectPath := splitPath[0], splitPath[1]
Jon Perritt28792af2015-02-02 11:00:04 -0700501 objectPath = opts.Split + objectPath
Jon Perritt90957602015-02-01 17:03:06 -0700502 body := fmt.Sprintf("%s\n%d\n%s", opts.Method, expiry, objectPath)
503 hash := hmac.New(sha1.New, secretKey)
504 hash.Write([]byte(body))
505 hexsum := fmt.Sprintf("%x", hash.Sum(nil))
506 return fmt.Sprintf("%s%s?temp_url_sig=%s&temp_url_expires=%d", baseURL, objectPath, hexsum, expiry), nil
507}