diff --git a/tests/acceptance/features/apiCors/cors.feature b/tests/acceptance/features/apiCors/cors.feature index cc5ceec868..fb35b2df57 100644 --- a/tests/acceptance/features/apiCors/cors.feature +++ b/tests/acceptance/features/apiCors/cors.feature @@ -120,7 +120,6 @@ Feature: CORS headers | Access-Control-Allow-Origin | https://aphno.badal | And for user "Alice" the content of the file "/textFile.txt" of the space "Personal" should be "01234" - @issue-8380 Scenario: uploading file using Tus using different CORS headers Given user "Alice" has created a new TUS resource for the space "Personal" with content "" using the WebDAV API with these headers: @@ -134,3 +133,28 @@ Feature: CORS headers | Upload-Checksum | MD5 4100c4d44da9177247e44a5fc1546778 | | Upload-Offset | 0 | Then the HTTP status code should be "403" + + @issue-8380 + Scenario Outline: CORS headers should be returned when an preflight request is sent to Tus upload + Given user "Alice" has created a new TUS resource for the space "Personal" with content "" using the WebDAV API with these headers: + | Upload-Length | 5 | + # dGV4dEZpbGUudHh0 is the base64 encode of textFile.txt + | Upload-Metadata | filename dGV4dEZpbGUudHh0 | + | Tus-Resumable | 1.0.0 | + When user "Alice" sends HTTP method "OPTIONS" to URL "" with headers + | header | value | + | Origin | https://aphno.badal | + | Access-Control-Request-Headers | Origin, Accept, Content-Type, Depth, Authorization, Ocs-Apirequest, If-None-Match, If-Match, Destination, Overwrite, X-Request-Id, X-Requested-With, Tus-Resumable, Tus-Checksum-Algorithm, Upload-Concat, Upload-Length, Upload-Metadata, Upload-Defer-Length, Upload-Expires, Upload-Checksum, Upload-Offset, X-Http-Method-Override, Cache-Control | + | Access-Control-Request-Method | | + And the HTTP status code should be "204" + And the following headers should be set + | header | value | + | Access-Control-Allow-Headers | Origin, Accept, Content-Type, Depth, Authorization, Ocs-Apirequest, If-None-Match, If-Match, Destination, Overwrite, X-Request-Id, X-Requested-With, Tus-Resumable, Tus-Checksum-Algorithm, Upload-Concat, Upload-Length, Upload-Metadata, Upload-Defer-Length, Upload-Expires, Upload-Checksum, Upload-Offset, X-Http-Method-Override, Cache-Control | + | Access-Control-Allow-Origin | https://aphno.badal | + | Access-Control-Allow-Methods | | + Examples: + | endpoint | request-method | + | /%tus_upload_location% | PUT | + | /%tus_upload_location% | POST | + | /%tus_upload_location% | HEAD | + | /%tus_upload_location% | PATCH | \ No newline at end of file diff --git a/tests/acceptance/features/bootstrap/FeatureContext.php b/tests/acceptance/features/bootstrap/FeatureContext.php index 118facc9bd..1937f20760 100644 --- a/tests/acceptance/features/bootstrap/FeatureContext.php +++ b/tests/acceptance/features/bootstrap/FeatureContext.php @@ -169,6 +169,7 @@ class FeatureContext extends BehatVariablesContext { private array $guzzleClientHeaders = []; public OCSContext $ocsContext; public AuthContext $authContext; + public TUSContext $tusContext; public GraphContext $graphContext; public SpacesContext $spacesContext; private array $initialTrustedServer; @@ -1397,7 +1398,35 @@ class FeatureContext extends BehatVariablesContext { public function userSendsHTTPMethodToUrl(string $user, string $verb, string $url): void { $user = $this->getActualUsername($user); $url = $this->substituteInLineCodes($url, $user); - $this->setResponse($this->sendingToWithDirectUrl($user, $verb, $url, null)); + $this->setResponse($this->sendingToWithDirectUrl($user, $verb, $url)); + } + + /** + * @When /^user "([^"]*)" sends HTTP method "([^"]*)" to URL "([^"]*)" with headers$/ + * + * @param string $user + * @param string $verb + * @param string $url + * @param string $headersTable + * + * @return void + */ + public function userSendsHTTPMethodToUrlWithHeaders(string $user, string $verb, string $url, TableNode $headersTable): void { + $this->verifyTableNodeColumns( + $headersTable, + ['header', 'value'] + ); + + $user = $this->getActualUsername($user); + $url = $this->substituteInLineCodes($url, $user); + $url = "/" . \ltrim(\str_replace($this->getBaseUrl(), "", $url), "/"); + + $headers = []; + foreach ($headersTable as $row) { + $headers[$row['header']] = $row['value']; + } + $response = $this->sendingToWithDirectUrl($user, $verb, $url, null, null, $headers); + $this->setResponse($response); } /** @@ -1458,23 +1487,24 @@ class FeatureContext extends BehatVariablesContext { } /** - * @param string|null $user - * @param string|null $verb - * @param string|null $url + * @param string $user + * @param string $verb + * @param string $url * @param string|null $body * @param string|null $password + * @param array|null $headers * * @return ResponseInterface * @throws GuzzleException */ - public function sendingToWithDirectUrl(?string $user, ?string $verb, ?string $url, string $body = null, ?string $password = null): ResponseInterface { + public function sendingToWithDirectUrl(string $user, string $verb, string $url, ?string $body = null, ?string $password = null, ?array $headers = null): ResponseInterface { $fullUrl = $this->getBaseUrl() . $url; if ($password === null) { $password = $this->getPasswordForUser($user); } - $headers = $this->guzzleClientHeaders; + $reqHeaders = $this->guzzleClientHeaders; $config = null; if ($this->sourceIpAddress !== null) { @@ -1491,7 +1521,11 @@ class FeatureContext extends BehatVariablesContext { } if (isset($this->requestToken)) { - $headers['requesttoken'] = $this->requestToken; + $reqHeaders['requesttoken'] = $this->requestToken; + } + + if ($headers) { + $reqHeaders = \array_merge($headers, $reqHeaders); } return HttpRequestHelper::sendRequest( @@ -1500,7 +1534,7 @@ class FeatureContext extends BehatVariablesContext { $verb, $user, $password, - $headers, + $reqHeaders, $body, $config, $cookies @@ -3001,6 +3035,14 @@ class FeatureContext extends BehatVariablesContext { "getEtagRegex" ], "parameter" => [] + ], + [ + "code" => "%tus_upload_location%", + "function" => [ + $this->tusContext, + "getTusResourceLocation" + ], + "parameter" => [] ] ]; if ($user !== null) { @@ -3402,10 +3444,13 @@ class FeatureContext extends BehatVariablesContext { // that calls BasicStructure.php $this->ocsContext = new OCSContext(); $this->authContext = new AuthContext(); + $this->tusContext = new TUSContext(); $this->ocsContext->before($scope); $this->authContext->setUpScenario($scope); + $this->tusContext->setUpScenario($scope); $environment->registerContext($this->ocsContext); $environment->registerContext($this->authContext); + $environment->registerContext($this->tusContext); $scenarioLine = $scope->getScenario()->getLine(); $featureFile = $scope->getFeature()->getFile(); $suiteName = $scope->getSuite()->getName(); diff --git a/tests/acceptance/features/bootstrap/TUSContext.php b/tests/acceptance/features/bootstrap/TUSContext.php index ef2292bdc8..99404723fa 100644 --- a/tests/acceptance/features/bootstrap/TUSContext.php +++ b/tests/acceptance/features/bootstrap/TUSContext.php @@ -42,6 +42,13 @@ class TUSContext implements Context { private ?string $resourceLocation = null; + /** + * @return string + */ + public function getTusResourceLocation(): string { + return $this->resourceLocation ?: ""; + } + /** * @param string $user * @param TableNode $headers