Skip to content

Commit 76a4146

Browse files
authored
NEW API: GetObjectAttributes (#1921)
1 parent 56d9949 commit 76a4146

File tree

5 files changed

+1230
-281
lines changed

5 files changed

+1230
-281
lines changed

api-get-object-attributes.go

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
3+
* Copyright 2020 MinIO, Inc.
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package minio
18+
19+
import (
20+
"context"
21+
"encoding/xml"
22+
"errors"
23+
"net/http"
24+
"net/url"
25+
"strconv"
26+
"time"
27+
28+
"github.com/minio/minio-go/v7/pkg/encrypt"
29+
"github.com/minio/minio-go/v7/pkg/s3utils"
30+
)
31+
32+
// ObjectAttributesOptions are options used for the GetObjectAttributes API
33+
//
34+
// - MaxParts
35+
// How many parts the caller wants to be returned (default: 1000)
36+
//
37+
// - VersionID
38+
// The object version you want to attributes for
39+
//
40+
// - PartNumberMarker
41+
// the listing will start AFTER the part matching PartNumberMarker
42+
//
43+
// - ServerSideEncryption
44+
// The server-side encryption algorithm used when storing this object in Minio
45+
type ObjectAttributesOptions struct {
46+
MaxParts int
47+
VersionID string
48+
PartNumberMarker int
49+
ServerSideEncryption encrypt.ServerSide
50+
}
51+
52+
// ObjectAttributes is the response object returned by the GetObjectAttributes API
53+
//
54+
// - VersionID
55+
// The object version
56+
//
57+
// - LastModified
58+
// The last time the object was modified
59+
//
60+
// - ObjectAttributesResponse
61+
// Contains more information about the object
62+
type ObjectAttributes struct {
63+
VersionID string
64+
LastModified time.Time
65+
ObjectAttributesResponse
66+
}
67+
68+
// ObjectAttributesResponse contains details returned by the GetObjectAttributes API
69+
//
70+
// Noteworthy fields:
71+
//
72+
// - ObjectParts.PartsCount
73+
// Contains the total part count for the object (not the current response)
74+
//
75+
// - ObjectParts.PartNumberMarker
76+
// Pagination of parts will begin at (but not include) PartNumberMarker
77+
//
78+
// - ObjectParts.NextPartNumberMarket
79+
// The next PartNumberMarker to be used in order to continue pagination
80+
//
81+
// - ObjectParts.IsTruncated
82+
// Indicates if the last part is included in the request (does not check if parts are missing from the start of the list, ONLY the end)
83+
//
84+
// - ObjectParts.MaxParts
85+
// Reflects the MaxParts used by the caller or the default MaxParts value of the API
86+
type ObjectAttributesResponse struct {
87+
ETag string `xml:",omitempty"`
88+
StorageClass string
89+
ObjectSize int
90+
Checksum struct {
91+
ChecksumCRC32 string `xml:",omitempty"`
92+
ChecksumCRC32C string `xml:",omitempty"`
93+
ChecksumSHA1 string `xml:",omitempty"`
94+
ChecksumSHA256 string `xml:",omitempty"`
95+
}
96+
ObjectParts struct {
97+
PartsCount int
98+
PartNumberMarker int
99+
NextPartNumberMarker int
100+
MaxParts int
101+
IsTruncated bool
102+
Parts []*ObjectAttributePart `xml:"Part"`
103+
}
104+
}
105+
106+
// ObjectAttributePart is used by ObjectAttributesResponse to describe an object part
107+
type ObjectAttributePart struct {
108+
ChecksumCRC32 string `xml:",omitempty"`
109+
ChecksumCRC32C string `xml:",omitempty"`
110+
ChecksumSHA1 string `xml:",omitempty"`
111+
ChecksumSHA256 string `xml:",omitempty"`
112+
PartNumber int
113+
Size int
114+
}
115+
116+
func (o *ObjectAttributes) parseResponse(resp *http.Response) (err error) {
117+
mod, err := parseRFC7231Time(resp.Header.Get("Last-Modified"))
118+
if err != nil {
119+
return err
120+
}
121+
o.LastModified = mod
122+
o.VersionID = resp.Header.Get(amzVersionID)
123+
124+
response := new(ObjectAttributesResponse)
125+
if err := xml.NewDecoder(resp.Body).Decode(response); err != nil {
126+
return err
127+
}
128+
o.ObjectAttributesResponse = *response
129+
130+
return
131+
}
132+
133+
// GetObjectAttributes API combines HeadObject and ListParts.
134+
// More details on usage can be found in the documentation for ObjectAttributesOptions{}
135+
func (c *Client) GetObjectAttributes(ctx context.Context, bucketName, objectName string, opts ObjectAttributesOptions) (*ObjectAttributes, error) {
136+
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
137+
return nil, err
138+
}
139+
140+
if err := s3utils.CheckValidObjectName(objectName); err != nil {
141+
return nil, err
142+
}
143+
144+
urlValues := make(url.Values)
145+
urlValues.Add("attributes", "")
146+
if opts.VersionID != "" {
147+
urlValues.Add("versionId", opts.VersionID)
148+
}
149+
150+
headers := make(http.Header)
151+
headers.Set(amzObjectAttributes, GetObjectAttributesTags)
152+
153+
if opts.PartNumberMarker > 0 {
154+
headers.Set(amzPartNumberMarker, strconv.Itoa(opts.PartNumberMarker))
155+
}
156+
157+
if opts.MaxParts > 0 {
158+
headers.Set(amzMaxParts, strconv.Itoa(opts.MaxParts))
159+
} else {
160+
headers.Set(amzMaxParts, strconv.Itoa(GetObjectAttributesMaxParts))
161+
}
162+
163+
if opts.ServerSideEncryption != nil {
164+
opts.ServerSideEncryption.Marshal(headers)
165+
}
166+
167+
resp, err := c.executeMethod(ctx, http.MethodGet, requestMetadata{
168+
bucketName: bucketName,
169+
objectName: objectName,
170+
queryValues: urlValues,
171+
contentSHA256Hex: emptySHA256Hex,
172+
customHeader: headers,
173+
})
174+
if err != nil {
175+
return nil, err
176+
}
177+
178+
defer closeResponse(resp)
179+
180+
hasEtag := resp.Header.Get(ETag)
181+
if hasEtag != "" {
182+
return nil, errors.New("getObjectAttributes is not supported by the current endpoint version")
183+
}
184+
185+
if resp.StatusCode != http.StatusOK {
186+
ER := new(ErrorResponse)
187+
if err := xml.NewDecoder(resp.Body).Decode(ER); err != nil {
188+
return nil, err
189+
}
190+
191+
return nil, *ER
192+
}
193+
194+
OA := new(ObjectAttributes)
195+
err = OA.parseResponse(resp)
196+
if err != nil {
197+
return nil, err
198+
}
199+
200+
return OA, nil
201+
}

constants.go

+20
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,32 @@ const (
6060
)
6161

6262
const (
63+
// GetObjectAttributesTags are tags used to defined
64+
// return values for the GetObjectAttributes API
65+
GetObjectAttributesTags = "ETag,Checksum,StorageClass,ObjectSize,ObjectParts"
66+
// GetObjectAttributesMaxParts defined the default maximum
67+
// number of parts returned by GetObjectAttributes
68+
GetObjectAttributesMaxParts = 1000
69+
)
70+
71+
const (
72+
// Response Headers
73+
74+
// ETag is a common response header
75+
ETag = "ETag"
76+
6377
// Storage class header.
6478
amzStorageClass = "X-Amz-Storage-Class"
6579

6680
// Website redirect location header
6781
amzWebsiteRedirectLocation = "X-Amz-Website-Redirect-Location"
6882

83+
// GetObjectAttributes headers
84+
amzPartNumberMarker = "X-Amz-Part-Number-Marker"
85+
amzExpectedBucketOnwer = "X-Amz-Expected-Bucket-Owner"
86+
amzMaxParts = "X-Amz-Max-Parts"
87+
amzObjectAttributes = "X-Amz-Object-Attributes"
88+
6989
// Object Tagging headers
7090
amzTaggingHeader = "X-Amz-Tagging"
7191
amzTaggingHeaderDirective = "X-Amz-Tagging-Directive"

docs/API.md

+55-1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func main() {
8181
| | [`GetObjectTagging`](#GetObjectTagging) | | | |
8282
| | [`RemoveObjectTagging`](#RemoveObjectTagging) | | | |
8383
| | [`RestoreObject`](#RestoreObject) | | | |
84+
| | [`GetObjectAttributes`](#GetObjectAttributes) | | | |
8485

8586
## 1. Constructor
8687
<a name="MinIO"></a>
@@ -445,8 +446,8 @@ __minio.GetObjectOptions__
445446
|:---|:---|:---|
446447
| `opts.ServerSideEncryption` | _encrypt.ServerSide_ | Interface provided by `encrypt` package to specify server-side-encryption. (For more information see https://godoc.org/github.com/minio/minio-go/v7) |
447448
| `opts.Internal` | _minio.AdvancedGetOptions_ | This option is intended for internal use by MinIO server. This option should not be set unless the application is aware of intended use.
448-
__Return Value__
449449

450+
__Return Value__
450451

451452
|Param |Type |Description |
452453
|:---|:---| :---|
@@ -1194,6 +1195,59 @@ if err != nil {
11941195
}
11951196
```
11961197

1198+
<a name="GetObjectAttributes"></a>
1199+
### GetObjectAttributes(ctx context.Context, bucketName, objectName string, opts ObjectAttributesOptions) (*ObjectAttributes, error)
1200+
Returns a stream of the object data. Most of the common errors occur when reading the stream.
1201+
1202+
1203+
__Parameters__
1204+
1205+
1206+
|Param |Type |Description |
1207+
|:---|:---| :---|
1208+
|`ctx` | _context.Context_ | Custom context for timeout/cancellation of the call|
1209+
|`bucketName` | _string_ |Name of the bucket |
1210+
|`objectName` | _string_ |Name of the object |
1211+
|`opts` | _minio.ObjectAttributesOptions_ | Configuration for pagination and selection of object attributes |
1212+
1213+
1214+
__minio.ObjectAttributesOptions__
1215+
1216+
|Field | Type | Description |
1217+
|:---|:---|:---|
1218+
| `opts.ServerSideEncryption` | _encrypt.ServerSide_ | Interface provided by `encrypt` package to specify server-side-encryption. (For more information see https://godoc.org/github.com/minio/minio-go/v7) |
1219+
| `opts.MaxParts` | _int | This option defines how many parts should be returned by the API
1220+
| `opts.VersionID` | _string | VersionID defines which version of the object will be used
1221+
| `opts.PartNumberMarker` | _int | This options defines which part number pagination will start after, the part which number is equal to PartNumberMarker will not be included in the response
1222+
1223+
__Return Value__
1224+
1225+
|Param |Type |Description |
1226+
|:---|:---| :---|
1227+
|`objectAttributes` | _*minio.ObjectAttributes_ |_minio.ObjectAttributes_ contains the information about the object and it's parts. |
1228+
1229+
__Example__
1230+
1231+
1232+
```go
1233+
objectAttributes, err := c.GetObjectAttributes(
1234+
context.Background(),
1235+
"your-bucket",
1236+
"your-object",
1237+
minio.ObjectAttributesOptions{
1238+
VersionID:"object-version-id",
1239+
NextPartMarker:0,
1240+
MaxParts:100,
1241+
})
1242+
1243+
if err != nil {
1244+
fmt.Println(err)
1245+
return
1246+
}
1247+
1248+
fmt.Println(objectAttributes)
1249+
```
1250+
11971251

11981252
<a name="RemoveIncompleteUpload"></a>
11991253
### RemoveIncompleteUpload(ctx context.Context, bucketName, objectName string) error

0 commit comments

Comments
 (0)