ResponseTest.php 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://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. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 2.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Network;
  16. use Cake\Network\Request;
  17. use Cake\Network\Response;
  18. use Cake\TestSuite\TestCase;
  19. /**
  20. * Class ResponseTest
  21. *
  22. */
  23. class ResponseTest extends TestCase {
  24. /**
  25. * Setup for tests
  26. *
  27. * @return void
  28. */
  29. public function setUp() {
  30. parent::setUp();
  31. include_once __DIR__ . DS . 'mocks.php';
  32. }
  33. /**
  34. * Cleanup after tests
  35. *
  36. * @return void
  37. */
  38. public function tearDown() {
  39. parent::tearDown();
  40. }
  41. /**
  42. * Tests the request object constructor
  43. *
  44. * @return void
  45. */
  46. public function testConstruct() {
  47. $response = new Response();
  48. $this->assertNull($response->body());
  49. $this->assertEquals('UTF-8', $response->charset());
  50. $this->assertEquals('text/html', $response->type());
  51. $this->assertEquals(200, $response->statusCode());
  52. $options = array(
  53. 'body' => 'This is the body',
  54. 'charset' => 'my-custom-charset',
  55. 'type' => 'mp3',
  56. 'status' => '203'
  57. );
  58. $response = new Response($options);
  59. $this->assertEquals('This is the body', $response->body());
  60. $this->assertEquals('my-custom-charset', $response->charset());
  61. $this->assertEquals('audio/mpeg', $response->type());
  62. $this->assertEquals(203, $response->statusCode());
  63. $options = array(
  64. 'body' => 'This is the body',
  65. 'charset' => 'my-custom-charset',
  66. 'type' => 'mp3',
  67. 'status' => '422',
  68. 'statusCodes' => array(
  69. 422 => 'Unprocessable Entity'
  70. )
  71. );
  72. $response = new Response($options);
  73. $this->assertEquals($options['body'], $response->body());
  74. $this->assertEquals($options['charset'], $response->charset());
  75. $this->assertEquals($response->getMimeType($options['type']), $response->type());
  76. $this->assertEquals($options['status'], $response->statusCode());
  77. }
  78. /**
  79. * Tests the body method
  80. *
  81. * @return void
  82. */
  83. public function testBody() {
  84. $response = new Response();
  85. $this->assertNull($response->body());
  86. $response->body('Response body');
  87. $this->assertEquals('Response body', $response->body());
  88. $this->assertEquals('Changed Body', $response->body('Changed Body'));
  89. }
  90. /**
  91. * Tests the charset method
  92. *
  93. * @return void
  94. */
  95. public function testCharset() {
  96. $response = new Response();
  97. $this->assertEquals('UTF-8', $response->charset());
  98. $response->charset('iso-8859-1');
  99. $this->assertEquals('iso-8859-1', $response->charset());
  100. $this->assertEquals('UTF-16', $response->charset('UTF-16'));
  101. }
  102. /**
  103. * Tests the statusCode method
  104. *
  105. * @expectedException InvalidArgumentException
  106. * @return void
  107. */
  108. public function testStatusCode() {
  109. $response = new Response();
  110. $this->assertEquals(200, $response->statusCode());
  111. $response->statusCode(404);
  112. $this->assertEquals(404, $response->statusCode());
  113. $this->assertEquals(500, $response->statusCode(500));
  114. //Throws exception
  115. $response->statusCode(1001);
  116. }
  117. /**
  118. * Tests the type method
  119. *
  120. * @return void
  121. */
  122. public function testType() {
  123. $response = new Response();
  124. $this->assertEquals('text/html', $response->type());
  125. $response->type('pdf');
  126. $this->assertEquals('application/pdf', $response->type());
  127. $this->assertEquals('application/crazy-mime', $response->type('application/crazy-mime'));
  128. $this->assertEquals('application/json', $response->type('json'));
  129. $this->assertEquals('text/vnd.wap.wml', $response->type('wap'));
  130. $this->assertEquals('application/vnd.wap.xhtml+xml', $response->type('xhtml-mobile'));
  131. $this->assertEquals('text/csv', $response->type('csv'));
  132. $response->type(array('keynote' => 'application/keynote', 'bat' => 'application/bat'));
  133. $this->assertEquals('application/keynote', $response->type('keynote'));
  134. $this->assertEquals('application/bat', $response->type('bat'));
  135. $this->assertFalse($response->type('wackytype'));
  136. }
  137. /**
  138. * Tests the header method
  139. *
  140. * @return void
  141. */
  142. public function testHeader() {
  143. $response = new Response();
  144. $headers = array();
  145. $this->assertEquals($headers, $response->header());
  146. $response->header('Location', 'http://example.com');
  147. $headers += array('Location' => 'http://example.com');
  148. $this->assertEquals($headers, $response->header());
  149. //Headers with the same name are overwritten
  150. $response->header('Location', 'http://example2.com');
  151. $headers = array('Location' => 'http://example2.com');
  152. $this->assertEquals($headers, $response->header());
  153. $response->header(array('WWW-Authenticate' => 'Negotiate'));
  154. $headers += array('WWW-Authenticate' => 'Negotiate');
  155. $this->assertEquals($headers, $response->header());
  156. $response->header(array('WWW-Authenticate' => 'Not-Negotiate'));
  157. $headers['WWW-Authenticate'] = 'Not-Negotiate';
  158. $this->assertEquals($headers, $response->header());
  159. $response->header(array('Age' => 12, 'Allow' => 'GET, HEAD'));
  160. $headers += array('Age' => 12, 'Allow' => 'GET, HEAD');
  161. $this->assertEquals($headers, $response->header());
  162. // String headers are allowed
  163. $response->header('Content-Language: da');
  164. $headers += array('Content-Language' => 'da');
  165. $this->assertEquals($headers, $response->header());
  166. $response->header('Content-Language: da');
  167. $headers += array('Content-Language' => 'da');
  168. $this->assertEquals($headers, $response->header());
  169. $response->header(array('Content-Encoding: gzip', 'Vary: *', 'Pragma' => 'no-cache'));
  170. $headers += array('Content-Encoding' => 'gzip', 'Vary' => '*', 'Pragma' => 'no-cache');
  171. $this->assertEquals($headers, $response->header());
  172. $response->header('Access-Control-Allow-Origin', array('domain1', 'domain2'));
  173. $headers += array('Access-Control-Allow-Origin' => array('domain1', 'domain2'));
  174. $this->assertEquals($headers, $response->header());
  175. }
  176. /**
  177. * Tests the send method
  178. *
  179. * @return void
  180. */
  181. public function testSend() {
  182. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent', '_setCookies'));
  183. $response->header(array(
  184. 'Content-Language' => 'es',
  185. 'WWW-Authenticate' => 'Negotiate',
  186. 'Access-Control-Allow-Origin' => array('domain1', 'domain2'),
  187. ));
  188. $response->body('the response body');
  189. $response->expects($this->once())->method('_sendContent')->with('the response body');
  190. $response->expects($this->at(0))->method('_setCookies');
  191. $response->expects($this->at(1))
  192. ->method('_sendHeader')->with('HTTP/1.1 200 OK');
  193. $response->expects($this->at(2))
  194. ->method('_sendHeader')->with('Content-Language', 'es');
  195. $response->expects($this->at(3))
  196. ->method('_sendHeader')->with('WWW-Authenticate', 'Negotiate');
  197. $response->expects($this->at(4))
  198. ->method('_sendHeader')->with('Access-Control-Allow-Origin', 'domain1');
  199. $response->expects($this->at(5))
  200. ->method('_sendHeader')->with('Access-Control-Allow-Origin', 'domain2');
  201. $response->expects($this->at(6))
  202. ->method('_sendHeader')->with('Content-Length', 17);
  203. $response->expects($this->at(7))
  204. ->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
  205. $response->send();
  206. }
  207. /**
  208. * Data provider for content type tests.
  209. *
  210. * @return array
  211. */
  212. public static function charsetTypeProvider() {
  213. return array(
  214. array('mp3', 'audio/mpeg'),
  215. array('js', 'application/javascript; charset=UTF-8'),
  216. array('json', 'application/json; charset=UTF-8'),
  217. array('xml', 'application/xml; charset=UTF-8'),
  218. array('txt', 'text/plain; charset=UTF-8'),
  219. );
  220. }
  221. /**
  222. * Tests the send method and changing the content type
  223. *
  224. * @dataProvider charsetTypeProvider
  225. * @return void
  226. */
  227. public function testSendChangingContentType($original, $expected) {
  228. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent', '_setCookies'));
  229. $response->type($original);
  230. $response->body('the response body');
  231. $response->expects($this->once())->method('_sendContent')->with('the response body');
  232. $response->expects($this->at(0))->method('_setCookies');
  233. $response->expects($this->at(1))
  234. ->method('_sendHeader')->with('HTTP/1.1 200 OK');
  235. $response->expects($this->at(2))
  236. ->method('_sendHeader')->with('Content-Length', 17);
  237. $response->expects($this->at(3))
  238. ->method('_sendHeader')->with('Content-Type', $expected);
  239. $response->send();
  240. }
  241. /**
  242. * Tests the send method and changing the content type to JS without adding the charset
  243. *
  244. * @return void
  245. */
  246. public function testSendChangingContentTypeWithoutCharset() {
  247. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent', '_setCookies'));
  248. $response->type('js');
  249. $response->charset('');
  250. $response->body('var $foo = "bar";');
  251. $response->expects($this->once())->method('_sendContent')->with('var $foo = "bar";');
  252. $response->expects($this->at(0))->method('_setCookies');
  253. $response->expects($this->at(1))
  254. ->method('_sendHeader')->with('HTTP/1.1 200 OK');
  255. $response->expects($this->at(2))
  256. ->method('_sendHeader')->with('Content-Length', 17);
  257. $response->expects($this->at(3))
  258. ->method('_sendHeader')->with('Content-Type', 'application/javascript');
  259. $response->send();
  260. }
  261. /**
  262. * Tests the send method and changing the content type
  263. *
  264. * @return void
  265. */
  266. public function testSendWithLocation() {
  267. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent', '_setCookies'));
  268. $response->header('Location', 'http://www.example.com');
  269. $response->expects($this->at(0))->method('_setCookies');
  270. $response->expects($this->at(1))
  271. ->method('_sendHeader')->with('HTTP/1.1 302 Found');
  272. $response->expects($this->at(2))
  273. ->method('_sendHeader')->with('Location', 'http://www.example.com');
  274. $response->expects($this->at(3))
  275. ->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
  276. $response->send();
  277. }
  278. /**
  279. * Tests the disableCache method
  280. *
  281. * @return void
  282. */
  283. public function testDisableCache() {
  284. $response = new Response();
  285. $expected = array(
  286. 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
  287. 'Last-Modified' => gmdate("D, d M Y H:i:s") . " GMT",
  288. 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
  289. );
  290. $response->disableCache();
  291. $this->assertEquals($expected, $response->header());
  292. }
  293. /**
  294. * Tests the cache method
  295. *
  296. * @return void
  297. */
  298. public function testCache() {
  299. $response = new Response();
  300. $since = time();
  301. $time = new \DateTime('+1 day', new \DateTimeZone('UTC'));
  302. $response->expires('+1 day');
  303. $expected = array(
  304. 'Date' => gmdate("D, j M Y G:i:s ", $since) . 'GMT',
  305. 'Last-Modified' => gmdate("D, j M Y H:i:s ", $since) . 'GMT',
  306. 'Expires' => $time->format('D, j M Y H:i:s') . ' GMT',
  307. 'Cache-Control' => 'public, max-age=' . ($time->format('U') - time())
  308. );
  309. $response->cache($since);
  310. $this->assertEquals($expected, $response->header());
  311. $response = new Response();
  312. $since = time();
  313. $time = '+5 day';
  314. $expected = array(
  315. 'Date' => gmdate("D, j M Y G:i:s ", $since) . 'GMT',
  316. 'Last-Modified' => gmdate("D, j M Y H:i:s ", $since) . 'GMT',
  317. 'Expires' => gmdate("D, j M Y H:i:s", strtotime($time)) . " GMT",
  318. 'Cache-Control' => 'public, max-age=' . (strtotime($time) - time())
  319. );
  320. $response->cache($since, $time);
  321. $this->assertEquals($expected, $response->header());
  322. $response = new Response();
  323. $since = time();
  324. $time = time();
  325. $expected = array(
  326. 'Date' => gmdate("D, j M Y G:i:s ", $since) . 'GMT',
  327. 'Last-Modified' => gmdate("D, j M Y H:i:s ", $since) . 'GMT',
  328. 'Expires' => gmdate("D, j M Y H:i:s", $time) . " GMT",
  329. 'Cache-Control' => 'public, max-age=0'
  330. );
  331. $response->cache($since, $time);
  332. $this->assertEquals($expected, $response->header());
  333. }
  334. /**
  335. * Tests the compress method
  336. *
  337. * @return void
  338. */
  339. public function testCompress() {
  340. if (php_sapi_name() !== 'cli') {
  341. $this->markTestSkipped('The response compression can only be tested in cli.');
  342. }
  343. $response = new Response();
  344. if (ini_get("zlib.output_compression") === '1' || !extension_loaded("zlib")) {
  345. $this->assertFalse($response->compress());
  346. $this->markTestSkipped('Is not possible to test output compression');
  347. }
  348. $_SERVER['HTTP_ACCEPT_ENCODING'] = '';
  349. $result = $response->compress();
  350. $this->assertFalse($result);
  351. $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip';
  352. $result = $response->compress();
  353. $this->assertTrue($result);
  354. $this->assertTrue(in_array('ob_gzhandler', ob_list_handlers()));
  355. ob_get_clean();
  356. }
  357. /**
  358. * Tests the httpCodes method
  359. *
  360. * @expectedException InvalidArgumentException
  361. * @return void
  362. */
  363. public function testHttpCodes() {
  364. $response = new Response();
  365. $result = $response->httpCodes();
  366. $this->assertEquals(40, count($result));
  367. $result = $response->httpCodes(100);
  368. $expected = array(100 => 'Continue');
  369. $this->assertEquals($expected, $result);
  370. $codes = array(
  371. 381 => 'Unicorn Moved',
  372. 555 => 'Unexpected Minotaur'
  373. );
  374. $result = $response->httpCodes($codes);
  375. $this->assertTrue($result);
  376. $this->assertEquals(42, count($response->httpCodes()));
  377. $result = $response->httpCodes(381);
  378. $expected = array(381 => 'Unicorn Moved');
  379. $this->assertEquals($expected, $result);
  380. $codes = array(404 => 'Sorry Bro');
  381. $result = $response->httpCodes($codes);
  382. $this->assertTrue($result);
  383. $this->assertEquals(42, count($response->httpCodes()));
  384. $result = $response->httpCodes(404);
  385. $expected = array(404 => 'Sorry Bro');
  386. $this->assertEquals($expected, $result);
  387. //Throws exception
  388. $response->httpCodes(array(
  389. 0 => 'Nothing Here',
  390. -1 => 'Reverse Infinity',
  391. 12345 => 'Universal Password',
  392. 'Hello' => 'World'
  393. ));
  394. }
  395. /**
  396. * Tests the download method
  397. *
  398. * @return void
  399. */
  400. public function testDownload() {
  401. $response = new Response();
  402. $expected = array(
  403. 'Content-Disposition' => 'attachment; filename="myfile.mp3"'
  404. );
  405. $response->download('myfile.mp3');
  406. $this->assertEquals($expected, $response->header());
  407. }
  408. /**
  409. * Tests the mapType method
  410. *
  411. * @return void
  412. */
  413. public function testMapType() {
  414. $response = new Response();
  415. $this->assertEquals('wav', $response->mapType('audio/x-wav'));
  416. $this->assertEquals('pdf', $response->mapType('application/pdf'));
  417. $this->assertEquals('xml', $response->mapType('text/xml'));
  418. $this->assertEquals('html', $response->mapType('*/*'));
  419. $this->assertEquals('csv', $response->mapType('application/vnd.ms-excel'));
  420. $expected = array('json', 'xhtml', 'css');
  421. $result = $response->mapType(array('application/json', 'application/xhtml+xml', 'text/css'));
  422. $this->assertEquals($expected, $result);
  423. }
  424. /**
  425. * Tests the outputCompressed method
  426. *
  427. * @return void
  428. */
  429. public function testOutputCompressed() {
  430. $response = new Response();
  431. $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip';
  432. $result = $response->outputCompressed();
  433. $this->assertFalse($result);
  434. $_SERVER['HTTP_ACCEPT_ENCODING'] = '';
  435. $result = $response->outputCompressed();
  436. $this->assertFalse($result);
  437. if (!extension_loaded("zlib")) {
  438. $this->markTestSkipped('Skipping further tests for outputCompressed as zlib extension is not loaded');
  439. }
  440. if (php_sapi_name() !== 'cli') {
  441. $this->markTestSkipped('Testing outputCompressed method with compression enabled done only in cli');
  442. }
  443. if (ini_get("zlib.output_compression") !== '1') {
  444. ob_start('ob_gzhandler');
  445. }
  446. $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip';
  447. $result = $response->outputCompressed();
  448. $this->assertTrue($result);
  449. $_SERVER['HTTP_ACCEPT_ENCODING'] = '';
  450. $result = $response->outputCompressed();
  451. $this->assertFalse($result);
  452. if (ini_get("zlib.output_compression") !== '1') {
  453. ob_get_clean();
  454. }
  455. }
  456. /**
  457. * Tests the send and setting of Content-Length
  458. *
  459. * @return void
  460. */
  461. public function testSendContentLength() {
  462. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  463. $response->body('the response body');
  464. $response->expects($this->once())->method('_sendContent')->with('the response body');
  465. $response->expects($this->at(0))
  466. ->method('_sendHeader')->with('HTTP/1.1 200 OK');
  467. $response->expects($this->at(2))
  468. ->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
  469. $response->expects($this->at(1))
  470. ->method('_sendHeader')->with('Content-Length', strlen('the response body'));
  471. $response->send();
  472. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  473. $body = '長い長い長いSubjectの場合はfoldingするのが正しいんだけどいったいどうなるんだろう?';
  474. $response->body($body);
  475. $response->expects($this->once())->method('_sendContent')->with($body);
  476. $response->expects($this->at(0))
  477. ->method('_sendHeader')->with('HTTP/1.1 200 OK');
  478. $response->expects($this->at(2))
  479. ->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
  480. $response->expects($this->at(1))
  481. ->method('_sendHeader')->with('Content-Length', 116);
  482. $response->send();
  483. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent', 'outputCompressed'));
  484. $body = '長い長い長いSubjectの場合はfoldingするのが正しいんだけどいったいどうなるんだろう?';
  485. $response->body($body);
  486. $response->expects($this->once())->method('outputCompressed')->will($this->returnValue(true));
  487. $response->expects($this->once())->method('_sendContent')->with($body);
  488. $response->expects($this->exactly(2))->method('_sendHeader');
  489. $response->send();
  490. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent', 'outputCompressed'));
  491. $body = 'hwy';
  492. $response->body($body);
  493. $response->header('Content-Length', 1);
  494. $response->expects($this->never())->method('outputCompressed');
  495. $response->expects($this->once())->method('_sendContent')->with($body);
  496. $response->expects($this->at(1))
  497. ->method('_sendHeader')->with('Content-Length', 1);
  498. $response->send();
  499. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  500. $body = 'content';
  501. $response->statusCode(301);
  502. $response->body($body);
  503. $response->expects($this->once())->method('_sendContent')->with($body);
  504. $response->expects($this->exactly(2))->method('_sendHeader');
  505. $response->send();
  506. ob_start();
  507. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  508. $goofyOutput = 'I am goofily sending output in the controller';
  509. echo $goofyOutput;
  510. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  511. $body = '長い長い長いSubjectの場合はfoldingするのが正しいんだけどいったいどうなるんだろう?';
  512. $response->body($body);
  513. $response->expects($this->once())->method('_sendContent')->with($body);
  514. $response->expects($this->at(0))
  515. ->method('_sendHeader')->with('HTTP/1.1 200 OK');
  516. $response->expects($this->at(1))
  517. ->method('_sendHeader')->with('Content-Length', strlen($goofyOutput) + 116);
  518. $response->expects($this->at(2))
  519. ->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
  520. $response->send();
  521. ob_end_clean();
  522. }
  523. /**
  524. * Tests getting/setting the protocol
  525. *
  526. * @return void
  527. */
  528. public function testProtocol() {
  529. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  530. $response->protocol('HTTP/1.0');
  531. $this->assertEquals('HTTP/1.0', $response->protocol());
  532. $response->expects($this->at(0))
  533. ->method('_sendHeader')->with('HTTP/1.0 200 OK');
  534. $response->send();
  535. }
  536. /**
  537. * Tests getting/setting the Content-Length
  538. *
  539. * @return void
  540. */
  541. public function testLength() {
  542. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  543. $response->length(100);
  544. $this->assertEquals(100, $response->length());
  545. $response->expects($this->at(1))
  546. ->method('_sendHeader')->with('Content-Length', 100);
  547. $response->send();
  548. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  549. $response->length(false);
  550. $this->assertFalse($response->length());
  551. $response->expects($this->exactly(2))
  552. ->method('_sendHeader');
  553. $response->send();
  554. }
  555. /**
  556. * Tests that the response body is unset if the status code is 304 or 204
  557. *
  558. * @return void
  559. */
  560. public function testUnmodifiedContent() {
  561. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  562. $response->body('This is a body');
  563. $response->statusCode(204);
  564. $response->expects($this->once())
  565. ->method('_sendContent')->with('');
  566. $response->send();
  567. $this->assertFalse(array_key_exists('Content-Type', $response->header()));
  568. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  569. $response->body('This is a body');
  570. $response->statusCode(304);
  571. $response->expects($this->once())
  572. ->method('_sendContent')->with('');
  573. $response->send();
  574. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  575. $response->body('This is a body');
  576. $response->statusCode(200);
  577. $response->expects($this->once())
  578. ->method('_sendContent')->with('This is a body');
  579. $response->send();
  580. }
  581. /**
  582. * Tests setting the expiration date
  583. *
  584. * @return void
  585. */
  586. public function testExpires() {
  587. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  588. $now = new \DateTime('now', new \DateTimeZone('America/Los_Angeles'));
  589. $response->expires($now);
  590. $now->setTimeZone(new \DateTimeZone('UTC'));
  591. $this->assertEquals($now->format('D, j M Y H:i:s') . ' GMT', $response->expires());
  592. $response->expects($this->at(1))
  593. ->method('_sendHeader')->with('Expires', $now->format('D, j M Y H:i:s') . ' GMT');
  594. $response->send();
  595. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  596. $now = time();
  597. $response->expires($now);
  598. $this->assertEquals(gmdate('D, j M Y H:i:s', $now) . ' GMT', $response->expires());
  599. $response->expects($this->at(1))
  600. ->method('_sendHeader')->with('Expires', gmdate('D, j M Y H:i:s', $now) . ' GMT');
  601. $response->send();
  602. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  603. $time = new \DateTime('+1 day', new \DateTimeZone('UTC'));
  604. $response->expires('+1 day');
  605. $this->assertEquals($time->format('D, j M Y H:i:s') . ' GMT', $response->expires());
  606. $response->expects($this->at(1))
  607. ->method('_sendHeader')->with('Expires', $time->format('D, j M Y H:i:s') . ' GMT');
  608. $response->send();
  609. }
  610. /**
  611. * Tests setting the modification date
  612. *
  613. * @return void
  614. */
  615. public function testModified() {
  616. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  617. $now = new \DateTime('now', new \DateTimeZone('America/Los_Angeles'));
  618. $response->modified($now);
  619. $now->setTimeZone(new \DateTimeZone('UTC'));
  620. $this->assertEquals($now->format('D, j M Y H:i:s') . ' GMT', $response->modified());
  621. $response->expects($this->at(1))
  622. ->method('_sendHeader')->with('Last-Modified', $now->format('D, j M Y H:i:s') . ' GMT');
  623. $response->send();
  624. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  625. $now = time();
  626. $response->modified($now);
  627. $this->assertEquals(gmdate('D, j M Y H:i:s', $now) . ' GMT', $response->modified());
  628. $response->expects($this->at(1))
  629. ->method('_sendHeader')->with('Last-Modified', gmdate('D, j M Y H:i:s', $now) . ' GMT');
  630. $response->send();
  631. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  632. $time = new \DateTime('+1 day', new \DateTimeZone('UTC'));
  633. $response->modified('+1 day');
  634. $this->assertEquals($time->format('D, j M Y H:i:s') . ' GMT', $response->modified());
  635. $response->expects($this->at(1))
  636. ->method('_sendHeader')->with('Last-Modified', $time->format('D, j M Y H:i:s') . ' GMT');
  637. $response->send();
  638. }
  639. /**
  640. * Tests setting of public/private Cache-Control directives
  641. *
  642. * @return void
  643. */
  644. public function testSharable() {
  645. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  646. $this->assertNull($response->sharable());
  647. $response->sharable(true);
  648. $headers = $response->header();
  649. $this->assertEquals('public', $headers['Cache-Control']);
  650. $response->expects($this->at(1))
  651. ->method('_sendHeader')->with('Cache-Control', 'public');
  652. $response->send();
  653. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  654. $response->sharable(false);
  655. $headers = $response->header();
  656. $this->assertEquals('private', $headers['Cache-Control']);
  657. $response->expects($this->at(1))
  658. ->method('_sendHeader')->with('Cache-Control', 'private');
  659. $response->send();
  660. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  661. $response->sharable(true);
  662. $headers = $response->header();
  663. $this->assertEquals('public', $headers['Cache-Control']);
  664. $response->sharable(false);
  665. $headers = $response->header();
  666. $this->assertEquals('private', $headers['Cache-Control']);
  667. $response->expects($this->at(1))
  668. ->method('_sendHeader')->with('Cache-Control', 'private');
  669. $response->send();
  670. $this->assertFalse($response->sharable());
  671. $response->sharable(true);
  672. $this->assertTrue($response->sharable());
  673. $response = $this->getMock('Cake\Network\Response', array('_sendHeader'));
  674. $response->sharable(true, 3600);
  675. $headers = $response->header();
  676. $this->assertEquals('public, max-age=3600', $headers['Cache-Control']);
  677. $response = $this->getMock('Cake\Network\Response', array('_sendHeader'));
  678. $response->sharable(false, 3600);
  679. $headers = $response->header();
  680. $this->assertEquals('private, max-age=3600', $headers['Cache-Control']);
  681. $response->send();
  682. }
  683. /**
  684. * Tests setting of max-age Cache-Control directive
  685. *
  686. * @return void
  687. */
  688. public function testMaxAge() {
  689. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  690. $this->assertNull($response->maxAge());
  691. $response->maxAge(3600);
  692. $this->assertEquals(3600, $response->maxAge());
  693. $headers = $response->header();
  694. $this->assertEquals('max-age=3600', $headers['Cache-Control']);
  695. $response->expects($this->at(1))
  696. ->method('_sendHeader')->with('Cache-Control', 'max-age=3600');
  697. $response->send();
  698. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  699. $response->maxAge(3600);
  700. $response->sharable(false);
  701. $headers = $response->header();
  702. $this->assertEquals('max-age=3600, private', $headers['Cache-Control']);
  703. $response->expects($this->at(1))
  704. ->method('_sendHeader')->with('Cache-Control', 'max-age=3600, private');
  705. $response->send();
  706. }
  707. /**
  708. * Tests setting of s-maxage Cache-Control directive
  709. *
  710. * @return void
  711. */
  712. public function testSharedMaxAge() {
  713. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  714. $this->assertNull($response->maxAge());
  715. $response->sharedMaxAge(3600);
  716. $this->assertEquals(3600, $response->sharedMaxAge());
  717. $headers = $response->header();
  718. $this->assertEquals('s-maxage=3600', $headers['Cache-Control']);
  719. $response->expects($this->at(1))
  720. ->method('_sendHeader')->with('Cache-Control', 's-maxage=3600');
  721. $response->send();
  722. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  723. $response->sharedMaxAge(3600);
  724. $response->sharable(true);
  725. $headers = $response->header();
  726. $this->assertEquals('s-maxage=3600, public', $headers['Cache-Control']);
  727. $response->expects($this->at(1))
  728. ->method('_sendHeader')->with('Cache-Control', 's-maxage=3600, public');
  729. $response->send();
  730. }
  731. /**
  732. * Tests setting of must-revalidate Cache-Control directive
  733. *
  734. * @return void
  735. */
  736. public function testMustRevalidate() {
  737. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  738. $this->assertFalse($response->mustRevalidate());
  739. $response->mustRevalidate(true);
  740. $this->assertTrue($response->mustRevalidate());
  741. $headers = $response->header();
  742. $this->assertEquals('must-revalidate', $headers['Cache-Control']);
  743. $response->expects($this->at(1))
  744. ->method('_sendHeader')->with('Cache-Control', 'must-revalidate');
  745. $response->send();
  746. $response->mustRevalidate(false);
  747. $this->assertFalse($response->mustRevalidate());
  748. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  749. $response->sharedMaxAge(3600);
  750. $response->mustRevalidate(true);
  751. $headers = $response->header();
  752. $this->assertEquals('s-maxage=3600, must-revalidate', $headers['Cache-Control']);
  753. $response->expects($this->at(1))
  754. ->method('_sendHeader')->with('Cache-Control', 's-maxage=3600, must-revalidate');
  755. $response->send();
  756. }
  757. /**
  758. * Tests getting/setting the Vary header
  759. *
  760. * @return void
  761. */
  762. public function testVary() {
  763. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  764. $response->vary('Accept-encoding');
  765. $this->assertEquals(array('Accept-encoding'), $response->vary());
  766. $response->expects($this->at(1))
  767. ->method('_sendHeader')->with('Vary', 'Accept-encoding');
  768. $response->send();
  769. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  770. $response->vary(array('Accept-language', 'Accept-encoding'));
  771. $response->expects($this->at(1))
  772. ->method('_sendHeader')->with('Vary', 'Accept-language, Accept-encoding');
  773. $response->send();
  774. $this->assertEquals(array('Accept-language', 'Accept-encoding'), $response->vary());
  775. }
  776. /**
  777. * Tests getting/setting the Etag header
  778. *
  779. * @return void
  780. */
  781. public function testEtag() {
  782. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  783. $response->etag('something');
  784. $this->assertEquals('"something"', $response->etag());
  785. $response->expects($this->at(1))
  786. ->method('_sendHeader')->with('Etag', '"something"');
  787. $response->send();
  788. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  789. $response->etag('something', true);
  790. $this->assertEquals('W/"something"', $response->etag());
  791. $response->expects($this->at(1))
  792. ->method('_sendHeader')->with('Etag', 'W/"something"');
  793. $response->send();
  794. }
  795. /**
  796. * Tests that the response is able to be marked as not modified
  797. *
  798. * @return void
  799. */
  800. public function testNotModified() {
  801. $response = $this->getMock('Cake\Network\Response', array('_sendHeader', '_sendContent'));
  802. $response->body('something');
  803. $response->statusCode(200);
  804. $response->length(100);
  805. $response->modified('now');
  806. $response->notModified();
  807. $this->assertEmpty($response->header());
  808. $this->assertEmpty($response->body());
  809. $this->assertEquals(304, $response->statusCode());
  810. }
  811. /**
  812. * Test checkNotModified method
  813. *
  814. * @return void
  815. */
  816. public function testCheckNotModifiedByEtagStar() {
  817. $_SERVER['HTTP_IF_NONE_MATCH'] = '*';
  818. $response = $this->getMock('Cake\Network\Response', array('notModified'));
  819. $response->etag('something');
  820. $response->expects($this->once())->method('notModified');
  821. $response->checkNotModified(new Request);
  822. }
  823. /**
  824. * Test checkNotModified method
  825. *
  826. * @return void
  827. */
  828. public function testCheckNotModifiedByEtagExact() {
  829. $_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
  830. $response = $this->getMock('Cake\Network\Response', array('notModified'));
  831. $response->etag('something', true);
  832. $response->expects($this->once())->method('notModified');
  833. $this->assertTrue($response->checkNotModified(new Request));
  834. }
  835. /**
  836. * Test checkNotModified method
  837. *
  838. * @return void
  839. */
  840. public function testCheckNotModifiedByEtagAndTime() {
  841. $_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
  842. $_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
  843. $response = $this->getMock('Cake\Network\Response', array('notModified'));
  844. $response->etag('something', true);
  845. $response->modified('2012-01-01 00:00:00');
  846. $response->expects($this->once())->method('notModified');
  847. $this->assertTrue($response->checkNotModified(new Request));
  848. }
  849. /**
  850. * Test checkNotModified method
  851. *
  852. * @return void
  853. */
  854. public function testCheckNotModifiedByEtagAndTimeMismatch() {
  855. $_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
  856. $_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
  857. $response = $this->getMock('Cake\Network\Response', array('notModified'));
  858. $response->etag('something', true);
  859. $response->modified('2012-01-01 00:00:01');
  860. $response->expects($this->never())->method('notModified');
  861. $this->assertFalse($response->checkNotModified(new Request));
  862. }
  863. /**
  864. * Test checkNotModified method
  865. *
  866. * @return void
  867. */
  868. public function testCheckNotModifiedByEtagMismatch() {
  869. $_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something-else", "other"';
  870. $_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
  871. $response = $this->getMock('Cake\Network\Response', array('notModified'));
  872. $response->etag('something', true);
  873. $response->modified('2012-01-01 00:00:00');
  874. $response->expects($this->never())->method('notModified');
  875. $this->assertFalse($response->checkNotModified(new Request));
  876. }
  877. /**
  878. * Test checkNotModified method
  879. *
  880. * @return void
  881. */
  882. public function testCheckNotModifiedByTime() {
  883. $_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
  884. $response = $this->getMock('Cake\Network\Response', array('notModified'));
  885. $response->modified('2012-01-01 00:00:00');
  886. $response->expects($this->once())->method('notModified');
  887. $this->assertTrue($response->checkNotModified(new Request));
  888. }
  889. /**
  890. * Test checkNotModified method
  891. *
  892. * @return void
  893. */
  894. public function testCheckNotModifiedNoHints() {
  895. $_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
  896. $_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
  897. $response = $this->getMock('Cake\Network\Response', array('notModified'));
  898. $response->expects($this->never())->method('notModified');
  899. $this->assertFalse($response->checkNotModified(new Request));
  900. }
  901. /**
  902. * Test cookie setting
  903. *
  904. * @return void
  905. */
  906. public function testCookieSettings() {
  907. $response = new Response();
  908. $cookie = array(
  909. 'name' => 'CakeTestCookie[Testing]'
  910. );
  911. $response->cookie($cookie);
  912. $expected = array(
  913. 'name' => 'CakeTestCookie[Testing]',
  914. 'value' => '',
  915. 'expire' => 0,
  916. 'path' => '/',
  917. 'domain' => '',
  918. 'secure' => false,
  919. 'httpOnly' => false);
  920. $result = $response->cookie('CakeTestCookie[Testing]');
  921. $this->assertEquals($expected, $result);
  922. $cookie = array(
  923. 'name' => 'CakeTestCookie[Testing2]',
  924. 'value' => '[a,b,c]',
  925. 'expire' => 1000,
  926. 'path' => '/test',
  927. 'secure' => true
  928. );
  929. $response->cookie($cookie);
  930. $expected = array(
  931. 'CakeTestCookie[Testing]' => array(
  932. 'name' => 'CakeTestCookie[Testing]',
  933. 'value' => '',
  934. 'expire' => 0,
  935. 'path' => '/',
  936. 'domain' => '',
  937. 'secure' => false,
  938. 'httpOnly' => false
  939. ),
  940. 'CakeTestCookie[Testing2]' => array(
  941. 'name' => 'CakeTestCookie[Testing2]',
  942. 'value' => '[a,b,c]',
  943. 'expire' => 1000,
  944. 'path' => '/test',
  945. 'domain' => '',
  946. 'secure' => true,
  947. 'httpOnly' => false
  948. )
  949. );
  950. $result = $response->cookie();
  951. $this->assertEquals($expected, $result);
  952. $cookie = $expected['CakeTestCookie[Testing]'];
  953. $cookie['value'] = 'test';
  954. $response->cookie($cookie);
  955. $expected = array(
  956. 'CakeTestCookie[Testing]' => array(
  957. 'name' => 'CakeTestCookie[Testing]',
  958. 'value' => 'test',
  959. 'expire' => 0,
  960. 'path' => '/',
  961. 'domain' => '',
  962. 'secure' => false,
  963. 'httpOnly' => false
  964. ),
  965. 'CakeTestCookie[Testing2]' => array(
  966. 'name' => 'CakeTestCookie[Testing2]',
  967. 'value' => '[a,b,c]',
  968. 'expire' => 1000,
  969. 'path' => '/test',
  970. 'domain' => '',
  971. 'secure' => true,
  972. 'httpOnly' => false
  973. )
  974. );
  975. $result = $response->cookie();
  976. $this->assertEquals($expected, $result);
  977. }
  978. /**
  979. * Test CORS
  980. *
  981. * @dataProvider corsData
  982. * @param Request $request
  983. * @param string $origin
  984. * @param string|array $domains
  985. * @param string|array $methods
  986. * @param string|array $headers
  987. * @param string|bool $expectedOrigin
  988. * @param string|bool $expectedMethods
  989. * @param string|bool $expectedHeaders
  990. * @return void
  991. */
  992. public function testCors($request, $origin, $domains, $methods, $headers, $expectedOrigin, $expectedMethods = false, $expectedHeaders = false) {
  993. $request->env('HTTP_ORIGIN', $origin);
  994. $response = $this->getMock('Cake\Network\Response', array('header'));
  995. $method = $response->expects(!$expectedOrigin ? $this->never() : $this->at(0))->method('header');
  996. $expectedOrigin && $method->with('Access-Control-Allow-Origin', $expectedOrigin ? $expectedOrigin : $this->anything());
  997. $i = 1;
  998. if ($expectedMethods) {
  999. $response->expects($this->at($i++))
  1000. ->method('header')
  1001. ->with('Access-Control-Allow-Methods', $expectedMethods ? $expectedMethods : $this->anything());
  1002. }
  1003. if ($expectedHeaders) {
  1004. $response->expects($this->at($i++))
  1005. ->method('header')
  1006. ->with('Access-Control-Allow-Headers', $expectedHeaders ? $expectedHeaders : $this->anything());
  1007. }
  1008. $response->cors($request, $domains, $methods, $headers);
  1009. unset($_SERVER['HTTP_ORIGIN']);
  1010. }
  1011. /**
  1012. * Feed for testCors
  1013. *
  1014. * @return array
  1015. */
  1016. public function corsData() {
  1017. $fooRequest = new Request();
  1018. $secureRequest = $this->getMock('Cake\Network\Request', array('is'));
  1019. $secureRequest->expects($this->any())
  1020. ->method('is')
  1021. ->with('ssl')
  1022. ->will($this->returnValue(true));
  1023. return array(
  1024. array($fooRequest, null, '*', '', '', false, false),
  1025. array($fooRequest, 'http://www.foo.com', '*', '', '', '*', false),
  1026. array($fooRequest, 'http://www.foo.com', 'www.foo.com', '', '', 'http://www.foo.com', false),
  1027. array($fooRequest, 'http://www.foo.com', '*.foo.com', '', '', 'http://www.foo.com', false),
  1028. array($fooRequest, 'http://www.foo.com', 'http://*.foo.com', '', '', 'http://www.foo.com', false),
  1029. array($fooRequest, 'http://www.foo.com', 'https://www.foo.com', '', '', false, false),
  1030. array($fooRequest, 'http://www.foo.com', 'https://*.foo.com', '', '', false, false),
  1031. array($fooRequest, 'http://www.foo.com', array('*.bar.com', '*.foo.com'), '', '', 'http://www.foo.com', false),
  1032. array($secureRequest, 'https://www.bar.com', 'www.bar.com', '', '', 'https://www.bar.com', false),
  1033. array($secureRequest, 'https://www.bar.com', 'http://www.bar.com', '', '', false, false),
  1034. array($secureRequest, 'https://www.bar.com', '*.bar.com', '', '', 'https://www.bar.com', false),
  1035. array($fooRequest, 'http://www.foo.com', '*', 'GET', '', '*', 'GET'),
  1036. array($fooRequest, 'http://www.foo.com', '*.foo.com', 'GET', '', 'http://www.foo.com', 'GET'),
  1037. array($fooRequest, 'http://www.foo.com', '*.foo.com', array('GET', 'POST'), '', 'http://www.foo.com', 'GET, POST'),
  1038. array($fooRequest, 'http://www.foo.com', '*', '', 'X-CakePHP', '*', false, 'X-CakePHP'),
  1039. array($fooRequest, 'http://www.foo.com', '*', '', array('X-CakePHP', 'X-MyApp'), '*', false, 'X-CakePHP, X-MyApp'),
  1040. array($fooRequest, 'http://www.foo.com', '*', array('GET', 'OPTIONS'), array('X-CakePHP', 'X-MyApp'), '*', 'GET, OPTIONS', 'X-CakePHP, X-MyApp'),
  1041. );
  1042. }
  1043. /**
  1044. * testFileNotFound
  1045. *
  1046. * @expectedException Cake\Network\Exception\NotFoundException
  1047. * @return void
  1048. */
  1049. public function testFileNotFound() {
  1050. $response = new Response();
  1051. $response->file('/some/missing/folder/file.jpg');
  1052. }
  1053. /**
  1054. * test file with ..
  1055. *
  1056. * @expectedException Cake\Network\Exception\NotFoundException
  1057. * @return void
  1058. */
  1059. public function testFileWithPathTraversal() {
  1060. $response = new Response();
  1061. $response->file('my/../cat.gif');
  1062. }
  1063. /**
  1064. * testFile method
  1065. *
  1066. * @return void
  1067. */
  1068. public function testFile() {
  1069. $response = $this->getMock('Cake\Network\Response', array(
  1070. 'header',
  1071. 'type',
  1072. '_sendHeader',
  1073. '_setContentType',
  1074. '_isActive',
  1075. '_clearBuffer',
  1076. '_flushBuffer'
  1077. ));
  1078. $response->expects($this->exactly(1))
  1079. ->method('type')
  1080. ->with('css')
  1081. ->will($this->returnArgument(0));
  1082. $response->expects($this->at(1))
  1083. ->method('header')
  1084. ->with('Content-Length', 38);
  1085. $response->expects($this->once())->method('_clearBuffer');
  1086. $response->expects($this->once())->method('_flushBuffer');
  1087. $response->expects($this->exactly(1))
  1088. ->method('_isActive')
  1089. ->will($this->returnValue(true));
  1090. $response->file(TEST_APP . 'vendor/css/test_asset.css');
  1091. ob_start();
  1092. $result = $response->send();
  1093. $output = ob_get_clean();
  1094. $this->assertEquals("/* this is the test asset css file */", trim($output));
  1095. $this->assertTrue($result !== false);
  1096. }
  1097. /**
  1098. * testFileWithDownloadAndName
  1099. *
  1100. * @return void
  1101. */
  1102. public function testFileWithDownloadAndName() {
  1103. $response = $this->getMock('Cake\Network\Response', array(
  1104. 'header',
  1105. 'type',
  1106. 'download',
  1107. '_sendHeader',
  1108. '_setContentType',
  1109. '_isActive',
  1110. '_clearBuffer',
  1111. '_flushBuffer'
  1112. ));
  1113. $response->expects($this->exactly(1))
  1114. ->method('type')
  1115. ->with('css')
  1116. ->will($this->returnArgument(0));
  1117. $response->expects($this->once())
  1118. ->method('download')
  1119. ->with('something_special.css');
  1120. $response->expects($this->at(2))
  1121. ->method('header')
  1122. ->with('Accept-Ranges', 'bytes');
  1123. $response->expects($this->at(3))
  1124. ->method('header')
  1125. ->with('Content-Transfer-Encoding', 'binary');
  1126. $response->expects($this->at(4))
  1127. ->method('header')
  1128. ->with('Content-Length', 38);
  1129. $response->expects($this->once())->method('_clearBuffer');
  1130. $response->expects($this->once())->method('_flushBuffer');
  1131. $response->expects($this->exactly(1))
  1132. ->method('_isActive')
  1133. ->will($this->returnValue(true));
  1134. $response->file(
  1135. TEST_APP . 'vendor' . DS . 'css' . DS . 'test_asset.css',
  1136. array(
  1137. 'name' => 'something_special.css',
  1138. 'download' => true,
  1139. )
  1140. );
  1141. ob_start();
  1142. $result = $response->send();
  1143. $output = ob_get_clean();
  1144. $this->assertEquals("/* this is the test asset css file */\n", $output);
  1145. $this->assertTrue($result !== false);
  1146. }
  1147. /**
  1148. * testFileWithUnknownFileTypeGeneric method
  1149. *
  1150. * @return void
  1151. */
  1152. public function testFileWithUnknownFileTypeGeneric() {
  1153. $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
  1154. $_SERVER['HTTP_USER_AGENT'] = 'Some generic browser';
  1155. $response = $this->getMock('Cake\Network\Response', array(
  1156. 'header',
  1157. 'type',
  1158. 'download',
  1159. '_sendHeader',
  1160. '_setContentType',
  1161. '_isActive',
  1162. '_clearBuffer',
  1163. '_flushBuffer'
  1164. ));
  1165. $response->expects($this->exactly(1))
  1166. ->method('type')
  1167. ->with('ini')
  1168. ->will($this->returnValue(false));
  1169. $response->expects($this->once())
  1170. ->method('download')
  1171. ->with('no_section.ini');
  1172. $response->expects($this->at(2))
  1173. ->method('header')
  1174. ->with('Accept-Ranges', 'bytes');
  1175. $response->expects($this->at(3))
  1176. ->method('header')
  1177. ->with('Content-Transfer-Encoding', 'binary');
  1178. $response->expects($this->at(4))
  1179. ->method('header')
  1180. ->with('Content-Length', 35);
  1181. $response->expects($this->once())->method('_clearBuffer');
  1182. $response->expects($this->once())->method('_flushBuffer');
  1183. $response->expects($this->exactly(1))
  1184. ->method('_isActive')
  1185. ->will($this->returnValue(true));
  1186. $response->file(CONFIG . 'no_section.ini');
  1187. ob_start();
  1188. $result = $response->send();
  1189. $output = ob_get_clean();
  1190. $this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
  1191. $this->assertTrue($result !== false);
  1192. if ($currentUserAgent !== null) {
  1193. $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
  1194. }
  1195. }
  1196. /**
  1197. * testFileWithUnknownFileTypeOpera method
  1198. *
  1199. * @return void
  1200. */
  1201. public function testFileWithUnknownFileTypeOpera() {
  1202. $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
  1203. $_SERVER['HTTP_USER_AGENT'] = 'Opera/9.80 (Windows NT 6.0; U; en) Presto/2.8.99 Version/11.10';
  1204. $response = $this->getMock('Cake\Network\Response', array(
  1205. 'header',
  1206. 'type',
  1207. 'download',
  1208. '_sendHeader',
  1209. '_setContentType',
  1210. '_isActive',
  1211. '_clearBuffer',
  1212. '_flushBuffer'
  1213. ));
  1214. $response->expects($this->at(0))
  1215. ->method('type')
  1216. ->with('ini')
  1217. ->will($this->returnValue(false));
  1218. $response->expects($this->at(1))
  1219. ->method('type')
  1220. ->with('application/octet-stream')
  1221. ->will($this->returnValue(false));
  1222. $response->expects($this->once())
  1223. ->method('download')
  1224. ->with('no_section.ini');
  1225. $response->expects($this->at(3))
  1226. ->method('header')
  1227. ->with('Accept-Ranges', 'bytes');
  1228. $response->expects($this->at(4))
  1229. ->method('header')
  1230. ->with('Content-Transfer-Encoding', 'binary');
  1231. $response->expects($this->at(5))
  1232. ->method('header')
  1233. ->with('Content-Length', 35);
  1234. $response->expects($this->once())->method('_clearBuffer');
  1235. $response->expects($this->once())->method('_flushBuffer');
  1236. $response->expects($this->exactly(1))
  1237. ->method('_isActive')
  1238. ->will($this->returnValue(true));
  1239. $response->file(CONFIG . 'no_section.ini');
  1240. ob_start();
  1241. $result = $response->send();
  1242. $output = ob_get_clean();
  1243. $this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
  1244. $this->assertTrue($result !== false);
  1245. if ($currentUserAgent !== null) {
  1246. $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
  1247. }
  1248. }
  1249. /**
  1250. * testFileWithUnknownFileTypeIE method
  1251. *
  1252. * @return void
  1253. */
  1254. public function testFileWithUnknownFileTypeIE() {
  1255. $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
  1256. $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320)';
  1257. $response = $this->getMock('Cake\Network\Response', array(
  1258. 'header',
  1259. 'type',
  1260. 'download',
  1261. '_sendHeader',
  1262. '_setContentType',
  1263. '_isActive',
  1264. '_clearBuffer',
  1265. '_flushBuffer'
  1266. ));
  1267. $response->expects($this->at(0))
  1268. ->method('type')
  1269. ->with('ini')
  1270. ->will($this->returnValue(false));
  1271. $response->expects($this->at(1))
  1272. ->method('type')
  1273. ->with('application/force-download')
  1274. ->will($this->returnValue(false));
  1275. $response->expects($this->once())
  1276. ->method('download')
  1277. ->with('config.ini');
  1278. $response->expects($this->at(3))
  1279. ->method('header')
  1280. ->with('Accept-Ranges', 'bytes');
  1281. $response->expects($this->at(4))
  1282. ->method('header')
  1283. ->with('Content-Transfer-Encoding', 'binary');
  1284. $response->expects($this->at(5))
  1285. ->method('header')
  1286. ->with('Content-Length', 35);
  1287. $response->expects($this->once())->method('_clearBuffer');
  1288. $response->expects($this->once())->method('_flushBuffer');
  1289. $response->expects($this->exactly(1))
  1290. ->method('_isActive')
  1291. ->will($this->returnValue(true));
  1292. $response->file(CONFIG . 'no_section.ini', array(
  1293. 'name' => 'config.ini'
  1294. ));
  1295. ob_start();
  1296. $result = $response->send();
  1297. $output = ob_get_clean();
  1298. $this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
  1299. $this->assertTrue($result !== false);
  1300. if ($currentUserAgent !== null) {
  1301. $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
  1302. }
  1303. }
  1304. /**
  1305. * testFileWithUnknownFileNoDownload method
  1306. *
  1307. * @return void
  1308. */
  1309. public function testFileWithUnknownFileNoDownload() {
  1310. $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
  1311. $_SERVER['HTTP_USER_AGENT'] = 'Some generic browser';
  1312. $response = $this->getMock('Cake\Network\Response', array(
  1313. 'header',
  1314. 'type',
  1315. 'download',
  1316. '_sendHeader',
  1317. '_setContentType',
  1318. '_isActive',
  1319. '_clearBuffer',
  1320. '_flushBuffer'
  1321. ));
  1322. $response->expects($this->exactly(1))
  1323. ->method('type')
  1324. ->with('ini')
  1325. ->will($this->returnValue(false));
  1326. $response->expects($this->never())
  1327. ->method('download');
  1328. $response->file(CONFIG . 'no_section.ini', array(
  1329. 'download' => false
  1330. ));
  1331. if ($currentUserAgent !== null) {
  1332. $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
  1333. }
  1334. }
  1335. /**
  1336. * testConnectionAbortedOnBuffering method
  1337. *
  1338. * @return void
  1339. */
  1340. public function testConnectionAbortedOnBuffering() {
  1341. $response = $this->getMock('Cake\Network\Response', array(
  1342. 'header',
  1343. 'type',
  1344. 'download',
  1345. '_sendHeader',
  1346. '_setContentType',
  1347. '_isActive',
  1348. '_clearBuffer',
  1349. '_flushBuffer'
  1350. ));
  1351. $response->expects($this->any())
  1352. ->method('type')
  1353. ->with('css')
  1354. ->will($this->returnArgument(0));
  1355. $response->expects($this->at(0))
  1356. ->method('_isActive')
  1357. ->will($this->returnValue(false));
  1358. $response->expects($this->once())->method('_clearBuffer');
  1359. $response->expects($this->never())->method('_flushBuffer');
  1360. $response->file(TEST_APP . 'vendor/css/test_asset.css');
  1361. $result = $response->send();
  1362. $this->assertNull($result);
  1363. }
  1364. /**
  1365. * Test downloading files with UPPERCASE extensions.
  1366. *
  1367. * @return void
  1368. */
  1369. public function testFileUpperExtension() {
  1370. $response = $this->getMock('Cake\Network\Response', array(
  1371. 'header',
  1372. 'type',
  1373. 'download',
  1374. '_sendHeader',
  1375. '_setContentType',
  1376. '_isActive',
  1377. '_clearBuffer',
  1378. '_flushBuffer'
  1379. ));
  1380. $response->expects($this->any())
  1381. ->method('type')
  1382. ->with('jpg')
  1383. ->will($this->returnArgument(0));
  1384. $response->expects($this->at(0))
  1385. ->method('_isActive')
  1386. ->will($this->returnValue(true));
  1387. $response->file(TEST_APP . 'vendor/img/test_2.JPG');
  1388. }
  1389. /**
  1390. * Test downloading files with extension not explicitly set.
  1391. *
  1392. * @return void
  1393. */
  1394. public function testFileExtensionNotSet() {
  1395. $response = $this->getMock('Cake\Network\Response', array(
  1396. 'header',
  1397. 'type',
  1398. 'download',
  1399. '_sendHeader',
  1400. '_setContentType',
  1401. '_isActive',
  1402. '_clearBuffer',
  1403. '_flushBuffer'
  1404. ));
  1405. $response->expects($this->any())
  1406. ->method('type')
  1407. ->with('jpg')
  1408. ->will($this->returnArgument(0));
  1409. $response->expects($this->at(0))
  1410. ->method('_isActive')
  1411. ->will($this->returnValue(true));
  1412. $response->file(TEST_APP . 'vendor/img/test_2.JPG');
  1413. }
  1414. /**
  1415. * A data provider for testing various ranges
  1416. *
  1417. * @return array
  1418. */
  1419. public static function rangeProvider() {
  1420. return array(
  1421. // suffix-byte-range
  1422. array(
  1423. 'bytes=-25', 25, 'bytes 13-37/38'
  1424. ),
  1425. array(
  1426. 'bytes=0-', 38, 'bytes 0-37/38'
  1427. ),
  1428. array(
  1429. 'bytes=10-', 28, 'bytes 10-37/38'
  1430. ),
  1431. array(
  1432. 'bytes=10-20', 11, 'bytes 10-20/38'
  1433. ),
  1434. );
  1435. }
  1436. /**
  1437. * Test the various range offset types.
  1438. *
  1439. * @dataProvider rangeProvider
  1440. * @return void
  1441. */
  1442. public function testFileRangeOffsets($range, $length, $offsetResponse) {
  1443. $_SERVER['HTTP_RANGE'] = $range;
  1444. $response = $this->getMock('Cake\Network\Response', array(
  1445. 'header',
  1446. 'type',
  1447. '_sendHeader',
  1448. '_isActive',
  1449. '_clearBuffer',
  1450. '_flushBuffer'
  1451. ));
  1452. $response->expects($this->at(1))
  1453. ->method('header')
  1454. ->with('Content-Disposition', 'attachment; filename="test_asset.css"');
  1455. $response->expects($this->at(2))
  1456. ->method('header')
  1457. ->with('Accept-Ranges', 'bytes');
  1458. $response->expects($this->at(3))
  1459. ->method('header')
  1460. ->with('Content-Transfer-Encoding', 'binary');
  1461. $response->expects($this->at(4))
  1462. ->method('header')
  1463. ->with(array(
  1464. 'Content-Length' => $length,
  1465. 'Content-Range' => $offsetResponse,
  1466. ));
  1467. $response->expects($this->any())
  1468. ->method('_isActive')
  1469. ->will($this->returnValue(true));
  1470. $response->file(
  1471. TEST_APP . 'vendor' . DS . 'css' . DS . 'test_asset.css',
  1472. array('download' => true)
  1473. );
  1474. ob_start();
  1475. $result = $response->send();
  1476. ob_get_clean();
  1477. }
  1478. /**
  1479. * Test fetching ranges from a file.
  1480. *
  1481. * @return void
  1482. */
  1483. public function testFileRange() {
  1484. $_SERVER['HTTP_RANGE'] = 'bytes=8-25';
  1485. $response = $this->getMock('Cake\Network\Response', array(
  1486. 'header',
  1487. 'type',
  1488. '_sendHeader',
  1489. '_setContentType',
  1490. '_isActive',
  1491. '_clearBuffer',
  1492. '_flushBuffer'
  1493. ));
  1494. $response->expects($this->exactly(1))
  1495. ->method('type')
  1496. ->with('css')
  1497. ->will($this->returnArgument(0));
  1498. $response->expects($this->at(1))
  1499. ->method('header')
  1500. ->with('Content-Disposition', 'attachment; filename="test_asset.css"');
  1501. $response->expects($this->at(2))
  1502. ->method('header')
  1503. ->with('Accept-Ranges', 'bytes');
  1504. $response->expects($this->at(3))
  1505. ->method('header')
  1506. ->with('Content-Transfer-Encoding', 'binary');
  1507. $response->expects($this->at(4))
  1508. ->method('header')
  1509. ->with(array(
  1510. 'Content-Length' => 18,
  1511. 'Content-Range' => 'bytes 8-25/38',
  1512. ));
  1513. $response->expects($this->once())->method('_clearBuffer');
  1514. $response->expects($this->any())
  1515. ->method('_isActive')
  1516. ->will($this->returnValue(true));
  1517. $response->file(
  1518. TEST_APP . 'vendor' . DS . 'css' . DS . 'test_asset.css',
  1519. array('download' => true)
  1520. );
  1521. ob_start();
  1522. $result = $response->send();
  1523. $output = ob_get_clean();
  1524. $this->assertEquals(206, $response->statusCode());
  1525. $this->assertEquals("is the test asset ", $output);
  1526. $this->assertTrue($result !== false);
  1527. }
  1528. /**
  1529. * Test invalid file ranges.
  1530. *
  1531. * @return void
  1532. */
  1533. public function testFileRangeInvalid() {
  1534. $_SERVER['HTTP_RANGE'] = 'bytes=30-2';
  1535. $response = $this->getMock('Cake\Network\Response', array(
  1536. 'header',
  1537. 'type',
  1538. '_sendHeader',
  1539. '_setContentType',
  1540. '_isActive',
  1541. '_clearBuffer',
  1542. '_flushBuffer'
  1543. ));
  1544. $response->expects($this->at(1))
  1545. ->method('header')
  1546. ->with('Content-Disposition', 'attachment; filename="test_asset.css"');
  1547. $response->expects($this->at(2))
  1548. ->method('header')
  1549. ->with('Accept-Ranges', 'bytes');
  1550. $response->expects($this->at(3))
  1551. ->method('header')
  1552. ->with('Content-Transfer-Encoding', 'binary');
  1553. $response->expects($this->at(4))
  1554. ->method('header')
  1555. ->with(array(
  1556. 'Content-Range' => 'bytes 0-37/38',
  1557. ));
  1558. $response->file(
  1559. TEST_APP . 'vendor' . DS . 'css' . DS . 'test_asset.css',
  1560. array('download' => true)
  1561. );
  1562. $this->assertEquals(416, $response->statusCode());
  1563. $result = $response->send();
  1564. }
  1565. /**
  1566. * Test the location method.
  1567. *
  1568. * @return void
  1569. */
  1570. public function testLocation() {
  1571. $response = new Response();
  1572. $this->assertNull($response->location(), 'No header should be set.');
  1573. $this->assertNull($response->location('http://example.org'), 'Setting a location should return null');
  1574. $this->assertEquals('http://example.org', $response->location(), 'Reading a location should return the value.');
  1575. }
  1576. }