blob: 7b96fa2fe5ab70b993a1d5bacc664e55205fd021 [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 {
Jon Perritt9415ca72014-11-03 11:58:48 -060021 // Full is a true/false value that represents the amount of object information
22 // returned. If Full is set to true, then the content-type, number of bytes, hash
23 // date last modified, and name are returned. If set to false or not set, then
24 // only the object names are returned.
Jon Perritt8c93a302014-09-28 22:35:57 -050025 Full bool
Jon Perritt04851d32014-10-14 02:07:13 -050026 Limit int `q:"limit"`
27 Marker string `q:"marker"`
28 EndMarker string `q:"end_marker"`
29 Format string `q:"format"`
30 Prefix string `q:"prefix"`
31 Delimiter string `q:"delimiter"`
32 Path string `q:"path"`
Ash Wilsonca6f7562014-09-16 15:43:54 -040033}
34
Jon Perritte90aced2014-10-12 23:24:06 -050035// ToObjectListParams formats a ListOpts into a query string and boolean
36// representing whether to list complete information for each object.
37func (opts ListOpts) ToObjectListParams() (bool, string, error) {
38 q, err := gophercloud.BuildQueryString(opts)
39 if err != nil {
40 return false, "", err
41 }
42 return opts.Full, q.String(), nil
43}
44
Jon Perritt816d2a02014-03-11 20:49:46 -050045// List is a function that retrieves all objects in a container. It also returns the details
46// for the container. To extract only the object information or names, pass the ListResult
Jon Perritteb575642014-04-24 15:16:31 -050047// response to the ExtractInfo or ExtractNames function, respectively.
Jon Perritte90aced2014-10-12 23:24:06 -050048func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager {
49 headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"}
Jon Perritt816d2a02014-03-11 20:49:46 -050050
Jon Perrittea4e3012014-10-09 22:03:19 -050051 url := listURL(c, containerName)
Jon Perrittde47eac2014-09-30 15:34:17 -050052 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -050053 full, query, err := opts.ToObjectListParams()
Jon Perrittde47eac2014-09-30 15:34:17 -050054 if err != nil {
Jon Perrittde47eac2014-09-30 15:34:17 -050055 return pagination.Pager{Err: err}
56 }
Jon Perritte90aced2014-10-12 23:24:06 -050057 url += query
Jon Perritt816d2a02014-03-11 20:49:46 -050058
Jon Perritte90aced2014-10-12 23:24:06 -050059 if full {
60 headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"}
Jon Perrittde47eac2014-09-30 15:34:17 -050061 }
Ash Wilsonca6f7562014-09-16 15:43:54 -040062 }
63
Ash Wilsonb8b16f82014-10-20 10:19:49 -040064 createPage := func(r pagination.PageResult) pagination.Page {
65 p := ObjectPage{pagination.MarkerPageBase{PageResult: r}}
Ash Wilsonca6f7562014-09-16 15:43:54 -040066 p.MarkerPageBase.Owner = p
67 return p
Jon Perritt816d2a02014-03-11 20:49:46 -050068 }
69
Ash Wilsonca6f7562014-09-16 15:43:54 -040070 pager := pagination.NewPager(c, url, createPage)
71 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.
110func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) DownloadResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500111 var res DownloadResult
Jon Perritt8c93a302014-09-28 22:35:57 -0500112
Jon Perrittea4e3012014-10-09 22:03:19 -0500113 url := downloadURL(c, containerName, objectName)
Ash Wilson77857dc2014-10-22 09:09:02 -0400114 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500115
Jon Perrittde47eac2014-09-30 15:34:17 -0500116 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500117 headers, query, err := opts.ToObjectDownloadParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500118 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500119 res.Err = err
120 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500121 }
122
123 for k, v := range headers {
124 h[k] = v
125 }
126
Jon Perritte90aced2014-10-12 23:24:06 -0500127 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500128 }
129
Jon Perritt816d2a02014-03-11 20:49:46 -0500130 resp, err := perigee.Request("GET", url, perigee.Options{
Jon Perritt816d2a02014-03-11 20:49:46 -0500131 MoreHeaders: h,
Paul Querna9163df22014-11-01 09:38:51 -0700132 OkCodes: []int{200, 304},
Jon Perritt816d2a02014-03-11 20:49:46 -0500133 })
Jamie Hannaford2e784862014-10-27 10:40:27 +0100134
135 res.Body = resp.HttpResponse.Body
Jon Perritt5db08922014-09-30 21:32:48 -0500136 res.Err = err
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400137 res.Header = resp.HttpResponse.Header
Jamie Hannaford2e784862014-10-27 10:40:27 +0100138
Jon Perritt5db08922014-09-30 21:32:48 -0500139 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500140}
141
Jon Perritte90aced2014-10-12 23:24:06 -0500142// CreateOptsBuilder allows extensions to add additional parameters to the
143// Create request.
144type CreateOptsBuilder interface {
145 ToObjectCreateParams() (map[string]string, string, error)
146}
147
Jon Perritt8c93a302014-09-28 22:35:57 -0500148// CreateOpts is a structure that holds parameters for creating an object.
149type CreateOpts struct {
150 Metadata map[string]string
151 ContentDisposition string `h:"Content-Disposition"`
152 ContentEncoding string `h:"Content-Encoding"`
Jon Perritte376fa52014-11-03 11:35:48 -0600153 ContentLength int64 `h:"Content-Length"`
Jon Perritt8c93a302014-09-28 22:35:57 -0500154 ContentType string `h:"Content-Type"`
155 CopyFrom string `h:"X-Copy-From"`
156 DeleteAfter int `h:"X-Delete-After"`
157 DeleteAt int `h:"X-Delete-At"`
158 DetectContentType string `h:"X-Detect-Content-Type"`
159 ETag string `h:"ETag"`
160 IfNoneMatch string `h:"If-None-Match"`
161 ObjectManifest string `h:"X-Object-Manifest"`
162 TransferEncoding string `h:"Transfer-Encoding"`
163 Expires string `q:"expires"`
164 MultipartManifest string `q:"multiple-manifest"`
165 Signature string `q:"signature"`
Jon Perritt816d2a02014-03-11 20:49:46 -0500166}
167
Jon Perritte90aced2014-10-12 23:24:06 -0500168// ToObjectCreateParams formats a CreateOpts into a query string and map of
169// headers.
170func (opts CreateOpts) ToObjectCreateParams() (map[string]string, string, error) {
171 q, err := gophercloud.BuildQueryString(opts)
172 if err != nil {
173 return nil, "", err
174 }
175 h, err := gophercloud.BuildHeaders(opts)
176 if err != nil {
177 return nil, q.String(), err
178 }
179
180 for k, v := range opts.Metadata {
181 h["X-Object-Meta-"+k] = v
182 }
183
184 return h, q.String(), nil
185}
186
Jon Perritt816d2a02014-03-11 20:49:46 -0500187// Create is a function that creates a new object or replaces an existing object.
Jon Perritte90aced2014-10-12 23:24:06 -0500188func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.Reader, opts CreateOptsBuilder) CreateResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500189 var res CreateResult
Jon Perritt816d2a02014-03-11 20:49:46 -0500190
Jon Perrittea4e3012014-10-09 22:03:19 -0500191 url := createURL(c, containerName, objectName)
Ash Wilson77857dc2014-10-22 09:09:02 -0400192 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500193
Jon Perrittde47eac2014-09-30 15:34:17 -0500194 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500195 headers, query, err := opts.ToObjectCreateParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500196 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500197 res.Err = err
198 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500199 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500200
Jon Perrittde47eac2014-09-30 15:34:17 -0500201 for k, v := range headers {
202 h[k] = v
203 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500204
Jon Perritte90aced2014-10-12 23:24:06 -0500205 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500206 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500207
Jon Perritta77ba0d2014-10-17 01:15:29 -0500208 contentType := h["Content-Type"]
Jon Perritt816d2a02014-03-11 20:49:46 -0500209
Jon Perritt5db08922014-09-30 21:32:48 -0500210 resp, err := perigee.Request("PUT", url, perigee.Options{
Jon Perritta77ba0d2014-10-17 01:15:29 -0500211 ContentType: contentType,
212 ReqBody: content,
Jon Perritt816d2a02014-03-11 20:49:46 -0500213 MoreHeaders: h,
Jon Perritta77ba0d2014-10-17 01:15:29 -0500214 OkCodes: []int{201, 202},
Jon Perritt816d2a02014-03-11 20:49:46 -0500215 })
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400216 res.Header = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500217 res.Err = err
218 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500219}
220
Jon Perritte90aced2014-10-12 23:24:06 -0500221// CopyOptsBuilder allows extensions to add additional parameters to the
222// Copy request.
223type CopyOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500224 ToObjectCopyMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500225}
226
227// CopyOpts is a structure that holds parameters for copying one object to
228// another.
Jon Perritt8c93a302014-09-28 22:35:57 -0500229type CopyOpts struct {
230 Metadata map[string]string
231 ContentDisposition string `h:"Content-Disposition"`
232 ContentEncoding string `h:"Content-Encoding"`
233 ContentType string `h:"Content-Type"`
234 Destination string `h:"Destination,required"`
235}
236
Jon Perritt04851d32014-10-14 02:07:13 -0500237// ToObjectCopyMap formats a CopyOpts into a map of headers.
238func (opts CopyOpts) ToObjectCopyMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500239 if opts.Destination == "" {
240 return nil, fmt.Errorf("Required CopyOpts field 'Destination' not set.")
241 }
242 h, err := gophercloud.BuildHeaders(opts)
243 if err != nil {
244 return nil, err
245 }
246 for k, v := range opts.Metadata {
247 h["X-Object-Meta-"+k] = v
248 }
249 return h, nil
250}
251
Jon Perritt816d2a02014-03-11 20:49:46 -0500252// Copy is a function that copies one object to another.
Jon Perritte90aced2014-10-12 23:24:06 -0500253func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) CopyResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500254 var res CopyResult
Ash Wilson77857dc2014-10-22 09:09:02 -0400255 h := c.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500256
Jon Perritt04851d32014-10-14 02:07:13 -0500257 headers, err := opts.ToObjectCopyMap()
Jon Perritt8c93a302014-09-28 22:35:57 -0500258 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500259 res.Err = err
260 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500261 }
Jon Perritte90aced2014-10-12 23:24:06 -0500262
Jon Perritt8c93a302014-09-28 22:35:57 -0500263 for k, v := range headers {
Jon Perritt816d2a02014-03-11 20:49:46 -0500264 h[k] = v
265 }
266
Jon Perrittea4e3012014-10-09 22:03:19 -0500267 url := copyURL(c, containerName, objectName)
Jon Perritt5db08922014-09-30 21:32:48 -0500268 resp, err := perigee.Request("COPY", url, perigee.Options{
Jon Perritt8c93a302014-09-28 22:35:57 -0500269 MoreHeaders: h,
270 OkCodes: []int{201},
271 })
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400272 res.Header = resp.HttpResponse.Header
jrperrittf7a8e282014-10-28 10:00:48 -0500273 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500274 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 {
Jon Perritt26780d52014-10-14 11:35:58 -0500280 ToObjectDeleteQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500281}
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 Perritt26780d52014-10-14 11:35:58 -0500288// ToObjectDeleteQuery formats a DeleteOpts into a query string.
289func (opts DeleteOpts) ToObjectDeleteQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500290 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 Perritt26780d52014-10-14 11:35:58 -0500303 query, err := opts.ToObjectDeleteQuery()
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 Perritt10a7ec12014-10-27 11:29:33 -0500311 resp, err := perigee.Request("DELETE", url, perigee.Options{
Ash Wilson77857dc2014-10-22 09:09:02 -0400312 MoreHeaders: c.AuthenticatedHeaders(),
Jon Perritt8c93a302014-09-28 22:35:57 -0500313 OkCodes: []int{204},
314 })
Jon Perritt10a7ec12014-10-27 11:29:33 -0500315 res.Header = resp.HttpResponse.Header
316 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500317 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 {
Jon Perritt26780d52014-10-14 11:35:58 -0500323 ToObjectGetQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500324}
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 Perritt26780d52014-10-14 11:35:58 -0500332// ToObjectGetQuery formats a GetOpts into a query string.
333func (opts GetOpts) ToObjectGetQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500334 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 Perritt26780d52014-10-14 11:35:58 -0500348 query, err := opts.ToObjectGetQuery()
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{
Ash Wilson77857dc2014-10-22 09:09:02 -0400357 MoreHeaders: c.AuthenticatedHeaders(),
Jon Perritt8c93a302014-09-28 22:35:57 -0500358 OkCodes: []int{200, 204},
359 })
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400360 res.Header = resp.HttpResponse.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)
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 })
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400417 res.Header = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500418 res.Err = err
419 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500420}