Skip to content

Commit

Permalink
Merge pull request #147 from utopia-php/feat-compression-0.33.x
Browse files Browse the repository at this point in the history
feat: utopia compression 0.33.x
  • Loading branch information
christyjacob4 authored Nov 8, 2024
2 parents a7f5775 + 58851dc commit 82c7252
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 150 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"bench": "vendor/bin/phpbench run --report=benchmark"
},
"require": {
"php": ">=8.0"
"php": ">=8.0",
"utopia-php/compression": "0.1.*"
},
"require-dev": {
"phpunit/phpunit": "^9.5.25",
Expand Down
300 changes: 174 additions & 126 deletions composer.lock

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

class App
{
public const COMPRESSION_MIN_SIZE_DEFAULT = 1024;

/**
* Request method constants
*/
Expand Down Expand Up @@ -102,6 +104,13 @@ class App
*/
protected static ?Route $wildcardRoute = null;

/**
* Compression
*/
protected bool $compression = false;
protected int $compressionMinSize = App::COMPRESSION_MIN_SIZE_DEFAULT;
protected mixed $compressionSupported = [];

/**
* App
*
Expand All @@ -112,6 +121,30 @@ public function __construct(string $timezone)
\date_default_timezone_set($timezone);
}

/**
* 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
*
Expand Down Expand Up @@ -642,6 +675,12 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
*/
public function run(Request $request, Response $response): static
{
if ($this->compression) {
$response->setAcceptEncoding($request->getHeader('accept-encoding', ''));
$response->setCompressionMinSize($this->compressionMinSize);
$response->setCompressionSupported($this->compressionSupported);
}

$this->resources['request'] = $request;
$this->resources['response'] = $response;

Expand Down
108 changes: 88 additions & 20 deletions src/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Utopia;

use Utopia\Compression\Compression;

class Response
{
/**
Expand Down Expand Up @@ -245,6 +247,21 @@ class Response
*/
protected int $size = 0;

/**
* @var string
*/
protected string $acceptEncoding = '';

/**
* @var int
*/
protected int $compressionMinSize = App::COMPRESSION_MIN_SIZE_DEFAULT;

/**
* @var mixed
*/
protected mixed $compressionSupported = [];

/**
* Response constructor.
*
Expand All @@ -270,6 +287,43 @@ 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;
}

/**
* Set supported compression algorithms
*
* @param mixed $compressionSupported
*/
public function setCompressionSupported(mixed $compressionSupported): static
{
$this->compressionSupported = $compressionSupported;
return $this;
}

/**
* Get content type
*
Expand Down Expand Up @@ -473,36 +527,50 @@ public function send(string $body = ''): void
return;
}

$this->sent = true;
$serverHeader = $this->headers['Server'] ?? 'Utopia/Http';
$this->addHeader('Server', $serverHeader);
$this->addHeader('X-Debug-Speed', (string) (microtime(true) - $this->startTime));

$this->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('Vary', 'Accept-Encoding');
}
}

$this->size = $this->size + strlen(implode("\n", $this->headers)) + $length;
$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();
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Validator/ArrayList.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function getDescription(): string
{
$msg = 'Value must a valid array';

if($this->length > 0) {
if ($this->length > 0) {
$msg .= ' no longer than ' . $this->length . ' items';
}

Expand Down
2 changes: 1 addition & 1 deletion tests/ResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function testCanSetStatus()

try {
$this->response->setStatusCode(0); // Unknown status code
} catch(\Exception $e) {
} catch (\Exception $e) {
$this->assertInstanceOf('\Exception', $e);

return;
Expand Down
2 changes: 1 addition & 1 deletion tests/ViewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function testCanRenderHtml()
$this->view->setRendered(false);
$this->view->setPath('just-a-broken-string.phtml');
$this->view->render();
} catch(\Exception $e) {
} catch (\Exception $e) {
return;
}

Expand Down
1 change: 1 addition & 0 deletions tests/e2e/server.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,5 @@
$response = new Response();

$app = new App('UTC');
$app->setCompression(true);
$app->run($request, $response);

0 comments on commit 82c7252

Please sign in to comment.