Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ jobs:
publish:
name: Publish new version to TER
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
env:
TYPO3_EXTENSION_KEY: ${{ secrets.TYPO3_EXTENSION_KEY }}
TYPO3_API_TOKEN: ${{ secrets.TYPO3_API_TOKEN }}

steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Check tag
run: |
Expand All @@ -31,14 +30,14 @@ jobs:
run: |
readonly local comment=$(git tag -n10 -l ${{ steps.get-version.outputs.version }} | sed "s/^[0-9.]*[ ]*//g")
if [[ -z "${comment// }" ]]; then
echo ::set-output name=comment::Released version ${{ steps.get-version.outputs.version }} of ${{ env.TYPO3_EXTENSION_KEY }}
echo ::set-output name=comment::Released version ${{ steps.get-version.outputs.version }} of http2
else
echo ::set-output name=comment::$comment
fi
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
php-version: 8.3
extensions: intl, mbstring, json, zip, curl

- name: Install tailor
Expand Down
32 changes: 17 additions & 15 deletions Classes/Http/ResourcePusher.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php
declare(strict_types = 1);

declare(strict_types=1);

namespace B13\Http2\Http;

/*
Expand Down Expand Up @@ -31,28 +33,28 @@ class ResourcePusher implements MiddlewareInterface
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$response = $handler->handle($request);
if (($GLOBALS['TSFE'] ?? null) instanceof TypoScriptFrontendController) {
$resources = $GLOBALS['TSFE']->config['b13/http2'] ?? null;
/** @var NormalizedParams $normalizedParams */
$normalizedParams = $request->getAttribute('normalizedParams');
if (is_array($resources) && $normalizedParams->isHttps()) {
foreach ($resources['scripts'] ?? [] as $resource) {
$response = $this->addPreloadHeaderToResponse($response, $resource, 'script');
}
foreach ($resources['styles'] ?? [] as $resource) {
$response = $this->addPreloadHeaderToResponse($response, $resource, 'style');
}
/** @var TypoScriptFrontendController $frontendController */
$frontendController = $request->getAttribute('frontend.controller');
$resources = $frontendController->config['b13/http2'] ?? null;
/** @var NormalizedParams $normalizedParams */
$normalizedParams = $request->getAttribute('normalizedParams');
if (is_array($resources) && $normalizedParams->isHttps()) {
foreach ($resources['scripts'] ?? [] as $resource) {
$response = $this->addPreloadHeaderToResponse($response, $resource, 'script');
}
foreach ($resources['styles'] ?? [] as $resource) {
$response = $this->addPreloadHeaderToResponse($response, $resource, 'style');
}
}
return $response;
}

protected function addPreloadHeaderToResponse(ResponseInterface $response, string $uri, string $type): ResponseInterface
{
if(str_contains($uri, '.mjs')) {
if (str_contains($uri, '.mjs')) {
return $response->withAddedHeader('Link', '<' . htmlspecialchars(PathUtility::getAbsoluteWebPath($uri)) . '>; rel=modulepreload; as=' . $type);
} else {
return $response->withAddedHeader('Link', '<' . htmlspecialchars(PathUtility::getAbsoluteWebPath($uri)) . '>; rel=preload; as=' . $type);
}
return $response->withAddedHeader('Link', '<' . htmlspecialchars(PathUtility::getAbsoluteWebPath($uri)) . '>; rel=preload; as=' . $type);

}
}
43 changes: 22 additions & 21 deletions Classes/PageRendererHook.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php
declare(strict_types = 1);

declare(strict_types=1);

namespace B13\Http2;

/*
Expand All @@ -10,6 +12,8 @@
* of the License, or any later version.
*/

use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Http\ApplicationType;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
Expand All @@ -22,18 +26,7 @@
*/
class PageRendererHook
{
/**
* @var ResourceMatcher
*/
protected $matcher;

/**
* @param ResourceMatcher|null $matcher
*/
public function __construct(ResourceMatcher $matcher = null)
{
$this->matcher = $matcher ?: GeneralUtility::makeInstance(ResourceMatcher::class);
}
public function __construct(protected ResourceMatcher $matcher) {}

/**
* @param array $params
Expand All @@ -42,9 +35,15 @@ public function __construct(ResourceMatcher $matcher = null)
*/
public function accumulateResources(array $params, PageRenderer $pageRenderer)
{
$request = $this->getRequest();
if ($request === null) {
return;
}
// If this is a second run (non-cached cObjects adding more data), then the existing cached data is fetched
if ($this->getTypoScriptFrontendController() instanceof TypoScriptFrontendController) {
$allResources = $this->getTypoScriptFrontendController()->config['b13/http2'] ?? [];
if (ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()) {
/** @var TypoScriptFrontendController $frontendController */
$frontendController = $request->getAttribute('frontend.controller');
$allResources = $frontendController->config['b13/http2'] ?? [];
} else {
$allResources = [];
}
Expand All @@ -64,7 +63,7 @@ public function accumulateResources(array $params, PageRenderer $pageRenderer)
$allResources['scripts'] = array_unique($allResources['scripts'] ?? []);
$allResources['styles'] = array_unique($allResources['styles'] ?? []);

$this->process($allResources);
$this->process($allResources, $request);
}

/**
Expand All @@ -73,18 +72,20 @@ public function accumulateResources(array $params, PageRenderer $pageRenderer)
*
* @param array $allResources
*/
protected function process(array $allResources)
protected function process(array $allResources, ServerRequestInterface $request): void
{
if ($this->getTypoScriptFrontendController() instanceof TypoScriptFrontendController) {
$this->getTypoScriptFrontendController()->config['b13/http2'] = $allResources;
if (ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()) {
/** @var TypoScriptFrontendController $frontendController */
$frontendController = $request->getAttribute('frontend.controller');
$frontendController->config['b13/http2'] = $allResources;
} elseif (GeneralUtility::getIndpEnv('TYPO3_SSL')) {
// Push directly into the TYPO3 Backend, but only if TYPO3 is running in SSL
GeneralUtility::makeInstance(ResourcePusher::class)->pushAll($allResources);
}
}

protected function getTypoScriptFrontendController()
protected function getRequest(): ?ServerRequestInterface
{
return $GLOBALS['TSFE'] ?? null;
return $GLOBALS['TYPO3_REQUEST'] ?? null;
}
}
8 changes: 5 additions & 3 deletions Classes/ResourceMatcher.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php
declare(strict_types = 1);

declare(strict_types=1);

namespace B13\Http2;

/*
Expand Down Expand Up @@ -35,12 +37,12 @@ public function match(string $input): array

// simple check - should be optimized to include further checks
$styles = array_filter($matches[2], function ($resource) {
return strpos($resource, '.css') !== false;
return str_contains($resource, '.css');
});

return [
'scripts' => array_values(array_filter($matches[1])),
'styles' => array_values($styles)
'styles' => array_values($styles),
];
}

Expand Down
7 changes: 3 additions & 4 deletions Classes/ResourcePusher.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php
declare(strict_types = 1);

declare(strict_types=1);

namespace B13\Http2;

/*
Expand All @@ -10,10 +12,7 @@
* of the License, or any later version.
*/

use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;

/**
* Takes existing accumulated resources and pushes them as HTTP2 <link> headers.
Expand Down
5 changes: 3 additions & 2 deletions Configuration/RequestMiddlewares.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

return [
'frontend' => [
'b13/http2/push-resources' => [
Expand All @@ -7,8 +8,8 @@
'typo3/cms-frontend/prepare-tsfe-rendering',
],
'after' => [
'typo3/cms-frontend/authentication',
'typo3/cms-frontend/tsfe',
],
],
]
],
];
11 changes: 11 additions & 0 deletions Configuration/Services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

B13\Http2\:
resource: '../Classes/*'

B13\Http2\PageRendererHook:
public: true
35 changes: 18 additions & 17 deletions Tests/Unit/ResourceMatcherTest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php
declare(strict_types = 1);

declare(strict_types=1);

namespace B13\Http2\Tests\Unit;

/*
Expand All @@ -10,69 +12,68 @@
* of the License, or any later version.
*/


use B13\Http2\ResourceMatcher;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

class ResourceMatcherTest extends TestCase
{
public function matchDataProvider()
public static function matchDataProvider()
{
return [
'nothing useful' => [
'<title>Good things must come</title>',
[],
[]
[],
],
'simple script tag' => [
'<script src="https://www.example.com/myfile.js" />',
['https://www.example.com/myfile.js'],
[]
[],
],
'simple script tag with parameter' => [
'<script src="https://www.example.com/myfile.js?foo" />',
['https://www.example.com/myfile.js?foo'],
[]
[],
],
'simple script tag with parameter and value' => [
'<script src="https://www.example.com/myfile.js?foo=bar" />',
['https://www.example.com/myfile.js?foo=bar'],
[]
[],
],
'multiple script tags' => [
'<script src="https://www.example.com/myfile.js" /><link><script src="/myfile.js"></script>',
['https://www.example.com/myfile.js', '/myfile.js'],
[]
[],
],
'multiple script tags with the same value finds duplicate hits' => [
'<script src="https://www.example.com/myfile.js" /><link><script src="/myfile.js"></script><script src="/myfile.js" />',
['https://www.example.com/myfile.js', '/myfile.js', '/myfile.js'],
[]
[],
],
'multiple script and link tags' => [
'<script src="https://www.example.com/myfile.js" /><link href="http://example.com/favicon.ico"><script src="/myfile.js"></script>',
['https://www.example.com/myfile.js', '/myfile.js'],
[]
[],
],
'multiple script and valid link tags' => [
'<script src="https://www.example.com/myfile.js" /><link href="http://example.com/base.css"><script src="/myfile.js"></script>',
['https://www.example.com/myfile.js', '/myfile.js'],
['http://example.com/base.css']
['http://example.com/base.css'],
],
];
}

/**
* @test
* @dataProvider matchDataProvider
*/
#[DataProvider('matchDataProvider')]
#[Test]
public function matchExtractsProperInformation($input, $expectedScripts, $expectedStyles)
{
$expectedResult = [
'scripts' => $expectedScripts,
'styles' => $expectedStyles
'styles' => $expectedStyles,
];
$result = (new ResourceMatcher())->match($input);
$this->assertEquals($expectedResult, $result);
self::assertEquals($expectedResult, $result);
}
}
11 changes: 4 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@
"type": "typo3-cms-extension",
"description": "Speed up TYPO3 rendering via HTTP/2 Server Push",
"require": {
"php": "^7.4 || ^8.0",
"psr/http-server-middleware": "^1.0",
"typo3/cms-core": "^10.0 || ^11.0 || ^12.0",
"typo3/cms-frontend": "^10.0 || ^11.0 || ^12.0"
"typo3/cms-core": "^12.4 || ^13.4",
"typo3/cms-frontend": "^12.4 || ^13.4"
},
"require-dev": {
"phpunit/phpunit": "~7.0",
"squizlabs/php_codesniffer": "^2.3",
"typo3/tailor": "^1.4.0"
"phpunit/phpunit": "^11.0",
"squizlabs/php_codesniffer": "^3.0"
},
"homepage": "https://b13.com",
"license": ["GPL-2.0-or-later"],
Expand Down