Skip to content

Commit

Permalink
api: fix upload to handle attributes FilePath, FileName
Browse files Browse the repository at this point in the history
When we receive headers, they are automatically formatted from any case to
only the first letter being uppercase. For example, `FilePath` transforms into
`Filepath`. However, NEOFS is case-sensitive for these attributes, which is why
we intentionally change them to CamelCase style. We hope this is a temporary
workaround and will be removed asap.
Connected to nspcc-dev/neofs-http-gw#255.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
  • Loading branch information
tatiana-nspcc committed Feb 7, 2024
1 parent 3b60381 commit 33d9972
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 3 deletions.
24 changes: 24 additions & 0 deletions gen/restapi/embedded_spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions gen/restapi/operations/upload_container_object_parameters.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions handlers/objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ const (
attributeFilePath = "FilePath"
sizeToDetectType = 512
userAttributeHeaderPrefix = "X-Attribute-"

attributeFilepathHTTP = "Filepath"
attributeFilenameHTTP = "Filename"
)

type readCloser struct {
Expand Down
15 changes: 15 additions & 0 deletions handlers/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ func filterHeaders(l *zap.Logger, header http.Header) (map[string]string, error)
continue
}

clearKey = formatSpecialAttribute(clearKey)
result[clearKey] = value

l.Debug("add attribute to result object",
Expand All @@ -299,3 +300,17 @@ func filterHeaders(l *zap.Logger, header http.Header) (map[string]string, error)
}
return result, nil
}

// formatSpecialAttribute checks if a key-string is one of the special NEOFS
// attributes and returns the string in the correct case.
// For example: "Filepath" -> "FilePath".
func formatSpecialAttribute(s string) string {
switch s {
case attributeFilepathHTTP:
return attributeFilePath
case attributeFilenameHTTP:
return object.AttributeFileName
default:
return s
}
}
14 changes: 11 additions & 3 deletions handlers/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,24 @@ func TestFilter(t *testing.T) {
req.Set("X-Attribute-Neofs-Expiration-Epoch1", "101")
req.Set("X-Attribute-NEOFS-Expiration-Epoch2", "102")
req.Set("X-Attribute-neofs-Expiration-Epoch3", "103")
req.Set("X-Attribute-FileName", "FileName") // This one will be overridden.
req.Set("X-Attribute-filename", "filename")
req.Set("X-Attribute-fIlePaTh", "fIlePaTh/") // This one will be overridden.
req.Set("X-Attribute-Filepath", "Filepath/")
req.Set("X-Attribute-FilePath1", "FilePath/1")
req.Set("X-Attribute-My-Attribute", "value")
req.Set("X-Attribute-MyAttribute", "value2")
req.Set("X-Attribute-Empty-Value", "")
req.Set("X-Attribute-", "prefix only")
req.Set("No-Prefix", "value")
req.Set("X-Attribute-Empty-Value", "") // This one will be skipped.
req.Set("X-Attribute-", "prefix only") // This one will be skipped.
req.Set("No-Prefix", "value") // This one will be skipped.

expected := map[string]string{
"__NEOFS__EXPIRATION_EPOCH1": "101",
"__NEOFS__EXPIRATION_EPOCH2": "102",
"__NEOFS__EXPIRATION_EPOCH3": "103",
"FileName": "filename",
"FilePath": "Filepath/",
"Filepath1": "FilePath/1",
"My-Attribute": "value",
"Myattribute": "value2",
}
Expand Down
10 changes: 10 additions & 0 deletions spec/rest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,16 @@ paths:
required: false
type: file
description: The file to upload. If no file is present in this field, any other field name will be accepted, except for an empty one.
- name: X-Attribute-Filename
in: header
required: false
type: string
description: This attribute, in any combination of upper/lower case, will be added to the object as the `FileName` attribute. It will also be returned as the `FileName` attribute in GET/HEAD API calls for the object (/get/{containerId}/{objectId}) and the `name` in POST call search in a container (/objects/{containerId}/search).
- name: X-Attribute-Filepath
in: header
required: false
type: string
description: This attribute, in any combination of upper/lower case, will be added to the object as the `FilePath` attribute. It will also be returned as the `FilePath` attribute in GET/HEAD API calls for the object (/get/{containerId}/{objectId}) or the `filePath` in POST call search in a container (/objects/{containerId}/search).
responses:
200:
headers:
Expand Down

0 comments on commit 33d9972

Please sign in to comment.