diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a6f1e642..797e1b87 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,5 +30,8 @@ jobs: - name: Run Swoole Tests run: docker compose exec swoole vendor/bin/phpunit --configuration phpunit.xml - - name: Run Swoole Corotuine Tests + - name: Run Swoole Coroutine Tests run: docker compose exec swoole-coroutine vendor/bin/phpunit --configuration phpunit.xml + + - name: Run Swoole Compression Tests + run: docker compose exec swoole-compression vendor/bin/phpunit --configuration phpunit.xml \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 36760e78..e922df85 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,6 +70,7 @@ $ git push origin [name_of_your_new_branch] - `docker compose exec fpm vendor/bin/phpunit --configuration phpunit.xml` - `docker compose exec swoole vendor/bin/phpunit --configuration phpunit.xml` - `docker compose exec swoole-coroutine vendor/bin/phpunit --configuration phpunit.xml` +- `docker compose exec swoole-compression vendor/bin/phpunit --configuration phpunit.xml` ## Introducing New Features diff --git a/Dockerfile.swoole_compression b/Dockerfile.swoole_compression new file mode 100644 index 00000000..446248bd --- /dev/null +++ b/Dockerfile.swoole_compression @@ -0,0 +1,48 @@ +FROM composer:2.0 AS step0 + +ARG TESTING=true +ARG DEBUG=false + +ENV TESTING=$TESTING +ENV DEBUG=$DEBUG + +WORKDIR /usr/local/src/ + +COPY composer.* /usr/local/src/ + +RUN composer install --ignore-platform-reqs --optimize-autoloader \ + --no-plugins --no-scripts --prefer-dist \ + `if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi` + +FROM appwrite/base:0.9.0 as final + +ARG TESTING=true +ARG DEBUG=false + +ENV TESTING=$TESTING +ENV DEBUG=$DEBUG + +LABEL maintainer="team@appwrite.io" + +RUN \ + if [ "$DEBUG" == "true" ]; then \ + apk add boost boost-dev; \ + fi + +WORKDIR /usr/src/code + +COPY ./dev /usr/src/code/dev +COPY ./src /usr/src/code/src +COPY ./tests /usr/src/code/tests +COPY ./phpunit.xml /usr/src/code/phpunit.xml +COPY ./phpbench.json /usr/src/code/phpbench.json +COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor + +# Enable Extensions +RUN if [ "$DEBUG" == "true" ]; then cp /usr/src/code/dev/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini; fi +RUN if [ "$DEBUG" = "false" ]; then rm -rf /usr/src/code/dev; fi +RUN if [ "$DEBUG" = "false" ]; then rm -f /usr/local/lib/php/extensions/no-debug-non-zts-20220829/xdebug.so; fi + +EXPOSE 80 + +CMD ["php", "tests/e2e/server-swoole-compression.php"] diff --git a/composer.json b/composer.json index 0cdace99..04f15e98 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "require": { "php": ">=8.0", "ext-swoole": "*", - "utopia-php/servers": "0.1.*" + "utopia-php/servers": "0.1.*", + "utopia-php/compression": "0.1.*" }, "require-dev": { "ext-xdebug": "*", diff --git a/composer.lock b/composer.lock index 0a04d66b..e60a1052 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,54 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f765427b1ac629c58be95cd57ffacda3", + "content-hash": "d32afe850b2efb8780a47961dd5ff634", "packages": [ + { + "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/di", "version": "0.1.0", @@ -334,16 +380,16 @@ }, { "name": "laravel/pint", - "version": "v1.17.3", + "version": "v1.18.1", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "9d77be916e145864f10788bb94531d03e1f7b482" + "reference": "35c00c05ec43e6b46d295efc0f4386ceb30d50d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/9d77be916e145864f10788bb94531d03e1f7b482", - "reference": "9d77be916e145864f10788bb94531d03e1f7b482", + "url": "https://api.github.com/repos/laravel/pint/zipball/35c00c05ec43e6b46d295efc0f4386ceb30d50d9", + "reference": "35c00c05ec43e6b46d295efc0f4386ceb30d50d9", "shasum": "" }, "require": { @@ -396,7 +442,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2024-09-03T15:00:28+00:00" + "time": "2024-09-24T17:22:50+00:00" }, { "name": "myclabs/deep-copy", @@ -460,16 +506,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.1.0", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", "shasum": "" }, "require": { @@ -512,9 +558,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" }, - "time": "2024-07-01T20:03:41+00:00" + "time": "2024-10-08T18:51:32+00:00" }, { "name": "phar-io/manifest", @@ -734,6 +780,7 @@ "issues": "https://github.com/phpbench/dom/issues", "source": "https://github.com/phpbench/dom/tree/0.3.3" }, + "abandoned": true, "time": "2023-03-06T23:46:57+00:00" }, { @@ -837,16 +884,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.3", + "version": "1.12.8", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0fcbf194ab63d8159bb70d9aa3e1350051632009" + "reference": "f6a60a4d66142b8156c9da923f1972657bc4748c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0fcbf194ab63d8159bb70d9aa3e1350051632009", - "reference": "0fcbf194ab63d8159bb70d9aa3e1350051632009", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f6a60a4d66142b8156c9da923f1972657bc4748c", + "reference": "f6a60a4d66142b8156c9da923f1972657bc4748c", "shasum": "" }, "require": { @@ -891,7 +938,7 @@ "type": "github" } ], - "time": "2024-09-09T08:10:35+00:00" + "time": "2024-11-06T19:06:49+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1214,16 +1261,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.20", + "version": "9.6.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "49d7820565836236411f5dc002d16dd689cde42f" + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", - "reference": "49d7820565836236411f5dc002d16dd689cde42f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", "shasum": "" }, "require": { @@ -1238,7 +1285,7 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.31", + "phpunit/php-code-coverage": "^9.2.32", "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.4", @@ -1297,7 +1344,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" }, "funding": [ { @@ -1313,7 +1360,7 @@ "type": "tidelift" } ], - "time": "2024-07-10T11:45:39+00:00" + "time": "2024-09-19T10:50:18+00:00" }, { "name": "psr/cache", @@ -1419,16 +1466,16 @@ }, { "name": "psr/log", - "version": "3.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "79dff0b268932c640297f5208d6298f71855c03e" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/79dff0b268932c640297f5208d6298f71855c03e", - "reference": "79dff0b268932c640297f5208d6298f71855c03e", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -1463,9 +1510,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.1" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2024-08-21T13:31:24+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "sebastian/cli-parser", @@ -2538,16 +2585,16 @@ }, { "name": "symfony/console", - "version": "v7.1.4", + "version": "v7.1.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "1eed7af6961d763e7832e874d7f9b21c3ea9c111" + "reference": "3284aafcac338b6e86fd955ee4d794cbe434151a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1eed7af6961d763e7832e874d7f9b21c3ea9c111", - "reference": "1eed7af6961d763e7832e874d7f9b21c3ea9c111", + "url": "https://api.github.com/repos/symfony/console/zipball/3284aafcac338b6e86fd955ee4d794cbe434151a", + "reference": "3284aafcac338b6e86fd955ee4d794cbe434151a", "shasum": "" }, "require": { @@ -2611,7 +2658,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.4" + "source": "https://github.com/symfony/console/tree/v7.1.7" }, "funding": [ { @@ -2627,7 +2674,7 @@ "type": "tidelift" } ], - "time": "2024-08-15T22:48:53+00:00" + "time": "2024-11-05T15:34:55+00:00" }, { "name": "symfony/deprecation-contracts", @@ -2698,16 +2745,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.1.2", + "version": "v7.1.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c" + "reference": "c835867b3c62bb05c7fe3d637c871c7ae52024d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/c835867b3c62bb05c7fe3d637c871c7ae52024d4", + "reference": "c835867b3c62bb05c7fe3d637c871c7ae52024d4", "shasum": "" }, "require": { @@ -2744,7 +2791,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.1.2" + "source": "https://github.com/symfony/filesystem/tree/v7.1.6" }, "funding": [ { @@ -2760,20 +2807,20 @@ "type": "tidelift" } ], - "time": "2024-06-28T10:03:55+00:00" + "time": "2024-10-25T15:11:02+00:00" }, { "name": "symfony/finder", - "version": "v7.1.4", + "version": "v7.1.6", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "d95bbf319f7d052082fb7af147e0f835a695e823" + "reference": "2cb89664897be33f78c65d3d2845954c8d7a43b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/d95bbf319f7d052082fb7af147e0f835a695e823", - "reference": "d95bbf319f7d052082fb7af147e0f835a695e823", + "url": "https://api.github.com/repos/symfony/finder/zipball/2cb89664897be33f78c65d3d2845954c8d7a43b8", + "reference": "2cb89664897be33f78c65d3d2845954c8d7a43b8", "shasum": "" }, "require": { @@ -2808,7 +2855,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.1.4" + "source": "https://github.com/symfony/finder/tree/v7.1.6" }, "funding": [ { @@ -2824,20 +2871,20 @@ "type": "tidelift" } ], - "time": "2024-08-13T14:28:19+00:00" + "time": "2024-10-01T08:31:23+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.1.1", + "version": "v7.1.6", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55" + "reference": "85e95eeede2d41cd146146e98c9c81d9214cae85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/47aa818121ed3950acd2b58d1d37d08a94f9bf55", - "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/85e95eeede2d41cd146146e98c9c81d9214cae85", + "reference": "85e95eeede2d41cd146146e98c9c81d9214cae85", "shasum": "" }, "require": { @@ -2875,7 +2922,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.1.1" + "source": "https://github.com/symfony/options-resolver/tree/v7.1.6" }, "funding": [ { @@ -2891,7 +2938,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3213,16 +3260,16 @@ }, { "name": "symfony/process", - "version": "v7.1.3", + "version": "v7.1.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca" + "reference": "9b8a40b7289767aa7117e957573c2a535efe6585" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7f2f542c668ad6c313dc4a5e9c3321f733197eca", - "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca", + "url": "https://api.github.com/repos/symfony/process/zipball/9b8a40b7289767aa7117e957573c2a535efe6585", + "reference": "9b8a40b7289767aa7117e957573c2a535efe6585", "shasum": "" }, "require": { @@ -3254,7 +3301,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.3" + "source": "https://github.com/symfony/process/tree/v7.1.7" }, "funding": [ { @@ -3270,7 +3317,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:44:47+00:00" + "time": "2024-11-06T09:25:12+00:00" }, { "name": "symfony/service-contracts", @@ -3357,16 +3404,16 @@ }, { "name": "symfony/string", - "version": "v7.1.4", + "version": "v7.1.6", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b" + "reference": "61b72d66bf96c360a727ae6232df5ac83c71f626" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/6cd670a6d968eaeb1c77c2e76091c45c56bc367b", - "reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b", + "url": "https://api.github.com/repos/symfony/string/zipball/61b72d66bf96c360a727ae6232df5ac83c71f626", + "reference": "61b72d66bf96c360a727ae6232df5ac83c71f626", "shasum": "" }, "require": { @@ -3424,7 +3471,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.1.4" + "source": "https://github.com/symfony/string/tree/v7.1.6" }, "funding": [ { @@ -3440,7 +3487,7 @@ "type": "tidelift" } ], - "time": "2024-08-12T09:59:40+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "theseer/tokenizer", @@ -3544,7 +3591,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/docker-compose.yml b/docker-compose.yml index bd2952c7..d88623ce 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,6 +38,19 @@ services: - ./tmp/xdebug:/tmp/xdebug networks: - testing + swoole-compression: + build: + context: . + dockerfile: Dockerfile.swoole_compression + ports: + - "9403:80" + volumes: + - ./dev:/usr/src/code/dev:rw + - ./src:/usr/src/code/src + - ./tests:/usr/src/code/tests + - ./tmp/xdebug:/tmp/xdebug + networks: + - testing mariadb: image: mariadb:10.11 # fix issues when upgrading using: mysql_upgrade -u root -p diff --git a/src/Http/Http.php b/src/Http/Http.php index 3a091c6a..8ff0abe7 100755 --- a/src/Http/Http.php +++ b/src/Http/Http.php @@ -8,6 +8,8 @@ class Http extends Base { + public const COMPRESSION_MIN_SIZE_DEFAULT = 1024; + /** * Request method constants */ @@ -49,6 +51,13 @@ class Http extends Base protected string|null $requestClass = null; protected string|null $responseClass = null; + /** + * Compression + */ + protected bool $compression = false; + protected int $compressionMinSize = Http::COMPRESSION_MIN_SIZE_DEFAULT; + protected mixed $compressionSupported = []; + /** * Http * @@ -79,6 +88,30 @@ public function setRequestClass(string $requestClass) $this->requestClass = $requestClass; } + /** + * Set compression + */ + public function setCompression(bool $compression) + { + $this->compression = $compression; + } + + /** + * Set minimum compression size + */ + public function setCompressionMinSize(int $compressionMinSize) + { + $this->compressionMinSize = $compressionMinSize; + } + + /** + * Set supported compression algorithms + */ + public function setCompressionSupported(mixed $compressionSupported) + { + $this->compressionSupported = $compressionSupported; + } + /** * GET * @@ -317,6 +350,12 @@ public function start() if (!\is_null($this->responseClass)) { $response = new $this->responseClass($response); + + if ($this->compression) { + $response->setAcceptEncoding($request->getHeader('accept-encoding') ?? ''); + $response->setCompressionMinSize($this->compressionMinSize); + $response->setCompressionSupported($this->compressionSupported); + } } $context = clone $this->container; diff --git a/src/Http/Response.php b/src/Http/Response.php index 66a0eeaa..60c32b1c 100755 --- a/src/Http/Response.php +++ b/src/Http/Response.php @@ -2,6 +2,8 @@ namespace Utopia\Http; +use Utopia\Compression\Compression; + abstract class Response { /** @@ -245,6 +247,21 @@ abstract class Response */ protected int $size = 0; + /** + * @var string + */ + protected string $acceptEncoding = ''; + + /** + * @var int + */ + protected int $compressionMinSize = Http::COMPRESSION_MIN_SIZE_DEFAULT; + + /** + * @var mixed + */ + protected mixed $compressionSupported = []; + /** * Response constructor. * @@ -270,6 +287,41 @@ public function setContentType(string $type, string $charset = ''): static return $this; } + /** + * Set accept encoding + * + * Set HTTP accept encoding header. + * + * @param string $acceptEncoding + */ + public function setAcceptEncoding(string $acceptEncoding): static + { + $this->acceptEncoding = $acceptEncoding; + return $this; + } + + /** + * Set min compression size + * + * Set minimum size for compression to be applied in bytes. + * + * @param int $compressionMinSize + */ + public function setCompressionMinSize(int $compressionMinSize): static + { + $this->compressionMinSize = $compressionMinSize; + return $this; + } + + /**s + * Set supported compression algorithms + */ + public function setCompressionSupported(mixed $compressionSupported): static + { + $this->compressionSupported = $compressionSupported; + return $this; + } + /** * Get content type * @@ -473,39 +525,51 @@ public function send(string $body = ''): void return; } - $this->sent = true; + $serverHeader = $this->headers['Server'] ?? 'Utopia/Http'; + $this->addHeader('Server', $serverHeader); - $this - ->addHeader('Server', array_key_exists('Server', $this->headers) ? $this->headers['Server'] : 'Utopia/Http') - ->addHeader('X-Debug-Speed', (string) (\microtime(true) - $this->startTime)) - ; + $this->appendCookies(); - $this - ->appendCookies() - ->appendHeaders(); + // Compress body + if ( + !empty($this->acceptEncoding) && + isset($this->compressed[$this->contentType]) && + strlen($body) > $this->compressionMinSize + ) { + $algorithm = Compression::fromAcceptEncoding($this->acceptEncoding, $this->compressionSupported); - if (!$this->disablePayload) { - $length = strlen($body); + if ($algorithm) { + $body = $algorithm->compress($body); + $this->addHeader('Content-Encoding', $algorithm->getContentEncoding()); + $this->addHeader('X-Utopia-Compression', 'true'); + $this->addHeader('Vary', 'Accept-Encoding'); + } + } - $this->size = $this->size + strlen(implode("\n", $this->headers)) + $length; + $this->addHeader('X-Debug-Speed', (string) (microtime(true) - $this->startTime)); + $this->appendHeaders(); - if (array_key_exists( - $this->contentType, - $this->compressed - ) && ($length <= self::CHUNK_SIZE)) { // Dont compress with GZIP / Brotli if header is not listed and size is bigger than 2mb - $this->end($body); - } else { - for ($i = 0; $i < ceil($length / self::CHUNK_SIZE); $i++) { - $this->write(substr($body, ($i * self::CHUNK_SIZE), min(self::CHUNK_SIZE, $length - ($i * self::CHUNK_SIZE)))); - } + // Send response + if ($this->disablePayload) { + $this->end(); + return; + } - $this->end(); - } + $headerSize = strlen(implode("\n", $this->headers)); + $bodyLength = strlen($body); + $this->size += $headerSize + $bodyLength; - $this->disablePayload(); + if ($bodyLength <= self::CHUNK_SIZE) { + $this->end($body); } else { + $chunks = str_split($body, self::CHUNK_SIZE); + foreach ($chunks as $chunk) { + $this->write($chunk); + } $this->end(); } + + $this->disablePayload(); } /** diff --git a/tests/e2e/ResponseSwooleCompression.php b/tests/e2e/ResponseSwooleCompression.php new file mode 100755 index 00000000..58c78a17 --- /dev/null +++ b/tests/e2e/ResponseSwooleCompression.php @@ -0,0 +1,17 @@ +client = new Client('http://swoole-compression'); + } +} diff --git a/tests/e2e/server-swoole-compression.php b/tests/e2e/server-swoole-compression.php new file mode 100644 index 00000000..e10c14d6 --- /dev/null +++ b/tests/e2e/server-swoole-compression.php @@ -0,0 +1,57 @@ +withHost('mariadb') + ->withPort(3306) + // ->withUnixSocket('/tmp/mysql.sock') + ->withDbName('test') + ->withCharset('utf8mb4') + ->withUsername('user') + ->withPassword('password'), 9000); + + +$dependency = new Dependency(); + +$dependency + ->setName('key') + ->inject('request') + ->setCallback(function (Request $request) { + return $request->getHeader('x-utopia-key', 'unknown'); + }); + +$container->set($dependency); + +$dependency1 = new Dependency(); +$dependency1 + ->setName('pool') + ->setCallback(function () use ($pool) { + return $pool; + }); + +$container->set($dependency1); + +$server = new Server('0.0.0.0', '80', [ + 'open_http2_protocol' => true, + 'http_compression' => false, // disable swoole compression +]); +$http = new Http($server, $container, 'UTC'); + +$http->setCompression(true); // enable utopia compression + +echo "Server started\n"; + +$http->start();