blob: 30ea94cc2d70e2509780c6ebab968ba475505a06 [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
Ash Wilson604320e2014-09-10 16:02:28 -040011 "github.com/rackspace/gophercloud"
Jon Perritt90957602015-02-01 17:03:06 -070012 "github.com/rackspace/gophercloud/openstack/objectstorage/v1/accounts"
Ash Wilsonca6f7562014-09-16 15:43:54 -040013 "github.com/rackspace/gophercloud/pagination"
Jon Perritt816d2a02014-03-11 20:49:46 -050014)
15
Jon Perritte90aced2014-10-12 23:24:06 -050016// ListOptsBuilder allows extensions to add additional parameters to the List
17// request.
18type ListOptsBuilder interface {
19 ToObjectListParams() (bool, string, error)
20}
21
Jon Perritt8c93a302014-09-28 22:35:57 -050022// ListOpts is a structure that holds parameters for listing objects.
23type ListOpts struct {
Jon Perritt9415ca72014-11-03 11:58:48 -060024 // Full is a true/false value that represents the amount of object information
25 // returned. If Full is set to true, then the content-type, number of bytes, hash
26 // date last modified, and name are returned. If set to false or not set, then
27 // only the object names are returned.
Jon Perritt8c93a302014-09-28 22:35:57 -050028 Full bool
Jon Perritt04851d32014-10-14 02:07:13 -050029 Limit int `q:"limit"`
30 Marker string `q:"marker"`
31 EndMarker string `q:"end_marker"`
32 Format string `q:"format"`
33 Prefix string `q:"prefix"`
34 Delimiter string `q:"delimiter"`
35 Path string `q:"path"`
Ash Wilsonca6f7562014-09-16 15:43:54 -040036}
37
Jon Perritte90aced2014-10-12 23:24:06 -050038// ToObjectListParams formats a ListOpts into a query string and boolean
39// representing whether to list complete information for each object.
40func (opts ListOpts) ToObjectListParams() (bool, string, error) {
41 q, err := gophercloud.BuildQueryString(opts)
42 if err != nil {
43 return false, "", err
44 }
45 return opts.Full, q.String(), nil
46}
47
Jon Perritt816d2a02014-03-11 20:49:46 -050048// List is a function that retrieves all objects in a container. It also returns the details
49// for the container. To extract only the object information or names, pass the ListResult
Jon Perritteb575642014-04-24 15:16:31 -050050// response to the ExtractInfo or ExtractNames function, respectively.
Jon Perritte90aced2014-10-12 23:24:06 -050051func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager {
52 headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"}
Jon Perritt816d2a02014-03-11 20:49:46 -050053
Jon Perrittea4e3012014-10-09 22:03:19 -050054 url := listURL(c, containerName)
Jon Perrittde47eac2014-09-30 15:34:17 -050055 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -050056 full, query, err := opts.ToObjectListParams()
Jon Perrittde47eac2014-09-30 15:34:17 -050057 if err != nil {
Jon Perrittde47eac2014-09-30 15:34:17 -050058 return pagination.Pager{Err: err}
59 }
Jon Perritte90aced2014-10-12 23:24:06 -050060 url += query
Jon Perritt816d2a02014-03-11 20:49:46 -050061
Jon Perritte90aced2014-10-12 23:24:06 -050062 if full {
63 headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"}
Jon Perrittde47eac2014-09-30 15:34:17 -050064 }
Ash Wilsonca6f7562014-09-16 15:43:54 -040065 }
66
Ash Wilsonb8b16f82014-10-20 10:19:49 -040067 createPage := func(r pagination.PageResult) pagination.Page {
68 p := ObjectPage{pagination.MarkerPageBase{PageResult: r}}
Ash Wilsonca6f7562014-09-16 15:43:54 -040069 p.MarkerPageBase.Owner = p
70 return p
Jon Perritt816d2a02014-03-11 20:49:46 -050071 }
72
Ash Wilsonca6f7562014-09-16 15:43:54 -040073 pager := pagination.NewPager(c, url, createPage)
74 pager.Headers = headers
75 return pager
Jon Perritt816d2a02014-03-11 20:49:46 -050076}
77
Jon Perritte90aced2014-10-12 23:24:06 -050078// DownloadOptsBuilder allows extensions to add additional parameters to the
79// Download request.
80type DownloadOptsBuilder interface {
81 ToObjectDownloadParams() (map[string]string, string, error)
82}
83
Jon Perritt8c93a302014-09-28 22:35:57 -050084// DownloadOpts is a structure that holds parameters for downloading an object.
85type DownloadOpts struct {
86 IfMatch string `h:"If-Match"`
87 IfModifiedSince time.Time `h:"If-Modified-Since"`
88 IfNoneMatch string `h:"If-None-Match"`
89 IfUnmodifiedSince time.Time `h:"If-Unmodified-Since"`
90 Range string `h:"Range"`
91 Expires string `q:"expires"`
92 MultipartManifest string `q:"multipart-manifest"`
93 Signature string `q:"signature"`
94}
95
Jon Perritte90aced2014-10-12 23:24:06 -050096// ToObjectDownloadParams formats a DownloadOpts into a query string and map of
97// headers.
Paul Querna7dc6fe62014-11-01 08:09:41 -070098func (opts DownloadOpts) ToObjectDownloadParams() (map[string]string, string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -050099 q, err := gophercloud.BuildQueryString(opts)
100 if err != nil {
101 return nil, "", err
102 }
103 h, err := gophercloud.BuildHeaders(opts)
104 if err != nil {
105 return nil, q.String(), err
106 }
107 return h, q.String(), nil
108}
109
Jon Perritt816d2a02014-03-11 20:49:46 -0500110// Download is a function that retrieves the content and metadata for an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500111// To extract just the content, pass the DownloadResult response to the
112// ExtractContent function.
113func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) DownloadResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500114 var res DownloadResult
Jon Perritt8c93a302014-09-28 22:35:57 -0500115
Jon Perrittea4e3012014-10-09 22:03:19 -0500116 url := downloadURL(c, containerName, objectName)
Ash Wilson77857dc2014-10-22 09:09:02 -0400117 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500118
Jon Perrittde47eac2014-09-30 15:34:17 -0500119 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500120 headers, query, err := opts.ToObjectDownloadParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500121 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500122 res.Err = err
123 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500124 }
125
126 for k, v := range headers {
127 h[k] = v
128 }
129
Jon Perritte90aced2014-10-12 23:24:06 -0500130 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500131 }
132
Ash Wilson4bf41a32015-02-12 15:52:44 -0500133 resp, err := c.Request("GET", url, gophercloud.RequestOpts{
Jon Perritt816d2a02014-03-11 20:49:46 -0500134 MoreHeaders: h,
Paul Querna9163df22014-11-01 09:38:51 -0700135 OkCodes: []int{200, 304},
Jon Perritt816d2a02014-03-11 20:49:46 -0500136 })
Jamie Hannaford2e784862014-10-27 10:40:27 +0100137
Ash Wilson2491b4c2015-02-12 16:13:39 -0500138 res.Body = resp.Body
Jon Perritt5db08922014-09-30 21:32:48 -0500139 res.Err = err
Ash Wilson2491b4c2015-02-12 16:13:39 -0500140 res.Header = resp.Header
Jamie Hannaford2e784862014-10-27 10:40:27 +0100141
Jon Perritt5db08922014-09-30 21:32:48 -0500142 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500143}
144
Jon Perritte90aced2014-10-12 23:24:06 -0500145// CreateOptsBuilder allows extensions to add additional parameters to the
146// Create request.
147type CreateOptsBuilder interface {
148 ToObjectCreateParams() (map[string]string, string, error)
149}
150
Jon Perritt8c93a302014-09-28 22:35:57 -0500151// CreateOpts is a structure that holds parameters for creating an object.
152type CreateOpts struct {
153 Metadata map[string]string
154 ContentDisposition string `h:"Content-Disposition"`
155 ContentEncoding string `h:"Content-Encoding"`
Jon Perritte376fa52014-11-03 11:35:48 -0600156 ContentLength int64 `h:"Content-Length"`
Jon Perritt8c93a302014-09-28 22:35:57 -0500157 ContentType string `h:"Content-Type"`
158 CopyFrom string `h:"X-Copy-From"`
159 DeleteAfter int `h:"X-Delete-After"`
160 DeleteAt int `h:"X-Delete-At"`
161 DetectContentType string `h:"X-Detect-Content-Type"`
162 ETag string `h:"ETag"`
163 IfNoneMatch string `h:"If-None-Match"`
164 ObjectManifest string `h:"X-Object-Manifest"`
165 TransferEncoding string `h:"Transfer-Encoding"`
166 Expires string `q:"expires"`
167 MultipartManifest string `q:"multiple-manifest"`
168 Signature string `q:"signature"`
Jon Perritt816d2a02014-03-11 20:49:46 -0500169}
170
Jon Perritte90aced2014-10-12 23:24:06 -0500171// ToObjectCreateParams formats a CreateOpts into a query string and map of
172// headers.
173func (opts CreateOpts) ToObjectCreateParams() (map[string]string, string, error) {
174 q, err := gophercloud.BuildQueryString(opts)
175 if err != nil {
176 return nil, "", err
177 }
178 h, err := gophercloud.BuildHeaders(opts)
179 if err != nil {
180 return nil, q.String(), err
181 }
182
183 for k, v := range opts.Metadata {
184 h["X-Object-Meta-"+k] = v
185 }
186
187 return h, q.String(), nil
188}
189
Jon Perritt816d2a02014-03-11 20:49:46 -0500190// Create is a function that creates a new object or replaces an existing object.
Jon Perritte90aced2014-10-12 23:24:06 -0500191func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.Reader, opts CreateOptsBuilder) CreateResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500192 var res CreateResult
Jon Perritt816d2a02014-03-11 20:49:46 -0500193
Jon Perrittea4e3012014-10-09 22:03:19 -0500194 url := createURL(c, containerName, objectName)
Ash Wilson322a7e62015-02-12 16:25:26 -0500195 h := make(map[string]string)
Jon Perritt816d2a02014-03-11 20:49:46 -0500196
Jon Perrittde47eac2014-09-30 15:34:17 -0500197 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500198 headers, query, err := opts.ToObjectCreateParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500199 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500200 res.Err = err
201 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500202 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500203
Jon Perrittde47eac2014-09-30 15:34:17 -0500204 for k, v := range headers {
205 h[k] = v
206 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500207
Jon Perritte90aced2014-10-12 23:24:06 -0500208 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500209 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500210
Ash Wilson322a7e62015-02-12 16:25:26 -0500211 ropts := gophercloud.RequestOpts{
212 RawBody: content,
Jon Perritt816d2a02014-03-11 20:49:46 -0500213 MoreHeaders: h,
Jon Perritta77ba0d2014-10-17 01:15:29 -0500214 OkCodes: []int{201, 202},
Ash Wilson45e34342015-01-23 14:25:34 -0500215 }
216
Ash Wilson322a7e62015-02-12 16:25:26 -0500217 resp, err := c.Request("PUT", url, ropts)
218 res.Header = resp.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500219 res.Err = err
220 return res
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"`
236 Destination string `h:"Destination,required"`
237}
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 if opts.Destination == "" {
242 return nil, fmt.Errorf("Required CopyOpts field 'Destination' not set.")
243 }
244 h, err := gophercloud.BuildHeaders(opts)
245 if err != nil {
246 return nil, err
247 }
248 for k, v := range opts.Metadata {
249 h["X-Object-Meta-"+k] = v
250 }
251 return h, nil
252}
253
Jon Perritt816d2a02014-03-11 20:49:46 -0500254// Copy is a function that copies one object to another.
Jon Perritte90aced2014-10-12 23:24:06 -0500255func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) CopyResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500256 var res CopyResult
Ash Wilson77857dc2014-10-22 09:09:02 -0400257 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500258
Jon Perritt04851d32014-10-14 02:07:13 -0500259 headers, err := opts.ToObjectCopyMap()
Jon Perritt8c93a302014-09-28 22:35:57 -0500260 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500261 res.Err = err
262 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500263 }
Jon Perritte90aced2014-10-12 23:24:06 -0500264
Jon Perritt8c93a302014-09-28 22:35:57 -0500265 for k, v := range headers {
Jon Perritt816d2a02014-03-11 20:49:46 -0500266 h[k] = v
267 }
268
Jon Perrittea4e3012014-10-09 22:03:19 -0500269 url := copyURL(c, containerName, objectName)
Ash Wilson4bf41a32015-02-12 15:52:44 -0500270 resp, err := c.Request("COPY", url, gophercloud.RequestOpts{
Jon Perritt8c93a302014-09-28 22:35:57 -0500271 MoreHeaders: h,
272 OkCodes: []int{201},
273 })
Ash Wilson2491b4c2015-02-12 16:13:39 -0500274 res.Header = resp.Header
jrperrittf7a8e282014-10-28 10:00:48 -0500275 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500276 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500277}
278
Jon Perritte90aced2014-10-12 23:24:06 -0500279// DeleteOptsBuilder allows extensions to add additional parameters to the
280// Delete request.
281type DeleteOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500282 ToObjectDeleteQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500283}
284
Jon Perritt8c93a302014-09-28 22:35:57 -0500285// DeleteOpts is a structure that holds parameters for deleting an object.
286type DeleteOpts struct {
287 MultipartManifest string `q:"multipart-manifest"`
288}
289
Jon Perritt26780d52014-10-14 11:35:58 -0500290// ToObjectDeleteQuery formats a DeleteOpts into a query string.
291func (opts DeleteOpts) ToObjectDeleteQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500292 q, err := gophercloud.BuildQueryString(opts)
293 if err != nil {
294 return "", err
295 }
296 return q.String(), nil
297}
298
Jon Perritt8c93a302014-09-28 22:35:57 -0500299// Delete is a function that deletes an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500300func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) DeleteResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500301 var res DeleteResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500302 url := deleteURL(c, containerName, objectName)
Jon Perritt8c93a302014-09-28 22:35:57 -0500303
Jon Perrittde47eac2014-09-30 15:34:17 -0500304 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500305 query, err := opts.ToObjectDeleteQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500306 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500307 res.Err = err
308 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500309 }
Jon Perritte90aced2014-10-12 23:24:06 -0500310 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500311 }
312
Ash Wilson4bf41a32015-02-12 15:52:44 -0500313 resp, err := c.Request("DELETE", url, gophercloud.RequestOpts{
314 OkCodes: []int{204},
Jon Perritt8c93a302014-09-28 22:35:57 -0500315 })
Ash Wilson2491b4c2015-02-12 16:13:39 -0500316 res.Header = resp.Header
Jon Perritt10a7ec12014-10-27 11:29:33 -0500317 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500318 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500319}
320
Jon Perritte90aced2014-10-12 23:24:06 -0500321// GetOptsBuilder allows extensions to add additional parameters to the
322// Get request.
323type GetOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500324 ToObjectGetQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500325}
326
Jon Perritt8c93a302014-09-28 22:35:57 -0500327// GetOpts is a structure that holds parameters for getting an object's metadata.
328type GetOpts struct {
329 Expires string `q:"expires"`
330 Signature string `q:"signature"`
331}
332
Jon Perritt26780d52014-10-14 11:35:58 -0500333// ToObjectGetQuery formats a GetOpts into a query string.
334func (opts GetOpts) ToObjectGetQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500335 q, err := gophercloud.BuildQueryString(opts)
336 if err != nil {
337 return "", err
338 }
339 return q.String(), nil
340}
341
Jon Perritt8c93a302014-09-28 22:35:57 -0500342// Get is a function that retrieves the metadata of an object. To extract just the custom
343// metadata, pass the GetResult response to the ExtractMetadata function.
Jon Perritte90aced2014-10-12 23:24:06 -0500344func Get(c *gophercloud.ServiceClient, containerName, objectName string, opts GetOptsBuilder) GetResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500345 var res GetResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500346 url := getURL(c, containerName, objectName)
Jon Perrittde47eac2014-09-30 15:34:17 -0500347
348 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500349 query, err := opts.ToObjectGetQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500350 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500351 res.Err = err
352 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500353 }
Jon Perritte90aced2014-10-12 23:24:06 -0500354 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500355 }
356
Ash Wilson4bf41a32015-02-12 15:52:44 -0500357 resp, err := c.Request("HEAD", url, gophercloud.RequestOpts{
358 OkCodes: []int{200, 204},
Jon Perritt8c93a302014-09-28 22:35:57 -0500359 })
Ash Wilson2491b4c2015-02-12 16:13:39 -0500360 res.Header = resp.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500361 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500362 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500363}
364
Jon Perritte90aced2014-10-12 23:24:06 -0500365// UpdateOptsBuilder allows extensions to add additional parameters to the
366// Update request.
367type UpdateOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500368 ToObjectUpdateMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500369}
370
Jon Perritt8c93a302014-09-28 22:35:57 -0500371// UpdateOpts is a structure that holds parameters for updating, creating, or deleting an
372// object's metadata.
373type UpdateOpts struct {
374 Metadata map[string]string
375 ContentDisposition string `h:"Content-Disposition"`
376 ContentEncoding string `h:"Content-Encoding"`
377 ContentType string `h:"Content-Type"`
378 DeleteAfter int `h:"X-Delete-After"`
379 DeleteAt int `h:"X-Delete-At"`
380 DetectContentType bool `h:"X-Detect-Content-Type"`
381}
382
Jon Perritt04851d32014-10-14 02:07:13 -0500383// ToObjectUpdateMap formats a UpdateOpts into a map of headers.
384func (opts UpdateOpts) ToObjectUpdateMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500385 h, err := gophercloud.BuildHeaders(opts)
386 if err != nil {
387 return nil, err
388 }
389 for k, v := range opts.Metadata {
390 h["X-Object-Meta-"+k] = v
391 }
392 return h, nil
393}
394
Jon Perritt8c93a302014-09-28 22:35:57 -0500395// Update is a function that creates, updates, or deletes an object's metadata.
Jon Perritte90aced2014-10-12 23:24:06 -0500396func Update(c *gophercloud.ServiceClient, containerName, objectName string, opts UpdateOptsBuilder) UpdateResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500397 var res UpdateResult
Ash Wilson77857dc2014-10-22 09:09:02 -0400398 h := c.AuthenticatedHeaders()
Jon Perritt8c93a302014-09-28 22:35:57 -0500399
Jon Perrittde47eac2014-09-30 15:34:17 -0500400 if opts != nil {
Jon Perritt04851d32014-10-14 02:07:13 -0500401 headers, err := opts.ToObjectUpdateMap()
Jon Perrittde47eac2014-09-30 15:34:17 -0500402 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500403 res.Err = err
404 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500405 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500406
Jon Perrittde47eac2014-09-30 15:34:17 -0500407 for k, v := range headers {
408 h[k] = v
409 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500410 }
411
Jon Perrittea4e3012014-10-09 22:03:19 -0500412 url := updateURL(c, containerName, objectName)
Ash Wilson4bf41a32015-02-12 15:52:44 -0500413 resp, err := c.Request("POST", url, gophercloud.RequestOpts{
Jon Perritt816d2a02014-03-11 20:49:46 -0500414 MoreHeaders: h,
Ash Wilsone47ea9e2014-09-10 16:03:44 -0400415 OkCodes: []int{202},
Jon Perritt816d2a02014-03-11 20:49:46 -0500416 })
Ash Wilson2491b4c2015-02-12 16:13:39 -0500417 res.Header = resp.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500418 res.Err = err
419 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500420}
Jon Perritt90957602015-02-01 17:03:06 -0700421
422// HTTPMethod represents an HTTP method string (e.g. "GET").
423type HTTPMethod string
424
425var (
426 // GET represents an HTTP "GET" method.
427 GET HTTPMethod = "GET"
428 // POST represents an HTTP "POST" method.
429 POST HTTPMethod = "POST"
430)
431
432// CreateTempURLOpts are options for creating a temporary URL for an object.
433type CreateTempURLOpts struct {
Jon Perritt28792af2015-02-02 11:00:04 -0700434 // (REQUIRED) Method is the HTTP method to allow for users of the temp URL. Valid values
Jon Perritt90957602015-02-01 17:03:06 -0700435 // are "GET" and "POST".
436 Method HTTPMethod
Jon Perritt28792af2015-02-02 11:00:04 -0700437 // (REQUIRED) TTL is the number of seconds the temp URL should be active.
Jon Perritt90957602015-02-01 17:03:06 -0700438 TTL int
Jon Perritt28792af2015-02-02 11:00:04 -0700439 // (Optional) Split is the string on which to split the object URL. Since only
440 // the object path is used in the hash, the object URL needs to be parsed. If
441 // empty, the default OpenStack URL split point will be used ("/v1/").
442 Split string
Jon Perritt90957602015-02-01 17:03:06 -0700443}
444
445// CreateTempURL is a function for creating a temporary URL for an object. It
446// allows users to have "GET" or "POST" access to a particular tenant's object
447// for a limited amount of time.
448func CreateTempURL(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateTempURLOpts) (string, error) {
Jon Perritt28792af2015-02-02 11:00:04 -0700449 if opts.Split == "" {
450 opts.Split = "/v1/"
451 }
Jon Perritt90957602015-02-01 17:03:06 -0700452 duration := time.Duration(opts.TTL) * time.Second
453 expiry := time.Now().Add(duration).Unix()
454 getHeader, err := accounts.Get(c, nil).Extract()
455 if err != nil {
456 return "", err
457 }
458 secretKey := []byte(getHeader.TempURLKey)
459 url := getURL(c, containerName, objectName)
Jon Perritt28792af2015-02-02 11:00:04 -0700460 splitPath := strings.Split(url, opts.Split)
Jon Perritt90957602015-02-01 17:03:06 -0700461 baseURL, objectPath := splitPath[0], splitPath[1]
Jon Perritt28792af2015-02-02 11:00:04 -0700462 objectPath = opts.Split + objectPath
Jon Perritt90957602015-02-01 17:03:06 -0700463 body := fmt.Sprintf("%s\n%d\n%s", opts.Method, expiry, objectPath)
464 hash := hmac.New(sha1.New, secretKey)
465 hash.Write([]byte(body))
466 hexsum := fmt.Sprintf("%x", hash.Sum(nil))
467 return fmt.Sprintf("%s%s?temp_url_sig=%s&temp_url_expires=%d", baseURL, objectPath, hexsum, expiry), nil
468}