diff --git a/app/http.php b/app/http.php index bec772c770..87472a3fbe 100644 --- a/app/http.php +++ b/app/http.php @@ -39,8 +39,7 @@ $http ->set([ 'worker_num' => $workerNumber, 'open_http2_protocol' => true, - 'http_compression' => true, - 'http_compression_level' => 6, + 'http_compression' => false, 'package_max_length' => $payloadSize, 'buffer_output_size' => $payloadSize, ]); @@ -61,6 +60,7 @@ include __DIR__ . '/controllers/general.php'; $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $register) { $app = new App('UTC'); + $app->setCompression(true); go(function () use ($register, $app) { $pools = $register->get('pools'); @@ -244,6 +244,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo } $app = new App('UTC'); + $app->setCompression(true); $pools = $register->get('pools'); App::setResource('pools', fn () => $pools); diff --git a/composer.lock b/composer.lock index c7ecca5034..0bcc5669ea 100644 --- a/composer.lock +++ b/composer.lock @@ -1671,6 +1671,52 @@ }, "time": "2024-10-04T13:55:36+00:00" }, + { + "name": "utopia-php/compression", + "version": "0.1.2", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/compression.git", + "reference": "6062f70596415f8d5de40a589367b0eb2a435f98" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/compression/zipball/6062f70596415f8d5de40a589367b0eb2a435f98", + "reference": "6062f70596415f8d5de40a589367b0eb2a435f98", + "shasum": "" + }, + "require": { + "php": ">=8.0" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3", + "vimeo/psalm": "4.0.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Compression\\": "src/Compression" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple Compression library to handle file compression", + "keywords": [ + "compression", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/compression/issues", + "source": "https://github.com/utopia-php/compression/tree/0.1.2" + }, + "time": "2024-11-08T14:59:54+00:00" + }, { "name": "utopia-php/config", "version": "0.2.2", @@ -1926,20 +1972,21 @@ }, { "name": "utopia-php/framework", - "version": "0.33.8", + "version": "0.33.10", "source": { "type": "git", "url": "https://github.com/utopia-php/http.git", - "reference": "a7f577540a25cb90896fef2b64767bf8d700f3c5" + "reference": "247b934529ab9bcde7d39d6e6212cefcccfc3b20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/http/zipball/a7f577540a25cb90896fef2b64767bf8d700f3c5", - "reference": "a7f577540a25cb90896fef2b64767bf8d700f3c5", + "url": "https://api.github.com/repos/utopia-php/http/zipball/247b934529ab9bcde7d39d6e6212cefcccfc3b20", + "reference": "247b934529ab9bcde7d39d6e6212cefcccfc3b20", "shasum": "" }, "require": { - "php": ">=8.0" + "php": ">=8.0", + "utopia-php/compression": "0.1.*" }, "require-dev": { "laravel/pint": "^1.2", @@ -1965,9 +2012,9 @@ ], "support": { "issues": "https://github.com/utopia-php/http/issues", - "source": "https://github.com/utopia-php/http/tree/0.33.8" + "source": "https://github.com/utopia-php/http/tree/0.33.10" }, - "time": "2024-08-15T14:10:09+00:00" + "time": "2024-11-08T15:02:59+00:00" }, { "name": "utopia-php/image", diff --git a/tests/e2e/Client.php b/tests/e2e/Client.php index 0774f1c6fd..dc80808b14 100644 --- a/tests/e2e/Client.php +++ b/tests/e2e/Client.php @@ -179,9 +179,14 @@ class Client default => http_build_query($params), }; - foreach ($headers as $i => $header) { - $headers[] = $i . ':' . $header; - unset($headers[$i]); + $formattedHeaders = []; + foreach ($headers as $key => $value) { + if (strtolower($key) === 'accept-encoding') { + curl_setopt($ch, CURLOPT_ENCODING, $value); + continue; + } else { + $formattedHeaders[] = $key . ': ' . $value; + } } curl_setopt($ch, CURLOPT_PATH_AS_IS, 1); @@ -189,7 +194,7 @@ class Client curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_HTTPHEADER, $formattedHeaders); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); curl_setopt($ch, CURLOPT_TIMEOUT, 15); curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders, &$cookies) { @@ -220,7 +225,6 @@ class Client curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - $responseBody = curl_exec($ch); $responseType = $responseHeaders['content-type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); diff --git a/tests/e2e/General/CompressionTest.php b/tests/e2e/General/CompressionTest.php new file mode 100644 index 0000000000..9affacfe0a --- /dev/null +++ b/tests/e2e/General/CompressionTest.php @@ -0,0 +1,137 @@ +client->call(Client::METHOD_GET, '/ping', [ + 'accept-encoding' => 'gzip', + 'x-appwrite-project' => $this->getProject()['$id'], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('Pong!', $response['body']); + $this->assertLessThan(1024, strlen($response['body'])); + $this->assertArrayNotHasKey('content-encoding', $response['headers']); + + // without header + $response = $this->client->call(Client::METHOD_GET, '/ping', [ + 'x-appwrite-project' => $this->getProject()['$id'], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('Pong!', $response['body']); + $this->assertLessThan(1024, strlen($response['body'])); + $this->assertArrayNotHasKey('content-encoding', $response['headers']); + } + + public function testLargeResponse() + { + // create an anonymous user + $response = $this->client->call(Client::METHOD_POST, '/users', array_merge([ + 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + ], $this->getHeaders()), [ + 'userId' => ID::unique(), + 'email' => 'test@localhost.test', + 'password' => 'password', + 'name' => 'User Name', + ]); + $this->assertEquals(201, $response['headers']['status-code']); + $userId = $response['body']['$id']; + + // set prefs with 2000 bytes of data + $prefs = ["longValue" => str_repeat('a', 2000)]; + + $response = $this->client->call(Client::METHOD_PATCH, '/users/' . $userId . '/prefs', array_merge([ + 'x-appwrite-project' => $this->getProject()['$id'], + 'content-type' => 'application/json', + ], $this->getHeaders()), [ + 'prefs' => $prefs, + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + // get prefs with compression + $response = $this->client->call(Client::METHOD_GET, '/users/' . $userId . '/prefs', array_merge([ + 'x-appwrite-project' => $this->getProject()['$id'], + 'accept-encoding' => 'gzip', + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertArrayHasKey('content-encoding', $response['headers'], 'Content encoding should be gzip, headers received: ' . json_encode($response['headers'], JSON_PRETTY_PRINT)); + $this->assertLessThan(2000, intval($response['headers']['content-length'])); + + // get prefs without compression + $response = $this->client->call(Client::METHOD_GET, '/users/' . $userId . '/prefs', array_merge([ + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertGreaterThanOrEqual(2000, intval($response['headers']['content-length'])); + $this->assertArrayNotHasKey('content-encoding', $response['headers']); + } + + public function testImageResponse() + { + // create bucket + $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'bucketId' => ID::unique(), + 'name' => 'Test Bucket', + 'fileSecurity' => true, + ]); + $bucketId = $bucket['body']['$id']; + $this->assertEquals(201, $bucket['headers']['status-code']); + + // upload image + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../resources/logo.png'), 'image/png', 'logo.png'), + 'permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + ]); + $fileId = $file['body']['$id']; + + // get image with header + $response = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + 'content-type' => 'application/json', + 'accept-encoding' => 'gzip', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertArrayNotHasKey('content-encoding', $response['headers']); + // get image without + $response = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertArrayNotHasKey('content-encoding', $response['headers']); + } +} diff --git a/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php b/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php index b1315103b1..4f4b0c960d 100644 --- a/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php +++ b/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php @@ -1,12 +1,13 @@