|  | package objects | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "io" | 
|  | "time" | 
|  |  | 
|  | "github.com/racker/perigee" | 
|  | "github.com/rackspace/gophercloud" | 
|  | "github.com/rackspace/gophercloud/pagination" | 
|  | ) | 
|  |  | 
|  | // ListOptsBuilder allows extensions to add additional parameters to the List | 
|  | // request. | 
|  | type ListOptsBuilder interface { | 
|  | ToObjectListParams() (bool, string, error) | 
|  | } | 
|  |  | 
|  | // ListOpts is a structure that holds parameters for listing objects. | 
|  | type ListOpts struct { | 
|  | Full      bool | 
|  | Limit     int    `q:"limit"` | 
|  | Marker    string `q:"marker"` | 
|  | EndMarker string `q:"end_marker"` | 
|  | Format    string `q:"format"` | 
|  | Prefix    string `q:"prefix"` | 
|  | Delimiter string `q:"delimiter"` | 
|  | Path      string `q:"path"` | 
|  | } | 
|  |  | 
|  | // ToObjectListParams formats a ListOpts into a query string and boolean | 
|  | // representing whether to list complete information for each object. | 
|  | func (opts ListOpts) ToObjectListParams() (bool, string, error) { | 
|  | q, err := gophercloud.BuildQueryString(opts) | 
|  | if err != nil { | 
|  | return false, "", err | 
|  | } | 
|  | return opts.Full, q.String(), nil | 
|  | } | 
|  |  | 
|  | // List is a function that retrieves all objects in a container. It also returns the details | 
|  | // for the container. To extract only the object information or names, pass the ListResult | 
|  | // response to the ExtractInfo or ExtractNames function, respectively. | 
|  | func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager { | 
|  | headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"} | 
|  |  | 
|  | url := listURL(c, containerName) | 
|  | if opts != nil { | 
|  | full, query, err := opts.ToObjectListParams() | 
|  | if err != nil { | 
|  | fmt.Printf("Error building query string: %v", err) | 
|  | return pagination.Pager{Err: err} | 
|  | } | 
|  | url += query | 
|  |  | 
|  | if full { | 
|  | headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"} | 
|  | } | 
|  | } | 
|  |  | 
|  | createPage := func(r pagination.LastHTTPResponse) pagination.Page { | 
|  | p := ObjectPage{pagination.MarkerPageBase{LastHTTPResponse: r}} | 
|  | p.MarkerPageBase.Owner = p | 
|  | return p | 
|  | } | 
|  |  | 
|  | pager := pagination.NewPager(c, url, createPage) | 
|  | pager.Headers = headers | 
|  | return pager | 
|  | } | 
|  |  | 
|  | // DownloadOptsBuilder allows extensions to add additional parameters to the | 
|  | // Download request. | 
|  | type DownloadOptsBuilder interface { | 
|  | ToObjectDownloadParams() (map[string]string, string, error) | 
|  | } | 
|  |  | 
|  | // DownloadOpts is a structure that holds parameters for downloading an object. | 
|  | type DownloadOpts struct { | 
|  | IfMatch           string    `h:"If-Match"` | 
|  | IfModifiedSince   time.Time `h:"If-Modified-Since"` | 
|  | IfNoneMatch       string    `h:"If-None-Match"` | 
|  | IfUnmodifiedSince time.Time `h:"If-Unmodified-Since"` | 
|  | Range             string    `h:"Range"` | 
|  | Expires           string    `q:"expires"` | 
|  | MultipartManifest string    `q:"multipart-manifest"` | 
|  | Signature         string    `q:"signature"` | 
|  | } | 
|  |  | 
|  | // ToObjectDownloadParams formats a DownloadOpts into a query string and map of | 
|  | // headers. | 
|  | func (opts ListOpts) ToObjectDownloadParams() (map[string]string, string, error) { | 
|  | q, err := gophercloud.BuildQueryString(opts) | 
|  | if err != nil { | 
|  | return nil, "", err | 
|  | } | 
|  | h, err := gophercloud.BuildHeaders(opts) | 
|  | if err != nil { | 
|  | return nil, q.String(), err | 
|  | } | 
|  | return h, q.String(), nil | 
|  | } | 
|  |  | 
|  | // Download is a function that retrieves the content and metadata for an object. | 
|  | // To extract just the content, pass the DownloadResult response to the | 
|  | // ExtractContent function. | 
|  | func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) DownloadResult { | 
|  | var res DownloadResult | 
|  |  | 
|  | url := downloadURL(c, containerName, objectName) | 
|  | h := c.Provider.AuthenticatedHeaders() | 
|  |  | 
|  | if opts != nil { | 
|  | headers, query, err := opts.ToObjectDownloadParams() | 
|  | if err != nil { | 
|  | res.Err = err | 
|  | return res | 
|  | } | 
|  |  | 
|  | for k, v := range headers { | 
|  | h[k] = v | 
|  | } | 
|  |  | 
|  | url += query | 
|  | } | 
|  |  | 
|  | resp, err := perigee.Request("GET", url, perigee.Options{ | 
|  | MoreHeaders: h, | 
|  | OkCodes:     []int{200}, | 
|  | }) | 
|  | res.Err = err | 
|  | res.Resp = &resp.HttpResponse | 
|  | return res | 
|  | } | 
|  |  | 
|  | // CreateOptsBuilder allows extensions to add additional parameters to the | 
|  | // Create request. | 
|  | type CreateOptsBuilder interface { | 
|  | ToObjectCreateParams() (map[string]string, string, error) | 
|  | } | 
|  |  | 
|  | // CreateOpts is a structure that holds parameters for creating an object. | 
|  | type CreateOpts struct { | 
|  | Metadata           map[string]string | 
|  | ContentDisposition string `h:"Content-Disposition"` | 
|  | ContentEncoding    string `h:"Content-Encoding"` | 
|  | ContentLength      int    `h:"Content-Length"` | 
|  | ContentType        string `h:"Content-Type"` | 
|  | CopyFrom           string `h:"X-Copy-From"` | 
|  | DeleteAfter        int    `h:"X-Delete-After"` | 
|  | DeleteAt           int    `h:"X-Delete-At"` | 
|  | DetectContentType  string `h:"X-Detect-Content-Type"` | 
|  | ETag               string `h:"ETag"` | 
|  | IfNoneMatch        string `h:"If-None-Match"` | 
|  | ObjectManifest     string `h:"X-Object-Manifest"` | 
|  | TransferEncoding   string `h:"Transfer-Encoding"` | 
|  | Expires            string `q:"expires"` | 
|  | MultipartManifest  string `q:"multiple-manifest"` | 
|  | Signature          string `q:"signature"` | 
|  | } | 
|  |  | 
|  | // ToObjectCreateParams formats a CreateOpts into a query string and map of | 
|  | // headers. | 
|  | func (opts CreateOpts) ToObjectCreateParams() (map[string]string, string, error) { | 
|  | q, err := gophercloud.BuildQueryString(opts) | 
|  | if err != nil { | 
|  | return nil, "", err | 
|  | } | 
|  | h, err := gophercloud.BuildHeaders(opts) | 
|  | if err != nil { | 
|  | return nil, q.String(), err | 
|  | } | 
|  |  | 
|  | for k, v := range opts.Metadata { | 
|  | h["X-Object-Meta-"+k] = v | 
|  | } | 
|  |  | 
|  | return h, q.String(), nil | 
|  | } | 
|  |  | 
|  | // Create is a function that creates a new object or replaces an existing object. | 
|  | func Create(c *gophercloud.ServiceClient, containerName, objectName string, content io.Reader, opts CreateOptsBuilder) CreateResult { | 
|  | var res CreateResult | 
|  | var reqBody []byte | 
|  |  | 
|  | url := createURL(c, containerName, objectName) | 
|  | h := c.Provider.AuthenticatedHeaders() | 
|  |  | 
|  | if opts != nil { | 
|  | headers, query, err := opts.ToObjectCreateParams() | 
|  | if err != nil { | 
|  | res.Err = err | 
|  | return res | 
|  | } | 
|  |  | 
|  | for k, v := range headers { | 
|  | h[k] = v | 
|  | } | 
|  |  | 
|  | url += query | 
|  | } | 
|  |  | 
|  | if content != nil { | 
|  | reqBody = make([]byte, 0) | 
|  | _, err := content.Read(reqBody) | 
|  | if err != nil { | 
|  | res.Err = err | 
|  | return res | 
|  | } | 
|  | } | 
|  |  | 
|  | resp, err := perigee.Request("PUT", url, perigee.Options{ | 
|  | ReqBody:     reqBody, | 
|  | MoreHeaders: h, | 
|  | OkCodes:     []int{201}, | 
|  | }) | 
|  | res.Resp = &resp.HttpResponse | 
|  | res.Err = err | 
|  | return res | 
|  | } | 
|  |  | 
|  | // CopyOptsBuilder allows extensions to add additional parameters to the | 
|  | // Copy request. | 
|  | type CopyOptsBuilder interface { | 
|  | ToObjectCopyMap() (map[string]string, error) | 
|  | } | 
|  |  | 
|  | // CopyOpts is a structure that holds parameters for copying one object to | 
|  | // another. | 
|  | type CopyOpts struct { | 
|  | Metadata           map[string]string | 
|  | ContentDisposition string `h:"Content-Disposition"` | 
|  | ContentEncoding    string `h:"Content-Encoding"` | 
|  | ContentType        string `h:"Content-Type"` | 
|  | Destination        string `h:"Destination,required"` | 
|  | } | 
|  |  | 
|  | // ToObjectCopyMap formats a CopyOpts into a map of headers. | 
|  | func (opts CopyOpts) ToObjectCopyMap() (map[string]string, error) { | 
|  | if opts.Destination == "" { | 
|  | return nil, fmt.Errorf("Required CopyOpts field 'Destination' not set.") | 
|  | } | 
|  | h, err := gophercloud.BuildHeaders(opts) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | for k, v := range opts.Metadata { | 
|  | h["X-Object-Meta-"+k] = v | 
|  | } | 
|  | return h, nil | 
|  | } | 
|  |  | 
|  | // Copy is a function that copies one object to another. | 
|  | func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) CopyResult { | 
|  | var res CopyResult | 
|  | h := c.Provider.AuthenticatedHeaders() | 
|  |  | 
|  | headers, err := opts.ToObjectCopyMap() | 
|  | if err != nil { | 
|  | res.Err = err | 
|  | return res | 
|  | } | 
|  |  | 
|  | for k, v := range headers { | 
|  | h[k] = v | 
|  | } | 
|  |  | 
|  | url := copyURL(c, containerName, objectName) | 
|  | resp, err := perigee.Request("COPY", url, perigee.Options{ | 
|  | MoreHeaders: h, | 
|  | OkCodes:     []int{201}, | 
|  | }) | 
|  | res.Resp = &resp.HttpResponse | 
|  | return res | 
|  | } | 
|  |  | 
|  | // DeleteOptsBuilder allows extensions to add additional parameters to the | 
|  | // Delete request. | 
|  | type DeleteOptsBuilder interface { | 
|  | ToObjectDeleteQuery() (string, error) | 
|  | } | 
|  |  | 
|  | // DeleteOpts is a structure that holds parameters for deleting an object. | 
|  | type DeleteOpts struct { | 
|  | MultipartManifest string `q:"multipart-manifest"` | 
|  | } | 
|  |  | 
|  | // ToObjectDeleteQuery formats a DeleteOpts into a query string. | 
|  | func (opts DeleteOpts) ToObjectDeleteQuery() (string, error) { | 
|  | q, err := gophercloud.BuildQueryString(opts) | 
|  | if err != nil { | 
|  | return "", err | 
|  | } | 
|  | return q.String(), nil | 
|  | } | 
|  |  | 
|  | // Delete is a function that deletes an object. | 
|  | func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) DeleteResult { | 
|  | var res DeleteResult | 
|  | url := deleteURL(c, containerName, objectName) | 
|  |  | 
|  | if opts != nil { | 
|  | query, err := opts.ToObjectDeleteQuery() | 
|  | if err != nil { | 
|  | res.Err = err | 
|  | return res | 
|  | } | 
|  | url += query | 
|  | } | 
|  |  | 
|  | resp, err := perigee.Request("DELETE", url, perigee.Options{ | 
|  | MoreHeaders: c.Provider.AuthenticatedHeaders(), | 
|  | OkCodes:     []int{204}, | 
|  | }) | 
|  | res.Resp = &resp.HttpResponse | 
|  | res.Err = err | 
|  | return res | 
|  | } | 
|  |  | 
|  | // GetOptsBuilder allows extensions to add additional parameters to the | 
|  | // Get request. | 
|  | type GetOptsBuilder interface { | 
|  | ToObjectGetQuery() (string, error) | 
|  | } | 
|  |  | 
|  | // GetOpts is a structure that holds parameters for getting an object's metadata. | 
|  | type GetOpts struct { | 
|  | Expires   string `q:"expires"` | 
|  | Signature string `q:"signature"` | 
|  | } | 
|  |  | 
|  | // ToObjectGetQuery formats a GetOpts into a query string. | 
|  | func (opts GetOpts) ToObjectGetQuery() (string, error) { | 
|  | q, err := gophercloud.BuildQueryString(opts) | 
|  | if err != nil { | 
|  | return "", err | 
|  | } | 
|  | return q.String(), nil | 
|  | } | 
|  |  | 
|  | // Get is a function that retrieves the metadata of an object. To extract just the custom | 
|  | // metadata, pass the GetResult response to the ExtractMetadata function. | 
|  | func Get(c *gophercloud.ServiceClient, containerName, objectName string, opts GetOptsBuilder) GetResult { | 
|  | var res GetResult | 
|  | url := getURL(c, containerName, objectName) | 
|  |  | 
|  | if opts != nil { | 
|  | query, err := opts.ToObjectGetQuery() | 
|  | if err != nil { | 
|  | res.Err = err | 
|  | return res | 
|  | } | 
|  | url += query | 
|  | } | 
|  |  | 
|  | resp, err := perigee.Request("HEAD", url, perigee.Options{ | 
|  | MoreHeaders: c.Provider.AuthenticatedHeaders(), | 
|  | OkCodes:     []int{200, 204}, | 
|  | }) | 
|  | res.Err = err | 
|  | res.Resp = &resp.HttpResponse | 
|  | return res | 
|  | } | 
|  |  | 
|  | // UpdateOptsBuilder allows extensions to add additional parameters to the | 
|  | // Update request. | 
|  | type UpdateOptsBuilder interface { | 
|  | ToObjectUpdateMap() (map[string]string, error) | 
|  | } | 
|  |  | 
|  | // UpdateOpts is a structure that holds parameters for updating, creating, or deleting an | 
|  | // object's metadata. | 
|  | type UpdateOpts struct { | 
|  | Metadata           map[string]string | 
|  | ContentDisposition string `h:"Content-Disposition"` | 
|  | ContentEncoding    string `h:"Content-Encoding"` | 
|  | ContentType        string `h:"Content-Type"` | 
|  | DeleteAfter        int    `h:"X-Delete-After"` | 
|  | DeleteAt           int    `h:"X-Delete-At"` | 
|  | DetectContentType  bool   `h:"X-Detect-Content-Type"` | 
|  | } | 
|  |  | 
|  | // ToObjectUpdateMap formats a UpdateOpts into a map of headers. | 
|  | func (opts UpdateOpts) ToObjectUpdateMap() (map[string]string, error) { | 
|  | h, err := gophercloud.BuildHeaders(opts) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | for k, v := range opts.Metadata { | 
|  | h["X-Object-Meta-"+k] = v | 
|  | } | 
|  | return h, nil | 
|  | } | 
|  |  | 
|  | // Update is a function that creates, updates, or deletes an object's metadata. | 
|  | func Update(c *gophercloud.ServiceClient, containerName, objectName string, opts UpdateOptsBuilder) UpdateResult { | 
|  | var res UpdateResult | 
|  | h := c.Provider.AuthenticatedHeaders() | 
|  |  | 
|  | if opts != nil { | 
|  | headers, err := opts.ToObjectUpdateMap() | 
|  | if err != nil { | 
|  | res.Err = err | 
|  | return res | 
|  | } | 
|  |  | 
|  | for k, v := range headers { | 
|  | h[k] = v | 
|  | } | 
|  | } | 
|  |  | 
|  | url := updateURL(c, containerName, objectName) | 
|  | resp, err := perigee.Request("POST", url, perigee.Options{ | 
|  | MoreHeaders: h, | 
|  | OkCodes:     []int{202}, | 
|  | }) | 
|  | res.Resp = &resp.HttpResponse | 
|  | res.Err = err | 
|  | return res | 
|  | } |