forked from loafle/openapi-generator-original
[php-symfony] Fix problem with clients, that put charset in content type header. (#6078)
* Fix problem with clients, that put charset in content type header. With this fix header "Content-Type: application/json; charset=utf-8" working same as "Content-Type: application/json" for parse input data * Fix code style, add $consumes length check. * Add isContentTypeAllowed static method and tests * Fix old tests Right now serializer doesn't support anything beside json and xml. Call tests with application/json instead of form data. Co-authored-by: Yuriy Belenko <yura-bely@mail.ru>
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
namespace OpenAPI\Server\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use OpenAPI\Server\Service\SerializerInterface;
|
||||
@@ -186,4 +187,40 @@ class Controller extends AbstractController
|
||||
// If we reach this point, we don't have a common ground between server and client
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether Content-Type request header presented in supported formats.
|
||||
*
|
||||
* @param Request $request Request instance.
|
||||
* @param array $consumes Array of supported content types.
|
||||
*
|
||||
* @return bool Returns true if Content-Type supported otherwise false.
|
||||
*/
|
||||
public static function isContentTypeAllowed(Request $request, array $consumes = [])
|
||||
{
|
||||
if (!empty($consumes) && $consumes[0] !== '*/*') {
|
||||
$currentFormat = $request->getContentType();
|
||||
foreach ($consumes as $mimeType) {
|
||||
// canonize mime type
|
||||
if (is_string($mimeType) && false !== $pos = strpos($mimeType, ';')) {
|
||||
$mimeType = trim(substr($mimeType, 0, $pos));
|
||||
}
|
||||
|
||||
if (!$format = $request->getFormat($mimeType)) {
|
||||
// add custom format to request
|
||||
$format = $mimeType;
|
||||
$request->setFormat($format, $format);
|
||||
$currentFormat = $request->getContentType();
|
||||
}
|
||||
|
||||
if ($format === $currentFormat) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,7 @@ class PetController extends Controller
|
||||
{
|
||||
// Make sure that the client is providing something that we can consume
|
||||
$consumes = ['application/json', 'application/xml'];
|
||||
$inputFormat = $request->headers->has('Content-Type')?$request->headers->get('Content-Type'):$consumes[0];
|
||||
if (!in_array($inputFormat, $consumes)) {
|
||||
if (!static::isContentTypeAllowed($request, $consumes)) {
|
||||
// We can't consume the content that the client is sending us
|
||||
return new Response('', 415);
|
||||
}
|
||||
@@ -80,6 +79,7 @@ class PetController extends Controller
|
||||
|
||||
// Deserialize the input values that needs it
|
||||
try {
|
||||
$inputFormat = $request->getMimeType($request->getContentType());
|
||||
$body = $this->deserialize($body, 'OpenAPI\Server\Model\Pet', $inputFormat);
|
||||
} catch (SerializerRuntimeException $exception) {
|
||||
return $this->createBadRequestResponse($exception->getMessage());
|
||||
@@ -491,8 +491,7 @@ class PetController extends Controller
|
||||
{
|
||||
// Make sure that the client is providing something that we can consume
|
||||
$consumes = ['application/json', 'application/xml'];
|
||||
$inputFormat = $request->headers->has('Content-Type')?$request->headers->get('Content-Type'):$consumes[0];
|
||||
if (!in_array($inputFormat, $consumes)) {
|
||||
if (!static::isContentTypeAllowed($request, $consumes)) {
|
||||
// We can't consume the content that the client is sending us
|
||||
return new Response('', 415);
|
||||
}
|
||||
@@ -509,6 +508,7 @@ class PetController extends Controller
|
||||
|
||||
// Deserialize the input values that needs it
|
||||
try {
|
||||
$inputFormat = $request->getMimeType($request->getContentType());
|
||||
$body = $this->deserialize($body, 'OpenAPI\Server\Model\Pet', $inputFormat);
|
||||
} catch (SerializerRuntimeException $exception) {
|
||||
return $this->createBadRequestResponse($exception->getMessage());
|
||||
|
||||
@@ -284,8 +284,7 @@ class StoreController extends Controller
|
||||
{
|
||||
// Make sure that the client is providing something that we can consume
|
||||
$consumes = [];
|
||||
$inputFormat = $request->headers->has('Content-Type')?$request->headers->get('Content-Type'):$consumes[0];
|
||||
if (!in_array($inputFormat, $consumes)) {
|
||||
if (!static::isContentTypeAllowed($request, $consumes)) {
|
||||
// We can't consume the content that the client is sending us
|
||||
return new Response('', 415);
|
||||
}
|
||||
@@ -308,6 +307,7 @@ class StoreController extends Controller
|
||||
|
||||
// Deserialize the input values that needs it
|
||||
try {
|
||||
$inputFormat = $request->getMimeType($request->getContentType());
|
||||
$body = $this->deserialize($body, 'OpenAPI\Server\Model\Order', $inputFormat);
|
||||
} catch (SerializerRuntimeException $exception) {
|
||||
return $this->createBadRequestResponse($exception->getMessage());
|
||||
|
||||
@@ -61,8 +61,7 @@ class UserController extends Controller
|
||||
{
|
||||
// Make sure that the client is providing something that we can consume
|
||||
$consumes = [];
|
||||
$inputFormat = $request->headers->has('Content-Type')?$request->headers->get('Content-Type'):$consumes[0];
|
||||
if (!in_array($inputFormat, $consumes)) {
|
||||
if (!static::isContentTypeAllowed($request, $consumes)) {
|
||||
// We can't consume the content that the client is sending us
|
||||
return new Response('', 415);
|
||||
}
|
||||
@@ -76,6 +75,7 @@ class UserController extends Controller
|
||||
|
||||
// Deserialize the input values that needs it
|
||||
try {
|
||||
$inputFormat = $request->getMimeType($request->getContentType());
|
||||
$body = $this->deserialize($body, 'OpenAPI\Server\Model\User', $inputFormat);
|
||||
} catch (SerializerRuntimeException $exception) {
|
||||
return $this->createBadRequestResponse($exception->getMessage());
|
||||
@@ -138,8 +138,7 @@ class UserController extends Controller
|
||||
{
|
||||
// Make sure that the client is providing something that we can consume
|
||||
$consumes = [];
|
||||
$inputFormat = $request->headers->has('Content-Type')?$request->headers->get('Content-Type'):$consumes[0];
|
||||
if (!in_array($inputFormat, $consumes)) {
|
||||
if (!static::isContentTypeAllowed($request, $consumes)) {
|
||||
// We can't consume the content that the client is sending us
|
||||
return new Response('', 415);
|
||||
}
|
||||
@@ -153,6 +152,7 @@ class UserController extends Controller
|
||||
|
||||
// Deserialize the input values that needs it
|
||||
try {
|
||||
$inputFormat = $request->getMimeType($request->getContentType());
|
||||
$body = $this->deserialize($body, 'array<OpenAPI\Server\Model\User>', $inputFormat);
|
||||
} catch (SerializerRuntimeException $exception) {
|
||||
return $this->createBadRequestResponse($exception->getMessage());
|
||||
@@ -217,8 +217,7 @@ class UserController extends Controller
|
||||
{
|
||||
// Make sure that the client is providing something that we can consume
|
||||
$consumes = [];
|
||||
$inputFormat = $request->headers->has('Content-Type')?$request->headers->get('Content-Type'):$consumes[0];
|
||||
if (!in_array($inputFormat, $consumes)) {
|
||||
if (!static::isContentTypeAllowed($request, $consumes)) {
|
||||
// We can't consume the content that the client is sending us
|
||||
return new Response('', 415);
|
||||
}
|
||||
@@ -232,6 +231,7 @@ class UserController extends Controller
|
||||
|
||||
// Deserialize the input values that needs it
|
||||
try {
|
||||
$inputFormat = $request->getMimeType($request->getContentType());
|
||||
$body = $this->deserialize($body, 'array<OpenAPI\Server\Model\User>', $inputFormat);
|
||||
} catch (SerializerRuntimeException $exception) {
|
||||
return $this->createBadRequestResponse($exception->getMessage());
|
||||
@@ -592,8 +592,7 @@ class UserController extends Controller
|
||||
{
|
||||
// Make sure that the client is providing something that we can consume
|
||||
$consumes = [];
|
||||
$inputFormat = $request->headers->has('Content-Type')?$request->headers->get('Content-Type'):$consumes[0];
|
||||
if (!in_array($inputFormat, $consumes)) {
|
||||
if (!static::isContentTypeAllowed($request, $consumes)) {
|
||||
// We can't consume the content that the client is sending us
|
||||
return new Response('', 415);
|
||||
}
|
||||
@@ -608,6 +607,7 @@ class UserController extends Controller
|
||||
// Deserialize the input values that needs it
|
||||
try {
|
||||
$username = $this->deserialize($username, 'string', 'string');
|
||||
$inputFormat = $request->getMimeType($request->getContentType());
|
||||
$body = $this->deserialize($body, 'OpenAPI\Server\Model\User', $inputFormat);
|
||||
} catch (SerializerRuntimeException $exception) {
|
||||
return $this->createBadRequestResponse($exception->getMessage());
|
||||
|
||||
@@ -85,7 +85,7 @@ class PetApiInterfaceTest extends WebTestCase
|
||||
|
||||
$path = '/pet';
|
||||
|
||||
$crawler = $client->request('POST', $path);
|
||||
$crawler = $client->request('POST', $path, [], [], ['CONTENT_TYPE' => 'application/json']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,7 +166,7 @@ class PetApiInterfaceTest extends WebTestCase
|
||||
|
||||
$path = '/pet';
|
||||
|
||||
$crawler = $client->request('PUT', $path);
|
||||
$crawler = $client->request('PUT', $path, [], [], ['CONTENT_TYPE' => 'application/json']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -136,7 +136,7 @@ class StoreApiInterfaceTest extends WebTestCase
|
||||
|
||||
$path = '/store/order';
|
||||
|
||||
$crawler = $client->request('POST', $path);
|
||||
$crawler = $client->request('POST', $path, [], [], ['CONTENT_TYPE' => 'application/json']);
|
||||
}
|
||||
|
||||
protected function genTestData($regexp)
|
||||
|
||||
@@ -85,7 +85,7 @@ class UserApiInterfaceTest extends WebTestCase
|
||||
|
||||
$path = '/user';
|
||||
|
||||
$crawler = $client->request('POST', $path);
|
||||
$crawler = $client->request('POST', $path, [], [], ['CONTENT_TYPE' => 'application/json']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +100,7 @@ class UserApiInterfaceTest extends WebTestCase
|
||||
|
||||
$path = '/user/createWithArray';
|
||||
|
||||
$crawler = $client->request('POST', $path);
|
||||
$crawler = $client->request('POST', $path, [], [], ['CONTENT_TYPE' => 'application/json']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,7 +115,7 @@ class UserApiInterfaceTest extends WebTestCase
|
||||
|
||||
$path = '/user/createWithList';
|
||||
|
||||
$crawler = $client->request('POST', $path);
|
||||
$crawler = $client->request('POST', $path, [], [], ['CONTENT_TYPE' => 'application/json']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,7 +199,7 @@ class UserApiInterfaceTest extends WebTestCase
|
||||
$data = $this->genTestData('[a-z0-9]+');
|
||||
$path = str_replace($pattern, $data, $path);
|
||||
|
||||
$crawler = $client->request('PUT', $path);
|
||||
$crawler = $client->request('PUT', $path, [], [], ['CONTENT_TYPE' => 'application/json']);
|
||||
}
|
||||
|
||||
protected function genTestData($regexp)
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* ControllerTest
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Class
|
||||
* @package OpenAPI\Server\Tests\Controller
|
||||
* @author openapi-generator contributors
|
||||
* @link https://github.com/openapitools/openapi-generator
|
||||
*/
|
||||
|
||||
/**
|
||||
* OpenAPI Petstore
|
||||
*
|
||||
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
*
|
||||
* Generated by: https://github.com/openapitools/openapi-generator.git
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* NOTE: This class is auto generated by the openapi generator program.
|
||||
* https://github.com/openapitools/openapi-generator
|
||||
* Please update the test case below to test the endpoint.
|
||||
*/
|
||||
|
||||
namespace OpenAPI\Server\Tests\Controller;
|
||||
|
||||
use OpenAPI\Server\Controller\Controller;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* ControllerTest Class Doc Comment
|
||||
*
|
||||
* @category Class
|
||||
* @package OpenAPI\Server\Tests\Controller
|
||||
* @author openapi-generator contributors
|
||||
* @link https://github.com/openapitools/openapi-generator
|
||||
* @coversDefaultClass \OpenAPI\Server\Controller\Controller
|
||||
*/
|
||||
class ControllerTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* Tests isContentTypeAllowed static method.
|
||||
*
|
||||
* @param string $contentType
|
||||
* @param array $consumes
|
||||
* @param bool $expectedReturn
|
||||
*
|
||||
* @covers ::isContentTypeAllowed
|
||||
* @dataProvider provideArgumentsForIsContentTypeAllowed
|
||||
*/
|
||||
public function testIsContentTypeAllowed($contentType, array $consumes, $expectedReturn)
|
||||
{
|
||||
$request = new Request();
|
||||
$request->headers->set('CONTENT_TYPE', $contentType, true);// last one argument overrides header
|
||||
$this->assertSame(
|
||||
$expectedReturn,
|
||||
Controller::isContentTypeAllowed($request, $consumes),
|
||||
sprintf(
|
||||
'Failed assertion that "Content-Type: %s" %s by [%s] consumes array.',
|
||||
$contentType,
|
||||
($expectedReturn) ? 'is allowed' : 'is forbidden',
|
||||
implode(', ', $consumes)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function provideArgumentsForIsContentTypeAllowed()
|
||||
{
|
||||
return [
|
||||
'usual JSON content type' => [
|
||||
'application/json',
|
||||
['application/json'],
|
||||
true,
|
||||
],
|
||||
'extended content type from PR #6078' => [
|
||||
'application/json; charset=utf-8',
|
||||
['application/json'],
|
||||
true,
|
||||
],
|
||||
'more than one content types' => [
|
||||
'application/json',
|
||||
['application/xml', 'application/json; charset=utf-8'],
|
||||
true,
|
||||
],
|
||||
'empty consumes array' => [
|
||||
'application/json',
|
||||
[],
|
||||
true,
|
||||
],
|
||||
'empty consumes and content type' => [
|
||||
null,
|
||||
[],
|
||||
true,
|
||||
],
|
||||
'consumes everything' => [
|
||||
'application/json',
|
||||
['*/*'],
|
||||
true,
|
||||
],
|
||||
'fancy custom content type' => [
|
||||
'foobar/foobaz',
|
||||
['application/xml', 'foobar/foobaz; charset=utf-8'],
|
||||
true,
|
||||
],
|
||||
'empty content type' => [
|
||||
null,
|
||||
['application/xml', 'application/json; charset=utf-8'],
|
||||
false,
|
||||
],
|
||||
'content type out of consumes' => [
|
||||
'text/html',
|
||||
['application/xml', 'application/json; charset=utf-8'],
|
||||
false,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,14 @@
|
||||
<testsuite>
|
||||
<directory>./Tests/Api</directory>
|
||||
<directory>./Tests/Model</directory>
|
||||
<directory>./Tests/Controller</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">././Api</directory>
|
||||
<directory suffix=".php">././Model</directory>
|
||||
<directory suffix=".php">././Controller</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<php>
|
||||
|
||||
Reference in New Issue
Block a user