AssetMiddlewareTest.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.3.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Routing\Middleware;
  16. use Cake\Core\Plugin;
  17. use Cake\Http\ServerRequestFactory;
  18. use Cake\Routing\Middleware\AssetMiddleware;
  19. use Cake\TestSuite\TestCase;
  20. use Zend\Diactoros\Response;
  21. /**
  22. * Test for AssetMiddleware
  23. */
  24. class AssetMiddlewareTest extends TestCase
  25. {
  26. /**
  27. * setup
  28. *
  29. * @return void
  30. */
  31. public function setUp()
  32. {
  33. parent::setUp();
  34. $this->loadPlugins(['TestPlugin', 'Company/TestPluginThree']);
  35. }
  36. /**
  37. * tearDown
  38. *
  39. * @return void
  40. */
  41. public function tearDown()
  42. {
  43. Plugin::unload();
  44. parent::tearDown();
  45. }
  46. /**
  47. * test that the if modified since header generates 304 responses
  48. *
  49. * @return void
  50. */
  51. public function testCheckIfModifiedHeader()
  52. {
  53. $modified = filemtime(TEST_APP . 'Plugin/TestPlugin/webroot/root.js');
  54. $request = ServerRequestFactory::fromGlobals([
  55. 'REQUEST_URI' => '/test_plugin/root.js',
  56. 'HTTP_IF_MODIFIED_SINCE' => date('D, j M Y G:i:s \G\M\T', $modified)
  57. ]);
  58. $response = new Response();
  59. $next = function ($req, $res) {
  60. return $res;
  61. };
  62. $middleware = new AssetMiddleware();
  63. $res = $middleware($request, $response, $next);
  64. $body = $res->getBody()->getContents();
  65. $this->assertEquals('', $body);
  66. $this->assertEquals(304, $res->getStatusCode());
  67. $this->assertNotEmpty($res->getHeaderLine('Last-Modified'));
  68. }
  69. /**
  70. * test missing plugin assets.
  71. *
  72. * @return void
  73. */
  74. public function testMissingPluginAsset()
  75. {
  76. $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/test_plugin/not_found.js']);
  77. $response = new Response();
  78. $next = function ($req, $res) {
  79. return $res;
  80. };
  81. $middleware = new AssetMiddleware();
  82. $res = $middleware($request, $response, $next);
  83. $body = $res->getBody()->getContents();
  84. $this->assertEquals('', $body);
  85. }
  86. /**
  87. * Data provider for assets.
  88. *
  89. * @return array
  90. */
  91. public function assetProvider()
  92. {
  93. return [
  94. // In plugin root.
  95. [
  96. '/test_plugin/root.js',
  97. TEST_APP . 'Plugin/TestPlugin/webroot/root.js'
  98. ],
  99. // Subdirectory
  100. [
  101. '/test_plugin/js/alert.js',
  102. TEST_APP . 'Plugin/TestPlugin/webroot/js/alert.js'
  103. ],
  104. // In path that matches the plugin name
  105. [
  106. '/test_plugin/js/test_plugin/test.js',
  107. TEST_APP . 'Plugin/TestPlugin/webroot/js/test_plugin/test.js'
  108. ],
  109. // In vendored plugin
  110. [
  111. '/company/test_plugin_three/css/company.css',
  112. TEST_APP . 'Plugin/Company/TestPluginThree/webroot/css/company.css'
  113. ],
  114. ];
  115. }
  116. /**
  117. * Test assets in a plugin.
  118. *
  119. * @dataProvider assetProvider
  120. */
  121. public function testPluginAsset($url, $expectedFile)
  122. {
  123. $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => $url]);
  124. $response = new Response();
  125. $next = function ($req, $res) {
  126. return $res;
  127. };
  128. $middleware = new AssetMiddleware();
  129. $res = $middleware($request, $response, $next);
  130. $body = $res->getBody()->getContents();
  131. $this->assertStringEqualsFile($expectedFile, $body);
  132. }
  133. /**
  134. * Test headers with plugin assets
  135. *
  136. * @return void
  137. */
  138. public function testPluginAssetHeaders()
  139. {
  140. $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/test_plugin/root.js']);
  141. $response = new Response();
  142. $next = function ($req, $res) {
  143. return $res;
  144. };
  145. $modified = filemtime(TEST_APP . 'Plugin/TestPlugin/webroot/root.js');
  146. $expires = strtotime('+4 hours');
  147. $time = time();
  148. $middleware = new AssetMiddleware(['cacheTime' => '+4 hours']);
  149. $res = $middleware($request, $response, $next);
  150. $this->assertEquals(
  151. 'application/javascript',
  152. $res->getHeaderLine('Content-Type')
  153. );
  154. $this->assertEquals(
  155. gmdate('D, j M Y G:i:s ', $time) . 'GMT',
  156. $res->getHeaderLine('Date')
  157. );
  158. $this->assertEquals(
  159. 'public,max-age=' . ($expires - $time),
  160. $res->getHeaderLine('Cache-Control')
  161. );
  162. $this->assertEquals(
  163. gmdate('D, j M Y G:i:s ', $modified) . 'GMT',
  164. $res->getHeaderLine('Last-Modified')
  165. );
  166. $this->assertEquals(
  167. gmdate('D, j M Y G:i:s ', $expires) . 'GMT',
  168. $res->getHeaderLine('Expires')
  169. );
  170. }
  171. /**
  172. * Test that content-types can be injected
  173. *
  174. * @return void
  175. */
  176. public function testCustomFileTypes()
  177. {
  178. $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/test_plugin/root.js']);
  179. $response = new Response();
  180. $next = function ($req, $res) {
  181. return $res;
  182. };
  183. $middleware = new AssetMiddleware(['types' => ['js' => 'custom/stuff']]);
  184. $res = $middleware($request, $response, $next);
  185. $this->assertEquals(
  186. 'custom/stuff',
  187. $res->getHeaderLine('Content-Type')
  188. );
  189. }
  190. /**
  191. * Test that // results in a 404
  192. *
  193. * @return void
  194. */
  195. public function test404OnDoubleSlash()
  196. {
  197. $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '//index.php']);
  198. $response = new Response();
  199. $next = function ($req, $res) {
  200. return $res;
  201. };
  202. $middleware = new AssetMiddleware();
  203. $res = $middleware($request, $response, $next);
  204. $this->assertEmpty($res->getBody()->getContents());
  205. }
  206. /**
  207. * Test that .. results in a 404
  208. *
  209. * @return void
  210. */
  211. public function test404OnDoubleDot()
  212. {
  213. $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/test_plugin/../webroot/root.js']);
  214. $response = new Response();
  215. $next = function ($req, $res) {
  216. return $res;
  217. };
  218. $middleware = new AssetMiddleware();
  219. $res = $middleware($request, $response, $next);
  220. $this->assertEmpty($res->getBody()->getContents());
  221. }
  222. /**
  223. * Test that hidden filenames result in a 404
  224. *
  225. * @return void
  226. */
  227. public function test404OnHiddenFile()
  228. {
  229. $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/test_plugin/.hiddenfile']);
  230. $response = new Response();
  231. $next = function ($req, $res) {
  232. return $res;
  233. };
  234. $middleware = new AssetMiddleware();
  235. $res = $middleware($request, $response, $next);
  236. $this->assertEmpty($res->getBody()->getContents());
  237. }
  238. /**
  239. * Test that hidden filenames result in a 404
  240. *
  241. * @return void
  242. */
  243. public function test404OnHiddenFolder()
  244. {
  245. $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/test_plugin/.hiddenfolder/some.js']);
  246. $response = new Response();
  247. $next = function ($req, $res) {
  248. return $res;
  249. };
  250. $middleware = new AssetMiddleware();
  251. $res = $middleware($request, $response, $next);
  252. $this->assertEmpty($res->getBody()->getContents());
  253. }
  254. }