blob: c97b4fe5663ee1add61183afab7ea70e8dcb38e9 [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"
Ash Wilsonaf262872014-10-20 09:32:29 -04006 "io/ioutil"
Jon Perritt8c93a302014-09-28 22:35:57 -05007 "time"
Ash Wilson604320e2014-09-10 16:02:28 -04008
9 "github.com/racker/perigee"
10 "github.com/rackspace/gophercloud"
Ash Wilsonca6f7562014-09-16 15:43:54 -040011 "github.com/rackspace/gophercloud/pagination"
Jon Perritt816d2a02014-03-11 20:49:46 -050012)
13
Jon Perritte90aced2014-10-12 23:24:06 -050014// ListOptsBuilder allows extensions to add additional parameters to the List
15// request.
16type ListOptsBuilder interface {
17 ToObjectListParams() (bool, string, error)
18}
19
Jon Perritt8c93a302014-09-28 22:35:57 -050020// ListOpts is a structure that holds parameters for listing objects.
21type ListOpts struct {
22 Full bool
Jon Perritt04851d32014-10-14 02:07:13 -050023 Limit int `q:"limit"`
24 Marker string `q:"marker"`
25 EndMarker string `q:"end_marker"`
26 Format string `q:"format"`
27 Prefix string `q:"prefix"`
28 Delimiter string `q:"delimiter"`
29 Path string `q:"path"`
Ash Wilsonca6f7562014-09-16 15:43:54 -040030}
31
Jon Perritte90aced2014-10-12 23:24:06 -050032// ToObjectListParams formats a ListOpts into a query string and boolean
33// representing whether to list complete information for each object.
34func (opts ListOpts) ToObjectListParams() (bool, string, error) {
35 q, err := gophercloud.BuildQueryString(opts)
36 if err != nil {
37 return false, "", err
38 }
39 return opts.Full, q.String(), nil
40}
41
Jon Perritt816d2a02014-03-11 20:49:46 -050042// List is a function that retrieves all objects in a container. It also returns the details
43// for the container. To extract only the object information or names, pass the ListResult
Jon Perritteb575642014-04-24 15:16:31 -050044// response to the ExtractInfo or ExtractNames function, respectively.
Jon Perritte90aced2014-10-12 23:24:06 -050045func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager {
46 headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"}
Jon Perritt816d2a02014-03-11 20:49:46 -050047
Jon Perrittea4e3012014-10-09 22:03:19 -050048 url := listURL(c, containerName)
Jon Perrittde47eac2014-09-30 15:34:17 -050049 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -050050 full, query, err := opts.ToObjectListParams()
Jon Perrittde47eac2014-09-30 15:34:17 -050051 if err != nil {
52 fmt.Printf("Error building query string: %v", err)
53 return pagination.Pager{Err: err}
54 }
Jon Perritte90aced2014-10-12 23:24:06 -050055 url += query
Jon Perritt816d2a02014-03-11 20:49:46 -050056
Jon Perritte90aced2014-10-12 23:24:06 -050057 if full {
58 headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"}
Jon Perrittde47eac2014-09-30 15:34:17 -050059 }
Ash Wilsonca6f7562014-09-16 15:43:54 -040060 }
61
62 createPage := func(r pagination.LastHTTPResponse) pagination.Page {
Jon Perritt8c93a302014-09-28 22:35:57 -050063 p := ObjectPage{pagination.MarkerPageBase{LastHTTPResponse: r}}
Ash Wilsonca6f7562014-09-16 15:43:54 -040064 p.MarkerPageBase.Owner = p
65 return p
Jon Perritt816d2a02014-03-11 20:49:46 -050066 }
67
Ash Wilsonca6f7562014-09-16 15:43:54 -040068 pager := pagination.NewPager(c, url, createPage)
69 pager.Headers = headers
70 return pager
Jon Perritt816d2a02014-03-11 20:49:46 -050071}
72
Jon Perritte90aced2014-10-12 23:24:06 -050073// DownloadOptsBuilder allows extensions to add additional parameters to the
74// Download request.
75type DownloadOptsBuilder interface {
76 ToObjectDownloadParams() (map[string]string, string, error)
77}
78
Jon Perritt8c93a302014-09-28 22:35:57 -050079// DownloadOpts is a structure that holds parameters for downloading an object.
80type DownloadOpts struct {
81 IfMatch string `h:"If-Match"`
82 IfModifiedSince time.Time `h:"If-Modified-Since"`
83 IfNoneMatch string `h:"If-None-Match"`
84 IfUnmodifiedSince time.Time `h:"If-Unmodified-Since"`
85 Range string `h:"Range"`
86 Expires string `q:"expires"`
87 MultipartManifest string `q:"multipart-manifest"`
88 Signature string `q:"signature"`
89}
90
Jon Perritte90aced2014-10-12 23:24:06 -050091// ToObjectDownloadParams formats a DownloadOpts into a query string and map of
92// headers.
93func (opts ListOpts) ToObjectDownloadParams() (map[string]string, string, error) {
94 q, err := gophercloud.BuildQueryString(opts)
95 if err != nil {
96 return nil, "", err
97 }
98 h, err := gophercloud.BuildHeaders(opts)
99 if err != nil {
100 return nil, q.String(), err
101 }
102 return h, q.String(), nil
103}
104
Jon Perritt816d2a02014-03-11 20:49:46 -0500105// Download is a function that retrieves the content and metadata for an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500106// To extract just the content, pass the DownloadResult response to the
107// ExtractContent function.
108func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) DownloadResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500109 var res DownloadResult
Jon Perritt8c93a302014-09-28 22:35:57 -0500110
Jon Perrittea4e3012014-10-09 22:03:19 -0500111 url := downloadURL(c, containerName, objectName)
Ash Wilson604320e2014-09-10 16:02:28 -0400112 h := c.Provider.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500113
Jon Perrittde47eac2014-09-30 15:34:17 -0500114 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500115 headers, query, err := opts.ToObjectDownloadParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500116 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500117 res.Err = err
118 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500119 }
120
121 for k, v := range headers {
122 h[k] = v
123 }
124
Jon Perritte90aced2014-10-12 23:24:06 -0500125 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500126 }
127
Jon Perritt816d2a02014-03-11 20:49:46 -0500128 resp, err := perigee.Request("GET", url, perigee.Options{
Jon Perritt816d2a02014-03-11 20:49:46 -0500129 MoreHeaders: h,
Ash Wilsone47ea9e2014-09-10 16:03:44 -0400130 OkCodes: []int{200},
Jon Perritt816d2a02014-03-11 20:49:46 -0500131 })
Ash Wilsonaf262872014-10-20 09:32:29 -0400132 defer resp.HttpResponse.Body.Close()
133 body, err := ioutil.ReadAll(resp.HttpResponse.Body)
134 res.Resp = map[string]interface{}{
135 "body": body,
136 }
Jon Perritt5db08922014-09-30 21:32:48 -0500137 res.Err = err
Ash Wilsonaf262872014-10-20 09:32:29 -0400138 res.Headers = resp.HttpResponse.Header
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"`
153 ContentLength int `h:"Content-Length"`
154 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 var reqBody []byte
191
Jon Perrittea4e3012014-10-09 22:03:19 -0500192 url := createURL(c, containerName, objectName)
Ash Wilson604320e2014-09-10 16:02:28 -0400193 h := c.Provider.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500194
Jon Perrittde47eac2014-09-30 15:34:17 -0500195 if opts != nil {
Jon Perritte90aced2014-10-12 23:24:06 -0500196 headers, query, err := opts.ToObjectCreateParams()
Jon Perrittde47eac2014-09-30 15:34:17 -0500197 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500198 res.Err = err
199 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500200 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500201
Jon Perrittde47eac2014-09-30 15:34:17 -0500202 for k, v := range headers {
203 h[k] = v
204 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500205
Jon Perritte90aced2014-10-12 23:24:06 -0500206 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500207 }
Jon Perritt816d2a02014-03-11 20:49:46 -0500208
Jon Perritt816d2a02014-03-11 20:49:46 -0500209 if content != nil {
Jon Perritt884e0312014-08-14 17:25:38 -0500210 reqBody = make([]byte, 0)
Ash Wilson604320e2014-09-10 16:02:28 -0400211 _, err := content.Read(reqBody)
Jon Perritt816d2a02014-03-11 20:49:46 -0500212 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500213 res.Err = err
214 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500215 }
216 }
217
Jon Perritt5db08922014-09-30 21:32:48 -0500218 resp, err := perigee.Request("PUT", url, perigee.Options{
Jon Perritt816d2a02014-03-11 20:49:46 -0500219 ReqBody: reqBody,
220 MoreHeaders: h,
Ash Wilsone47ea9e2014-09-10 16:03:44 -0400221 OkCodes: []int{201},
Jon Perritt816d2a02014-03-11 20:49:46 -0500222 })
Ash Wilsonaf262872014-10-20 09:32:29 -0400223 res.Headers = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500224 res.Err = err
225 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500226}
227
Jon Perritte90aced2014-10-12 23:24:06 -0500228// CopyOptsBuilder allows extensions to add additional parameters to the
229// Copy request.
230type CopyOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500231 ToObjectCopyMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500232}
233
234// CopyOpts is a structure that holds parameters for copying one object to
235// another.
Jon Perritt8c93a302014-09-28 22:35:57 -0500236type CopyOpts struct {
237 Metadata map[string]string
238 ContentDisposition string `h:"Content-Disposition"`
239 ContentEncoding string `h:"Content-Encoding"`
240 ContentType string `h:"Content-Type"`
241 Destination string `h:"Destination,required"`
242}
243
Jon Perritt04851d32014-10-14 02:07:13 -0500244// ToObjectCopyMap formats a CopyOpts into a map of headers.
245func (opts CopyOpts) ToObjectCopyMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500246 if opts.Destination == "" {
247 return nil, fmt.Errorf("Required CopyOpts field 'Destination' not set.")
248 }
249 h, err := gophercloud.BuildHeaders(opts)
250 if err != nil {
251 return nil, err
252 }
253 for k, v := range opts.Metadata {
254 h["X-Object-Meta-"+k] = v
255 }
256 return h, nil
257}
258
Jon Perritt816d2a02014-03-11 20:49:46 -0500259// Copy is a function that copies one object to another.
Jon Perritte90aced2014-10-12 23:24:06 -0500260func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) CopyResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500261 var res CopyResult
Ash Wilson604320e2014-09-10 16:02:28 -0400262 h := c.Provider.AuthenticatedHeaders()
Jon Perritt816d2a02014-03-11 20:49:46 -0500263
Jon Perritt04851d32014-10-14 02:07:13 -0500264 headers, err := opts.ToObjectCopyMap()
Jon Perritt8c93a302014-09-28 22:35:57 -0500265 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500266 res.Err = err
267 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500268 }
Jon Perritte90aced2014-10-12 23:24:06 -0500269
Jon Perritt8c93a302014-09-28 22:35:57 -0500270 for k, v := range headers {
Jon Perritt816d2a02014-03-11 20:49:46 -0500271 h[k] = v
272 }
273
Jon Perrittea4e3012014-10-09 22:03:19 -0500274 url := copyURL(c, containerName, objectName)
Jon Perritt5db08922014-09-30 21:32:48 -0500275 resp, err := perigee.Request("COPY", url, perigee.Options{
Jon Perritt8c93a302014-09-28 22:35:57 -0500276 MoreHeaders: h,
277 OkCodes: []int{201},
278 })
Ash Wilsonaf262872014-10-20 09:32:29 -0400279 res.Headers = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500280 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500281}
282
Jon Perritte90aced2014-10-12 23:24:06 -0500283// DeleteOptsBuilder allows extensions to add additional parameters to the
284// Delete request.
285type DeleteOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500286 ToObjectDeleteQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500287}
288
Jon Perritt8c93a302014-09-28 22:35:57 -0500289// DeleteOpts is a structure that holds parameters for deleting an object.
290type DeleteOpts struct {
291 MultipartManifest string `q:"multipart-manifest"`
292}
293
Jon Perritt26780d52014-10-14 11:35:58 -0500294// ToObjectDeleteQuery formats a DeleteOpts into a query string.
295func (opts DeleteOpts) ToObjectDeleteQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500296 q, err := gophercloud.BuildQueryString(opts)
297 if err != nil {
298 return "", err
299 }
300 return q.String(), nil
301}
302
Jon Perritt8c93a302014-09-28 22:35:57 -0500303// Delete is a function that deletes an object.
Jon Perritte90aced2014-10-12 23:24:06 -0500304func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) DeleteResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500305 var res DeleteResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500306 url := deleteURL(c, containerName, objectName)
Jon Perritt8c93a302014-09-28 22:35:57 -0500307
Jon Perrittde47eac2014-09-30 15:34:17 -0500308 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500309 query, err := opts.ToObjectDeleteQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500310 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500311 res.Err = err
312 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500313 }
Jon Perritte90aced2014-10-12 23:24:06 -0500314 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500315 }
316
Jon Perritt5db08922014-09-30 21:32:48 -0500317 resp, err := perigee.Request("DELETE", url, perigee.Options{
Jon Perrittde47eac2014-09-30 15:34:17 -0500318 MoreHeaders: c.Provider.AuthenticatedHeaders(),
Jon Perritt8c93a302014-09-28 22:35:57 -0500319 OkCodes: []int{204},
320 })
Ash Wilsonaf262872014-10-20 09:32:29 -0400321 res.Headers = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500322 res.Err = err
323 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500324}
325
Jon Perritte90aced2014-10-12 23:24:06 -0500326// GetOptsBuilder allows extensions to add additional parameters to the
327// Get request.
328type GetOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -0500329 ToObjectGetQuery() (string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500330}
331
Jon Perritt8c93a302014-09-28 22:35:57 -0500332// GetOpts is a structure that holds parameters for getting an object's metadata.
333type GetOpts struct {
334 Expires string `q:"expires"`
335 Signature string `q:"signature"`
336}
337
Jon Perritt26780d52014-10-14 11:35:58 -0500338// ToObjectGetQuery formats a GetOpts into a query string.
339func (opts GetOpts) ToObjectGetQuery() (string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500340 q, err := gophercloud.BuildQueryString(opts)
341 if err != nil {
342 return "", err
343 }
344 return q.String(), nil
345}
346
Jon Perritt8c93a302014-09-28 22:35:57 -0500347// Get is a function that retrieves the metadata of an object. To extract just the custom
348// metadata, pass the GetResult response to the ExtractMetadata function.
Jon Perritte90aced2014-10-12 23:24:06 -0500349func Get(c *gophercloud.ServiceClient, containerName, objectName string, opts GetOptsBuilder) GetResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500350 var res GetResult
Jon Perrittea4e3012014-10-09 22:03:19 -0500351 url := getURL(c, containerName, objectName)
Jon Perrittde47eac2014-09-30 15:34:17 -0500352
353 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -0500354 query, err := opts.ToObjectGetQuery()
Jon Perrittde47eac2014-09-30 15:34:17 -0500355 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500356 res.Err = err
357 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500358 }
Jon Perritte90aced2014-10-12 23:24:06 -0500359 url += query
Jon Perritt8c93a302014-09-28 22:35:57 -0500360 }
361
Jon Perritt8c93a302014-09-28 22:35:57 -0500362 resp, err := perigee.Request("HEAD", url, perigee.Options{
363 MoreHeaders: c.Provider.AuthenticatedHeaders(),
364 OkCodes: []int{200, 204},
365 })
Ash Wilsonaf262872014-10-20 09:32:29 -0400366 res.Headers = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500367 res.Err = err
Jon Perritt5db08922014-09-30 21:32:48 -0500368 return res
Jon Perritt8c93a302014-09-28 22:35:57 -0500369}
370
Jon Perritte90aced2014-10-12 23:24:06 -0500371// UpdateOptsBuilder allows extensions to add additional parameters to the
372// Update request.
373type UpdateOptsBuilder interface {
Jon Perritt04851d32014-10-14 02:07:13 -0500374 ToObjectUpdateMap() (map[string]string, error)
Jon Perritte90aced2014-10-12 23:24:06 -0500375}
376
Jon Perritt8c93a302014-09-28 22:35:57 -0500377// UpdateOpts is a structure that holds parameters for updating, creating, or deleting an
378// object's metadata.
379type UpdateOpts struct {
380 Metadata map[string]string
381 ContentDisposition string `h:"Content-Disposition"`
382 ContentEncoding string `h:"Content-Encoding"`
383 ContentType string `h:"Content-Type"`
384 DeleteAfter int `h:"X-Delete-After"`
385 DeleteAt int `h:"X-Delete-At"`
386 DetectContentType bool `h:"X-Detect-Content-Type"`
387}
388
Jon Perritt04851d32014-10-14 02:07:13 -0500389// ToObjectUpdateMap formats a UpdateOpts into a map of headers.
390func (opts UpdateOpts) ToObjectUpdateMap() (map[string]string, error) {
Jon Perritte90aced2014-10-12 23:24:06 -0500391 h, err := gophercloud.BuildHeaders(opts)
392 if err != nil {
393 return nil, err
394 }
395 for k, v := range opts.Metadata {
396 h["X-Object-Meta-"+k] = v
397 }
398 return h, nil
399}
400
Jon Perritt8c93a302014-09-28 22:35:57 -0500401// Update is a function that creates, updates, or deletes an object's metadata.
Jon Perritte90aced2014-10-12 23:24:06 -0500402func Update(c *gophercloud.ServiceClient, containerName, objectName string, opts UpdateOptsBuilder) UpdateResult {
Jon Perritt5db08922014-09-30 21:32:48 -0500403 var res UpdateResult
Jon Perritt8c93a302014-09-28 22:35:57 -0500404 h := c.Provider.AuthenticatedHeaders()
405
Jon Perrittde47eac2014-09-30 15:34:17 -0500406 if opts != nil {
Jon Perritt04851d32014-10-14 02:07:13 -0500407 headers, err := opts.ToObjectUpdateMap()
Jon Perrittde47eac2014-09-30 15:34:17 -0500408 if err != nil {
Jon Perritt5db08922014-09-30 21:32:48 -0500409 res.Err = err
410 return res
Jon Perrittde47eac2014-09-30 15:34:17 -0500411 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500412
Jon Perrittde47eac2014-09-30 15:34:17 -0500413 for k, v := range headers {
414 h[k] = v
415 }
Jon Perritt8c93a302014-09-28 22:35:57 -0500416 }
417
Jon Perrittea4e3012014-10-09 22:03:19 -0500418 url := updateURL(c, containerName, objectName)
Jon Perritt5db08922014-09-30 21:32:48 -0500419 resp, err := perigee.Request("POST", url, perigee.Options{
Jon Perritt816d2a02014-03-11 20:49:46 -0500420 MoreHeaders: h,
Ash Wilsone47ea9e2014-09-10 16:03:44 -0400421 OkCodes: []int{202},
Jon Perritt816d2a02014-03-11 20:49:46 -0500422 })
Ash Wilsonaf262872014-10-20 09:32:29 -0400423 res.Headers = resp.HttpResponse.Header
Jon Perritt5db08922014-09-30 21:32:48 -0500424 res.Err = err
425 return res
Jon Perritt816d2a02014-03-11 20:49:46 -0500426}