Fix #104338: Error performing BAT pack
Use RFC 2047 (aka MIME encoding) to send the original filename when uploading a file to the Shaman server. HTTP headers should be ASCII-only, and some systems use Latin-1 as fallback. That's not suitable in general, though, because almost all characters fall outside the Latin-1 range.
This commit is contained in:
parent
1f562b3cbc
commit
2e0e211b26
@ -17,6 +17,7 @@ bugs in actually-released versions.
|
|||||||
- Security updates of dependencies:
|
- Security updates of dependencies:
|
||||||
- [GO-2024-3106: Stack exhaustion in Decoder.Decode in encoding/gob](https://pkg.go.dev/vuln/GO-2024-3106)
|
- [GO-2024-3106: Stack exhaustion in Decoder.Decode in encoding/gob](https://pkg.go.dev/vuln/GO-2024-3106)
|
||||||
- Fix bug where database foreign key constraints could be deactivated ([#104305](https://projects.blender.org/studio/flamenco/issues/104305)).
|
- Fix bug where database foreign key constraints could be deactivated ([#104305](https://projects.blender.org/studio/flamenco/issues/104305)).
|
||||||
|
- Fix bug when submitting a file with a non-ASCII name via Shaman ([#104338](https://projects.blender.org/studio/flamenco/issues/104338)).
|
||||||
|
|
||||||
## 3.5 - released 2024-04-16
|
## 3.5 - released 2024-04-16
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
"""BAT interface for sending files to the Manager via the Shaman API."""
|
"""BAT interface for sending files to the Manager via the Shaman API."""
|
||||||
|
|
||||||
|
import email.header
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
import platform
|
import platform
|
||||||
@ -366,6 +367,7 @@ class Transferrer(submodules.transfer.FileTransferer): # type: ignore
|
|||||||
)
|
)
|
||||||
|
|
||||||
local_filepath = self._rel_to_local_path[file_spec.path]
|
local_filepath = self._rel_to_local_path[file_spec.path]
|
||||||
|
filename_header = _encode_original_filename_header(file_spec.path)
|
||||||
try:
|
try:
|
||||||
with local_filepath.open("rb") as file_reader:
|
with local_filepath.open("rb") as file_reader:
|
||||||
self.shaman_api.shaman_file_store(
|
self.shaman_api.shaman_file_store(
|
||||||
@ -373,7 +375,7 @@ class Transferrer(submodules.transfer.FileTransferer): # type: ignore
|
|||||||
filesize=file_spec.size,
|
filesize=file_spec.size,
|
||||||
body=file_reader,
|
body=file_reader,
|
||||||
x_shaman_can_defer_upload=can_defer,
|
x_shaman_can_defer_upload=can_defer,
|
||||||
x_shaman_original_filename=file_spec.path,
|
x_shaman_original_filename=filename_header,
|
||||||
)
|
)
|
||||||
except ApiException as ex:
|
except ApiException as ex:
|
||||||
if ex.status == 425:
|
if ex.status == 425:
|
||||||
@ -527,3 +529,16 @@ def _root_path_strip(path: PurePath) -> PurePosixPath:
|
|||||||
if path.is_absolute():
|
if path.is_absolute():
|
||||||
return PurePosixPath(*path.parts[1:])
|
return PurePosixPath(*path.parts[1:])
|
||||||
return PurePosixPath(path)
|
return PurePosixPath(path)
|
||||||
|
|
||||||
|
|
||||||
|
def _encode_original_filename_header(filename: str) -> str:
|
||||||
|
"""Encode the 'original filename' as valid HTTP Header.
|
||||||
|
|
||||||
|
See the specs for the X-Shaman-Original-Filename header in the OpenAPI
|
||||||
|
operation `shamanFileStore`, defined in flamenco-openapi.yaml.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# This is a no-op when the filename is already in ASCII.
|
||||||
|
fake_header = email.header.Header()
|
||||||
|
fake_header.append(filename, charset="utf-8")
|
||||||
|
return fake_header.encode()
|
||||||
|
@ -3,6 +3,7 @@ package api_impl
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
@ -110,8 +111,22 @@ func (f *Flamenco) ShamanFileStore(e echo.Context, checksum string, filesize int
|
|||||||
canDefer = *params.XShamanCanDeferUpload
|
canDefer = *params.XShamanCanDeferUpload
|
||||||
logCtx = logCtx.Bool("canDefer", canDefer)
|
logCtx = logCtx.Bool("canDefer", canDefer)
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.XShamanOriginalFilename != nil {
|
if params.XShamanOriginalFilename != nil {
|
||||||
origFilename = *params.XShamanOriginalFilename
|
rawHeadervalue := *params.XShamanOriginalFilename
|
||||||
|
decoder := mime.WordDecoder{}
|
||||||
|
|
||||||
|
var err error // origFilename has to be used from the outer scope.
|
||||||
|
origFilename, err = decoder.DecodeHeader(rawHeadervalue)
|
||||||
|
if err != nil {
|
||||||
|
logger := logCtx.Logger()
|
||||||
|
logger.Error().
|
||||||
|
Str("headerValue", rawHeadervalue).
|
||||||
|
Err(err).
|
||||||
|
Msg("shaman: received invalid X-Shaman-Original-Filename header")
|
||||||
|
return sendAPIError(e, http.StatusBadRequest, "invalid X-Shaman-Original-Filename header: %q", rawHeadervalue)
|
||||||
|
}
|
||||||
|
|
||||||
logCtx = logCtx.Str("originalFilename", origFilename)
|
logCtx = logCtx.Str("originalFilename", origFilename)
|
||||||
}
|
}
|
||||||
logger := logCtx.Logger()
|
logger := logCtx.Logger()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user