diff --git a/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php b/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php index ea8cbbb360..211de1f58b 100644 --- a/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php +++ b/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php @@ -172,7 +172,7 @@ public function post(Request $request, $entity_type_id, $bundle, $field_name) { // Create the file. $file_uri = "{$destination}/{$filename}"; - $temp_file_path = $this->streamUploadData($file_uri); + $temp_file_path = $this->streamUploadData(); // This will take care of altering $file_uri if a file already exists. file_unmanaged_prepare($temp_file_path, $file_uri); @@ -189,14 +189,14 @@ public function post(Request $request, $entity_type_id, $bundle, $field_name) { ]; $file = File::create($values); - // Validate the file entity against entiy level validation and field level + // Validate the file entity against entity level validation and field level // validators. $this->validate($file, $field_definition); - // Move the file to the correct location after validation. - // Move the file to the correct location based on the file entity, - // replacing any existing file. - if (!file_unmanaged_move($temp_file_path, $file_uri)) { + // Move the file to the correct location after validation. Use + // FILE_EXISTS_ERROR as the file location has already been determined above + // in file_unmanaged_prepare(). + if (!file_unmanaged_move($temp_file_path, $file_uri, FILE_EXISTS_ERROR)) { throw new HttpException(500, 'Temporary file could not be moved to file location'); } diff --git a/core/modules/rest/tests/src/Functional/FileUploadResourceTestBase.php b/core/modules/rest/tests/src/Functional/FileUploadResourceTestBase.php index 1ec01d3eda..59019e3fe2 100644 --- a/core/modules/rest/tests/src/Functional/FileUploadResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/FileUploadResourceTestBase.php @@ -174,6 +174,43 @@ public function testPostFileUpload() { $this->assertSame($this->testFileData, file_get_contents('public://foobar/example.txt')); } + /** + * Tests using the file upload POST route with a duplicate file. + * + * A new file should be created with a suffixed name. + */ + public function testPostFileUploadDuplicateFile() { + $this->initAuthentication(); + + $this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']); + + $this->setUpAuthorization('POST'); + + $uri = Url::fromUri('base:' . static::$postUri); + + // This request will have the default 'application/octet-stream' content + // type header. + $response = $this->fileRequest($uri, $this->testFileData); + + $this->assertSame(201, $response->getStatusCode()); + + // Make the same request again. The file should be saved as a new file + // entity that has the same file name but a suffixed file URI. + $response = $this->fileRequest($uri, $this->testFileData); + + $this->assertSame(201, $response->getStatusCode()); + + // Loading expected normalized data for file 2. + $expected = $this->getExpectedNormalizedEntity(2); + // Update the file URI to match the generated name. + $expected['uri'][0]['value'] = 'public://foobar/example_0.txt'; + + $this->assertResponseData($expected, $response); + + // Check the actual file data. + $this->assertSame($this->testFileData, file_get_contents('public://foobar/example_0.txt')); + } + /** * Tests using the file upload route with a zero byte file. */ @@ -266,15 +303,21 @@ protected function getExpectedUnauthorizedAccessMessage($method) { /** * Gets the expected file entity. + * + * @param int $fid + * The file ID to load and create normalized data for. + * + * @return array + * The expected normalized data array. */ - protected function getExpectedNormalizedEntity() { + protected function getExpectedNormalizedEntity($fid = 1) { $author = User::load(static::$auth ? $this->account->id() : 0); - $file = File::load(1); + $file = File::load($fid); $expected_normalization = [ 'fid' => [ [ - 'value' => 1, + 'value' => (int) $file->id(), ], ], 'uuid' => [