forked from b13/http2
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 238ab55
Showing
13 changed files
with
770 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/.gitattributes export-ignore | ||
/.gitignore export-ignore | ||
/.travis.yml export-ignore | ||
/phpunit.xml.dist export-ignore | ||
/Tests export-ignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Build | ||
composer.lock | ||
vendor | ||
public | ||
.phpunit.result.cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
<?php | ||
declare(strict_types = 1); | ||
namespace B13\Http2; | ||
|
||
/* | ||
* This file is part of TYPO3 CMS-based extension "http2" by b13. | ||
* | ||
* It is free software; you can redistribute it and/or modify it under | ||
* the terms of the GNU General Public License, either version 2 | ||
* of the License, or any later version. | ||
*/ | ||
|
||
use TYPO3\CMS\Core\Page\PageRenderer; | ||
use TYPO3\CMS\Core\Utility\GeneralUtility; | ||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; | ||
|
||
/** | ||
* Hooks into PageRenderer before the rendering is taken care of, and remember the files | ||
* that can be sent as resources. | ||
* | ||
* This considers that everything is required, thus is marked as "preload", not via "prefetch". | ||
*/ | ||
class PageRendererHook | ||
{ | ||
/** | ||
* @var ResourceMatcher | ||
*/ | ||
protected $matcher; | ||
|
||
/** | ||
* @param ResourceMatcher|null $matcher | ||
*/ | ||
public function __construct(ResourceMatcher $matcher = null) | ||
{ | ||
$this->matcher = $matcher ?: GeneralUtility::makeInstance(ResourceMatcher::class); | ||
} | ||
|
||
/** | ||
* @param array $params | ||
* @param PageRenderer $pageRenderer | ||
* @internal this is just a hook implementation. | ||
*/ | ||
public function accumulateResources(array $params, PageRenderer $pageRenderer) | ||
{ | ||
// 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'] ?? []; | ||
} else { | ||
$allResources = []; | ||
} | ||
foreach ($params['headerData'] as $headerData) { | ||
$allResources = array_merge_recursive($allResources, $this->matcher->match($headerData)); | ||
} | ||
foreach ($params['footerData'] as $footerData) { | ||
$allResources = array_merge_recursive($allResources, $this->matcher->match($footerData)); | ||
} | ||
$allResources = array_merge_recursive($allResources, $this->matcher->match($params['jsLibs'])); | ||
$allResources = array_merge_recursive($allResources, $this->matcher->match($params['jsFiles'])); | ||
$allResources = array_merge_recursive($allResources, $this->matcher->match($params['jsFooterLibs'])); | ||
$allResources = array_merge_recursive($allResources, $this->matcher->match($params['jsFooterFiles'])); | ||
$allResources = array_merge_recursive($allResources, $this->matcher->match($params['cssLibs'])); | ||
$allResources = array_merge_recursive($allResources, $this->matcher->match($params['cssFiles'])); | ||
|
||
$allResources['scripts'] = array_unique($allResources['scripts']); | ||
$allResources['styles'] = array_unique($allResources['styles']); | ||
|
||
$this->process($allResources); | ||
} | ||
|
||
/** | ||
* In FE the data is stored in TSFE->config. | ||
* In BE it is sent directly to the HTTP response. | ||
* | ||
* @param array $allResources | ||
*/ | ||
protected function process(array $allResources) | ||
{ | ||
if ($this->getTypoScriptFrontendController() instanceof TypoScriptFrontendController) { | ||
$this->getTypoScriptFrontendController()->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() | ||
{ | ||
return $GLOBALS['TSFE']; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
declare(strict_types = 1); | ||
namespace B13\Http2; | ||
|
||
/* | ||
* This file is part of TYPO3 CMS-based extension "http2" by b13. | ||
* | ||
* It is free software; you can redistribute it and/or modify it under | ||
* the terms of the GNU General Public License, either version 2 | ||
* of the License, or any later version. | ||
*/ | ||
|
||
/** | ||
* Parses a string by detecting <script> and <link> tags. | ||
*/ | ||
class ResourceMatcher | ||
{ | ||
protected $resourcePattern = '[\'"]?([\w\s\/\-:?.]*)["\']?'; | ||
|
||
/** | ||
* @param string $input | ||
* @return array | ||
*/ | ||
public function match(string $input): array | ||
{ | ||
if (empty($input)) { | ||
return ['scripts' => [], 'styles' => []]; | ||
} | ||
$matches = []; | ||
preg_match_all( | ||
'/<script[\/\s\w-="]*src=' . $this->resourcePattern . '[^>]*>' | ||
. '|' . | ||
'<link[\/\s\w-="]*href=' . $this->resourcePattern . '[^>]*>' | ||
. '/ui', | ||
$input, | ||
$matches | ||
); | ||
|
||
// simple check - should be optimized to include further checks | ||
$styles = array_filter($matches[2], function ($resource) { | ||
return strpos($resource, '.css') !== false; | ||
}); | ||
|
||
return [ | ||
'scripts' => array_values(array_filter($matches[1])), | ||
'styles' => array_values($styles) | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<?php | ||
declare(strict_types = 1); | ||
namespace B13\Http2; | ||
|
||
/* | ||
* This file is part of TYPO3 CMS-based extension "http2" by b13. | ||
* | ||
* It is free software; you can redistribute it and/or modify it under | ||
* the terms of the GNU General Public License, either version 2 | ||
* of the License, or any later version. | ||
*/ | ||
|
||
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. | ||
* | ||
* This considers that everything is required, thus is marked as "preload", not via "prefetch". | ||
* | ||
* Also, it only tackles "script", "style", but we should incorporate font as well. | ||
* See https://w3c.github.io/preload/#as-attribute | ||
*/ | ||
class ResourcePusher | ||
{ | ||
/** | ||
* @param array $resources | ||
*/ | ||
public function pushAll(array $resources) | ||
{ | ||
foreach ($resources['scripts'] as $resource) { | ||
$this->addPreloadHeader($resource, 'script'); | ||
} | ||
foreach ($resources['styles'] as $resource) { | ||
$this->addPreloadHeader($resource, 'style'); | ||
} | ||
} | ||
|
||
/** | ||
* @param array $params | ||
* @param TypoScriptFrontendController $typoScriptFrontendController | ||
* @internal this is just a hook implementation. | ||
*/ | ||
public function pushForFrontend(array $params, TypoScriptFrontendController $typoScriptFrontendController) | ||
{ | ||
$allResources = $typoScriptFrontendController->config['b13/http2']; | ||
if (GeneralUtility::getIndpEnv('TYPO3_SSL') && is_array($allResources)) { | ||
$this->pushAll($allResources); | ||
} | ||
} | ||
|
||
/** | ||
* as="{style/script/image}" | ||
* | ||
* @param string $uri | ||
* @param string $type | ||
*/ | ||
protected function addPreloadHeader(string $uri, string $type) | ||
{ | ||
header('Link: <' . htmlspecialchars(PathUtility::getAbsoluteWebPath($uri)) . '>; rel=preload; as=' . $type, false); | ||
} | ||
} |
Oops, something went wrong.