Skip to content

Commit

Permalink
* Add workaround for clients uploading files with missing 'filename' …
Browse files Browse the repository at this point in the history
…directive in 'Content-Disposition'

header of multipart/form-data POST
* Add unit tests
  • Loading branch information
tobiasgv committed Nov 13, 2024
1 parent 2982ce8 commit 4e38567
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 47 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

* Add workaround for clients uploading files with missing 'filename' directive in 'Content-Disposition'
header of multipart/form-data POST
* Add unit tests

## v0.1.5

* Adapt to CAMPUSonline DMS API spec version 1.5.0
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"php": ">=8.1",
"ext-json": "*",
"api-platform/core": "^3.2",
"dbp/relay-blob-bundle": "^0.1.54",
"dbp/relay-blob-bundle": "^0.1.66",
"dbp/relay-core-bundle": "^0.1.187",
"doctrine/doctrine-migrations-bundle": "^3.3",
"symfony/config": "^6.4",
Expand Down
55 changes: 29 additions & 26 deletions composer.lock

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

26 changes: 23 additions & 3 deletions src/Rest/Common.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,51 @@
namespace Dbp\Relay\BlobConnectorCampusonlineDmsBundle\Rest;

use Dbp\Relay\BlobConnectorCampusonlineDmsBundle\Entity\Error;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class Common
{
/**
* @throws Error
*/
public static function ensureUpdatedFileIsValid(mixed $uploadedFile, string $fileParameterName = 'binary_content'): void
public static function getAndValidateUploadedFile(Request $request, string $fileParameterName): File
{
$uploadedFile = $request->files->get($fileParameterName);
if ($uploadedFile === null) {
// look into form parameters if the file was sent in the form of a binary string parameter,
// i.e. without the 'filename' directive in the 'content-disposition' header, which CO currently does.
$binaryContent = $request->request->get($fileParameterName);
if ($binaryContent === null) {
throw new Error(Response::HTTP_BAD_REQUEST, 'parameter \'binary_content\' must not be empty',
errorCode: 'REQUIRED_PARAMETER_MISSING', errorDetail: 'binary_content');
}
$filesystem = new Filesystem();
$tempFilePath = $filesystem->tempnam('/tmp', 'php');
file_put_contents($tempFilePath, $binaryContent);
$uploadedFile = new File($tempFilePath);
}

if ($uploadedFile === null) {
throw new Error(Response::HTTP_BAD_REQUEST, 'Parameter \''.$fileParameterName.'\' is required',
errorCode: 'REQUIRED_PARAMETER_MISSING', errorDetail: $fileParameterName);
}
if ($uploadedFile instanceof UploadedFile === false) {
if ($uploadedFile instanceof File === false) {
throw new Error(Response::HTTP_BAD_REQUEST, 'Parameter \''.$fileParameterName.'\' must be a file stream',
errorCode: 'PARAMETER_TYPE_INVALID', errorDetail: $fileParameterName);
}
if ($uploadedFile->getError() !== UPLOAD_ERR_OK) {
if ($uploadedFile instanceof UploadedFile && $uploadedFile->getError() !== UPLOAD_ERR_OK) {
throw new Error(Response::HTTP_BAD_REQUEST, sprintf('file stream upload failed: %d', $uploadedFile->getError()),
errorCode: 'FILE_UPLOAD_FAILED', errorDetail: $fileParameterName);
}
if ($uploadedFile->getSize() === 0) {
throw new Error(Response::HTTP_BAD_REQUEST, 'uploaded file stream must not be empty',
errorCode: 'FILE_MUST_NOT_BE_EMPTY', errorDetail: $fileParameterName);
}

return $uploadedFile;
}
}
3 changes: 1 addition & 2 deletions src/Rest/CreateDocumentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ public function __invoke(Request $request): Document
errorCode: 'REQUIRED_PARAMETER_MISSING', errorDetail: 'name');
}

$uploadedFile = $request->files->get('binary_content');
Common::ensureUpdatedFileIsValid($uploadedFile);
$uploadedFile = Common::getAndValidateUploadedFile($request, 'binary_content');

$metadata = $request->request->get('metadata');
if ($metadata === null) {
Expand Down
3 changes: 1 addition & 2 deletions src/Rest/CreateDocumentVersionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ public function __invoke(Request $request, string $uid): ?Document
$name = $request->request->get('name');
$documentType = $request->request->get('document_type');

$uploadedFile = $request->files->get('binary_content');
Common::ensureUpdatedFileIsValid($uploadedFile);
$uploadedFile = Common::getAndValidateUploadedFile($request, 'binary_content');

$documentVersionMetadataArray = null;
$documentVersionMetadata = $request->request->get('metadata');
Expand Down
27 changes: 14 additions & 13 deletions src/Service/DocumentService.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
use Dbp\Relay\BlobConnectorCampusonlineDmsBundle\Entity\Document;
use Dbp\Relay\BlobConnectorCampusonlineDmsBundle\Entity\DocumentVersionInfo;
use Dbp\Relay\BlobConnectorCampusonlineDmsBundle\Entity\Error;
use Dbp\Relay\BlobConnectorCampusonlineDmsBundle\Entity\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Dbp\Relay\BlobConnectorCampusonlineDmsBundle\Entity\File as FileEntity;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Uid\Uuid;

class DocumentService
{
private const DOCUMENT_VERSION_METADATA_TYPE = 'document_version'; // config value?
private const BUCKET_ID = 'campusonline-dms-bucket';
public const BUCKET_ID = 'campusonline-dms-bucket';

private const DOCUMENT_VERSION_METADATA_TYPE = 'document_version'; // config value?
private const DOCUMENT_VERSION_METADATA_METADATA_KEY = 'doc_version_metadata';
private const DOCUMENT_METADATA_METADATA_KEY = 'doc_metadata';
private const VERSION_NUMBER_METADATA_KEY = 'version';
Expand Down Expand Up @@ -64,7 +64,7 @@ public function getDocument(string $uid): Document
/**
* @throws \Exception
*/
public function addDocument(Document $document, UploadedFile $uploadedFile, string $name,
public function addDocument(Document $document, File $uploadedFile, string $name,
?array $documentVersionMetadata = null, ?string $documentType = null): Document
{
$document->setUid((string) Uuid::v7());
Expand All @@ -91,7 +91,7 @@ public function removeDocument(string $uid): void
/**
* @throws \Exception
*/
public function addDocumentVersion(string $documentUid, UploadedFile $uploadedFile,
public function addDocumentVersion(string $documentUid, File $uploadedFile,
string $name, ?array $documentVersionMetadata = null, ?string $documentType = null): ?Document
{
$document = $this->getDocument($documentUid);
Expand Down Expand Up @@ -140,36 +140,36 @@ public function getDocumentVersionBinaryFileResponse(string $uid): Response
}
}

public function getFile(string $uid): ?File
public function getFile(string $uid): ?FileEntity
{
$file = new File();
$file = new FileEntity();
$file->setUid($uid);

return $file;
}

public function addFile(File $file): File
public function addFile(FileEntity $file): FileEntity
{
$file->setUid((string) Uuid::v7());

return $file;
}

public function replaceFile(string $uid, File $file): File
public function replaceFile(string $uid, FileEntity $file): FileEntity
{
$file->setUid($uid);

return $file;
}

public function removeFile(string $uid, File $file): void
public function removeFile(string $uid, FileEntity $file): void
{
}

/**
* @throws \Exception
*/
private function createDocumentVersion(Document $document, UploadedFile $uploadedFile, string $name,
private function createDocumentVersion(Document $document, File $uploadedFile, string $name,
?array $documentVersionMetadata = null, ?string $documentType = null, ?string $lastVersion = null): DocumentVersionInfo
{
$versionNumber = $lastVersion ? strval(intval($lastVersion) + 1) : '1';
Expand Down Expand Up @@ -198,9 +198,10 @@ private function createDocumentVersion(Document $document, UploadedFile $uploade
$fileData->setPrefix($document->getUid());
$fileData->setType(self::DOCUMENT_VERSION_METADATA_TYPE);
$fileData->setMetadata($metadataEncoded);
$fileData->setBucketId(self::BUCKET_ID);

try {
$fileData = $this->fileApi->addFile($fileData, self::BUCKET_ID);
$fileData = $this->fileApi->addFile($fileData);
} catch (FileApiException $fileApiException) {
throw self::createException($fileApiException);
}
Expand Down
Loading

0 comments on commit 4e38567

Please sign in to comment.