blob: 7acff1109b876e26e2ea8cca7a8669c1b1e67c59 [file] [log] [blame]
Jon Perritt816d2a02014-03-11 20:49:46 -05001package objects
2
3import (
Jon Perritt90957602015-02-01 17:03:06 -07004 "crypto/hmac"
5 "crypto/sha1"
Jon Perritt816d2a02014-03-11 20:49:46 -05006 "fmt"
Jon Perritt8c93a302014-09-28 22:35:57 -05007 "io"
Jon Perritt90957602015-02-01 17:03:06 -07008 "strings"
Jon Perritt8c93a302014-09-28 22:35:57 -05009 "time"
Ash Wilson604320e2014-09-10 16:02:28 -040010
11 "github.com/racker/perigee"
12 "github.com/rackspace/gophercloud"
Jon Perritt90957602015-02-01 17:03:06 -070013 "github.com/rackspace/gophercloud/openstack/objectstorage/v1/accounts"
Ash Wilsonca6f7562014-09-16 15:43:54 -040014 "github.com/rackspace/gophercloud/pagination"
Jon Perritt816d2a02014-03-11 20:49:46 -050015)
16
Jon Perritte90aced2014-10-12 23:24:06 -050017// ListOptsBuilder allows extensions to add additional parameters to the List
18// request.
19type ListOptsBuilder interface {
20 ToObjectListParams() (bool, string, error)
21}
22
Jon Perritt8c93a302014-09-28 22:35:57 -050023// ListOpts is a structure that holds parameters for listing objects.
24type ListOpts struct {
Jon Perritt9415ca72014-11-03 11:58:48 -060025 // Full is a true/false value that represents the amount of object information
26 // returned. If Full is set to true, then the content-type, number of bytes, hash
27 // date last modified, and name are returned. If set to false or not set, then
28 // only the object names are returned.
Jon Perritt8c93a302014-09-28 22:35:57 -050029 Full bool
Jon Perritt04851d32014-10-14 02:07:13 -050030 Limit int `q:"limit"`
31 Marker string `q:"marker"`
32 EndMarker string `q:"end_marker"`
33 Format string `q:"format"`
34 Prefix string `q:"prefix"`
35 Delimiter string `q:"delimiter"`
36 Path string `q:"path"`
Ash Wilsonca6f7562014-09-16 15:43:54 -040037}
38
Jon Perritte90aced2014-10-12 23:24:06 -050039// ToObjectListParams formats a ListOpts into a query string and boolean
40// representing whether to list complete information for each object.
41func (opts ListOpts) ToObjectListParams() (bool, string, error) {
42 q, err := gophercloud.BuildQueryString(opts)
43 if err != nil {
44 return false, "", err
45 }
46 return opts.Full, q.String(), nil
47}
48
Jon Perritt816d2a02014-03-11 20:49:46 -050049// List is a function that retrieves all objects in a container. It also returns the details
50// for the container. To extract only the object information or names, pass the ListResult
Jon Perritteb575642014-04-24 15:16:31 -050051// response to the ExtractInfo or ExtractNames function, respectively.
Jon Perritte90aced2014-10-12 23:24:06 -050052func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager {
53 headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"}
Jon Perritt816d2a02014-03-11 20:49:46 -050054
Jon Perrittea4e3012014-10-09 22:03:19 -050055 url := listURL(c, containerName)
Jon Perrittde47eac2014-09-30 15:34:17 -050056 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -050057 full, query, err := opts.ToObjectListParams()
Jon Perrittde47eac2014-09-30 15:34:17 -050058 if err != nil {
Jon Perrittde47eac2014-09-30 15:34:17 -050059 return pagination.Pager{Err: err}
60 }
Jon Perritte90aced2014-10-12 23:24:06 -050061 url += query
Jon Perritt816d2a02014-03-11 20:49:46 -050062
Jon Perritte90aced2014-10-12 23:24:06 -050063 if full {
64 headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"}
Jon Perrittde47eac2014-09-30 15:34:17 -050065 }
Ash Wilsonca6f7562014-09-16 15:43:54 -040066 }
67
Ash Wilsonb8b16f82014-10-20 10:19:49 -040068 createPage := func(r pagination.PageResult) pagination.Page {
69 p := ObjectPage{pagination.MarkerPageBase{PageResult: r}}
Ash Wilsonca6f7562014-09-16 15:43:54 -040070 p.MarkerPageBase.Owner = p
71 return p
Jon Perritt816d2a02014-03-11 20:49:46 -050072 }
73
Ash Wilsonca6f7562014-09-16 15:43:54 -040074 pager := pagination.NewPager(c, url, createPage)
75 pager.Headers = headers
76 return pager
Jon Perritt816d2a02014-03-11 20:49:46 -050077}
78
Jon Perritte90aced2014-10-12 23:24:06 -050079// DownloadOptsBuilder allows extensions to add additional parameters to the
80// Download request.
81type DownloadOptsBuilder interface {
82 ToObjectDownloadParams() (map[string]string, string, error)
83}
84
Jon Perritt8c93a302014-09-28 22:35:57 -050085// DownloadOpts is a structure that holds parameters for downloading an object.
86type DownloadOpts struct {
87 IfMatch string `h:"If-Match"`
88 IfModifiedSince time.Time `h:"If-Modified-Since"`
89 IfNoneMatch string `h:"If-None-Match"`
90 IfUnmodifiedSince time.Time `h:"If-Unmodified-Since"`
91 Range string `h:"Range"`
92 Expires string `q:"expires"`
93 MultipartManifest string `q:"multipart-manifest"`
94 Signature string `q:"signature"`
95}
96
Jon Perritte90aced2014-10-12 23:24:06 -050097// ToObjectDownloadParams formats a DownloadOpts into a query string and map of
98// headers.
Paul Querna7dc6fe62014-11-01 08:09:41 -070099func (opts DownloadOpts) ToObjectDownloadParams() (map[string]string, string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500100 q, err := gophercloud.BuildQueryString(opts)
101 if err != nil {
102 return nil, "", err
103 }
104 h, err := gophercloud.BuildHeaders(opts)
105 if err != nil {
106 return nil, q.String(), err
107 }
108 return h, q.String(), nil
109}
110
Jon Perritt816d2a02014-03-11 20:49:46 -0500111// Download is a function that retrieves the content and metadata for an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500112// To extract just the content, pass the DownloadResult response to the
113// ExtractContent function.
114func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) DownloadResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500115 var res DownloadResult
Jon Perritt8c93a302014-09-28 22:35:57 -0500116
Jon Perrittea4e3012014-10-09 22:03:19 -0500117 url := downloadURL(c, containerName, objectName)
Ash Wilson77857dc2014-10-22 09:09:02 -0400118 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500119
Jon Perrittde47eac2014-09-30 15:34:17 -0500120 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500121 headers, query, err := opts.ToObjectDownloadParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500122 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500123 res.Err = err
124 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500125 }
126
127 for k, v := range headers {
128 h[k] = v
129 }
130
Jon Perritte90aced2014-10-12 23:24:06 -0500131 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500132 }
133
Jon Perritt816d2a02014-03-11 20:49:46 -0500134 resp, err := perigee.Request("GET", url, perigee.Options{
Jon Perritt816d2a02014-03-11 20:49:46 -0500135 MoreHeaders: h,
Paul Querna9163df22014-11-01 09:38:51 -0700136 OkCodes: []int{200, 304},
Jon Perritt816d2a02014-03-11 20:49:46 -0500137 })
Jamie Hannaford2e784862014-10-27 10:40:27 +0100138
139 res.Body = resp.HttpResponse.Body
Jon Perritt5db08922014-09-30 21:32:48 -0500140 res.Err = err
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400141 res.Header = resp.HttpResponse.Header
Jamie Hannaford2e784862014-10-27 10:40:27 +0100142
Jon Perritt5db08922014-09-30 21:32:48 -0500143 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500144}
145
Jon Perritte90aced2014-10-12 23:24:06 -0500146// CreateOptsBuilder allows extensions to add additional parameters to the
147// Create request.
148type CreateOptsBuilder interface {
149 ToObjectCreateParams() (map[string]string, string, error)
150}
151
Jon Perritt8c93a302014-09-28 22:35:57 -0500152// CreateOpts is a structure that holds parameters for creating an object.
153type CreateOpts struct {
154 Metadata map[string]string
155 ContentDisposition string `h:"Content-Disposition"`
156 ContentEncoding string `h:"Content-Encoding"`
Jon Perritte376fa52014-11-03 11:35:48 -0600157 ContentLength int64 `h:"Content-Length"`
Jon Perritt8c93a302014-09-28 22:35:57 -0500158 ContentType string `h:"Content-Type"`
159 CopyFrom string `h:"X-Copy-From"`
160 DeleteAfter int `h:"X-Delete-After"`
161 DeleteAt int `h:"X-Delete-At"`
162 DetectContentType string `h:"X-Detect-Content-Type"`
163 ETag string `h:"ETag"`
164 IfNoneMatch string `h:"If-None-Match"`
165 ObjectManifest string `h:"X-Object-Manifest"`
166 TransferEncoding string `h:"Transfer-Encoding"`
167 Expires string `q:"expires"`
168 MultipartManifest string `q:"multiple-manifest"`
169 Signature string `q:"signature"`
Jon Perritt816d2a02014-03-11 20:49:46 -0500170}
171
Jon Perritte90aced2014-10-12 23:24:06 -0500172// ToObjectCreateParams formats a CreateOpts into a query string and map of
173// headers.
174func (opts CreateOpts) ToObjectCreateParams() (map[string]string, string, error) {
175 q, err := gophercloud.BuildQueryString(opts)
176 if err != nil {
177 return nil, "", err
178 }
179 h, err := gophercloud.BuildHeaders(opts)
180 if err != nil {
181 return nil, q.String(), err
182 }
183
184 for k, v := range opts.Metadata {
185 h["X-Object-Meta-"+k] = v
186 }
187
188 return h, q.String(), nil
189}
190
Jon Perritt816d2a02014-03-11 20:49:46 -0500191// Create is a function that creates a new object or replaces an existing object.
Jon Perritte90aced2014-10-12 23:24:06 -0500192func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.Reader, opts CreateOptsBuilder) CreateResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500193 var res CreateResult
Jon Perritt816d2a02014-03-11 20:49:46 -0500194
Jon Perrittea4e3012014-10-09 22:03:19 -0500195 url := createURL(c, containerName, objectName)
Ash Wilson77857dc2014-10-22 09:09:02 -0400196 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500197
Jon Perrittde47eac2014-09-30 15:34:17 -0500198 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500199 headers, query, err := opts.ToObjectCreateParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500200 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500201 res.Err = err
202 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500203 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500204
Jon Perrittde47eac2014-09-30 15:34:17 -0500205 for k, v := range headers {
206 h[k] = v
207 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500208
Jon Perritte90aced2014-10-12 23:24:06 -0500209 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500210 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500211
Ash Wilson45e34342015-01-23 14:25:34 -0500212 popts := perigee.Options{
Jon Perritta77ba0d2014-10-17 01:15:29 -0500213 ReqBody: content,
Jon Perritt816d2a02014-03-11 20:49:46 -0500214 MoreHeaders: h,
Jon Perritta77ba0d2014-10-17 01:15:29 -0500215 OkCodes: []int{201, 202},
Ash Wilson45e34342015-01-23 14:25:34 -0500216 }
217
218 if contentType, explicit := h["Content-Type"]; explicit {
219 popts.ContentType = contentType
220 delete(h, "Content-Type")
221 } else {
222 popts.OmitContentType = true
223 }
224
225 resp, err := perigee.Request("PUT", url, popts)
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400226 res.Header = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500227 res.Err = err
228 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500229}
230
Jon Perritte90aced2014-10-12 23:24:06 -0500231// CopyOptsBuilder allows extensions to add additional parameters to the
232// Copy request.
233type CopyOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500234 ToObjectCopyMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500235}
236
237// CopyOpts is a structure that holds parameters for copying one object to
238// another.
Jon Perritt8c93a302014-09-28 22:35:57 -0500239type CopyOpts struct {
240 Metadata map[string]string
241 ContentDisposition string `h:"Content-Disposition"`
242 ContentEncoding string `h:"Content-Encoding"`
243 ContentType string `h:"Content-Type"`
244 Destination string `h:"Destination,required"`
245}
246
Jon Perritt04851d32014-10-14 02:07:13 -0500247// ToObjectCopyMap formats a CopyOpts into a map of headers.
248func (opts CopyOpts) ToObjectCopyMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500249 if opts.Destination == "" {
250 return nil, fmt.Errorf("Required CopyOpts field 'Destination' not set.")
251 }
252 h, err := gophercloud.BuildHeaders(opts)
253 if err != nil {
254 return nil, err
255 }
256 for k, v := range opts.Metadata {
257 h["X-Object-Meta-"+k] = v
258 }
259 return h, nil
260}
261
Jon Perritt816d2a02014-03-11 20:49:46 -0500262// Copy is a function that copies one object to another.
Jon Perritte90aced2014-10-12 23:24:06 -0500263func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) CopyResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500264 var res CopyResult
Ash Wilson77857dc2014-10-22 09:09:02 -0400265 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500266
Jon Perritt04851d32014-10-14 02:07:13 -0500267 headers, err := opts.ToObjectCopyMap()
Jon Perritt8c93a302014-09-28 22:35:57 -0500268 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500269 res.Err = err
270 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500271 }
Jon Perritte90aced2014-10-12 23:24:06 -0500272
Jon Perritt8c93a302014-09-28 22:35:57 -0500273 for k, v := range headers {
Jon Perritt816d2a02014-03-11 20:49:46 -0500274 h[k] = v
275 }
276
Jon Perrittea4e3012014-10-09 22:03:19 -0500277 url := copyURL(c, containerName, objectName)
Jon Perritt5db08922014-09-30 21:32:48 -0500278 resp, err := perigee.Request("COPY", url, perigee.Options{
Jon Perritt8c93a302014-09-28 22:35:57 -0500279 MoreHeaders: h,
280 OkCodes: []int{201},
281 })
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400282 res.Header = resp.HttpResponse.Header
jrperrittf7a8e282014-10-28 10:00:48 -0500283 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500284 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500285}
286
Jon Perritte90aced2014-10-12 23:24:06 -0500287// DeleteOptsBuilder allows extensions to add additional parameters to the
288// Delete request.
289type DeleteOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500290 ToObjectDeleteQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500291}
292
Jon Perritt8c93a302014-09-28 22:35:57 -0500293// DeleteOpts is a structure that holds parameters for deleting an object.
294type DeleteOpts struct {
295 MultipartManifest string `q:"multipart-manifest"`
296}
297
Jon Perritt26780d52014-10-14 11:35:58 -0500298// ToObjectDeleteQuery formats a DeleteOpts into a query string.
299func (opts DeleteOpts) ToObjectDeleteQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500300 q, err := gophercloud.BuildQueryString(opts)
301 if err != nil {
302 return "", err
303 }
304 return q.String(), nil
305}
306
Jon Perritt8c93a302014-09-28 22:35:57 -0500307// Delete is a function that deletes an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500308func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) DeleteResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500309 var res DeleteResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500310 url := deleteURL(c, containerName, objectName)
Jon Perritt8c93a302014-09-28 22:35:57 -0500311
Jon Perrittde47eac2014-09-30 15:34:17 -0500312 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500313 query, err := opts.ToObjectDeleteQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500314 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500315 res.Err = err
316 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500317 }
Jon Perritte90aced2014-10-12 23:24:06 -0500318 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500319 }
320
Jon Perritt10a7ec12014-10-27 11:29:33 -0500321 resp, err := perigee.Request("DELETE", url, perigee.Options{
Ash Wilson77857dc2014-10-22 09:09:02 -0400322 MoreHeaders: c.AuthenticatedHeaders(),
Jon Perritt8c93a302014-09-28 22:35:57 -0500323 OkCodes: []int{204},
324 })
Jon Perritt10a7ec12014-10-27 11:29:33 -0500325 res.Header = resp.HttpResponse.Header
326 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500327 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500328}
329
Jon Perritte90aced2014-10-12 23:24:06 -0500330// GetOptsBuilder allows extensions to add additional parameters to the
331// Get request.
332type GetOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500333 ToObjectGetQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500334}
335
Jon Perritt8c93a302014-09-28 22:35:57 -0500336// GetOpts is a structure that holds parameters for getting an object's metadata.
337type GetOpts struct {
338 Expires string `q:"expires"`
339 Signature string `q:"signature"`
340}
341
Jon Perritt26780d52014-10-14 11:35:58 -0500342// ToObjectGetQuery formats a GetOpts into a query string.
343func (opts GetOpts) ToObjectGetQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500344 q, err := gophercloud.BuildQueryString(opts)
345 if err != nil {
346 return "", err
347 }
348 return q.String(), nil
349}
350
Jon Perritt8c93a302014-09-28 22:35:57 -0500351// Get is a function that retrieves the metadata of an object. To extract just the custom
352// metadata, pass the GetResult response to the ExtractMetadata function.
Jon Perritte90aced2014-10-12 23:24:06 -0500353func Get(c *gophercloud.ServiceClient, containerName, objectName string, opts GetOptsBuilder) GetResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500354 var res GetResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500355 url := getURL(c, containerName, objectName)
Jon Perrittde47eac2014-09-30 15:34:17 -0500356
357 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500358 query, err := opts.ToObjectGetQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500359 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500360 res.Err = err
361 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500362 }
Jon Perritte90aced2014-10-12 23:24:06 -0500363 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500364 }
365
Jon Perritt8c93a302014-09-28 22:35:57 -0500366 resp, err := perigee.Request("HEAD", url, perigee.Options{
Ash Wilson77857dc2014-10-22 09:09:02 -0400367 MoreHeaders: c.AuthenticatedHeaders(),
Jon Perritt8c93a302014-09-28 22:35:57 -0500368 OkCodes: []int{200, 204},
369 })
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400370 res.Header = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500371 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500372 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500373}
374
Jon Perritte90aced2014-10-12 23:24:06 -0500375// UpdateOptsBuilder allows extensions to add additional parameters to the
376// Update request.
377type UpdateOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500378 ToObjectUpdateMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500379}
380
Jon Perritt8c93a302014-09-28 22:35:57 -0500381// UpdateOpts is a structure that holds parameters for updating, creating, or deleting an
382// object's metadata.
383type UpdateOpts struct {
384 Metadata map[string]string
385 ContentDisposition string `h:"Content-Disposition"`
386 ContentEncoding string `h:"Content-Encoding"`
387 ContentType string `h:"Content-Type"`
388 DeleteAfter int `h:"X-Delete-After"`
389 DeleteAt int `h:"X-Delete-At"`
390 DetectContentType bool `h:"X-Detect-Content-Type"`
391}
392
Jon Perritt04851d32014-10-14 02:07:13 -0500393// ToObjectUpdateMap formats a UpdateOpts into a map of headers.
394func (opts UpdateOpts) ToObjectUpdateMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500395 h, err := gophercloud.BuildHeaders(opts)
396 if err != nil {
397 return nil, err
398 }
399 for k, v := range opts.Metadata {
400 h["X-Object-Meta-"+k] = v
401 }
402 return h, nil
403}
404
Jon Perritt8c93a302014-09-28 22:35:57 -0500405// Update is a function that creates, updates, or deletes an object's metadata.
Jon Perritte90aced2014-10-12 23:24:06 -0500406func Update(c *gophercloud.ServiceClient, containerName, objectName string, opts UpdateOptsBuilder) UpdateResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500407 var res UpdateResult
Ash Wilson77857dc2014-10-22 09:09:02 -0400408 h := c.AuthenticatedHeaders()
Jon Perritt8c93a302014-09-28 22:35:57 -0500409
Jon Perrittde47eac2014-09-30 15:34:17 -0500410 if opts != nil {
Jon Perritt04851d32014-10-14 02:07:13 -0500411 headers, err := opts.ToObjectUpdateMap()
Jon Perrittde47eac2014-09-30 15:34:17 -0500412 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500413 res.Err = err
414 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500415 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500416
Jon Perrittde47eac2014-09-30 15:34:17 -0500417 for k, v := range headers {
418 h[k] = v
419 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500420 }
421
Jon Perrittea4e3012014-10-09 22:03:19 -0500422 url := updateURL(c, containerName, objectName)
Jon Perritt5db08922014-09-30 21:32:48 -0500423 resp, err := perigee.Request("POST", url, perigee.Options{
Jon Perritt816d2a02014-03-11 20:49:46 -0500424 MoreHeaders: h,
Ash Wilsone47ea9e2014-09-10 16:03:44 -0400425 OkCodes: []int{202},
Jon Perritt816d2a02014-03-11 20:49:46 -0500426 })
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400427 res.Header = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500428 res.Err = err
429 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500430}
Jon Perritt90957602015-02-01 17:03:06 -0700431
432// HTTPMethod represents an HTTP method string (e.g. "GET").
433type HTTPMethod string
434
435var (
436 // GET represents an HTTP "GET" method.
437 GET HTTPMethod = "GET"
438 // POST represents an HTTP "POST" method.
439 POST HTTPMethod = "POST"
440)
441
442// CreateTempURLOpts are options for creating a temporary URL for an object.
443type CreateTempURLOpts struct {
444 // Method is the HTTP method to allow for users of the temp URL. Valid values
445 // are "GET" and "POST".
446 Method HTTPMethod
447 // TTL is the amount of time the temp URL should be active (in seconds).
448 TTL int
449}
450
451// CreateTempURL is a function for creating a temporary URL for an object. It
452// allows users to have "GET" or "POST" access to a particular tenant's object
453// for a limited amount of time.
454func CreateTempURL(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateTempURLOpts) (string, error) {
455 duration := time.Duration(opts.TTL) * time.Second
456 expiry := time.Now().Add(duration).Unix()
457 getHeader, err := accounts.Get(c, nil).Extract()
458 if err != nil {
459 return "", err
460 }
461 secretKey := []byte(getHeader.TempURLKey)
462 url := getURL(c, containerName, objectName)
463 splitPath := strings.Split(url, "/v1/")
464 baseURL, objectPath := splitPath[0], splitPath[1]
465 objectPath = "/v1/" + objectPath
466 body := fmt.Sprintf("%s\n%d\n%s", opts.Method, expiry, objectPath)
467 hash := hmac.New(sha1.New, secretKey)
468 hash.Write([]byte(body))
469 hexsum := fmt.Sprintf("%x", hash.Sum(nil))
470 return fmt.Sprintf("%s%s?temp_url_sig=%s&temp_url_expires=%d", baseURL, objectPath, hexsum, expiry), nil
471}