blob: c0d532beba639627e958a67174900a0bac864038 [file] [log] [blame]
Jon Perritt8c93a302014-09-28 22:35:57 -05001package objects
2
3import (
4 "fmt"
Jamie Hannaford2e784862014-10-27 10:40:27 +01005 "io"
6 "io/ioutil"
Jon Perritt8c93a302014-09-28 22:35:57 -05007 "strings"
8
Jon Perritt27249f42016-02-18 10:35:59 -06009 "github.com/gophercloud/gophercloud"
10 "github.com/gophercloud/gophercloud/pagination"
Jon Perritt8c93a302014-09-28 22:35:57 -050011)
12
13// Object is a structure that holds information related to a storage object.
Jon Perritt8aa40262014-09-29 15:41:32 -050014type Object struct {
Jon Perritt9415ca72014-11-03 11:58:48 -060015 // Bytes is the total number of bytes that comprise the object.
Jon Perritt3c166472016-02-25 03:07:41 -060016 Bytes int64 `json:"bytes"`
Jon Perritt9415ca72014-11-03 11:58:48 -060017
18 // ContentType is the content type of the object.
Jon Perritt3c166472016-02-25 03:07:41 -060019 ContentType string `json:"content_type"`
Jon Perritt9415ca72014-11-03 11:58:48 -060020
21 // Hash represents the MD5 checksum value of the object's content.
Jon Perritt3c166472016-02-25 03:07:41 -060022 Hash string `json:"hash"`
Jon Perritt9415ca72014-11-03 11:58:48 -060023
24 // LastModified is the RFC3339Milli time the object was last modified, represented
25 // as a string. For any given object (obj), this value may be parsed to a time.Time:
26 // lastModified, err := time.Parse(gophercloud.RFC3339Milli, obj.LastModified)
Jon Perritt3c166472016-02-25 03:07:41 -060027 LastModified string `json:"last_modified"`
Jon Perritt9415ca72014-11-03 11:58:48 -060028
29 // Name is the unique name for the object.
Jon Perritt3c166472016-02-25 03:07:41 -060030 Name string `json:"name"`
Jon Perritt8aa40262014-09-29 15:41:32 -050031}
Jon Perritt8c93a302014-09-28 22:35:57 -050032
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +020033// ObjectPage is a single page of objects that is returned from a call to the
34// List function.
Jon Perritt8c93a302014-09-28 22:35:57 -050035type ObjectPage struct {
36 pagination.MarkerPageBase
37}
38
39// IsEmpty returns true if a ListResult contains no object names.
40func (r ObjectPage) IsEmpty() (bool, error) {
41 names, err := ExtractNames(r)
Jon Perritt3c166472016-02-25 03:07:41 -060042 return len(names) == 0, err
Jon Perritt8c93a302014-09-28 22:35:57 -050043}
44
45// LastMarker returns the last object name in a ListResult.
46func (r ObjectPage) LastMarker() (string, error) {
47 names, err := ExtractNames(r)
48 if err != nil {
49 return "", err
50 }
51 if len(names) == 0 {
52 return "", nil
53 }
54 return names[len(names)-1], nil
55}
56
Jon Perritt8c93a302014-09-28 22:35:57 -050057// ExtractInfo is a function that takes a page of objects and returns their full information.
Jon Perritt3c166472016-02-25 03:07:41 -060058func ExtractInfo(r pagination.Page) ([]Object, error) {
59 var s []Object
60 err := (r.(ObjectPage)).ExtractInto(&s)
61 return s, err
Jon Perritt8c93a302014-09-28 22:35:57 -050062}
63
64// ExtractNames is a function that takes a page of objects and returns only their names.
Jon Perritt3c166472016-02-25 03:07:41 -060065func ExtractNames(r pagination.Page) ([]string, error) {
66 casted := r.(ObjectPage)
Ash Wilson72e4d2c2014-10-20 10:27:30 -040067 ct := casted.Header.Get("Content-Type")
Jon Perritt8c93a302014-09-28 22:35:57 -050068 switch {
69 case strings.HasPrefix(ct, "application/json"):
Jon Perritt3c166472016-02-25 03:07:41 -060070 parsed, err := ExtractInfo(r)
Jon Perritt8c93a302014-09-28 22:35:57 -050071 if err != nil {
72 return nil, err
73 }
74
75 names := make([]string, 0, len(parsed))
76 for _, object := range parsed {
Jon Perritt8aa40262014-09-29 15:41:32 -050077 names = append(names, object.Name)
Jon Perritt8c93a302014-09-28 22:35:57 -050078 }
Jon Perrittfdac6e52014-09-29 19:43:45 -050079
Jon Perritt8c93a302014-09-28 22:35:57 -050080 return names, nil
81 case strings.HasPrefix(ct, "text/plain"):
82 names := make([]string, 0, 50)
83
Jon Perritt3c166472016-02-25 03:07:41 -060084 body := string(r.(ObjectPage).Body.([]uint8))
Jon Perritt8c93a302014-09-28 22:35:57 -050085 for _, name := range strings.Split(body, "\n") {
86 if len(name) > 0 {
87 names = append(names, name)
88 }
89 }
90
91 return names, nil
Jon Perrittfdac6e52014-09-29 19:43:45 -050092 case strings.HasPrefix(ct, "text/html"):
93 return []string{}, nil
Jon Perritt8c93a302014-09-28 22:35:57 -050094 default:
95 return nil, fmt.Errorf("Cannot extract names from response with content-type: [%s]", ct)
96 }
97}
98
Jon Perritt8c31b2a2014-12-03 10:21:11 -070099// DownloadHeader represents the headers returned in the response from a Download request.
100type DownloadHeader struct {
Jon Perritt3c166472016-02-25 03:07:41 -0600101 AcceptRanges string `json:"Accept-Ranges"`
102 ContentDisposition string `json:"Content-Disposition"`
103 ContentEncoding string `json:"Content-Encoding"`
104 ContentLength string `json:"Content-Length"`
105 ContentType string `json:"Content-Type"`
106 Date gophercloud.JSONRFC1123 `json:"Date"`
107 DeleteAt gophercloud.JSONUnix `json:"X-Delete-At"`
108 ETag string `json:"Etag"`
109 LastModified gophercloud.JSONRFC1123 `json:"Last-Modified"`
110 ObjectManifest string `json:"X-Object-Manifest"`
111 StaticLargeObject bool `json:"X-Static-Large-Object"`
112 TransID string `json:"X-Trans-Id"`
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700113}
114
Jon Perritt5db08922014-09-30 21:32:48 -0500115// DownloadResult is a *http.Response that is returned from a call to the Download function.
116type DownloadResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500117 gophercloud.HeaderResult
Jamie Hannafordee115552014-10-27 16:11:05 +0100118 Body io.ReadCloser
Jon Perritt5db08922014-09-30 21:32:48 -0500119}
120
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700121// Extract will return a struct of headers returned from a call to Download. To obtain
122// a map of headers, call the ExtractHeader method on the DownloadResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600123func (r DownloadResult) Extract() (*DownloadHeader, error) {
124 var s *DownloadHeader
125 err := r.ExtractInto(&s)
126 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700127}
128
Jamie Hannaford2e784862014-10-27 10:40:27 +0100129// ExtractContent is a function that takes a DownloadResult's io.Reader body
130// and reads all available data into a slice of bytes. Please be aware that due
131// the nature of io.Reader is forward-only - meaning that it can only be read
132// once and not rewound. You can recreate a reader from the output of this
133// function by using bytes.NewReader(downloadBytes)
Jon Perritt3c166472016-02-25 03:07:41 -0600134func (r *DownloadResult) ExtractContent() ([]byte, error) {
135 if r.Err != nil {
136 return nil, r.Err
Jon Perritt8c93a302014-09-28 22:35:57 -0500137 }
Jon Perritt3c166472016-02-25 03:07:41 -0600138 defer r.Body.Close()
139 body, err := ioutil.ReadAll(r.Body)
Jamie Hannaford2e784862014-10-27 10:40:27 +0100140 if err != nil {
141 return nil, err
142 }
Jon Perritt3c166472016-02-25 03:07:41 -0600143 r.Body.Close()
Jamie Hannaford2e784862014-10-27 10:40:27 +0100144 return body, nil
Jon Perritt8c93a302014-09-28 22:35:57 -0500145}
146
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700147// GetHeader represents the headers returned in the response from a Get request.
148type GetHeader struct {
Jon Perritt3c166472016-02-25 03:07:41 -0600149 ContentDisposition string `json:"Content-Disposition"`
150 ContentEncoding string `json:"Content-Encoding"`
151 ContentLength string `json:"Content-Length"`
152 ContentType string `json:"Content-Type"`
153 Date gophercloud.JSONRFC1123 `json:"Date"`
154 DeleteAt gophercloud.JSONUnix `json:"X-Delete-At"`
155 ETag string `json:"Etag"`
156 LastModified gophercloud.JSONRFC1123 `json:"Last-Modified"`
157 ObjectManifest string `json:"X-Object-Manifest"`
158 StaticLargeObject bool `json:"X-Static-Large-Object"`
159 TransID string `json:"X-Trans-Id"`
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700160}
161
Jon Perritt5db08922014-09-30 21:32:48 -0500162// GetResult is a *http.Response that is returned from a call to the Get function.
163type GetResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500164 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500165}
166
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700167// Extract will return a struct of headers returned from a call to Get. To obtain
168// a map of headers, call the ExtractHeader method on the GetResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600169func (r GetResult) Extract() (*GetHeader, error) {
170 var s *GetHeader
171 err := r.ExtractInto(&s)
172 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700173}
174
Jon Perritt8c93a302014-09-28 22:35:57 -0500175// ExtractMetadata is a function that takes a GetResult (of type *http.Response)
176// and returns the custom metadata associated with the object.
Jon Perritt3c166472016-02-25 03:07:41 -0600177func (r GetResult) ExtractMetadata() (map[string]string, error) {
178 if r.Err != nil {
179 return nil, r.Err
Jon Perritt8c93a302014-09-28 22:35:57 -0500180 }
181 metadata := make(map[string]string)
Jon Perritt3c166472016-02-25 03:07:41 -0600182 for k, v := range r.Header {
Jon Perritt8c93a302014-09-28 22:35:57 -0500183 if strings.HasPrefix(k, "X-Object-Meta-") {
184 key := strings.TrimPrefix(k, "X-Object-Meta-")
185 metadata[key] = v[0]
186 }
187 }
188 return metadata, nil
189}
Jon Perritt5db08922014-09-30 21:32:48 -0500190
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700191// CreateHeader represents the headers returned in the response from a Create request.
192type CreateHeader struct {
Jon Perritt3c166472016-02-25 03:07:41 -0600193 ContentLength string `json:"Content-Length"`
194 ContentType string `json:"Content-Type"`
195 Date gophercloud.JSONRFC1123 `json:"Date"`
196 ETag string `json:"Etag"`
197 LastModified gophercloud.JSONRFC1123 `json:"Last-Modified"`
198 TransID string `json:"X-Trans-Id"`
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700199}
200
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200201// CreateResult represents the result of a create operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500202type CreateResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500203 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500204}
205
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700206// Extract will return a struct of headers returned from a call to Create. To obtain
207// a map of headers, call the ExtractHeader method on the CreateResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600208func (r CreateResult) Extract() (*CreateHeader, error) {
209 var s *CreateHeader
210 err := r.ExtractInto(&s)
211 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700212}
213
214// UpdateHeader represents the headers returned in the response from a Update request.
215type UpdateHeader struct {
Jon Perritt3c166472016-02-25 03:07:41 -0600216 ContentLength string `json:"Content-Length"`
217 ContentType string `json:"Content-Type"`
218 Date gophercloud.JSONRFC1123 `json:"Date"`
219 TransID string `json:"X-Trans-Id"`
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700220}
221
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200222// UpdateResult represents the result of an update operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500223type UpdateResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500224 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500225}
226
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700227// Extract will return a struct of headers returned from a call to Update. To obtain
228// a map of headers, call the ExtractHeader method on the UpdateResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600229func (r UpdateResult) Extract() (*UpdateHeader, error) {
230 var s *UpdateHeader
231 err := r.ExtractInto(&s)
232 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700233}
234
235// DeleteHeader represents the headers returned in the response from a Delete request.
236type DeleteHeader struct {
Jon Perritt3c166472016-02-25 03:07:41 -0600237 ContentLength string `json:"Content-Length"`
238 ContentType string `json:"Content-Type"`
239 Date gophercloud.JSONRFC1123 `json:"Date"`
240 TransID string `json:"X-Trans-Id"`
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700241}
242
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200243// DeleteResult represents the result of a delete operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500244type DeleteResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500245 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500246}
247
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700248// Extract will return a struct of headers returned from a call to Delete. To obtain
249// a map of headers, call the ExtractHeader method on the DeleteResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600250func (r DeleteResult) Extract() (*DeleteHeader, error) {
251 var s *DeleteHeader
252 err := r.ExtractInto(&s)
253 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700254}
255
256// CopyHeader represents the headers returned in the response from a Copy request.
257type CopyHeader struct {
Jon Perritt3c166472016-02-25 03:07:41 -0600258 ContentLength int64 `json:"Content-Length"`
259 ContentType string `json:"Content-Type"`
260 CopiedFrom string `json:"X-Copied-From"`
261 CopiedFromLastModified gophercloud.JSONRFC1123 `json:"X-Copied-From-Last-Modified"`
262 Date gophercloud.JSONRFC1123 `json:"Date"`
263 ETag string `json:"Etag"`
264 LastModified gophercloud.JSONRFC1123 `json:"Last-Modified"`
265 TransID string `json:"X-Trans-Id"`
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700266}
267
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200268// CopyResult represents the result of a copy operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500269type CopyResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500270 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500271}
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700272
273// Extract will return a struct of headers returned from a call to Copy. To obtain
274// a map of headers, call the ExtractHeader method on the CopyResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600275func (r CopyResult) Extract() (*CopyHeader, error) {
276 var s *CopyHeader
277 err := r.ExtractInto(&s)
278 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700279}