blob: 3cfe1f4ee85434c44b02981e5f859e072af09a03 [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 Perrittfea90732016-03-15 02:57:05 -0500203 checksum string
Jon Perrittd50f93e2014-10-27 14:19:27 -0500204 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500205}
206
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700207// Extract will return a struct of headers returned from a call to Create. To obtain
208// a map of headers, call the ExtractHeader method on the CreateResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600209func (r CreateResult) Extract() (*CreateHeader, error) {
Jon Perrittfea90732016-03-15 02:57:05 -0500210 //if r.Header.Get("ETag") != fmt.Sprintf("%x", localChecksum) {
211 // return nil, ErrWrongChecksum{}
212 //}
Jon Perritt3c166472016-02-25 03:07:41 -0600213 var s *CreateHeader
214 err := r.ExtractInto(&s)
215 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700216}
217
218// UpdateHeader represents the headers returned in the response from a Update request.
219type UpdateHeader struct {
Jon Perritt3c166472016-02-25 03:07:41 -0600220 ContentLength string `json:"Content-Length"`
221 ContentType string `json:"Content-Type"`
222 Date gophercloud.JSONRFC1123 `json:"Date"`
223 TransID string `json:"X-Trans-Id"`
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700224}
225
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200226// UpdateResult represents the result of an update operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500227type UpdateResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500228 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500229}
230
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700231// Extract will return a struct of headers returned from a call to Update. To obtain
232// a map of headers, call the ExtractHeader method on the UpdateResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600233func (r UpdateResult) Extract() (*UpdateHeader, error) {
234 var s *UpdateHeader
235 err := r.ExtractInto(&s)
236 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700237}
238
239// DeleteHeader represents the headers returned in the response from a Delete request.
240type DeleteHeader struct {
Jon Perritt3c166472016-02-25 03:07:41 -0600241 ContentLength string `json:"Content-Length"`
242 ContentType string `json:"Content-Type"`
243 Date gophercloud.JSONRFC1123 `json:"Date"`
244 TransID string `json:"X-Trans-Id"`
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700245}
246
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200247// DeleteResult represents the result of a delete operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500248type DeleteResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500249 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500250}
251
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700252// Extract will return a struct of headers returned from a call to Delete. To obtain
253// a map of headers, call the ExtractHeader method on the DeleteResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600254func (r DeleteResult) Extract() (*DeleteHeader, error) {
255 var s *DeleteHeader
256 err := r.ExtractInto(&s)
257 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700258}
259
260// CopyHeader represents the headers returned in the response from a Copy request.
261type CopyHeader struct {
Jon Perritt3c166472016-02-25 03:07:41 -0600262 ContentLength int64 `json:"Content-Length"`
263 ContentType string `json:"Content-Type"`
264 CopiedFrom string `json:"X-Copied-From"`
265 CopiedFromLastModified gophercloud.JSONRFC1123 `json:"X-Copied-From-Last-Modified"`
266 Date gophercloud.JSONRFC1123 `json:"Date"`
267 ETag string `json:"Etag"`
268 LastModified gophercloud.JSONRFC1123 `json:"Last-Modified"`
269 TransID string `json:"X-Trans-Id"`
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700270}
271
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200272// CopyResult represents the result of a copy operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500273type CopyResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500274 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500275}
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700276
277// Extract will return a struct of headers returned from a call to Copy. To obtain
278// a map of headers, call the ExtractHeader method on the CopyResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600279func (r CopyResult) Extract() (*CopyHeader, error) {
280 var s *CopyHeader
281 err := r.ExtractInto(&s)
282 return s, err
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700283}