mirror of
https://github.com/versity/versitygw.git
synced 2026-01-06 11:46:20 +00:00
feat: Added FE support for SelectObjectContent action
This commit is contained in:
@@ -43,6 +43,7 @@ type Backend interface {
|
||||
ListParts(context.Context, *s3.ListPartsInput) (s3response.ListPartsResult, error)
|
||||
UploadPart(context.Context, *s3.UploadPartInput) (etag string, err error)
|
||||
UploadPartCopy(context.Context, *s3.UploadPartCopyInput) (s3response.CopyObjectResult, error)
|
||||
SelectObjectContent(context.Context, *s3.SelectObjectContentInput) (s3response.SelectObjectContentResult, error)
|
||||
|
||||
PutObject(context.Context, *s3.PutObjectInput) (string, error)
|
||||
HeadObject(context.Context, *s3.HeadObjectInput) (*s3.HeadObjectOutput, error)
|
||||
@@ -100,6 +101,9 @@ func (BackendUnsupported) CreateBucket(context.Context, *s3.CreateBucketInput) e
|
||||
func (BackendUnsupported) DeleteBucket(context.Context, *s3.DeleteBucketInput) error {
|
||||
return s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
func (BackendUnsupported) SelectObjectContent(context.Context, *s3.SelectObjectContentInput) (s3response.SelectObjectContentResult, error) {
|
||||
return s3response.SelectObjectContentResult{}, s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
|
||||
func (BackendUnsupported) CreateMultipartUpload(context.Context, *s3.CreateMultipartUploadInput) (*s3.CreateMultipartUploadOutput, error) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
|
||||
@@ -97,6 +97,9 @@ var _ backend.Backend = &BackendMock{}
|
||||
// RestoreObjectFunc: func(contextMoqParam context.Context, restoreObjectInput *s3.RestoreObjectInput) error {
|
||||
// panic("mock out the RestoreObject method")
|
||||
// },
|
||||
// SelectObjectContentFunc: func(contextMoqParam context.Context, selectObjectContentInput *s3.SelectObjectContentInput) (s3response.SelectObjectContentResult, error) {
|
||||
// panic("mock out the SelectObjectContent method")
|
||||
// },
|
||||
// SetTagsFunc: func(contextMoqParam context.Context, bucket string, object string, tags map[string]string) error {
|
||||
// panic("mock out the SetTags method")
|
||||
// },
|
||||
@@ -194,6 +197,9 @@ type BackendMock struct {
|
||||
// RestoreObjectFunc mocks the RestoreObject method.
|
||||
RestoreObjectFunc func(contextMoqParam context.Context, restoreObjectInput *s3.RestoreObjectInput) error
|
||||
|
||||
// SelectObjectContentFunc mocks the SelectObjectContent method.
|
||||
SelectObjectContentFunc func(contextMoqParam context.Context, selectObjectContentInput *s3.SelectObjectContentInput) (s3response.SelectObjectContentResult, error)
|
||||
|
||||
// SetTagsFunc mocks the SetTags method.
|
||||
SetTagsFunc func(contextMoqParam context.Context, bucket string, object string, tags map[string]string) error
|
||||
|
||||
@@ -396,6 +402,13 @@ type BackendMock struct {
|
||||
// RestoreObjectInput is the restoreObjectInput argument value.
|
||||
RestoreObjectInput *s3.RestoreObjectInput
|
||||
}
|
||||
// SelectObjectContent holds details about calls to the SelectObjectContent method.
|
||||
SelectObjectContent []struct {
|
||||
// ContextMoqParam is the contextMoqParam argument value.
|
||||
ContextMoqParam context.Context
|
||||
// SelectObjectContentInput is the selectObjectContentInput argument value.
|
||||
SelectObjectContentInput *s3.SelectObjectContentInput
|
||||
}
|
||||
// SetTags holds details about calls to the SetTags method.
|
||||
SetTags []struct {
|
||||
// ContextMoqParam is the contextMoqParam argument value.
|
||||
@@ -453,6 +466,7 @@ type BackendMock struct {
|
||||
lockPutObjectAcl sync.RWMutex
|
||||
lockRemoveTags sync.RWMutex
|
||||
lockRestoreObject sync.RWMutex
|
||||
lockSelectObjectContent sync.RWMutex
|
||||
lockSetTags sync.RWMutex
|
||||
lockShutdown sync.RWMutex
|
||||
lockString sync.RWMutex
|
||||
@@ -1380,6 +1394,42 @@ func (mock *BackendMock) RestoreObjectCalls() []struct {
|
||||
return calls
|
||||
}
|
||||
|
||||
// SelectObjectContent calls SelectObjectContentFunc.
|
||||
func (mock *BackendMock) SelectObjectContent(contextMoqParam context.Context, selectObjectContentInput *s3.SelectObjectContentInput) (s3response.SelectObjectContentResult, error) {
|
||||
if mock.SelectObjectContentFunc == nil {
|
||||
panic("BackendMock.SelectObjectContentFunc: method is nil but Backend.SelectObjectContent was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
ContextMoqParam context.Context
|
||||
SelectObjectContentInput *s3.SelectObjectContentInput
|
||||
}{
|
||||
ContextMoqParam: contextMoqParam,
|
||||
SelectObjectContentInput: selectObjectContentInput,
|
||||
}
|
||||
mock.lockSelectObjectContent.Lock()
|
||||
mock.calls.SelectObjectContent = append(mock.calls.SelectObjectContent, callInfo)
|
||||
mock.lockSelectObjectContent.Unlock()
|
||||
return mock.SelectObjectContentFunc(contextMoqParam, selectObjectContentInput)
|
||||
}
|
||||
|
||||
// SelectObjectContentCalls gets all the calls that were made to SelectObjectContent.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedBackend.SelectObjectContentCalls())
|
||||
func (mock *BackendMock) SelectObjectContentCalls() []struct {
|
||||
ContextMoqParam context.Context
|
||||
SelectObjectContentInput *s3.SelectObjectContentInput
|
||||
} {
|
||||
var calls []struct {
|
||||
ContextMoqParam context.Context
|
||||
SelectObjectContentInput *s3.SelectObjectContentInput
|
||||
}
|
||||
mock.lockSelectObjectContent.RLock()
|
||||
calls = mock.calls.SelectObjectContent
|
||||
mock.lockSelectObjectContent.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// SetTags calls SetTagsFunc.
|
||||
func (mock *BackendMock) SetTags(contextMoqParam context.Context, bucket string, object string, tags map[string]string) error {
|
||||
if mock.SetTagsFunc == nil {
|
||||
|
||||
@@ -830,6 +830,34 @@ func (c S3ApiController) CreateActions(ctx *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
if ctx.Request().URI().QueryArgs().Has("select") && ctx.Query("select-type") == "2" {
|
||||
var payload s3response.SelectObjectContentPayload
|
||||
|
||||
if err := xml.Unmarshal(ctx.Body(), &payload); err != nil {
|
||||
return SendXMLResponse(ctx, nil, s3err.GetAPIError(s3err.ErrMalformedXML), &MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "SelectObjectContent",
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil {
|
||||
return SendXMLResponse(ctx, nil, err, &MetaOpts{Logger: c.logger, Action: "SelectObjectContent", BucketOwner: parsedAcl.Owner})
|
||||
}
|
||||
|
||||
res, err := c.be.SelectObjectContent(ctx.Context(), &s3.SelectObjectContentInput{
|
||||
Bucket: &bucket,
|
||||
Key: &key,
|
||||
Expression: payload.Expression,
|
||||
ExpressionType: payload.ExpressionType,
|
||||
InputSerialization: payload.InputSerialization,
|
||||
OutputSerialization: payload.OutputSerialization,
|
||||
RequestProgress: payload.RequestProgress,
|
||||
ScanRange: payload.ScanRange,
|
||||
})
|
||||
return SendXMLResponse(ctx, res, err, &MetaOpts{Logger: c.logger, Action: "SelectObjectContent", BucketOwner: parsedAcl.Owner})
|
||||
}
|
||||
|
||||
if uploadId != "" {
|
||||
data := struct {
|
||||
Parts []types.CompletedPart `xml:"Part"`
|
||||
|
||||
@@ -1299,9 +1299,19 @@ func TestS3ApiController_CreateActions(t *testing.T) {
|
||||
CreateMultipartUploadFunc: func(context.Context, *s3.CreateMultipartUploadInput) (*s3.CreateMultipartUploadOutput, error) {
|
||||
return &s3.CreateMultipartUploadOutput{}, nil
|
||||
},
|
||||
SelectObjectContentFunc: func(contextMoqParam context.Context, selectObjectContentInput *s3.SelectObjectContentInput) (s3response.SelectObjectContentResult, error) {
|
||||
return s3response.SelectObjectContentResult{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
bdy := `
|
||||
<SelectObjectContentRequest>
|
||||
<Expression>string</Expression>
|
||||
<ExpressionType>string</ExpressionType>
|
||||
</SelectObjectContentRequest>
|
||||
`
|
||||
|
||||
app.Use(func(ctx *fiber.Ctx) error {
|
||||
ctx.Locals("access", "valid access")
|
||||
ctx.Locals("isRoot", true)
|
||||
@@ -1336,6 +1346,24 @@ func TestS3ApiController_CreateActions(t *testing.T) {
|
||||
wantErr: false,
|
||||
statusCode: 500,
|
||||
},
|
||||
{
|
||||
name: "Select-object-content-invalid-body",
|
||||
app: app,
|
||||
args: args{
|
||||
req: httptest.NewRequest(http.MethodPost, "/my-bucket/my-key?select&select-type=2", nil),
|
||||
},
|
||||
wantErr: false,
|
||||
statusCode: 400,
|
||||
},
|
||||
{
|
||||
name: "Select-object-content-invalid-body",
|
||||
app: app,
|
||||
args: args{
|
||||
req: httptest.NewRequest(http.MethodPost, "/my-bucket/my-key?select&select-type=2", strings.NewReader(bdy)),
|
||||
},
|
||||
wantErr: false,
|
||||
statusCode: 200,
|
||||
},
|
||||
{
|
||||
name: "Complete-multipart-upload-error",
|
||||
app: app,
|
||||
|
||||
@@ -118,3 +118,19 @@ type DeleteObjectsResult struct {
|
||||
Deleted []types.DeletedObject
|
||||
Errors []types.Error
|
||||
}
|
||||
type SelectObjectContentPayload struct {
|
||||
Expression *string
|
||||
ExpressionType types.ExpressionType
|
||||
RequestProgress *types.RequestProgress
|
||||
InputSerialization *types.InputSerialization
|
||||
OutputSerialization *types.OutputSerialization
|
||||
ScanRange *types.ScanRange
|
||||
}
|
||||
|
||||
type SelectObjectContentResult struct {
|
||||
Records *types.RecordsEvent
|
||||
Stats *types.StatsEvent
|
||||
Progress *types.ProgressEvent
|
||||
Cont *string
|
||||
End *string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user