From 94ff3baa9c559d67b73075589355d2be31c08ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 27 Oct 2023 10:26:46 +0200 Subject: [PATCH] Fix cookie headers --- app/controllers/general.php | 15 +++- .../Functions/FunctionsCustomServerTest.php | 88 +++++++++++++++++++ .../resources/functions/php-cookie/index.php | 6 ++ 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 tests/resources/functions/php-cookie/index.php diff --git a/app/controllers/general.php b/app/controllers/general.php index 0a67148576..448f23c875 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -117,12 +117,23 @@ function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleReques $path .= '?' . $query; } + $swooleHeaders = $swooleRequest->header; + + $cookieHeaders = []; + foreach ($swooleRequest->cookie as $key => $value) { + $cookieHeaders[] = "{$key}={$value}"; + } + + if(!empty($cookieHeaders)) { + $swooleHeaders['cookie'] = \implode('; ', $cookieHeaders); + } + $body = \json_encode([ 'async' => false, 'body' => $swooleRequest->getContent() ?? '', 'method' => $swooleRequest->server['request_method'], 'path' => $path, - 'headers' => $swooleRequest->header + 'headers' => $swooleHeaders ]); $headers = [ @@ -406,7 +417,7 @@ App::init() * @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers */ if (App::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS - if ($request->getProtocol() !== 'https' && ($swooleRequest->header['host'] ?? '') !== 'localhost' && ($swooleRequest->header['host'] ?? '') !== APP_HOSTNAME_INTERNAL) { // localhost allowed for proxy, APP_HOSTNAME_INTERNAL allowed for migrations + if ($request->getProtocol() !== 'https' && ($swooleHeaders['host'] ?? '') !== 'localhost' && ($swooleHeaders['host'] ?? '') !== APP_HOSTNAME_INTERNAL) { // localhost allowed for proxy, APP_HOSTNAME_INTERNAL allowed for migrations if ($request->getMethod() !== Request::METHOD_GET) { throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.'); } diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index cdc9ec846f..58c89f5687 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -1344,4 +1344,92 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); } + + public function testCookieExecution() + { + $timeout = 5; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/php-cookie/code.tar.gz"; + $this->packageCode('php-cookie'); + + $function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'functionId' => ID::unique(), + 'name' => 'Test PHP Cookie executions', + 'runtime' => 'php-8.0', + 'entrypoint' => 'index.php', + 'timeout' => $timeout, + ]); + + $functionId = $function['body']['$id'] ?? ''; + + $this->assertEquals(201, $function['headers']['status-code']); + + $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'entrypoint' => 'index.php', + 'code' => new CURLFile($code, 'application/x-gzip', basename($code)), + 'activate' => true + ]); + + $deploymentId = $deployment['body']['$id'] ?? ''; + $this->assertEquals(202, $deployment['headers']['status-code']); + + // Poll until deployment is built + while (true) { + $deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + if ( + $deployment['headers']['status-code'] >= 400 + || \in_array($deployment['body']['status'], ['ready', 'failed']) + ) { + break; + } + + \sleep(1); + } + + $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + + $this->assertEquals(200, $deployment['headers']['status-code']); + + // Wait a little for activation to finish + sleep(5); + + $cookie = 'cookieName=cookieValue; cookie2=value2; cookie3=value=3; cookie4=value4'; + + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'async' => false, + 'headers' => [ + 'cookie' => $cookie + ] + ]); + + $this->assertEquals(201, $execution['headers']['status-code']); + $this->assertEquals('completed', $execution['body']['status']); + $this->assertEquals(200, $execution['body']['responseStatusCode']); + $this->assertEquals($cookie, $execution['body']['responseBody']); + + // Cleanup : Delete function + $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], []); + + $this->assertEquals(204, $response['headers']['status-code']); + } } diff --git a/tests/resources/functions/php-cookie/index.php b/tests/resources/functions/php-cookie/index.php new file mode 100644 index 0000000000..2812dbc24e --- /dev/null +++ b/tests/resources/functions/php-cookie/index.php @@ -0,0 +1,6 @@ +log($context->req->headers); + return $context->res->send($context->req->headers['cookie'] ?? ''); +};