Skip to content

Commit

Permalink
Limit DeleteObjects request object amount (#849)
Browse files Browse the repository at this point in the history
Closes #844.
  • Loading branch information
roman-khimov committed Oct 16, 2023
2 parents 59f3825 + 47368f9 commit d5e1860
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 4 deletions.
9 changes: 5 additions & 4 deletions api/handler/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ type (

// Config contains data which handler needs to keep.
Config struct {
Policy PlacementPolicy
DefaultMaxAge int
NotificatorEnabled bool
CopiesNumber uint32
Policy PlacementPolicy
DefaultMaxAge int
NotificatorEnabled bool
CopiesNumber uint32
MaxDeletePerRequest int
}

PlacementPolicy interface {
Expand Down
5 changes: 5 additions & 0 deletions api/handler/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Re
return
}

if len(requested.Objects) > h.cfg.MaxDeletePerRequest {
h.logAndSendError(w, "too many objects to delete", reqInfo, layer.ErrTooManyObjectForDeletion)
return
}

removed := make(map[string]*layer.VersionedObject)
toRemove := make([]*layer.VersionedObject, 0, len(requested.Objects))
for _, obj := range requested.Objects {
Expand Down
4 changes: 4 additions & 0 deletions api/handler/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func transformToS3Error(err error) error {
return s3errors.GetAPIError(s3errors.ErrUnsupportedMetadata)
}

if errors.Is(err, layer.ErrTooManyObjectForDeletion) {
return s3errors.GetAPIError(s3errors.ErrBadRequest)
}

return s3errors.GetAPIError(s3errors.ErrInternalError)
}

Expand Down
3 changes: 3 additions & 0 deletions api/layer/neofs.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ var ErrAccessDenied = errors.New("access denied")
// ErrMetaEmptyParameterValue describes situation when meta parameter was passed but with empty value.
var ErrMetaEmptyParameterValue = errors.New("meta empty parameter value")

// ErrTooManyObjectForDeletion is returned if user is trying to delete to many objects per request.
var ErrTooManyObjectForDeletion = errors.New("to many objects for deletion")

// NeoFS represents virtual connection to NeoFS network.
type NeoFS interface {
// CreateContainer creates and saves parameterized container in NeoFS.
Expand Down
5 changes: 5 additions & 0 deletions cmd/s3-gw/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,11 @@ func (a *App) initHandler() {
cfg.CopiesNumber = val
}

cfg.MaxDeletePerRequest = a.cfg.GetInt(cfgMaxObjectToDeletePerRequest)
if cfg.MaxDeletePerRequest == 0 {
cfg.MaxDeletePerRequest = defaultMaxObjectDeletePerRequest
}

var err error
a.api, err = handler.New(a.log, a.obj, a.nc, cfg)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions cmd/s3-gw/app_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const (

defaultMaxClientsCount = 100
defaultMaxClientsDeadline = time.Second * 30

defaultMaxObjectDeletePerRequest = 1000
)

const ( // Settings.
Expand Down Expand Up @@ -121,6 +123,9 @@ const ( // Settings.
// Number of the object copies to consider PUT to NeoFS successful.
cfgSetCopiesNumber = "neofs.set_copies_number"

// Maximum number of objects to be deleted per request limit by this value.
cfgMaxObjectToDeletePerRequest = "s3.max_object_to_delete_per_request"

// Timeout between retrieving actual epoch from NeoFS. Actual only if slicer.enabled = true.
cfgEpochUpdateInterval = "neofs.epoch_update_interval"

Expand Down
6 changes: 6 additions & 0 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,9 @@ allowed_access_key_id_prefixes:

# Allows to use slicer for Object uploading.
internal_slicer: false

# S3

s3:
# Maximum number of objects to be deleted per request limit by this value.
max_object_to_delete_per_request: 1000
2 changes: 2 additions & 0 deletions docs/aws_s3_compat.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Reference:
| 🔵 | WriteGetObjectResponse | Waiting for Lambda to be developed |
| 🟢 | GetObjectAttributes | |

* DeleteObjects limited by max amount of objects which can be deleted per request. See `max_object_to_delete_per_request` parameter.

## ACL

For now there are some limitations:
Expand Down
13 changes: 13 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -455,3 +455,16 @@ neofs:
| Parameter | Type | Default value | Description |
|---------------------|----------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `set_copies_number` | `uint32` | `0` | Number of the object copies to consider PUT to NeoFS successful. <br/>Default value `0` means that object will be processed according to the container's placement policy |

# `s3` section

Contains parameters to configure requests runtime.

```yaml
s3:
max_object_to_delete_per_request: 1000
```

| Parameter | Type | Default value | Description |
|------------------------------------|-------|---------------|-------------------------------------------------------------------------------------------------------------------------------|
| `max_object_to_delete_per_request` | `int` | `1000` | Allows to set maximum object amount which can be deleted per request. If amount is higher, the `Bad request` will be returned |

0 comments on commit d5e1860

Please sign in to comment.