Skip to content

Commit a03e7ac

Browse files
NurantoJacobBennett
authored andcommitted
Config file for : Size limit, exceptions, base path (#28)
* #25 deduplicate header links * - Add config file - Add size limit - Add base path configuration - Add exceptions filters - Update test - Updates doc solves #23, #27 * update travis : - remove PHP5.6, - add PHP7.2 and 7.3
1 parent 2c861a2 commit a03e7ac

File tree

6 files changed

+103
-10
lines changed

6 files changed

+103
-10
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
language: php
22

33
php:
4-
- 5.6
54
- 7.0
65
- 7.1
6+
- 7.2
7+
- 7.3
78

89
env:
910
matrix:

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ protected $middlewareGroups = [
3434
];
3535
```
3636

37+
## Publish config
38+
39+
```php
40+
php artisan vendor:publish --provider="JacobBennett\Http2ServerPush\ServiceProvider"
41+
```
42+
43+
3744
## Usage
3845

3946
When you route a request through the `AddHttp2ServerPush` middleware, the response is scanned for any `link`, `script` or `img` tags that could benefit from being loaded using Server Push.

src/Middleware/AddHttp2ServerPush.php

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,38 +24,61 @@ class AddHttp2ServerPush
2424
*
2525
* @return mixed
2626
*/
27-
public function handle(Request $request, Closure $next, $limit = null)
27+
public function handle(Request $request, Closure $next, $limit = null, $sizeLimit = null, $excludeKeywords=null)
2828
{
2929
$response = $next($request);
3030

3131
if ($response->isRedirection() || !$response instanceof Response || $request->isJson()) {
3232
return $response;
3333
}
3434

35-
$this->generateAndAttachLinkHeaders($response, $limit);
35+
$this->generateAndAttachLinkHeaders($response, $limit, $sizeLimit, $excludeKeywords);
3636

3737
return $response;
3838
}
3939

40+
public function getConfig($key, $default=false) {
41+
if(!function_exists('config')) { // for tests..
42+
return $default;
43+
}
44+
return config('http2serverpush.'.$key, $default);
45+
}
46+
4047
/**
4148
* @param \Illuminate\Http\Response $response
4249
*
4350
* @return $this
4451
*/
45-
protected function generateAndAttachLinkHeaders(Response $response, $limit = null)
52+
protected function generateAndAttachLinkHeaders(Response $response, $limit = null, $sizeLimit = null, $excludeKeywords=null)
4653
{
54+
$excludeKeywords ?? $this->getConfig('exclude_keywords', []);
4755
$headers = $this->fetchLinkableNodes($response)
4856
->flatten(1)
4957
->map(function ($url) {
5058
return $this->buildLinkHeaderString($url);
5159
})
52-
->filter()
5360
->unique()
54-
->take($limit)
55-
->implode(',');
61+
->filter(function($value, $key) use ($excludeKeywords){
62+
if(!$value) return false;
63+
$exclude_keywords = collect($excludeKeywords)->map(function ($keyword) {
64+
return preg_quote($keyword);
65+
});
66+
if($exclude_keywords->count() <= 0) {
67+
return true;
68+
}
69+
return !preg_match('%('.$exclude_keywords->implode('|').')%i', $value);
70+
})
71+
->take($limit);
72+
73+
$sizeLimit = $sizeLimit ?? max(1, intval($this->getConfig('size_limit', 32*1024)));
74+
$headersText = trim($headers->implode(','));
75+
while(strlen($headersText) > $sizeLimit) {
76+
$headers->pop();
77+
$headersText = trim($headers->implode(','));
78+
}
5679

57-
if (!empty(trim($headers))) {
58-
$this->addLinkHeader($response, $headers);
80+
if (!empty($headersText)) {
81+
$this->addLinkHeader($response, $headersText);
5982
}
6083

6184
return $this;
@@ -115,6 +138,12 @@ private function buildLinkHeaderString($url)
115138
$type = collect($linkTypeMap)->first(function ($type, $extension) use ($url) {
116139
return str_contains(strtoupper($url), $extension);
117140
});
141+
142+
143+
if(!preg_match('%^https?://%i', $url)) {
144+
$basePath = $this->getConfig('base_path', '/');
145+
$url = $basePath . ltrim($url, $basePath);
146+
}
118147

119148
return is_null($type) ? null : "<{$url}>; rel=preload; as={$type}";
120149
}

src/ServiceProvider.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace JacobBennett\Http2ServerPush;
4+
use Illuminate\Foundation\AliasLoader;
5+
use Illuminate\Support\ServiceProvider as LaravelServiceProvider;
6+
7+
class ServiceProvider extends LaravelServiceProvider
8+
{
9+
/**
10+
* Perform post-registration booting of services.
11+
*
12+
* @return void
13+
*/
14+
public function boot()
15+
{
16+
// Register paths to be published by 'vendor:publish' Artisan command
17+
$this->publishes([
18+
__DIR__ . '/config.php' => config_path('http2serverpush.php'),
19+
]);
20+
}
21+
22+
}

src/config.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
4+
return [
5+
'size_limit' => '6000', // in bytes
6+
'base_path' => '/',
7+
'exclude_keywords' => []
8+
];

tests/AddHttp2ServerPushTest.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,32 @@ public function setUp()
1414
$this->middleware = new AddHttp2ServerPush();
1515
}
1616

17+
18+
/** @test */
19+
public function it_will_not_exceed_size_limit()
20+
{
21+
$request = new Request();
22+
23+
$limit = 50;
24+
$response = $this->middleware->handle($request, $this->getNext('pageWithCssAndJs'), null, $limit, []);
25+
26+
$this->assertTrue($this->isServerPushResponse($response));
27+
$this->assertTrue(strlen($response->headers->get('link')) <= $limit );
28+
$this->assertCount(1, explode(",", $response->headers->get('link')));
29+
}
30+
31+
/** @test */
32+
public function it_will_not_add_excluded_asset()
33+
{
34+
$request = new Request();
35+
36+
$response = $this->middleware->handle($request, $this->getNext('pageWithCssAndJs'), null, null, ['thing']);
37+
38+
$this->assertTrue($this->isServerPushResponse($response));
39+
$this->assertTrue(!str_contains($response->headers, 'thing'));
40+
$this->assertCount(1, explode(",", $response->headers->get('link')));
41+
}
42+
1743
/** @test */
1844
public function it_will_not_modify_a_response_with_no_server_push_assets()
1945
{
@@ -77,7 +103,7 @@ public function it_returns_well_formatted_link_headers()
77103

78104
$response = $this->middleware->handle($request, $this->getNext('pageWithCss'));
79105

80-
$this->assertEquals("<css/test.css>; rel=preload; as=style", $response->headers->get('link'));
106+
$this->assertEquals("</css/test.css>; rel=preload; as=style", $response->headers->get('link'));
81107
}
82108

83109
/** @test */

0 commit comments

Comments
 (0)