From 967d3eac06c9ed7ccac41885d3461fd48920a8ad Mon Sep 17 00:00:00 2001 From: Jordan Mele Date: Sun, 15 Mar 2020 18:51:57 +1100 Subject: [PATCH 1/9] Cache transfered on last modified date and time --- src/AssetLoader.php | 10 ++++++++++ src/ServeAsset/SlimServeAsset.php | 20 +++++++++++++++++--- tests/ServeAsset/SlimServeAssetTest.php | 18 ++++++++++++++---- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/AssetLoader.php b/src/AssetLoader.php index 5e4121f..84280a2 100644 --- a/src/AssetLoader.php +++ b/src/AssetLoader.php @@ -91,4 +91,14 @@ public function getType() { return MimeType::detectByFilename($this->fullPath); } + + /** + * Get the last modified date and time. + * + * @return \DateTime + */ + public function getLastModified(): \DateTime + { + return new \DateTime('@' . filemtime($this->fullPath)); + } } diff --git a/src/ServeAsset/SlimServeAsset.php b/src/ServeAsset/SlimServeAsset.php index 518e4b9..cbb2d51 100644 --- a/src/ServeAsset/SlimServeAsset.php +++ b/src/ServeAsset/SlimServeAsset.php @@ -58,9 +58,23 @@ public function serveAsset(RequestInterface $request, ResponseInterface $respons return $response->withStatus(404); } - return $response - ->withHeader('Content-Type', $assetLoader->getType()) + // Generate file last modified + $lastModified = $assetLoader->getLastModified()->format('D, d M Y H:i:s \G\M\T'); + + // Return 304 if asset not modified + try { + $clientLastModified = $request->getHeader('If-Modified-Since')[0] ?? false; + if ($lastModified === $clientLastModified) { + return $response->withStatus(304); + } + } catch (\Exception $e) { + // Fallback to regular response + } + + $response->getBody()->write($assetLoader->getContent()); + return $response->withHeader('Content-Type', $assetLoader->getType()) ->withHeader('Content-Length', $assetLoader->getLength()) - ->write($assetLoader->getContent()); + ->withHeader('Cache-Control', 'no-cache') + ->withHeader('Last-Modified', $lastModified); } } diff --git a/tests/ServeAsset/SlimServeAssetTest.php b/tests/ServeAsset/SlimServeAssetTest.php index 8d00b4a..c80274e 100644 --- a/tests/ServeAsset/SlimServeAssetTest.php +++ b/tests/ServeAsset/SlimServeAssetTest.php @@ -110,9 +110,7 @@ public function testAssetMatchesExpectations(SlimServeAsset $controller) $response = new Response(); // Invoke controller method. - $response = $controller->serveAsset($request, $response, [ - 'url' => 'allowed.txt', - ]); + $response = $controller->serveAsset($request, $response, [ 'url' => 'allowed.txt' ]); // Assert 200 response $this->assertSame($response->getStatusCode(), 200); @@ -122,10 +120,22 @@ public function testAssetMatchesExpectations(SlimServeAsset $controller) // Assert correct MIME $this->assertSame($response->getHeader('Content-Type'), ['text/plain']); + + // Asset last-modified set + $this->assertStringEndsWith('GMT', $response->getHeader('Last-Modified')[0] ?? false); + + // Last modified support + $request = Request::createFromEnvironment($environment) + ->withHeader('If-Modified-Since', $response->getHeader('Last-Modified')[0]); + $response = new Response(); + $response = $controller->serveAsset($request, $response, [ 'url' => 'allowed.txt' ]); + + // Assert 304 response + $this->assertSame($response->getStatusCode(), 304); } /** - * Test with existent asset. + * Test with existent asset of unknown type. * * @param SlimServeAsset $controller * From 260d21458c2be26274dbfc4814ddaf7481a8cce3 Mon Sep 17 00:00:00 2001 From: Jordan Mele Date: Sun, 15 Mar 2020 19:04:48 +1100 Subject: [PATCH 2/9] Switched to Github Actions for CI --- .appveyor.yml | 53 ---------------------------------------- .github/workflows/CI.yml | 26 ++++++++++++++++++++ .travis.yml | 21 ---------------- 3 files changed, 26 insertions(+), 74 deletions(-) delete mode 100644 .appveyor.yml create mode 100644 .github/workflows/CI.yml delete mode 100644 .travis.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index fd7168c..0000000 --- a/.appveyor.yml +++ /dev/null @@ -1,53 +0,0 @@ -## Thanks to Cees-Jan Kiewiet: https://blog.wyrihaximus.net/2016/11/running-php-unit-tests-on-windows-using-appveyor-and-chocolatey/ - -## Versioning pattern -version: 6.0.0-{build} - -## Disable unneeded features -build: off -deploy: off - -## Test against various PHP versions -environment: - matrix: - - php_version: "7.1" - - php_version: "7.2" - - php_version: "7.3" - -## Cache composer, chocolatey and php. -cache: - # Composer - - '%LOCALAPPDATA%\Composer\files -> composer.lock' - - composer.phar - # Cache chocolatey packages - - C:\ProgramData\chocolatey\bin -> .appveyor.yml - - C:\ProgramData\chocolatey\lib -> .appveyor.yml - # Cache php install - - c:\tools\php -> .appveyor.yml - -## Set up environment variables -init: - - SET PATH=C:\Program Files\OpenSSL;c:\tools\php;%PATH% - - SET COMPOSER_NO_INTERACTION=1 - - SET PHP=1 # This var is connected to PHP install cache - - SET ANSICON=121x90 (121x90) - -## Install PHP and composer, and run the appropriate composer command -install: - - IF EXIST c:\tools\php (SET PHP=0) # Checks for the PHP install being cached - - ps: appveyor-retry cinst --params '""/InstallDir:C:\tools\php""' --ignore-checksums -y php --version ((choco search php --exact --all-versions -r | select-string -pattern $env:php_version | sort { [version]($_ -split '\|' | select -last 1) } -Descending | Select-Object -first 1) -replace '[php|]','') - - cd c:\tools\php - - IF %PHP%==1 copy php.ini-production php.ini /Y - - IF %PHP%==1 echo date.timezone="UTC" >> php.ini - - IF %PHP%==1 echo extension_dir=ext >> php.ini - - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini - - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini - - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini - - IF %PHP%==1 echo @php %%~dp0composer.phar %%* > composer.bat - - appveyor-retry appveyor DownloadFile https://getcomposer.org/composer.phar - - cd c:\projects\assets - - appveyor-retry composer update --no-progress - -## Run the actual test -test_script: - - vendor/bin/phpunit diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..6a929a0 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,26 @@ +name: Continuous Integration +on: + # Every push + push: + schedule: + # Every Monday and Thursday at 12PM UTC + - cron: '0 12 * * 1,4' + +jobs: + test: + strategy: + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + php-version: [ '7.1', '7.2', '7.3', '7.4' ] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: xdebug + - run: composer install + - run: vendor/bin/phpunit --coverage-clover=coverage.xml +# - uses: codecov/codecov-action@v1 +# with: +# token: ${{ secrets.CODECOV_UPLOAD_TOKEN }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fa2ae23..0000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -sudo: false -dist: trusty -language: php - -php: - - 7.1 - - 7.2 - - 7.3 - -cache: - directories: - - $HOME/.composer/cache - -before_script: - - composer install - -script: - - vendor/bin/phpunit --coverage-clover=coverage.xml - -after_success: - - bash <(curl -s https://codecov.io/bash) From 5eafcefee4946700513af9810e1634f843aa1290 Mon Sep 17 00:00:00 2001 From: Jordan Mele Date: Sun, 15 Mar 2020 19:12:48 +1100 Subject: [PATCH 3/9] Updated README badges --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 107d265..5003ba4 100644 --- a/README.md +++ b/README.md @@ -7,26 +7,24 @@ | Branch | Build | Coverage | Style | | ------ | ----- | -------- | ----- | -| [master][master] | [![Build Status][master-build-travis-badge]][travis] [![Windows Build][master-build-appveyor-badge]][appveyor] | [![codecov][master-codecov-badge]][codecov] | [![][master-styleci-badge]][styleci] | -| [develop][develop] | [![Build Status][develop-build-travis-badge]][travis] [![Windows Build][develop-build-appveyor-badge]][appveyor] | [![codecov][develop-codecov-badge]][codecov] | [![][develop-styleci-badge]][styleci] | +| [master][master] | [![Continuous Integration](master-gh-ci-badge)](master-gh-ci) | [![codecov][master-codecov-badge]][codecov] | [![][master-styleci-badge]][styleci] | +| [develop][develop] | [![Continuous Integration](develop-gh-ci-badge)](develop-gh-ci) | [![codecov][develop-codecov-badge]][codecov] | [![][develop-styleci-badge]][styleci] | [codecov]: https://codecov.io/gh/userfrosting/assets [releases]: https://github.com/userfrosting/assets/releases [styleci]: https://github.styleci.io/repos/55460230 -[travis]: https://travis-ci.org/userfrosting/assets -[appveyor]: https://ci.appveyor.com/project/userfrosting/assets [version-badge]: https://img.shields.io/github/release/userfrosting/assets.svg [master]: https://github.com/userfrosting/assets/tree/master +[master-gh-ci]: https://github.com/userfrosting/assets/actions?query=branch:master+workflow:"Continuous+Integration" +[master-gh-ci-badge]: https://github.com/userfrosting/assets/workflows/Continuous%20Integration/badge.svg?branch=master [master-styleci-badge]: https://github.styleci.io/repos/55460230/shield?branch=master&style=flat [master-codecov-badge]: https://codecov.io/gh/userfrosting/assets/branch/master/graph/badge.svg -[master-build-travis-badge]: https://travis-ci.org/userfrosting/assets.svg?branch=master -[master-build-appveyor-badge]: https://ci.appveyor.com/api/projects/status/github/userfrosting/assets?branch=master&svg=true [develop]: https://github.com/userfrosting/assets/tree/develop +[develop-gh-ci]: https://github.com/userfrosting/assets/actions?query=branch:develop+workflow:"Continuous+Integration" +[develop-gh-ci-badge]: https://github.com/userfrosting/assets/workflows/Continuous%20Integration/badge.svg?branch=develop [develop-styleci-badge]: https://github.styleci.io/repos/55460230/shield?branch=develop&style=flat [develop-codecov-badge]: https://codecov.io/gh/userfrosting/assets/branch/develop/graph/badge.svg -[develop-build-travis-badge]: https://travis-ci.org/userfrosting/assets.svg?branch=develop -[develop-build-appveyor-badge]: https://ci.appveyor.com/api/projects/status/github/userfrosting/assets?branch=develop&svg=true **Assets** is a library originally created for UserFrosting 4 to make it much easier to reference frontend assets in both production and development contexts. From b0eaab4bc50f361eb73f501b7e288df9ee6b82a1 Mon Sep 17 00:00:00 2001 From: Jordan Mele Date: Sun, 15 Mar 2020 19:13:15 +1100 Subject: [PATCH 4/9] Include `mbstring` extension in CI --- .github/workflows/CI.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 6a929a0..99b1423 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -19,6 +19,7 @@ jobs: with: php-version: ${{ matrix.php-version }} coverage: xdebug + extensions: mbstring - run: composer install - run: vendor/bin/phpunit --coverage-clover=coverage.xml # - uses: codecov/codecov-action@v1 From c678aa9f77fde3d60e8631f60168986428de2518 Mon Sep 17 00:00:00 2001 From: Jordan Mele Date: Sun, 15 Mar 2020 19:16:09 +1100 Subject: [PATCH 5/9] Code style adjustments --- src/AssetLoader.php | 2 +- src/Assets.php | 2 +- src/ServeAsset/SlimServeAsset.php | 1 + tests/ServeAsset/SlimServeAssetTest.php | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/AssetLoader.php b/src/AssetLoader.php index 84280a2..2d06ab3 100644 --- a/src/AssetLoader.php +++ b/src/AssetLoader.php @@ -99,6 +99,6 @@ public function getType() */ public function getLastModified(): \DateTime { - return new \DateTime('@' . filemtime($this->fullPath)); + return new \DateTime('@'.filemtime($this->fullPath)); } } diff --git a/src/Assets.php b/src/Assets.php index 6f0a176..3c7051c 100644 --- a/src/Assets.php +++ b/src/Assets.php @@ -29,7 +29,7 @@ class Assets /** @var ResourceLocatorInterface Resource locator used to find assets. */ protected $locator; - /** @var string Scheme used when finding assets via $locator. */ + /** @var string Scheme used when finding assets via the provided locator. */ protected $locatorScheme; /** @var string Sites base URL and optionally assets directory. */ diff --git a/src/ServeAsset/SlimServeAsset.php b/src/ServeAsset/SlimServeAsset.php index cbb2d51..45dd94f 100644 --- a/src/ServeAsset/SlimServeAsset.php +++ b/src/ServeAsset/SlimServeAsset.php @@ -72,6 +72,7 @@ public function serveAsset(RequestInterface $request, ResponseInterface $respons } $response->getBody()->write($assetLoader->getContent()); + return $response->withHeader('Content-Type', $assetLoader->getType()) ->withHeader('Content-Length', $assetLoader->getLength()) ->withHeader('Cache-Control', 'no-cache') diff --git a/tests/ServeAsset/SlimServeAssetTest.php b/tests/ServeAsset/SlimServeAssetTest.php index c80274e..f7fecf4 100644 --- a/tests/ServeAsset/SlimServeAssetTest.php +++ b/tests/ServeAsset/SlimServeAssetTest.php @@ -110,7 +110,7 @@ public function testAssetMatchesExpectations(SlimServeAsset $controller) $response = new Response(); // Invoke controller method. - $response = $controller->serveAsset($request, $response, [ 'url' => 'allowed.txt' ]); + $response = $controller->serveAsset($request, $response, ['url' => 'allowed.txt']); // Assert 200 response $this->assertSame($response->getStatusCode(), 200); @@ -128,7 +128,7 @@ public function testAssetMatchesExpectations(SlimServeAsset $controller) $request = Request::createFromEnvironment($environment) ->withHeader('If-Modified-Since', $response->getHeader('Last-Modified')[0]); $response = new Response(); - $response = $controller->serveAsset($request, $response, [ 'url' => 'allowed.txt' ]); + $response = $controller->serveAsset($request, $response, ['url' => 'allowed.txt']); // Assert 304 response $this->assertSame($response->getStatusCode(), 304); From 7cbd8bdb178729d9698c1a6fd6764f42614ef1ea Mon Sep 17 00:00:00 2001 From: Jordan Mele Date: Sun, 15 Mar 2020 19:22:43 +1100 Subject: [PATCH 6/9] Fix README link syntax --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5003ba4..b2363d6 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ | Branch | Build | Coverage | Style | | ------ | ----- | -------- | ----- | -| [master][master] | [![Continuous Integration](master-gh-ci-badge)](master-gh-ci) | [![codecov][master-codecov-badge]][codecov] | [![][master-styleci-badge]][styleci] | -| [develop][develop] | [![Continuous Integration](develop-gh-ci-badge)](develop-gh-ci) | [![codecov][develop-codecov-badge]][codecov] | [![][develop-styleci-badge]][styleci] | +| [master][master] | [![Continuous Integration][master-gh-ci-badge]](master-gh-ci) | [![codecov][master-codecov-badge]][codecov] | [![][master-styleci-badge]][styleci] | +| [develop][develop] | [![Continuous Integration][develop-gh-ci-badge]](develop-gh-ci) | [![codecov][develop-codecov-badge]][codecov] | [![][develop-styleci-badge]][styleci] | [codecov]: https://codecov.io/gh/userfrosting/assets From e828fb0c3b86c9f9b1b09682f9362442402e0af6 Mon Sep 17 00:00:00 2001 From: Jordan Mele Date: Sun, 15 Mar 2020 19:29:17 +1100 Subject: [PATCH 7/9] CI composer cache --- .github/workflows/CI.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 99b1423..442a7ff 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,6 +20,14 @@ jobs: php-version: ${{ matrix.php-version }} coverage: xdebug extensions: mbstring + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Retain composer cache + uses: actions/cache@v1 + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- - run: composer install - run: vendor/bin/phpunit --coverage-clover=coverage.xml # - uses: codecov/codecov-action@v1 From e44db6890357235f185be4802762accb2f06a74a Mon Sep 17 00:00:00 2001 From: Jordan Mele Date: Sun, 15 Mar 2020 19:32:21 +1100 Subject: [PATCH 8/9] Composer cache correction --- .github/workflows/CI.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 442a7ff..c464e2d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -25,8 +25,9 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Retain composer cache uses: actions/cache@v1 + with: path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer- - run: composer install - run: vendor/bin/phpunit --coverage-clover=coverage.xml From 61c9c5aed141137b92c154a0fe9658df36f3c27b Mon Sep 17 00:00:00 2001 From: Jordan Mele Date: Sun, 15 Mar 2020 19:42:08 +1100 Subject: [PATCH 9/9] Updated changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b043af2..a2f17c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [Unknown] +- Added partial caching support to development server + ## [6.0.0] - 2019-06-22 - Dropping support for PHP 5.6 & 7.0 - Updated PHPUnit to 7.5