blob: 77b8380dcce8a7b9d0039c6b2acd35ec70dfa683 [file] [log] [blame]
Jon Perritt816d2a02014-03-11 20:49:46 -05001package objects
2
3import (
4 "fmt"
Jon Perritt8c93a302014-09-28 22:35:57 -05005 "io"
6 "time"
Ash Wilson604320e2014-09-10 16:02:28 -04007
8 "github.com/racker/perigee"
9 "github.com/rackspace/gophercloud"
Ash Wilsonca6f7562014-09-16 15:43:54 -040010 "github.com/rackspace/gophercloud/pagination"
Jon Perritt816d2a02014-03-11 20:49:46 -050011)
12
Jon Perritte90aced2014-10-12 23:24:06 -050013// ListOptsBuilder allows extensions to add additional parameters to the List
14// request.
15type ListOptsBuilder interface {
16 ToObjectListParams() (bool, string, error)
17}
18
Jon Perritt8c93a302014-09-28 22:35:57 -050019// ListOpts is a structure that holds parameters for listing objects.
20type ListOpts struct {
21 Full bool
22 Limit int `q:"limit"`
23 Marker string `q:"marker"`
24 EndMarker string `q:"end_marker"`
25 Format string `q:"format"`
26 Prefix string `q:"prefix"`
27 Delimiter [1]byte `q:"delimiter"`
28 Path string `q:"path"`
Ash Wilsonca6f7562014-09-16 15:43:54 -040029}
30
Jon Perritte90aced2014-10-12 23:24:06 -050031// ToObjectListParams formats a ListOpts into a query string and boolean
32// representing whether to list complete information for each object.
33func (opts ListOpts) ToObjectListParams() (bool, string, error) {
34 q, err := gophercloud.BuildQueryString(opts)
35 if err != nil {
36 return false, "", err
37 }
38 return opts.Full, q.String(), nil
39}
40
Jon Perritt816d2a02014-03-11 20:49:46 -050041// List is a function that retrieves all objects in a container. It also returns the details
42// for the container. To extract only the object information or names, pass the ListResult
Jon Perritteb575642014-04-24 15:16:31 -050043// response to the ExtractInfo or ExtractNames function, respectively.
Jon Perritte90aced2014-10-12 23:24:06 -050044func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager {
45 headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"}
Jon Perritt816d2a02014-03-11 20:49:46 -050046
Jon Perrittea4e3012014-10-09 22:03:19 -050047 url := listURL(c, containerName)
Jon Perrittde47eac2014-09-30 15:34:17 -050048 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -050049 full, query, err := opts.ToObjectListParams()
Jon Perrittde47eac2014-09-30 15:34:17 -050050 if err != nil {
51 fmt.Printf("Error building query string: %v", err)
52 return pagination.Pager{Err: err}
53 }
Jon Perritte90aced2014-10-12 23:24:06 -050054 url += query
Jon Perritt816d2a02014-03-11 20:49:46 -050055
Jon Perritte90aced2014-10-12 23:24:06 -050056 if full {
57 headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"}
Jon Perrittde47eac2014-09-30 15:34:17 -050058 }
Ash Wilsonca6f7562014-09-16 15:43:54 -040059 }
60
61 createPage := func(r pagination.LastHTTPResponse) pagination.Page {
Jon Perritt8c93a302014-09-28 22:35:57 -050062 p := ObjectPage{pagination.MarkerPageBase{LastHTTPResponse: r}}
Ash Wilsonca6f7562014-09-16 15:43:54 -040063 p.MarkerPageBase.Owner = p
64 return p
Jon Perritt816d2a02014-03-11 20:49:46 -050065 }
66
Ash Wilsonca6f7562014-09-16 15:43:54 -040067 pager := pagination.NewPager(c, url, createPage)
68 pager.Headers = headers
69 return pager
Jon Perritt816d2a02014-03-11 20:49:46 -050070}
71
Jon Perritte90aced2014-10-12 23:24:06 -050072// DownloadOptsBuilder allows extensions to add additional parameters to the
73// Download request.
74type DownloadOptsBuilder interface {
75 ToObjectDownloadParams() (map[string]string, string, error)
76}
77
Jon Perritt8c93a302014-09-28 22:35:57 -050078// DownloadOpts is a structure that holds parameters for downloading an object.
79type DownloadOpts struct {
80 IfMatch string `h:"If-Match"`
81 IfModifiedSince time.Time `h:"If-Modified-Since"`
82 IfNoneMatch string `h:"If-None-Match"`
83 IfUnmodifiedSince time.Time `h:"If-Unmodified-Since"`
84 Range string `h:"Range"`
85 Expires string `q:"expires"`
86 MultipartManifest string `q:"multipart-manifest"`
87 Signature string `q:"signature"`
88}
89
Jon Perritte90aced2014-10-12 23:24:06 -050090// ToObjectDownloadParams formats a DownloadOpts into a query string and map of
91// headers.
92func (opts ListOpts) ToObjectDownloadParams() (map[string]string, string, error) {
93 q, err := gophercloud.BuildQueryString(opts)
94 if err != nil {
95 return nil, "", err
96 }
97 h, err := gophercloud.BuildHeaders(opts)
98 if err != nil {
99 return nil, q.String(), err
100 }
101 return h, q.String(), nil
102}
103
Jon Perritt816d2a02014-03-11 20:49:46 -0500104// Download is a function that retrieves the content and metadata for an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500105// To extract just the content, pass the DownloadResult response to the
106// ExtractContent function.
107func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) DownloadResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500108 var res DownloadResult
Jon Perritt8c93a302014-09-28 22:35:57 -0500109
Jon Perrittea4e3012014-10-09 22:03:19 -0500110 url := downloadURL(c, containerName, objectName)
Ash Wilson604320e2014-09-10 16:02:28 -0400111 h := c.Provider.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500112
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 Perritt5db08922014-09-30 21:32:48 -0500116 res.Err = err
117 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500118 }
119
120 for k, v := range headers {
121 h[k] = v
122 }
123
Jon Perritte90aced2014-10-12 23:24:06 -0500124 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500125 }
126
Jon Perritt816d2a02014-03-11 20:49:46 -0500127 resp, err := perigee.Request("GET", url, perigee.Options{
Jon Perritt816d2a02014-03-11 20:49:46 -0500128 MoreHeaders: h,
Ash Wilsone47ea9e2014-09-10 16:03:44 -0400129 OkCodes: []int{200},
Jon Perritt816d2a02014-03-11 20:49:46 -0500130 })
Jon Perritt5db08922014-09-30 21:32:48 -0500131 res.Err = err
132 res.Resp = &resp.HttpResponse
133 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500134}
135
Jon Perritte90aced2014-10-12 23:24:06 -0500136// CreateOptsBuilder allows extensions to add additional parameters to the
137// Create request.
138type CreateOptsBuilder interface {
139 ToObjectCreateParams() (map[string]string, string, error)
140}
141
Jon Perritt8c93a302014-09-28 22:35:57 -0500142// CreateOpts is a structure that holds parameters for creating an object.
143type CreateOpts struct {
144 Metadata map[string]string
145 ContentDisposition string `h:"Content-Disposition"`
146 ContentEncoding string `h:"Content-Encoding"`
147 ContentLength int `h:"Content-Length"`
148 ContentType string `h:"Content-Type"`
149 CopyFrom string `h:"X-Copy-From"`
150 DeleteAfter int `h:"X-Delete-After"`
151 DeleteAt int `h:"X-Delete-At"`
152 DetectContentType string `h:"X-Detect-Content-Type"`
153 ETag string `h:"ETag"`
154 IfNoneMatch string `h:"If-None-Match"`
155 ObjectManifest string `h:"X-Object-Manifest"`
156 TransferEncoding string `h:"Transfer-Encoding"`
157 Expires string `q:"expires"`
158 MultipartManifest string `q:"multiple-manifest"`
159 Signature string `q:"signature"`
Jon Perritt816d2a02014-03-11 20:49:46 -0500160}
161
Jon Perritte90aced2014-10-12 23:24:06 -0500162// ToObjectCreateParams formats a CreateOpts into a query string and map of
163// headers.
164func (opts CreateOpts) ToObjectCreateParams() (map[string]string, string, error) {
165 q, err := gophercloud.BuildQueryString(opts)
166 if err != nil {
167 return nil, "", err
168 }
169 h, err := gophercloud.BuildHeaders(opts)
170 if err != nil {
171 return nil, q.String(), err
172 }
173
174 for k, v := range opts.Metadata {
175 h["X-Object-Meta-"+k] = v
176 }
177
178 return h, q.String(), nil
179}
180
Jon Perritt816d2a02014-03-11 20:49:46 -0500181// Create is a function that creates a new object or replaces an existing object.
Jon Perritte90aced2014-10-12 23:24:06 -0500182func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.Reader, opts CreateOptsBuilder) CreateResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500183 var res CreateResult
Jon Perritt816d2a02014-03-11 20:49:46 -0500184 var reqBody []byte
185
Jon Perrittea4e3012014-10-09 22:03:19 -0500186 url := createURL(c, containerName, objectName)
Ash Wilson604320e2014-09-10 16:02:28 -0400187 h := c.Provider.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500188
Jon Perrittde47eac2014-09-30 15:34:17 -0500189 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500190 headers, query, err := opts.ToObjectCreateParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500191 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500192 res.Err = err
193 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500194 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500195
Jon Perrittde47eac2014-09-30 15:34:17 -0500196 for k, v := range headers {
197 h[k] = v
198 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500199
Jon Perritte90aced2014-10-12 23:24:06 -0500200 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500201 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500202
Jon Perritt816d2a02014-03-11 20:49:46 -0500203 if content != nil {
Jon Perritt884e0312014-08-14 17:25:38 -0500204 reqBody = make([]byte, 0)
Ash Wilson604320e2014-09-10 16:02:28 -0400205 _, err := content.Read(reqBody)
Jon Perritt816d2a02014-03-11 20:49:46 -0500206 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500207 res.Err = err
208 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500209 }
210 }
211
Jon Perritt5db08922014-09-30 21:32:48 -0500212 resp, err := perigee.Request("PUT", url, perigee.Options{
Jon Perritt816d2a02014-03-11 20:49:46 -0500213 ReqBody: reqBody,
214 MoreHeaders: h,
Ash Wilsone47ea9e2014-09-10 16:03:44 -0400215 OkCodes: []int{201},
Jon Perritt816d2a02014-03-11 20:49:46 -0500216 })
Jon Perritt5db08922014-09-30 21:32:48 -0500217 res.Resp = &resp.HttpResponse
218 res.Err = err
219 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500220}
221
Jon Perritte90aced2014-10-12 23:24:06 -0500222// CopyOptsBuilder allows extensions to add additional parameters to the
223// Copy request.
224type CopyOptsBuilder interface {
225 ToObjectCopyParams() (map[string]string, error)
226}
227
228// CopyOpts is a structure that holds parameters for copying one object to
229// another.
Jon Perritt8c93a302014-09-28 22:35:57 -0500230type CopyOpts struct {
231 Metadata map[string]string
232 ContentDisposition string `h:"Content-Disposition"`
233 ContentEncoding string `h:"Content-Encoding"`
234 ContentType string `h:"Content-Type"`
235 Destination string `h:"Destination,required"`
236}
237
Jon Perritte90aced2014-10-12 23:24:06 -0500238// ToObjectCopyParams formats a CopyOpts into a map of headers.
239func (opts CopyOpts) ToObjectCopyParams() (map[string]string, error) {
240 if opts.Destination == "" {
241 return nil, fmt.Errorf("Required CopyOpts field 'Destination' not set.")
242 }
243 h, err := gophercloud.BuildHeaders(opts)
244 if err != nil {
245 return nil, err
246 }
247 for k, v := range opts.Metadata {
248 h["X-Object-Meta-"+k] = v
249 }
250 return h, nil
251}
252
Jon Perritt816d2a02014-03-11 20:49:46 -0500253// Copy is a function that copies one object to another.
Jon Perritte90aced2014-10-12 23:24:06 -0500254func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) CopyResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500255 var res CopyResult
Ash Wilson604320e2014-09-10 16:02:28 -0400256 h := c.Provider.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500257
Jon Perritte90aced2014-10-12 23:24:06 -0500258 headers, err := opts.ToObjectCopyParams()
Jon Perritt8c93a302014-09-28 22:35:57 -0500259 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500260 res.Err = err
261 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500262 }
Jon Perritte90aced2014-10-12 23:24:06 -0500263
Jon Perritt8c93a302014-09-28 22:35:57 -0500264 for k, v := range headers {
Jon Perritt816d2a02014-03-11 20:49:46 -0500265 h[k] = v
266 }
267
Jon Perrittea4e3012014-10-09 22:03:19 -0500268 url := copyURL(c, containerName, objectName)
Jon Perritt5db08922014-09-30 21:32:48 -0500269 resp, err := perigee.Request("COPY", url, perigee.Options{
Jon Perritt8c93a302014-09-28 22:35:57 -0500270 MoreHeaders: h,
271 OkCodes: []int{201},
272 })
Jon Perritt5db08922014-09-30 21:32:48 -0500273 res.Resp = &resp.HttpResponse
274 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500275}
276
Jon Perritte90aced2014-10-12 23:24:06 -0500277// DeleteOptsBuilder allows extensions to add additional parameters to the
278// Delete request.
279type DeleteOptsBuilder interface {
280 ToObjectDeleteParams() (string, error)
281}
282
Jon Perritt8c93a302014-09-28 22:35:57 -0500283// DeleteOpts is a structure that holds parameters for deleting an object.
284type DeleteOpts struct {
285 MultipartManifest string `q:"multipart-manifest"`
286}
287
Jon Perritte90aced2014-10-12 23:24:06 -0500288// ToObjectDeleteParams formats a DeleteOpts into a query string.
289func (opts DeleteOpts) ToObjectDeleteParams() (string, error) {
290 q, err := gophercloud.BuildQueryString(opts)
291 if err != nil {
292 return "", err
293 }
294 return q.String(), nil
295}
296
Jon Perritt8c93a302014-09-28 22:35:57 -0500297// Delete is a function that deletes an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500298func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) DeleteResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500299 var res DeleteResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500300 url := deleteURL(c, containerName, objectName)
Jon Perritt8c93a302014-09-28 22:35:57 -0500301
Jon Perrittde47eac2014-09-30 15:34:17 -0500302 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500303 query, err := opts.ToObjectDeleteParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500304 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500305 res.Err = err
306 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500307 }
Jon Perritte90aced2014-10-12 23:24:06 -0500308 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500309 }
310
Jon Perritt5db08922014-09-30 21:32:48 -0500311 resp, err := perigee.Request("DELETE", url, perigee.Options{
Jon Perrittde47eac2014-09-30 15:34:17 -0500312 MoreHeaders: c.Provider.AuthenticatedHeaders(),
Jon Perritt8c93a302014-09-28 22:35:57 -0500313 OkCodes: []int{204},
314 })
Jon Perritt5db08922014-09-30 21:32:48 -0500315 res.Resp = &resp.HttpResponse
316 res.Err = err
317 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500318}
319
Jon Perritte90aced2014-10-12 23:24:06 -0500320// GetOptsBuilder allows extensions to add additional parameters to the
321// Get request.
322type GetOptsBuilder interface {
323 ToObjectGetParams() (string, error)
324}
325
Jon Perritt8c93a302014-09-28 22:35:57 -0500326// GetOpts is a structure that holds parameters for getting an object's metadata.
327type GetOpts struct {
328 Expires string `q:"expires"`
329 Signature string `q:"signature"`
330}
331
Jon Perritte90aced2014-10-12 23:24:06 -0500332// ToObjectGetParams formats a GetOpts into a query string.
333func (opts GetOpts) ToObjectGetParams() (string, error) {
334 q, err := gophercloud.BuildQueryString(opts)
335 if err != nil {
336 return "", err
337 }
338 return q.String(), nil
339}
340
Jon Perritt8c93a302014-09-28 22:35:57 -0500341// Get is a function that retrieves the metadata of an object. To extract just the custom
342// metadata, pass the GetResult response to the ExtractMetadata function.
Jon Perritte90aced2014-10-12 23:24:06 -0500343func Get(c *gophercloud.ServiceClient, containerName, objectName string, opts GetOptsBuilder) GetResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500344 var res GetResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500345 url := getURL(c, containerName, objectName)
Jon Perrittde47eac2014-09-30 15:34:17 -0500346
347 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500348 query, err := opts.ToObjectGetParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500349 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500350 res.Err = err
351 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500352 }
Jon Perritte90aced2014-10-12 23:24:06 -0500353 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500354 }
355
Jon Perritt8c93a302014-09-28 22:35:57 -0500356 resp, err := perigee.Request("HEAD", url, perigee.Options{
357 MoreHeaders: c.Provider.AuthenticatedHeaders(),
358 OkCodes: []int{200, 204},
359 })
Jon Perritt5db08922014-09-30 21:32:48 -0500360 res.Err = err
361 res.Resp = &resp.HttpResponse
362 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 {
368 ToObjectUpdateParams() (map[string]string, error)
369}
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 Perritte90aced2014-10-12 23:24:06 -0500383// ToObjectUpdateParams formats a UpdateOpts into a map of headers.
384func (opts UpdateOpts) ToObjectUpdateParams() (map[string]string, error) {
385 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
Jon Perritt8c93a302014-09-28 22:35:57 -0500398 h := c.Provider.AuthenticatedHeaders()
399
Jon Perrittde47eac2014-09-30 15:34:17 -0500400 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500401 headers, err := opts.ToObjectUpdateParams()
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)
Jon Perritt5db08922014-09-30 21:32:48 -0500413 resp, err := perigee.Request("POST", url, perigee.Options{
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 })
Jon Perritt5db08922014-09-30 21:32:48 -0500417 res.Resp = &resp.HttpResponse
418 res.Err = err
419 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500420}