|
|
@@ -0,0 +1,345 @@
|
|
|
+<?php
|
|
|
+/**
|
|
|
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
|
|
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
|
|
+ *
|
|
|
+ * Licensed under The MIT License
|
|
|
+ * For full copyright and license information, please see the LICENSE.txt
|
|
|
+ * Redistributions of files must retain the above copyright notice.
|
|
|
+ *
|
|
|
+ * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
|
|
+ * @link http://cakephp.org CakePHP(tm) Project
|
|
|
+ * @since 3.5.0
|
|
|
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
|
|
|
+ */
|
|
|
+namespace Cake\Test\TestCase\Http\Middleware;
|
|
|
+
|
|
|
+use Cake\Http\Exception\BadRequestException;
|
|
|
+use Cake\Http\Middleware\BodyParserMiddleware;
|
|
|
+use Cake\Http\Response;
|
|
|
+use Cake\Http\ServerRequest;
|
|
|
+use Cake\TestSuite\TestCase;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Test for BodyParser
|
|
|
+ */
|
|
|
+class BodyParserMiddlewareTest extends TestCase
|
|
|
+{
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Data provider for HTTP method tests.
|
|
|
+ *
|
|
|
+ * HEAD and GET do not populate $_POST or request->data.
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public static function safeHttpMethodProvider()
|
|
|
+ {
|
|
|
+ return [
|
|
|
+ ['GET'],
|
|
|
+ ['HEAD'],
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Data provider for HTTP methods that can contain request bodies.
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public static function httpMethodProvider()
|
|
|
+ {
|
|
|
+ return [
|
|
|
+ ['PATCH'], ['PUT'], ['POST'], ['DELETE']
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test constructor options
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testConstructorMethodsOption()
|
|
|
+ {
|
|
|
+ $parser = new BodyParserMiddleware(['methods' => ['PUT']]);
|
|
|
+ $this->assertAttributeEquals(['PUT'], 'methods', $parser);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test constructor options
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testConstructorXmlOption()
|
|
|
+ {
|
|
|
+ $parser = new BodyParserMiddleware(['json' => false]);
|
|
|
+ $this->assertAttributeEquals([], 'parsers', $parser, 'Xml off by default');
|
|
|
+
|
|
|
+ $parser = new BodyParserMiddleware(['json' => false, 'xml' => false]);
|
|
|
+ $this->assertAttributeEquals([], 'parsers', $parser, 'No Xml types set.');
|
|
|
+
|
|
|
+ $parser = new BodyParserMiddleware(['json' => false, 'xml' => true]);
|
|
|
+ $expected = [
|
|
|
+ 'application/xml' => [$parser, 'decodeXml'],
|
|
|
+ 'text/xml' => [$parser, 'decodeXml'],
|
|
|
+ ];
|
|
|
+ $this->assertAttributeEquals($expected, 'parsers', $parser, 'Xml types are incorrect.');
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test constructor options
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testConstructorJsonOption()
|
|
|
+ {
|
|
|
+ $parser = new BodyParserMiddleware(['json' => false]);
|
|
|
+ $this->assertAttributeEquals([], 'parsers', $parser, 'No JSON types set.');
|
|
|
+
|
|
|
+ $parser = new BodyParserMiddleware([]);
|
|
|
+ $expected = [
|
|
|
+ 'application/json' => [$parser, 'decodeJson'],
|
|
|
+ 'text/json' => [$parser, 'decodeJson'],
|
|
|
+ ];
|
|
|
+ $this->assertAttributeEquals($expected, 'parsers', $parser, 'JSON types are incorrect.');
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test setMethods()
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testSetMethodsReturn()
|
|
|
+ {
|
|
|
+ $parser = new BodyParserMiddleware();
|
|
|
+ $this->assertSame($parser, $parser->setMethods(['PUT']));
|
|
|
+ $this->assertAttributeEquals(['PUT'], 'methods', $parser);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test addParser()
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testAddParserReturn()
|
|
|
+ {
|
|
|
+ $parser = new BodyParserMiddleware(['json' => false]);
|
|
|
+ $this->assertSame($parser, $parser->addParser(['application/json'], 'json_decode'));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test last parser defined wins
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testAddParserOverwrite()
|
|
|
+ {
|
|
|
+ $parser = new BodyParserMiddleware(['json' => false]);
|
|
|
+ $parser->addParser(['application/json'], 'json_decode');
|
|
|
+ $parser->addParser(['application/json'], 'strpos');
|
|
|
+
|
|
|
+ $this->assertAttributeEquals(['application/json' => 'strpos'], 'parsers', $parser);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * test parsing on valid http method
|
|
|
+ *
|
|
|
+ * @dataProvider httpMethodProvider
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testInvokeCaseInsensitiveContentType($method)
|
|
|
+ {
|
|
|
+ $parser = new BodyParserMiddleware();
|
|
|
+
|
|
|
+ $request = new ServerRequest([
|
|
|
+ 'environment' => [
|
|
|
+ 'REQUEST_METHOD' => $method,
|
|
|
+ 'CONTENT_TYPE' => 'ApPlIcAtIoN/JSoN',
|
|
|
+ ],
|
|
|
+ 'input' => '{"title": "yay"}'
|
|
|
+ ]);
|
|
|
+ $response = new Response();
|
|
|
+ $next = function ($req, $res) {
|
|
|
+ $this->assertEquals(['title' => 'yay'], $req->getParsedBody());
|
|
|
+ };
|
|
|
+ $parser($request, $response, $next);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test parsing on valid http method
|
|
|
+ *
|
|
|
+ * @dataProvider httpMethodProvider
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testInvokeParse($method)
|
|
|
+ {
|
|
|
+ $parser = new BodyParserMiddleware();
|
|
|
+
|
|
|
+ $request = new ServerRequest([
|
|
|
+ 'environment' => [
|
|
|
+ 'REQUEST_METHOD' => $method,
|
|
|
+ 'CONTENT_TYPE' => 'application/json',
|
|
|
+ ],
|
|
|
+ 'input' => '{"title": "yay"}'
|
|
|
+ ]);
|
|
|
+ $response = new Response();
|
|
|
+ $next = function ($req, $res) {
|
|
|
+ $this->assertEquals(['title' => 'yay'], $req->getParsedBody());
|
|
|
+ };
|
|
|
+ $parser($request, $response, $next);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test parsing on ignored http method
|
|
|
+ *
|
|
|
+ * @dataProvider safeHttpMethodProvider
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testInvokeNoParseOnSafe($method)
|
|
|
+ {
|
|
|
+ $parser = new BodyParserMiddleware();
|
|
|
+
|
|
|
+ $request = new ServerRequest([
|
|
|
+ 'environment' => [
|
|
|
+ 'REQUEST_METHOD' => $method,
|
|
|
+ 'CONTENT_TYPE' => 'application/json',
|
|
|
+ ],
|
|
|
+ 'input' => '{"title": "yay"}'
|
|
|
+ ]);
|
|
|
+ $response = new Response();
|
|
|
+ $next = function ($req, $res) {
|
|
|
+ $this->assertEquals([], $req->getParsedBody());
|
|
|
+ };
|
|
|
+ $parser($request, $response, $next);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test parsing XML bodies.
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testInvokeXml()
|
|
|
+ {
|
|
|
+ $xml = <<<XML
|
|
|
+<?xml version="1.0" encoding="utf-8"?>
|
|
|
+<article>
|
|
|
+ <title>yay</title>
|
|
|
+</article>
|
|
|
+XML;
|
|
|
+
|
|
|
+ $request = new ServerRequest([
|
|
|
+ 'environment' => [
|
|
|
+ 'REQUEST_METHOD' => 'POST',
|
|
|
+ 'CONTENT_TYPE' => 'application/xml',
|
|
|
+ ],
|
|
|
+ 'input' => $xml
|
|
|
+ ]);
|
|
|
+ $response = new Response();
|
|
|
+ $next = function ($req, $res) {
|
|
|
+ $expected = [
|
|
|
+ 'article' => ['title' => 'yay']
|
|
|
+ ];
|
|
|
+ $this->assertEquals($expected, $req->getParsedBody());
|
|
|
+ };
|
|
|
+
|
|
|
+ $parser = new BodyParserMiddleware(['xml' => true]);
|
|
|
+ $parser($request, $response, $next);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test that CDATA is removed in XML data.
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testInvokeXmlCdata()
|
|
|
+ {
|
|
|
+ $xml = <<<XML
|
|
|
+<?xml version="1.0" encoding="utf-8"?>
|
|
|
+<article>
|
|
|
+ <id>1</id>
|
|
|
+ <title><![CDATA[first]]></title>
|
|
|
+</article>
|
|
|
+XML;
|
|
|
+ $request = new ServerRequest([
|
|
|
+ 'environment' => [
|
|
|
+ 'REQUEST_METHOD' => 'POST',
|
|
|
+ 'CONTENT_TYPE' => 'application/xml',
|
|
|
+ ],
|
|
|
+ 'input' => $xml
|
|
|
+ ]);
|
|
|
+ $response = new Response();
|
|
|
+ $next = function ($req, $res) {
|
|
|
+ $expected = [
|
|
|
+ 'article' => [
|
|
|
+ 'id' => 1,
|
|
|
+ 'title' => 'first'
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+ $this->assertEquals($expected, $req->getParsedBody());
|
|
|
+ };
|
|
|
+
|
|
|
+ $parser = new BodyParserMiddleware(['xml' => true]);
|
|
|
+ $parser($request, $response, $next);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test that internal entity recursion is ignored.
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testInvokeXmlInternalEntities()
|
|
|
+ {
|
|
|
+ $xml = <<<XML
|
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
|
+<!DOCTYPE item [
|
|
|
+ <!ENTITY item "item">
|
|
|
+ <!ENTITY item1 "&item;&item;&item;&item;&item;&item;">
|
|
|
+ <!ENTITY item2 "&item1;&item1;&item1;&item1;&item1;&item1;&item1;&item1;&item1;">
|
|
|
+ <!ENTITY item3 "&item2;&item2;&item2;&item2;&item2;&item2;&item2;&item2;&item2;">
|
|
|
+ <!ENTITY item4 "&item3;&item3;&item3;&item3;&item3;&item3;&item3;&item3;&item3;">
|
|
|
+ <!ENTITY item5 "&item4;&item4;&item4;&item4;&item4;&item4;&item4;&item4;&item4;">
|
|
|
+ <!ENTITY item6 "&item5;&item5;&item5;&item5;&item5;&item5;&item5;&item5;&item5;">
|
|
|
+ <!ENTITY item7 "&item6;&item6;&item6;&item6;&item6;&item6;&item6;&item6;&item6;">
|
|
|
+ <!ENTITY item8 "&item7;&item7;&item7;&item7;&item7;&item7;&item7;&item7;&item7;">
|
|
|
+]>
|
|
|
+<item>
|
|
|
+ <description>&item8;</description>
|
|
|
+</item>
|
|
|
+XML;
|
|
|
+ $request = new ServerRequest([
|
|
|
+ 'environment' => [
|
|
|
+ 'REQUEST_METHOD' => 'POST',
|
|
|
+ 'CONTENT_TYPE' => 'application/xml',
|
|
|
+ ],
|
|
|
+ 'input' => $xml
|
|
|
+ ]);
|
|
|
+ $response = new Response();
|
|
|
+ $next = function ($req, $res) {
|
|
|
+ $this->assertEquals([], $req->getParsedBody());
|
|
|
+ };
|
|
|
+
|
|
|
+ $parser = new BodyParserMiddleware(['xml' => true]);
|
|
|
+ $parser($request, $response, $next);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test parsing fails will raise a bad request.
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testInvokeParseNoArray()
|
|
|
+ {
|
|
|
+ $request = new ServerRequest([
|
|
|
+ 'environment' => [
|
|
|
+ 'REQUEST_METHOD' => 'POST',
|
|
|
+ 'CONTENT_TYPE' => 'application/json',
|
|
|
+ ],
|
|
|
+ 'input' => 'lol'
|
|
|
+ ]);
|
|
|
+ $response = new Response();
|
|
|
+ $next = function ($req, $res) {
|
|
|
+ };
|
|
|
+
|
|
|
+ $this->expectException(BadRequestException::class);
|
|
|
+ $parser = new BodyParserMiddleware();
|
|
|
+ $parser($request, $response, $next);
|
|
|
+ }
|
|
|
+}
|