123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- package objects
- import (
- "bytes"
- "crypto/hmac"
- "crypto/md5"
- "crypto/sha1"
- "fmt"
- "io"
- "strings"
- "time"
- "devel.mephi.ru/iacherepanov/openstack-gophercloud"
- "devel.mephi.ru/iacherepanov/openstack-gophercloud/openstack/objectstorage/v1/accounts"
- "devel.mephi.ru/iacherepanov/openstack-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 is a true/false value that represents the amount of object information
- // returned. If Full is set to true, then the content-type, number of bytes,
- // hash date last modified, and name are returned. If set to false or not set,
- // then only the object names are returned.
- 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)
- return opts.Full, q.String(), err
- }
- // 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 {
- return pagination.Pager{Err: err}
- }
- url += query
- if full {
- headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"}
- }
- }
- pager := pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
- p := ObjectPage{pagination.MarkerPageBase{PageResult: r}}
- p.MarkerPageBase.Owner = p
- return p
- })
- 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 DownloadOpts) 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) (r DownloadResult) {
- url := downloadURL(c, containerName, objectName)
- h := make(map[string]string)
- if opts != nil {
- headers, query, err := opts.ToObjectDownloadParams()
- if err != nil {
- r.Err = err
- return
- }
- for k, v := range headers {
- h[k] = v
- }
- url += query
- }
- resp, err := c.Get(url, nil, &gophercloud.RequestOpts{
- MoreHeaders: h,
- OkCodes: []int{200, 304},
- })
- if resp != nil {
- r.Header = resp.Header
- r.Body = resp.Body
- }
- r.Err = err
- return
- }
- // CreateOptsBuilder allows extensions to add additional parameters to the
- // Create request.
- type CreateOptsBuilder interface {
- ToObjectCreateParams() (io.Reader, map[string]string, string, error)
- }
- // CreateOpts is a structure that holds parameters for creating an object.
- type CreateOpts struct {
- Content io.Reader
- Metadata map[string]string
- NoETag bool
- CacheControl string `h:"Cache-Control"`
- ContentDisposition string `h:"Content-Disposition"`
- ContentEncoding string `h:"Content-Encoding"`
- ContentLength int64 `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:"multipart-manifest"`
- Signature string `q:"signature"`
- }
- // ToObjectCreateParams formats a CreateOpts into a query string and map of
- // headers.
- func (opts CreateOpts) ToObjectCreateParams() (io.Reader, map[string]string, string, error) {
- q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return nil, nil, "", err
- }
- h, err := gophercloud.BuildHeaders(opts)
- if err != nil {
- return nil, nil, "", err
- }
- for k, v := range opts.Metadata {
- h["X-Object-Meta-"+k] = v
- }
- if opts.NoETag {
- delete(h, "etag")
- return opts.Content, h, q.String(), nil
- }
- if h["ETag"] != "" {
- return opts.Content, h, q.String(), nil
- }
- hash := md5.New()
- buf := bytes.NewBuffer([]byte{})
- _, err = io.Copy(io.MultiWriter(hash, buf), opts.Content)
- if err != nil {
- return nil, nil, "", err
- }
- localChecksum := fmt.Sprintf("%x", hash.Sum(nil))
- h["ETag"] = localChecksum
- return buf, h, q.String(), nil
- }
- // Create is a function that creates a new object or replaces an existing
- // object. If the returned response's ETag header fails to match the local
- // checksum, the failed request will automatically be retried up to a maximum
- // of 3 times.
- func Create(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateOptsBuilder) (r CreateResult) {
- url := createURL(c, containerName, objectName)
- h := make(map[string]string)
- var b io.Reader
- if opts != nil {
- tmpB, headers, query, err := opts.ToObjectCreateParams()
- if err != nil {
- r.Err = err
- return
- }
- for k, v := range headers {
- h[k] = v
- }
- url += query
- b = tmpB
- }
- resp, err := c.Put(url, nil, nil, &gophercloud.RequestOpts{
- RawBody: b,
- MoreHeaders: h,
- })
- r.Err = err
- if resp != nil {
- r.Header = resp.Header
- }
- return
- }
- // 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:"true"`
- }
- // ToObjectCopyMap formats a CopyOpts into a map of headers.
- func (opts CopyOpts) ToObjectCopyMap() (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
- }
- // Copy is a function that copies one object to another.
- func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) (r CopyResult) {
- h := make(map[string]string)
- headers, err := opts.ToObjectCopyMap()
- if err != nil {
- r.Err = err
- return
- }
- for k, v := range headers {
- h[k] = v
- }
- url := copyURL(c, containerName, objectName)
- resp, err := c.Request("COPY", url, &gophercloud.RequestOpts{
- MoreHeaders: h,
- OkCodes: []int{201},
- })
- if resp != nil {
- r.Header = resp.Header
- }
- r.Err = err
- return
- }
- // 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)
- return q.String(), err
- }
- // Delete is a function that deletes an object.
- func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) (r DeleteResult) {
- url := deleteURL(c, containerName, objectName)
- if opts != nil {
- query, err := opts.ToObjectDeleteQuery()
- if err != nil {
- r.Err = err
- return
- }
- url += query
- }
- resp, err := c.Delete(url, nil)
- if resp != nil {
- r.Header = resp.Header
- }
- r.Err = err
- return
- }
- // 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)
- return q.String(), err
- }
- // 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) (r GetResult) {
- url := getURL(c, containerName, objectName)
- if opts != nil {
- query, err := opts.ToObjectGetQuery()
- if err != nil {
- r.Err = err
- return
- }
- url += query
- }
- resp, err := c.Head(url, &gophercloud.RequestOpts{
- OkCodes: []int{200, 204},
- })
- if resp != nil {
- r.Header = resp.Header
- }
- r.Err = err
- return
- }
- // 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) (r UpdateResult) {
- h := make(map[string]string)
- if opts != nil {
- headers, err := opts.ToObjectUpdateMap()
- if err != nil {
- r.Err = err
- return
- }
- for k, v := range headers {
- h[k] = v
- }
- }
- url := updateURL(c, containerName, objectName)
- resp, err := c.Post(url, nil, nil, &gophercloud.RequestOpts{
- MoreHeaders: h,
- })
- if resp != nil {
- r.Header = resp.Header
- }
- r.Err = err
- return
- }
- // HTTPMethod represents an HTTP method string (e.g. "GET").
- type HTTPMethod string
- var (
- // GET represents an HTTP "GET" method.
- GET HTTPMethod = "GET"
- // POST represents an HTTP "POST" method.
- POST HTTPMethod = "POST"
- )
- // CreateTempURLOpts are options for creating a temporary URL for an object.
- type CreateTempURLOpts struct {
- // (REQUIRED) Method is the HTTP method to allow for users of the temp URL.
- // Valid values are "GET" and "POST".
- Method HTTPMethod
- // (REQUIRED) TTL is the number of seconds the temp URL should be active.
- TTL int
- // (Optional) Split is the string on which to split the object URL. Since only
- // the object path is used in the hash, the object URL needs to be parsed. If
- // empty, the default OpenStack URL split point will be used ("/v1/").
- Split string
- }
- // CreateTempURL is a function for creating a temporary URL for an object. It
- // allows users to have "GET" or "POST" access to a particular tenant's object
- // for a limited amount of time.
- func CreateTempURL(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateTempURLOpts) (string, error) {
- if opts.Split == "" {
- opts.Split = "/v1/"
- }
- duration := time.Duration(opts.TTL) * time.Second
- expiry := time.Now().Add(duration).Unix()
- getHeader, err := accounts.Get(c, nil).Extract()
- if err != nil {
- return "", err
- }
- secretKey := []byte(getHeader.TempURLKey)
- url := getURL(c, containerName, objectName)
- splitPath := strings.Split(url, opts.Split)
- baseURL, objectPath := splitPath[0], splitPath[1]
- objectPath = opts.Split + objectPath
- body := fmt.Sprintf("%s\n%d\n%s", opts.Method, expiry, objectPath)
- hash := hmac.New(sha1.New, secretKey)
- hash.Write([]byte(body))
- hexsum := fmt.Sprintf("%x", hash.Sum(nil))
- return fmt.Sprintf("%s%s?temp_url_sig=%s&temp_url_expires=%d", baseURL, objectPath, hexsum, expiry), nil
- }
|