Skip to content

Commit 4e2c194

Browse files
committed
fix: removed list of operation from sdk
Signed-off-by: Amr-Shams <amr.shams2015.as@gmail.com>
1 parent 71928fa commit 4e2c194

3 files changed

Lines changed: 54 additions & 200 deletions

File tree

api.go

Lines changed: 8 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -563,9 +563,6 @@ type requestMetadata struct {
563563
trailer http.Header // (http.Request).Trailer. Requires v4 signature.
564564

565565
expect200OKWithError bool
566-
567-
// s3 operation name
568-
s3Operation string
569566
}
570567

571568
// dumpHTTP - dump HTTP request and response.
@@ -721,16 +718,11 @@ func (c *Client) executeMethod(ctx context.Context, method string, metadata requ
721718
metadata.trailer.Set(metadata.addCrc.Key(), base64.StdEncoding.EncodeToString(crc.Sum(nil)))
722719
}
723720

724-
opt := metadata.s3Operation
725-
if opt == "" {
726-
opt = resolveS3Operation(method, metadata)
727-
}
728-
metadata.s3Operation = opt
729-
730721
execCtx := ExecutionContext{
731-
Operation: opt,
732-
BucketName: metadata.bucketName,
733-
ObjectName: metadata.objectName,
722+
Method: method,
723+
BucketName: metadata.bucketName,
724+
ObjectName: metadata.objectName,
725+
QueryValues: metadata.queryValues,
734726
}
735727

736728
for _, m := range c.middlewares {
@@ -946,12 +938,10 @@ func (c *Client) newRequest(ctx context.Context, method string, metadata request
946938
return nil, err
947939
}
948940
execCtx := ExecutionContext{
949-
Operation: metadata.s3Operation,
950-
BucketName: metadata.bucketName,
951-
ObjectName: metadata.objectName,
952-
}
953-
if execCtx.Operation == "" {
954-
execCtx.Operation = resolveS3Operation(method, metadata)
941+
Method: method,
942+
BucketName: metadata.bucketName,
943+
ObjectName: metadata.objectName,
944+
QueryValues: metadata.queryValues,
955945
}
956946
for _, m := range c.middlewares {
957947
if serializeM, ok := m.(SerializeMiddleware); ok {
@@ -1236,150 +1226,4 @@ func (c *Client) GetCreds() (credentials.Value, error) {
12361226
return c.credsProvider.GetWithContext(c.CredContext())
12371227
}
12381228

1239-
func resolveS3Operation(method string, metadata requestMetadata) string {
1240-
if metadata.s3Operation != "" {
1241-
return metadata.s3Operation
1242-
}
1243-
1244-
hasQuery := func(key string) bool {
1245-
return metadata.queryValues.Get(key) != "" || metadata.queryValues.Has(key)
1246-
}
1247-
1248-
isObject := metadata.objectName != ""
12491229

1250-
switch method {
1251-
case http.MethodGet:
1252-
if isObject {
1253-
if hasQuery("tagging") {
1254-
return "GetObjectTagging"
1255-
}
1256-
if hasQuery("acl") {
1257-
return "GetObjectAcl"
1258-
}
1259-
if hasQuery("legal-hold") {
1260-
return "GetObjectLegalHold"
1261-
}
1262-
if hasQuery("retention") {
1263-
return "GetObjectRetention"
1264-
}
1265-
return "GetObject"
1266-
} else {
1267-
if hasQuery("lifecycle") {
1268-
return "GetBucketLifecycle"
1269-
}
1270-
if hasQuery("policy") {
1271-
return "GetBucketPolicy"
1272-
}
1273-
if hasQuery("notification") {
1274-
return "GetBucketNotification"
1275-
}
1276-
if hasQuery("cors") {
1277-
return "GetBucketCors"
1278-
}
1279-
if hasQuery("encryption") {
1280-
return "GetBucketEncryption"
1281-
}
1282-
if hasQuery("tagging") {
1283-
return "GetBucketTagging"
1284-
}
1285-
if hasQuery("versioning") {
1286-
return "GetBucketVersioning"
1287-
}
1288-
if metadata.bucketName != "" {
1289-
return "ListObjectsV2"
1290-
}
1291-
return "ListBuckets"
1292-
}
1293-
1294-
case http.MethodPut:
1295-
if isObject {
1296-
if hasQuery("tagging") {
1297-
return "PutObjectTagging"
1298-
}
1299-
if hasQuery("acl") {
1300-
return "PutObjectAcl"
1301-
}
1302-
if hasQuery("legal-hold") {
1303-
return "PutObjectLegalHold"
1304-
}
1305-
if hasQuery("retention") {
1306-
return "PutObjectRetention"
1307-
}
1308-
return "PutObject"
1309-
} else {
1310-
if hasQuery("lifecycle") {
1311-
return "PutBucketLifecycle"
1312-
}
1313-
if hasQuery("policy") {
1314-
return "PutBucketPolicy"
1315-
}
1316-
if hasQuery("notification") {
1317-
return "PutBucketNotification"
1318-
}
1319-
if hasQuery("cors") {
1320-
return "PutBucketCors"
1321-
}
1322-
if hasQuery("encryption") {
1323-
return "PutBucketEncryption"
1324-
}
1325-
if hasQuery("tagging") {
1326-
return "PutBucketTagging"
1327-
}
1328-
if hasQuery("versioning") {
1329-
return "PutBucketVersioning"
1330-
}
1331-
return "CreateBucket"
1332-
}
1333-
1334-
case http.MethodDelete:
1335-
if isObject {
1336-
if hasQuery("tagging") {
1337-
return "DeleteObjectTagging"
1338-
}
1339-
return "DeleteObject"
1340-
} else {
1341-
if hasQuery("lifecycle") {
1342-
return "DeleteBucketLifecycle"
1343-
}
1344-
if hasQuery("policy") {
1345-
return "DeleteBucketPolicy"
1346-
}
1347-
if hasQuery("cors") {
1348-
return "DeleteBucketCors"
1349-
}
1350-
if hasQuery("encryption") {
1351-
return "DeleteBucketEncryption"
1352-
}
1353-
if hasQuery("tagging") {
1354-
return "DeleteBucketTagging"
1355-
}
1356-
return "DeleteBucket"
1357-
}
1358-
1359-
case http.MethodHead:
1360-
if isObject {
1361-
return "HeadObject"
1362-
}
1363-
return "HeadBucket"
1364-
1365-
case http.MethodPost:
1366-
if isObject {
1367-
if hasQuery("uploads") {
1368-
return "CreateMultipartUpload"
1369-
}
1370-
if hasQuery("restore") {
1371-
return "RestoreObject"
1372-
}
1373-
if hasQuery("select") {
1374-
return "SelectObjectContent"
1375-
}
1376-
return "PostObject"
1377-
} else {
1378-
if hasQuery("delete") {
1379-
return "DeleteObjects"
1380-
}
1381-
}
1382-
}
1383-
1384-
return method
1385-
}

middleware.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package minio
33
import (
44
"context"
55
"net/http"
6+
"net/url"
67
)
78

89
// ExecutionContext provides context metadata about the S3 operation currently running.
910
type ExecutionContext struct {
10-
Operation string // e.g. "GetObject", "PutObject", "ListBuckets"
11-
BucketName string
12-
ObjectName string
11+
Method string // e.g. "GET", "PUT", "DELETE"
12+
BucketName string
13+
ObjectName string
14+
QueryValues url.Values // e.g. ?policy, ?tagging, ?versioning
1315
}
1416

1517
// Middleware is the base interface for all pipeline interceptors.
@@ -30,8 +32,7 @@ type InitializeMiddleware interface {
3032
// SerializeMiddleware runs AFTER the request is created, but BEFORE it is signed.
3133
// It can mutate headers, query parameters, etc.
3234
//
33-
// NOTE: This fires on EVERY retry attempt (new request per attempt).
34-
// Only InitializeMiddleware runs once per API call.
35+
// NOTE: This fires on every retry attempt. Only Initialize runs once.
3536
type SerializeMiddleware interface {
3637
Middleware
3738
Serialize(ctx context.Context, execCtx ExecutionContext, req *http.Request) error
@@ -40,8 +41,7 @@ type SerializeMiddleware interface {
4041
// FinalizeMiddleware runs AFTER the request is signed and ready to go out.
4142
// Ideal for logging request sizes, outbound traffic, or tracing.
4243
//
43-
// NOTE: This fires on EVERY retry attempt inside the retry loop, not once per
44-
// top-level API call. Only InitializeMiddleware runs once.
44+
// NOTE: This fires on every retry attempt. Only Initialize runs once.
4545
type FinalizeMiddleware interface {
4646
Middleware
4747
Finalize(ctx context.Context, execCtx ExecutionContext, req *http.Request) error
@@ -50,11 +50,10 @@ type FinalizeMiddleware interface {
5050
// DeserializeMiddleware runs AFTER the HTTP response is received from the server.
5151
// It can inspect status codes, headers, or modify/log errors.
5252
//
53-
// NOTE: This fires on EVERY retry attempt inside the retry loop.
54-
// Only InitializeMiddleware runs once per API call.
53+
// NOTE: This fires on every retry attempt. Only Initialize runs once.
5554
// Errors from all Deserialize middleware stack via errors.Join with the transport
5655
// error. If any middleware returns a non-nil error, the request aborts even on
57-
// 2xx responses. Use this for response validation.
56+
// 2xx responses.
5857
type DeserializeMiddleware interface {
5958
Middleware
6059
Deserialize(ctx context.Context, execCtx ExecutionContext, resp *http.Response, err error) error

middleware_test.go

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,26 @@ import (
44
"context"
55
"net/http"
66
"net/http/httptest"
7+
"net/url"
78
"sync"
89
"testing"
910

1011
"github.com/minio/minio-go/v7/pkg/credentials"
1112
)
1213

14+
type recordedPhase struct {
15+
method string
16+
bucketName string
17+
objectName string
18+
queryValues url.Values
19+
}
20+
1321
type mockMiddleware struct {
1422
mu sync.Mutex
15-
initialized []string
16-
serialized []string
17-
finalized []string
18-
deserialized []string
23+
initialized []recordedPhase
24+
serialized []recordedPhase
25+
finalized []recordedPhase
26+
deserialized []recordedPhase
1927
}
2028

2129
func (m *mockMiddleware) ID() string {
@@ -25,36 +33,34 @@ func (m *mockMiddleware) ID() string {
2533
func (m *mockMiddleware) Initialize(ctx context.Context, execCtx ExecutionContext) (context.Context, error) {
2634
m.mu.Lock()
2735
defer m.mu.Unlock()
28-
m.initialized = append(m.initialized, execCtx.Operation)
36+
m.initialized = append(m.initialized, recordedPhase{method: execCtx.Method, bucketName: execCtx.BucketName, objectName: execCtx.ObjectName, queryValues: execCtx.QueryValues})
2937
return ctx, nil
3038
}
3139

3240
func (m *mockMiddleware) Serialize(ctx context.Context, execCtx ExecutionContext, req *http.Request) error {
3341
m.mu.Lock()
3442
defer m.mu.Unlock()
35-
m.serialized = append(m.serialized, execCtx.Operation)
43+
m.serialized = append(m.serialized, recordedPhase{method: execCtx.Method, bucketName: execCtx.BucketName, objectName: execCtx.ObjectName, queryValues: execCtx.QueryValues})
3644
req.Header.Set("X-Mock-Header", "Hello")
3745
return nil
3846
}
3947

4048
func (m *mockMiddleware) Finalize(ctx context.Context, execCtx ExecutionContext, req *http.Request) error {
4149
m.mu.Lock()
4250
defer m.mu.Unlock()
43-
m.finalized = append(m.finalized, execCtx.Operation)
51+
m.finalized = append(m.finalized, recordedPhase{method: execCtx.Method, bucketName: execCtx.BucketName, objectName: execCtx.ObjectName, queryValues: execCtx.QueryValues})
4452
return nil
4553
}
4654

4755
func (m *mockMiddleware) Deserialize(ctx context.Context, execCtx ExecutionContext, resp *http.Response, err error) error {
4856
m.mu.Lock()
4957
defer m.mu.Unlock()
50-
m.deserialized = append(m.deserialized, execCtx.Operation)
58+
m.deserialized = append(m.deserialized, recordedPhase{method: execCtx.Method, bucketName: execCtx.BucketName, objectName: execCtx.ObjectName, queryValues: execCtx.QueryValues})
5159
return nil
5260
}
5361

5462
func TestMiddlewareIntegration(t *testing.T) {
55-
// Start local mock S3 server
5663
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
57-
// Verify custom header was injected by Serialize middleware
5864
if r.Header.Get("X-Mock-Header") != "Hello" {
5965
t.Errorf("Expected X-Mock-Header: 'Hello', got '%s'", r.Header.Get("X-Mock-Header"))
6066
}
@@ -64,38 +70,43 @@ func TestMiddlewareIntegration(t *testing.T) {
6470

6571
mw := &mockMiddleware{}
6672

67-
// Instantiate client with middleware options
6873
client, err := New(server.URL[7:], &Options{
69-
Creds: credentials.NewStaticV4("mockkey", "mocksecret", ""),
70-
Secure: false,
71-
Region: "us-east-1",
72-
Middlewares: []Middleware{mw},
74+
Creds: credentials.NewStaticV4("mockkey", "mocksecret", ""),
75+
Secure: false,
76+
Region: "us-east-1",
77+
Middlewares: []Middleware{mw},
7378
})
7479
if err != nil {
7580
t.Fatalf("Failed to create minio client: %v", err)
7681
}
7782

78-
// Make a GetBucketPolicy request (which uses executeMethod under the hood)
7983
_, err = client.GetBucketPolicy(context.Background(), "mybucket")
80-
// Since the mock server returns 200 OK but empty payload, GetBucketPolicy may return XML parsing error or nil, but HTTP request was triggered.
8184

8285
mw.mu.Lock()
8386
defer mw.mu.Unlock()
8487

85-
// Verify the S3 Operation was correctly resolved by resolveS3Operation (GetBucketPolicy)
86-
if len(mw.initialized) != 1 || mw.initialized[0] != "GetBucketPolicy" {
87-
t.Errorf("Expected initialized operation to be 'GetBucketPolicy', got %v", mw.initialized)
88+
if len(mw.initialized) != 1 {
89+
t.Fatalf("Expected 1 initialized call, got %d", len(mw.initialized))
90+
}
91+
if mw.initialized[0].method != "GET" {
92+
t.Errorf("Expected method GET, got %s", mw.initialized[0].method)
93+
}
94+
if !mw.initialized[0].queryValues.Has("policy") {
95+
t.Errorf("Expected queryValues to have 'policy', got %v", mw.initialized[0].queryValues)
8896
}
8997

90-
if len(mw.serialized) != 1 || mw.serialized[0] != "GetBucketPolicy" {
91-
t.Errorf("Expected serialized operation to be 'GetBucketPolicy', got %v", mw.serialized)
98+
if len(mw.serialized) != 1 {
99+
t.Fatalf("Expected 1 serialized call, got %d", len(mw.serialized))
100+
}
101+
if mw.serialized[0].method != "GET" {
102+
t.Errorf("Expected method GET, got %s", mw.serialized[0].method)
92103
}
93104

94-
if len(mw.finalized) != 1 || mw.finalized[0] != "GetBucketPolicy" {
95-
t.Errorf("Expected finalized operation to be 'GetBucketPolicy', got %v", mw.finalized)
105+
if len(mw.finalized) != 1 {
106+
t.Fatalf("Expected 1 finalized call, got %d", len(mw.finalized))
96107
}
97108

98-
if len(mw.deserialized) != 1 || mw.deserialized[0] != "GetBucketPolicy" {
99-
t.Errorf("Expected deserialized operation to be 'GetBucketPolicy', got %v", mw.deserialized)
109+
if len(mw.deserialized) != 1 {
110+
t.Fatalf("Expected 1 deserialized call, got %d", len(mw.deserialized))
100111
}
101112
}

0 commit comments

Comments
 (0)